Postmortem and inspirations
10 day marathon is over. NUKEHECK is playable for the next month (maybe more, server needs money to stay up, if strangest.io includes us in their bundle maybe they can host the servers, maybe you can donate to keep the lights on, anyway..) Lets talk about how things went.
Juice and Aesthetic
It all started early-mid august when Ash first heard about the jam. Was working on a godot juice system and thought why the hell not, it's done, might as well use it. It is mostly responsible for the overlay effects, shattering screen and camera movement. Currently selling it on my itch page. Features 3 types of shake (slap, shiver and breathing), shattering the screen, an inverting shader, the noisy version of my old color crunching overlay (in this game it transforms full color badphotoshop images into pico8 palette ones) also had a barebones implementation of persistent decals. For use with the game it was seriously improved and reworked throughout the jam transforming it to the point where it is barely recognizable.
The aesthetic inspirations for the game came from various places. It's got a bit of cruelty squad, its themes and its assault on the senses. A bit of POST VOID vibes.
A big part of NUKEHECKs visual side was inspired by games from sonoshee who makes extensive use of crunched color palettes and intense shaders like nothing you have seen before.
A more deliberate inspiration was Enter the Void, its opening credits specifically which were adapted into many of our effects for getting upgrades & taking damage as well as our own opening credits where the intensity was cranked up even further and condensed to a shorter period of time.
The last two were brought to our attention by droqen after ash mentioned wanting to inflict sensory damage upon players for fun and profit. Big thanks to the paradise discord and its wonderful residents!
The creative commons music album Thunderdoom was also a big influence on the project as it was found early in development and it hit all the vibes we was looking for for the arena side of the game. It is loud, intense, full of energy and doesnt care about your eardrums. In short, it was everything we wanted and it was free, even with commercial use! God bless these guys. Ended up chopping the songs into 90 second pieces to fit the maximum round length and avoid weird transitions in the middle of the action. (btw, the text flashing on top of a dog image in the itntro is listing all of the musicians who worked on the album in a stylized manner)
For the crater camp side of the game we used some creative commons sounds of nature, campfires and an oppressive low pitch melodic drone. You can only hear it with decent headphones but it adds a lot to the atmosphere. Some of the ambient sounds in the "flashing lights warning" part of the opening are from a fridge and a microwave. Really wanted the game to have an unusual soundscape right from the strart. This project really taught me a lot about sound design for games and helped me develop a certain style, hope it will be noticable in the future projects!
A big part of the game is non stop full auto shooting. Didnt want the shooting sounds to overpower the soundscape and drown out everything else. At the same time making them quiet or weak was not a compromise we were willing to make. Ended up starting them out somewhat loud and then making them quieter with every shot while they appoach a stable quieter volume. After you cease shooting for a short while the volume resets to default levels, making the first shot after a break always feel powerful. Identical system is used for the soul receiving sounds for the same reason. We were not ready to play as many as 60 sounds per second at full volume.
Most sounds in the game are from freesound org. Some of them, like the generic functional sound of enemies dying (not the long screams and screeches, those are from freesound) is me blowing air through my teeth. Some others like the chanting of the soulstone (kinda hidden by the music in the final version) are a lot more silly in origin. It's a reversed, distorted, reverbed and pitched down reading of the CBT from Wikipedia copypasta.
Most objects in the world are assembled out of free stock images from pexels and wikimedia commons. when combined with a limited color palette and a small resolutions all the rough edges in my assemblages become imperceivable. Others are simply squares, circles and triangles.
- 2 different craters overlaid on top of each other. one had a pretty outside, the other - a pretty inside
- a pic of a truck
- some tent pictures
- image of a campfire with 3 images of flames of different shapes and colors jumping around it
- some pulsating blurry circles to imitate the lighting from the flame
- track prints in the sand that were squashed and duplicated many times over to imitate tire prints
- single pic of a barbed wire fence that was stretched and deformed using a polygon to form the perimeter of the crater
- grocery bag
- crab legs
- white pool ball
- brain material render
- raw steak
- cube of procedural brain material
- colorful bath foam
- souls of the damned
- weirdo bones in flesh material render (mirrored in both directions)
- very thin leaves (for their veins)
- Upgrade stations:
- scifi looking "help needed" button ( text edited to say "HELL" (because these stations upgrade the enemies you fight) )
- various antenas and their bases
- scifi helmet with person still inside
- speed gun
The animations on the players are realised by having visual parts of the body lerp towards their target points. This allows us to quickly and easily change animations and hand positions in response to actions or lack thereof. This approach and player character were inspired by a tutorial hacktrout posted on twitter a while ago. The body tilt and squash are based on speed and acceleration, so are the dust puffs when you change direction. The eyes are animated in code using trig functions and are made invisible when they are on the back side of the head.
Having more than one head and a small train of spare ones following you was an idea that Linn came up with while we were brainstorming ideas for how to display HP. At that time the collected souls were already being displayed circling the player. Quite enjoyed this type of display: in the world, easy to read at a glance and lacking text or numbers. As a bonus for the head health system - we added an ability to live without a head with impaired aim and camera shaking wildly around the screen. This was done because not having a head and still going is inherently fun and rad while also giving you a chance to run up to a heal station for a satisfying comeback. In multiplayer after you loose all your heads and get killed - you turn into a ghost standing in a pentagram. Other players can res you using their souls because waiting for your pals to die is not fun and also because it feels good to help and be helped. (also supports a major design pillar, explained below)
A small detail you probably didnt notice in the middle of the battle is that the arena is made out of flesh and has a pulse. Pulse gets faster as you fight, going from 60 to 180 bpm before the song ends and you are kicked out. It deforms the texture of the arena within a mask so that the edges remain stationary while the middle shifts slightly. The blood splatter from the enemies uses the same shader and exactly the same parameters, so as a result - both deform in unison making it look like the blood is stuck to the surface! This was inspired by a much simpler pixelart tile based version of this concept that droqen shared not too long ago.
The decision to make it multiplayer was a consequence of the jam being sponsored by multiplayer framework guys and an extra prize for best multiplayer game. Neither me nor Maks have ever done anything like it so this was a pretty intense learning experience. First couple days of the jam Maks spent figuring it out and setting things up while Ash was refining games design and drawing diagrams to illustrate it. Rami Ismail's recent post about a layered look at a game helped a lot. After the basics were set up we just developed the game part by part, me making the user facing stuff and pretty bits while Maks worked hard behind the scenes to make sure that it all played together nicely and yall could actually experience it as intended. Wanna clarify that this would not be possible without him.
(TxP refers to Tormentor x Punisher, a top down shooter designed by Joonas Turner where to upgrade yourself you have to do trick kills (set bullets on fire first, ricochet off a wall, infuse with enemy lightning bolt projectile, etc.). These are never explained outright but are easy to discover and result in the game being very satisfying to master. Ended up being too hard for a jam, was replaced by the mechanic of spending souls dropped by enemies on upgrades early in developent to encourage cooperation and the theme of collecting a resource in a hostile environment )
As you can see in the design sketches, the tone of the game was originally inspired by deeprock galactic: group of equals with tight emotional bonds working in a dangerous environment, extracting a precious and hard to acquire resource. Then it kind of evolved into the whole "power a nuke with souls from hell". Like that change, makes killing enemies and gathering the resources sides of gameplay loop tightly connected. The main goal was to make an online game where you work towards a greater goal and help others. We also didnt want any vandalism or negative relations between players besides light hearted rivalry about who is capable of getting the biggest haul of souls. Think we succeeded with both of those. Knew that the game would not have a huge playerbase so the players should be encouraged to cooperate where possible and stick together. More players in the arena at the same time should always be more fun and profitable. Because of that we do not split the souls thrown at the soulstone and instead give everyone the entire amount. The upgrade buildings also affect everyone in the arena, players can resurrect each other to keep going allowing them to be more risky, and are also able to divide their tasks (someone on the team doesn't shoot much and collects+deposits souls most of the time). Believe that all of these together resulted in a strong "the more the merrier" vibe which is exactly what we wanted!
(players working toward a common goal with elements of asynchronous multiplayer. Was this a strand type game all along?)
(shards were meant to be the currency available inside hub before Maks said "why do we need a 1 to 1 conversion between souls and shards, it's not like theres a reason for it, just give em souls in the lobby" and couldnt argue with that logic + an excuse to do less work for the same result)
(boarding refers to the hellevator/dropship, before it was implemented Maks suggested replacing it with saying stuff inside of a pentagram which was WAY cooler and also didnt require us to add code for an "interract key" that would only be used in this one spot as talking was already implemented and easy to detect)
I kind of fucked up with the mechanic where players can't suck in souls while they are shooting. Most don't read description with controls because first thing people want to do is play the game, not read a manual (don't blame them, am like that myself). Should've added an in game tutorial that explains it. Luckily the game is somewhat fun even without realizing that, and in a couple games people eventually figure it out and open a whole new world of upgrades and stuff for themselves!
The original idea was that players would be able to slowly unlock all the different upgrades in the hub - expanding the possibility space for themselves and everyone else. Due to time constraints we only left the nuke in the hub. It still provides people with a common goal to contribute to without leaving them locked away from upgrades.
Rounds are limited to be only 90 seconds long, this is kind of inspired by the ubermosh series(notice the large text displaying seconds left in the top left of screenshot). Some upgrades can be taken multiple times in a single round resulting in some weird combos that might make you somewhat unkillable (or make the onslaught of enemies impossible to keep at bay), this ensures that you cant fuck things up long term, encourages experimentation cuz stakes are low, and makes fast and reckless playstyles significantly more effective than slow and reasonable ones. It also means that after you are able to survive for the entire duration of the round you have a new challenge - kill more enemies and get more souls in the same amount of time. How do you do that? Simple! Enemies come when most of the last wave is killed so you can just kill them faster. Alternatively you can spend some of their souls to make the waves more intense and enemies much more numerous while also increasing the amount of souls they drop. Aint nothing like some good ol' risk & reward. It's great when the optimal approach to a game results in the most fun gameplay. In our case - if you want a high score you need to make the enemies more difficult on purpose, make yourself more powerful but at the same time not spend all your souls doing that, bring a friend and disregard your own safety as survival past the first 90 seconds does not matter.
Multiplayer and technical side
Engine of our choice - Godot supports multiplayer, but it still takes a lot of work to make it work.
First of all our main export target is HTML5, so that limits our protocol choices to WebSocket and WebRTC.
We actually had to use both, because WebRTC requires a signaling server make a connection and the only way to connect to it is to use WebSocket.
I took code of an example for WebRTC lobbies from the godot-demos repository, and it did almost everything we needed to connect players.
Players want to play they request to be connected to a certain lobby, if lobby exists they negotiate a connection though a signaling server with the other players and the host.
In case if lobby doesn't exist, they become the host, except for the hub, in that case they go to the offline mode. Also if the player looses connection to the signaling server, they go offline too.
But that's not all, because after the players are connected we need to sync the state. We made a mistake of building our code from the roof to the ground, because we first had a single-player version and then trying to make it multiplayer, NEVER EVER DO THIS. Anyway how are we going to do this? Godot support RPC(remote procedure call), essentially it calls functions over network, and we can try to use it as is, but if user is offline it starts spewing errors, plus syncing positions 60 times a second is not necessary. So Maks came up with a centralized solution make a Singleton responsible for updating game state. It has a concept of an events and states. (Singletons are great, lost of stuff in this game besides the multiplayer use them as well: camera effects, getting upgrade prices from a server, the upgrades to your & enemies stats after buying an upgrade) Object can declare that it wants it's state to be polled, in that case singleton calls get_state and tries to update it remotely using set_state, this happens 30 times a second on a centralized timer. Object can declare itself as an event giver, in that case it can request to directly and reliably call a function remotely. The engine automatically verifies that only the owner of the object can perform rpc. Also there's a bonus feature called starting state, if object says that it has a starting state, any joining player will get a copy of the state, it is used in buildings, because they send their state on join and then send it again when soul count updates.
So after trying to make single player code work in multiplayer and testing it, a day before the dead line Maks decided to test launching a HUB server. And it appears that server builds have some kind of a bug regarding networking, one other person a year ago tried reporting it but contributors could not reproduce it, I'll report it a when I'll have some free time. After this we decided that Ash is going to host the server for a couple of days on their computer.
6 hours before the deadline, we decide to get one more friend to test, they ask if we can provide a browser version, of course we say yes, and after exporting and putting it on itch.io they say it doesn't connect. After looking into the dev console we found out that since itch.io is a https website, unsecured WebSocket connections are not allowed. OH NO... that requires an SSL certificate. Thought maybe a self signed certificate will do, but those are not excepted, unless you go to a website that uses it and click "Let me see the website anyway" manually, but this was at least something. After a few hours of looking for information how to get a valid certificate, decided to actually do it, and it was a glorious success. After spending a miserable hour trying to make the server and the game use the safe version of the protocol.
After all that we released the game, twice, because it was in the middle of the night and we broke some piece of code. Also windows version became borked because we forgot to tell the engine to export json files.
Actually there was an interesting development, Maks wanted to patch the engine to make the server build work, but first decided to compile it as is and test again, and after the compilation from source it worked like charm.
Also Maks made a custom client that tries to connect to the hub and reports the result twice every hour into a telegram channel which is publicly available for everyone to see and for me to react.
(project name was originally coxplode and is still referred to as such in game files. Is a more intense and vulgar play on the name of our first big project Boomchick (chick - cock, boom - xplode), was originally meant to recreate an earlier version of that games vision that was an arena platformer-shooter in a more visceral style. things didn't exactly go as planned)
It was a very interesting experience and we learned a lot from it!
P.S. A cool design side technical thing we implemented here for the first time was reading a balancing json hosted online. When the arena loads it requests a file from a github pages site with the prices for all upgrades and if it gets a valid response - it replaces them with what it got. Very good for balancing the game post release without compiling and uploading new builds leading to all sorts of fun problems with players on different versions desyncing.
(a = arena, u = unlock, unlock is unused at the moment because we decided to have everything unlocked)
thx to Lintilion for proofreading :)
if you got any questions that post mortem didnt answer - ask them in the comments, ill answer them as soon as i see em
Leave a comment
Log in with itch.io to leave a comment.