Ludum Dare 53 Post Mortem - A Different Approach
Testing my WebGL engine while creating a game from scratch in 48 hours04.05.2023 - 13:21
Last weekend was the 53rd iteration of the Ludum Dare game jam where you have 48 hours to create a game completely from scratch. This time the theme was Delivery.
Leading up to the event, I wasn't sure whether I wanted to participate or not. I've been quite busy recently and I could have used a weekend off. However, I'm glad that I joined and made my 14th Ludum Dare game.
Testing Sparrow WebGL
The main reason why I joined the event was that I wanted to test Sparrow, the WebGL engine that I have been working on for the past few weeks. It's still in the very early stages of development and it doesn't have many features that would be useful for a game jam. However, I have always said that for small games you only really need to be able to render a 2D image and text, which is something my engine can do already. Therefore, I decided to start to work on a game and see how far I can get.
Besides finding issues and missing features during development, Ludum Dare is also great for user testing. The other participants are going to play your game and rate it, which is basically a free way to get a bunch of people to test your engine and find potential problems with other system configurations and browsers.
Theme and Idea
As mentioned, the theme for this Ludum Dare was Delivery. I wasn't a big fan of the theme, but it presented another good opportunity. I have been playing and watching some Trackmania content recently, and I realized that I have never made a driving game. Deliveries tend to happen with a vehicle of some kind, so I just started to work on driving mechanics without having any ideas for the rest of the game.
Only by the end of the first day when the driving mechanics felt good, I planned some more features. I wanted to have a big open area to drive around, which meant that delivering parcels in a city was out of the question. Instead, I chose the space/sci-fi route and used a rover that delivers energy crystals back to its base. The crystals can be spent to purchase upgrades to increase max speed, acceleration, pickup range, and carrying capacity. However, while I like open-ended games, game jam submissions benefit from a victory and loss condition. I couldn't come up with any good ideas, so I just added a timer until an asteroid strikes the planet and you have to leave before the time runs out to win.
My main focus was implementing the driving mechanics. I had the basic driving done quite quickly, but I really wanted to add drifting too, which turned out to be more tricky and took me a few attempts. Driving physics is a very complicated topic and there is a lot that could be improved, but for simple top-down driving during a game jam, I am very happy with the result. As soon as the car reaches a minimum drifting speed, it starts to slide out and the faster it goes, the more it drifts.
Another important aspect of driving and drifting is the tire tracks. It looks so much better when the tires leave a trail. Unfortunately, my engine did not have a feature for this yet, so I had to create it during the event. It took some effort to ensure that the line strip for each wheel updates accurately every frame, taking into account the steering and drifting angles.
The trails behind the rover when it is drifting:
The other mechanics and features of the game were quite straightforward to implement, although I'm very happy with the upgrade system and its code. During game jams, I tend to just hardcode things like that because it's only a handful of upgrades anyway. However, this game's upgrade system is very dynamic and everything can be controlled with a single data structure and changing the values within it.
I didn't spend much time on the art for this game. I only drew some fairly generic pixel art assets in Krita. Still, I think the rover, the base, and the rocket look pretty good, while the crystals and the background could have been a lot better.
One of the biggest advantages of using my WebGL engine over HTML5 is having access to UI elements. For pretty much every previous Ludum Dare event, I had to create a simple button class because every game needs buttons. With Sparrow, however, I already worked on its UI features in the second dev log, so I could use them for the game. I had to add and fix some features, but it was still a very good way to implement and design the UI for the game.
Normally, this section is called "Music and Sound Effects", but I didn't add any music to my game. I always struggle with creating music, so this was a great decision. I think I can get away with it for this game because most of the time you can hear the engine sound of the rover. Speaking of the engine sound, I think it turned out pretty well. I generated brown noise in Audacity and then heavily tweaked it until it sounded like a rover. But my favorite part about it is a very simple line of code: The volume of the engine sound depends on the speed of the rover, which makes it a lot more realistic. I also added a beeping sound effect when driving backward like trucks when they drive backwards.
I had a lot of fun with the game-over sound effect. It's not great, but very funny: A voice saying "Brace for Impact", followed by a woman's scream, and an explosion. And yes, that is me trying to high pitch scream with some Audacity effects.
Overall, the mechanics of the game are not very complicated and in addition to not needing any music, I was able to spend some time polishing some aspects of the game. I mostly worked on the winning animation. Functionally, clicking the rocket button, playing a "ding" sound effect, and showing the victory screen would have been fine for a game jam and it's what many of my games in the past have done. However, this time I went all out. When you click the rocket button, the camera moves to a fixed point, after a short delay, the door of the base opens, and then the rocket slowly rises out of the base and accelerates into the sky with a rumbling sound effect. The victory screen only appears after the rocket has left the screen. Even the game-over popup is timed so that the menu only appears when the sound effect gets to the explosion.
Working on these little details is a lot of fun and you normally don't get to do it during game jams.
As it's tradition, I once again struggled with balancing the game. It's extremely difficult to make something that's challenging but beatable, especially in less than an hour, close to the deadline. There is also a gap in player skill. The feedback I got already is divided: Some people think the game is too easy, and others struggle with it. Sadly, there seems to be a cheese strategy too and the game is beatable without buying any upgrades. There is a small amount of randomness in the game because the crystals are distributed randomly across the map, but with ~100 initial crystals and a new one every 2 seconds, luck should more or less equal out.
The final look of the game:
For the most part, my WebGL engine held up pretty well during the event, but I added a few features on the fly. My engine didn't have a 2D camera class, so I created a very simple one, and I also had to add texture filtering options to my quad class so I could use nearest neighbor filtering for the pixel art aesthetic.
The biggest issue only appeared after I finished and uploaded my game: I tested it in different browsers and it did not work at all in Firefox. It turns out, Firefox doesn't support the fontBoundingBoxAscent and fontBoundingBoxDescent fields of the TextMetrics object, which I had been using to position text in UI elements. This still seems weird to me because I'm pretty sure I have used those fields in the past with HTML5 to position text as well, and it always seemed to work in Firefox.
Another problem I found when I was working on the tire trails was that WebGL does not support glLineWidth. Changing the width of a line is such a fundamental feature that I never even considered that WebGL might not support it. I wanted the tires to leave wider tracks, but it still kind of works with thin lines as well. I may have to look into different solutions for drawing wider lines in WebGL in the future.
I took a different approach for this Ludum Dare and I must say it was quite refreshing. My main goal was to try my WebGL engine and implement decent 2D driving mechanics. Making a game was optional, if I only had a 2D driving simulator in the end, I would have been happy. When I added some game mechanics later they were not very complicated, which meant I had some time for polishing and working on the rocket launch animation and the game-over sound effect was a lot of fun. I think I have tried too hard to make good games in some of the previous Ludum Dares, and going at it with a much more relaxed attitude is more fun. Hopefully, by the next event, my WebGL engine is a lot more complete and I can use it to its fullest potential to create a better game with less effort.
Play my game: https://pingpoli.de/ld53/
Ludum Dare game page: https://ldjam.com/events/ludum-dare/53/crystal-courier
by Christian - 04.05.2023 - 13:21