cerno-b

Ludum Dare 50

uh-oh

Animation3.gif 51qZvK-zdIL.em_AC/emSX300emSY300/emQL70emML2/em.jpg

Some juice for breakfast

I know I have much more pressing matters to attend to, but I wanted to have a little fun before starting the day, so I added some particles, camera movement and sweet screenshake. Will still need some tuning, but I'm really happy with Godot's built-in camera and particle mechanisms!

Animation4.gif

Let's dance

All weapon systems are in place, lots of balancing to do. Graphics are not final, particle effects missing, but this was one of my biggest obstacles, I'm regaining confidence that this could become something coherent.

Animation5.gif

It's coming together...

I'm getting there... The game is running a full cycle from start to game over now.

Really need to start composing soon and then off for tweaking, balancing and artwork improvements. Might become a close call... again.

Animation6_small.gif

Music done

I't a bit rougher than I had in mind, maybe I'll have some time for fine-tuning in the end.

https://soundcloud.com/cerno_b/the-inevitable-v0

2022-04-03em20h39/em32.png

Paranoia

I always get paranoid around this time in the Compo. The submission hour is counted on top of the current countdown, right?

So 2:15 hours (the current countdown) from now + 1 hour for packing up and uploading?

Eternal Crisis has an HTML5 port

After some hiccups with sound delay, I was able to get my game running in HTML5.

Animation8.gif

Eternal Crisis

Fullscreen should still work and is strongly advised. I'd be happy if someone could give me some quick feedback whether this works for you, it's my first HTML5 export for LD.

Service Announcement: Remember to write your Post-Mortems

In case you wanted to write a post-mortem, I would recommond to start taking down notes while the memory is still fresh.

Writing a post-mortem analysis of your game design journey is a great way to remember how the competition went for you so you can revisit problems in advance next time you participate. It is also a very helpful document for other people to learn from your successes and mistakes.

As a nice side-effect, it attracts more eyes to your game as some find information about other people's design process particularly interesting.

So, let me encourage you to share your journey with the rest of us.

And if you want to, you can play my game Eternal Crisis.

Post-Mortem: Eternal Crisis

Looking through all the screeshots I made for my timelapse video, I was able to recreate a pretty detailed Post Mortem of the design process, in case anyone is interested. Danger, wall of text ahead!

Preparation

It's always good to set some goals before Ludum Dare, so I started out with a few plans beforehand:

  • Make something with really good mood and create a fitting orchestral soundtrack
  • Move away from GameMaker Studio and learn to make a game with Godot instead.

I expected the engine switch to be quite a big challenge so I did not set any other goals.

After my previous Ludum Dare 43 entry The Omicron Fleet had been quite successful (my first bronze medal and top 10 game!), I was a bit apprehensive because I thought I had to live up to that success. However, I forced myself to focus on the process instead of the outcome because I don't deal with that kind of pressure well.

As always, it is important to make sure in advance that all the tools work and everything is properly set up. I had played around with Godot a few weeks before the competition, so I wouldn't have to start at zero. I also set up Reaper with Miroslav Philharmonic and my MIDI keyboard since I very often run into hardware trouble just when I am ready to go.

I usually do a mental exercise and pick one of the theme finalists to think about the kind of game I would make out of it, but this time I didn't really find one that I was excited about. However, after a lot of people wanted Folklore to win, I thought that would give me a lot of freedom in terms of game mechanics and focus on making something with good atmosphere.

Day 1

7:00

I make it a rule to follow a normal sleep schedule in order to have a rested brain, so I started my day at 7:00 after the theme was already announced for a few hours. Turned out it was Delay the inevitable.

It's usually a good idea to make a list of all the ideas that come to mind and cross out the most obvious ones. This reduces the chance of making something that ten other people have also made. This time, I really struggled at that stage. With the pandemic on the way out, the war in Ukraine currently going on and the effects of climate change on the horizon, I didn't really feel like making a game where the inevitable would be war, death or the downfall of civilization. That would have been way too depressing.

One idea I played around with was a story-driven adventure game of a mouse who lives a peaceful life in a human house when suddenly a fire breaks out so the mouse has to help the human family escape. The inevitable would be the house being completely burned down, so there would be a positive outcome in the story because the family would be safe. I didn't go through with it because I felt intimidated by all the assets I would have to draw and I also didn't feel I could invent a sufficient number of interesting puzzles that went beyond "nibble this rope", "unblock that path", "find a hidden escape route". Being a regular mouse is fairly limiting after all.

So after over two hours of wracking my brain, I did something that I usually try to avoid: Go the path of the least resistance. I've always wanted to do an homage to one of my favorite SHMUPs - Warning Forever - and the concept of playing against a timer that would eventually run out fit the theme quite well. I wasn't going to win any innovation prizes but at least I wouldn't have to worry about learning a new engine and developing interesting game mechanics from scratch.

10:30

All this planning took way longer than usual, so when I finally fired up my PC, I had already lost more than three hours.

Warning Forever is a game where you have to battle increasingly difficult bosses that are made up of randomly assembled parts, which not only makes each battle unique, but allows for organically ramping up the difficulty by adding more and more parts to the boss. I realized that I could represent the boss parts as trees from graph theory.

So I started to draw the building blocks: Center piece, line piece, split piece and gun piece. Now I had to write some code that would enable me to randomly put these parts together. It didn't take long to realize how little I really knew about Godot after all, and I had to constantly look stuff up. I mean, really basic stuff, like how to convert degrees to radians without having to write down the formula all the time?, or how to spawn instances of a node?. This would become a theme for this LD and I think my timelapse video will probably be pretty boring because I spend most of my time in the code editor or googling stuff.

00_parts.png

When I tried to align the pieces and rotate them, I realized that Godot doesn't like rotating around single pixels in pixel-perfect mode, likely because the float pixel coordinates are not centered, but aligned with the edge of a pixel. Apparently I should not use sprites with an uneven size. Fortunately I realized this early on and adapted my sprites accordingly before it would break something later on.

In order to randomly create the boss, I thought about a simple data structure that allowed me to create the definition of the boss without actually having to create actual game elements. This decision would later pay off towards the end of the project. I wrote a simple function to randomize these structures without worrying too much about overlapping parts, I would fix those later (spoiler: I didn't).

01_randomize.gif

15:00

After a small break, I drew a placeholder spaceship, but as these things go, it would end up as the final design. I added player control and shots which again took a lot of googling until I found out how angles work in Godot. One reason everything was taking so long was that I wanted to find "good" solutions for my problems, so once I found something that worked, but seemed a little more hacky than it had any right to be, I kept looking for a potentially better solution. I know a game jam is not the place to write nice code, but I didn't want to start off with a new engine and fall into bad habits right away.

18:00

Now that things were moving along, I had to nail down one of the core concepts of Warning Forever: You could either shoot off a part at the end of the ship, or you could shoot off a whole branch. However, the longer the branch, the more damage you would have to deal in order to get rid of the thing. This should be implemented in a way that would promote damage down the line when an inner block was attacked, so that each individual block would get partially damaged as well. Also shooting off a branch should be slightly faster than shooting off the individual parts one by one to reward the player for this more risky strategy.

This was one of the moments where I was really glad to make this game in Godot, since GameMaker is notorious for its ugly data structure handling and honestly it would have been a nightmare.

19:30

With the damage model now in place, it was time for dinner (I skipped lunch because I had prepared a lot of snacks before the event).

20:30

Next were the boss's attacks. I wanted lasers that fire in the player's direction, a shotgun to fill a larger area with projectiles, a death ray that would cover the whole screen but would be telegraphed so the player could prepare, and heat-seeking missiles that followed the player but could be shot down. I had some more ideas but ended up scrapping them as I didn't want to overscope.

In order for the guns to track the player, I had to have the gun sprites trained on the player's position, but I wanted the gun towers to rotate at different speeds, so I had to change their angles incrementally. This caused me a headache because I introduced a bug that caused a gun to not take the shortest route towards the player, but do a full turn in the opposite direction instead. Angles are weird that way and I was already getting tired. I had spent way too long on this problem, so I decided to postpone this, and think about it with a fresh head the next day.

22:00

I used the remaining time till bedtime by starting on the logic for the different shots. After the first iteration of the laser shots worked now, I was getting a bit frustrated at my slow progress and the open rotation bug, but thought it would be wiser to go to bed, especially since I wanted to keep a proper sleeping schedule for the first day. So I went to bed...

02emfirst/emlaser.png

...and about five minutes after I had laid down, the solution to the rotation bug fell into my head. Funny how the brain works.

Day 2

7:00

The first thing I did when I woke up was to reconsider whether the bug fix in my head would actually work, and I could see no reason why not. I took a shower, which usually helps me gather my thoughts and I started humming a few tunes when I stumbled upon a melody that I could actually use. Knowing how my brain is really bad at remembering music, I recorded the tune with my phone for later use.

7:30

I implemented the bugfix and it really worked. Nice.

I knew that I had a lot on my plate, but I was in a playful mood so I decided to juice up what I had so far. I added a camera, which was surprisingly easy in Godot including smooth motion and handling screen limits. I also stole a few lines of code off the internet to create a camera shake system. Then I played around with Godot's particle generator to create some explosions, which worked really well. In less than an hour I had both systems in place.

9:00

Time for breakfast. I decided that it would be a good idea to write an open points list for my remaining tasks and conservatively estimate how long each step would take. To my delight I would only take about an hour longer than the deadline, so my estimate wasn't too far off from the time I had left.

10:00

Next, I added the missing weapons systems. Death Ray, Shotgun, Rockets. It was amazing seeing the rockets fly around and explode with a satisfying screen shake when I shot them. This was surprisingly smooth sailing. It felt like I was slowly starting to stand on my own two legs with Godot. In order to give the player a better grasp on what was happening I designed different sprites for the different gun systems.

03_rockets.gif

11:30

One core aspect of the game was the timer. I browsed online for some fonts and found some free ones that I really liked, but the license was not 100% clear so I wrote to the author hoping that he would answer before the deadline... And he totally did. Shoutout to http://www.imagex-fonts.com who let me use his fonts for free until the day I take this game to a commercial level (likely never).

12:30

I wanted to get rid of the bland background next. I had made a space game in the past and usually I just use the spraypaint tool and fill a black screen with differently colored pixels. I wanted to do it better this time and found this amazing tutorial by Slynyrd:

04_space.gif

I used his brushes with my old spraypaint technique. The final result is not as artistic as the tutorial example, but it is way better than any of my previous attempts at drawing space.

05_background.png

13:30

So far my game now was almost a complete vertical slice, with the all the mechanics in place, and it was time to go horizontal: Make the game playable from start to finish, which would include the boss approaching from off screen, handling what happens when the boss or the player dies until the game over screen and a retry option.

I needed to implement a state machine for that, and as far as I know there is no such thing baked into Godot, as I assume these things are better written from scratch. Fortunately I had some experience with state machines from my LD37 entry Henry Snackleworth's Weird Day, so it worked fairly well.

This was a pretty intense session where I added a lot of small touches as they became necessary. Player invincibility, text popup that informs the player when time is added or deducted, etc.

17:00

It was now time for something I had been putting off for a while now. Music is usually something that stumps me in Ludum Dare. I start out highly motivated and five minutes later I realize I have no idea what I am actually doing. I used to write simple chiptunes with Bosca Ceoil for Ludum Dare, even if I had set my sights on something more orchestral and epic. Although I had managed to pull off an orchestral score in Ludum Dare before, it has always given me trouble and I have never been happy with the results.

This time though I had a melody ready and I was feeling confident that three years after my last attempt at composing something for orchestra, I would have learned some additional skills that would make this easier, right? Right?

Well, no.

It was the same struggle as every time and instead of approaching this in a structured way, I fell back to the old desperately poking around different instruments and melody lines until something half-presentable came out.

Out of my originally planned two hours for music I took more than three. Good that I had written the schedule, so I realized this and could force myself to stop before sinking even more time into composition.

20:30

In contrast to music, creating the sound effects was smooth sailing. I returned to my tried-and-true method of using Chiptone to create all my sounds. One of these days I would like to try and record my own foley for Ludum Dare, but that would have to be a very small game as the recording would probably take so much time.

22:00

I drew a title and end game screen and decided on a name for the game. A fitting name for an homage to Warning Forever would be Infinite Danger. A quick google search revealed that not only did someone else already have that idea, they also made a Warning Forever clone with that name. Okay, so I tried a few alternatives and landed on the current name of Eternal Crisis.

22:30

Now that I had everything important out of the way and still more than four hours to go, I started juicing the crap out of the game. I improved the graphics, fine-tuned parts of the music, fiddled with the particle generators to make the explosions more impressive, added a missile exhaust particle generator (probably the single thing I am most happy with in this game because it turned out so pretty).

In the middle of all that I realized that I still didn't have a good grasp on level progress. All the bosses were completely random, but I wanted them to become progressively harder. But there was a problem caused by the random nature of generating the boss: Whenever an arm did not branch off often enough due to bad RNG, it was limiting the number of guns the boss could carry. So even if I wanted to have a very hard boss, this limitation could by chance force it to only have a few guns attached.

Fortunately, I had built the definition structure I mentioned earlier, that allowed me to define what a boss would look like without actually having to create all the game nodes. So my solution was to set the number of guns as a target and generate 100 different definitions, then pick the one that came closest to the target number. This turned out to be a pretty good way to control the size and difficulty of the boss.

Now the deadline had approached and I decided to better quit before adding any last-minute bugs and started packing up.

I swear, this is the second time I submitted a game with a misremembered name and now the link to the game page shows "endless-crisis" instead of "eternal-crisis". Crap.

06_game.gif

Summary

The Good

  • I made my first Godot game. I was totally won over by the experience. This is going to be my new go-to game engine. Goodbye GameMaker Studio, thank you for all the good memories, but I'm not coming back.
  • I think I made my most visually polished LD game so far
  • I am very happy with how my time management went this time. I finished the complete game with enough time left for fine-tuning and polishing and didn't fall into a last-minute panic.

The Unfortunate

  • I wanted to make an atmospheric game, but I wasn't able to fit this into the theme, so instead I ended up copying an existing game idea with little to no innovation
  • I wanted to compose an emotional orchestral soundtrack. Since I ended up making an action game that wouldn't have worked and I am not super happy with how the music fits the game feel.
  • I struggled with composing again. I think I need more practice writing music for orchestra before I attempt this again, as I would like to become more fluent in the process. It's a fascinating field, but I have to learn this outside of the tight schedule of LD I think.

The Bottom Line

I'm really happy with the way this game turned out. There are imperfections, but for a LD Compo game I think it turned out pretty well. It's not as good as The Omicron Fleet, but I still like it a lot. I feel like I made a good transition to Godot and hope that I can be more efficient next time I use it. For this learning experience alone, all the crunch was worth it.

So, congratulations for making it this far, thanks for reading this novel.

If you want to give the game a go, please be my guest: https://ldjam.com/events/ludum-dare/50/endless-crisis

Eternal Crisis Timelapse

I made a timelapse video for my Compo entry Eternal Crisis

https://youtu.be/jPx5rfK00VU

It was my first Godot game so most of the video is spent in the code editor and googling stuff lol.

If you're interested in reading my post-mortem analysis of the event, you can here