FutureFunkorp

A Post Mortem by George Baron

06 January 2018

Introduction

FutureFunkorp is a game I made for Shef Jam V, a game jam held by the Computer Science Society at the University of Sheffield. The theme was “Powerless” and the jam lasted 30 hours over a weekend. Usually when I enter a game jam, I use a specific set of tools that I know I am very fast with; namely HaxeFlixel. This time however, I wanted to try something different!

My aim for this game jam was to test the feasibility of the ray marching framework that I’ve been developing over the past few months in my spare time and to show off what a ray marcher could do. Originally, it was created for the sole purpose of making procedurally generated intros. This time, I decided to repurpose the framework to be used for making games. Personally, I have never seen a game created using a ray marcher, or at least not a genuine original and complete one - you can see recreations of the first levels of various famous games such as Mario and DOOM on Shadertoy. I saw this as a challenge! Why not make a game with a ray marcher?

For more information on what a ray marcher actually is, I wrote a previous article on it here, specifically about how I used the technology to create a music-based animation. I also covered some of the fallbacks with using a ray marcher, which will rear their ugly heads in this article too!

Video

The in-game music is “That Love” by “Pop Up!” available for free on Bandcamp!

How the Game Works

You play as a prisoner that has committed a dubiously heinous crime in the distant future where a Totalitarian government has taken control. To please government officials, “FutureFunkorp” was established - an initiative that allows powerless convicts to dance and amuse the higher-ups with the promise of a reduced prison sentence.

Stupid premise aside, the actual gameplay is very simple. After a short introduction, the player is dropped into an arena where music starts to play and the environment bounces along to the music. The player’s goal is to simply stay on top of the blocks for as long as possible!

Challenges

There were a whole heap of challenges involved with making a game like this. These came in many sizes big and small - for instance, C++ isn’t exactly the best language for quickly hammering games out with. I will skip over the smaller challenges though and focus on the actual, stress-inducing difficulties that presented themselves.

Oh God that Frame Rate

I pretty much expected this but bloody hell maintaining a decent frame rate for a game is difficult at the best of times, and with a ray marcher thrown in as well? Hell. Absolute hell. Let me put it this way; you can render a simple sphere with nothing else in the environment and still drop to half the desired frame rate if you look at it at a funny angle. This poses an extreme problem - with intros, the director personally guides the camera through an environment with the ability to perfectly tweak values allowing them to hide the cracks and keep the frame rate high. With a game however, the player guides the camera and can look anywhere they bloody well like. The lack of control on the creator’s side is a real problem.

So how do we fix this? By acting extremely carefully with how the environment is both produced and rendered. Development was basically like walking on a minefield, so I set a bunch of criteria for myself in an attempt to minimise problems:

  • 1. Keep the geometry as simple as possible.
  • 2. Keep the shading as simple as possible.
  • 3. Make use of bitmaps wherever possible.

The running theme here is “as simple as possible”. Even if it looked like the boat could be pushed out a little more, I opted not to. This was because of the previously stated problem of not knowing where the player may be looking and what looking angle might potentially tank the frame rate.

Getting something that actually looked and felt like a game under these circumstances was a massive uphill battle. With the added stress of being under the time limited environment of a game jam, I was starting to realise why this route wasn’t exactly ever taken. Ever. Regardless, I pushed on and came up with some solutions I am quite proud of.

Solution 1: The simple geometry

Deciding on the geometry was going to be a big problem. Not only does it have to be simple enough to render efficiently, it also had to be complex enough to provide the player with something interesting to look at and interact with. My solution was to generate terrain using a height map created on the fly in the background. The computations for this were quite simple (all the ray marcher has to do is do a quick height look up at each step) but it also had the potential to look pretty good. The world was infinite and no matter where the player could look there would always be something interesting on display. Notice how I am talking about potentials here; unfortunately another problem arose.

When I tried to render the terrain using the same ray marching model I had in my previous article I noticed that it uh… looked like shit. Below is a screenshot of what I’m talking about.

Hahahaha... fuck.

This problem arose because the ray marcher I was currently using was adapted for rendering objects close to the camera, and not terrain that spreads out into the distance. The solution to this was simple; change the ray marcher so each step was of a fixed size. A large max step count had to be defined however to realise the geometry properly. I was sure this wouldn’t cause any problems though.

Solution 2: The large max step size caused problems

You know that feeling of finally solving a problem, only for another to stick its neck out? The large max step size worked fabulously for the terrain, but the moment I pointed the camera up to the sky, the frame rate slowed to a crawl. This was because the rays were not intercepting any geometry, so every single ray was completing max iterations - the large max step size. My solutions to this were… questionable. I first lowered the max step size. This meant the geometry had a kind of wobbly feel to it but I decided to attempt to incorporate that into the art style. The next solution was to just make the sky box perfectly black. Who can tell if the camera is moving jankily if there isn’t any point of reference? Perfect, next problem.

Solution 3: Throwing the lighting model out of the window

I realised quite fast with the new fixed step size ray marcher that my wonderful fake global lighting model was not going to cut it. Not only was it expensive, but the inaccuracy with some of the ray collisions meant normal calculations were all wonk and I didn’t fancy trying to fix that with the given time limit. Therefore, I opted for a flat shading approach with no lighting model whatsoever. I relied upon a varying colour palette and the bumps in the terrain to distinguish shape.

Solution 4: Need detail? Bitmaps. Use bitmaps

Incorporating the theme was going to be a rather tricky problem. Anything produced with a ray marcher usually has a pretty damn abstract story to get around the fact that the geometry is usually also abstract. Unfortunately, I did not have this luxury and had to somehow tell a story. To solve this, I incorporated the ability to render “billboards” - bitmaps drawn onto a flat surface and placed in a 3D world. Although seeming like a good solution, I learned fast that the billboards could not be rendered using the fixed step size ray marcher and therefore could not be in the same scene as the terrain. The solution to this was to divide the story and gameplay, add the ability to switch the type of rendering on the fly and then hide the transition between renderers somehow. In the final solution, the type of rendering changes while the player is falling into the arena.

The billboard characters rendered in the introduction.

The Framework Had Bugs

Since this was the very first time using the framework to make a game, bugs were to be expected. Fortunately, not too many were found which is a pretty good testimony for the stability of the framework! Besides one bug, most of them were also fixed relatively quickly. Of all the time lost during the development, I expected bugs to be the biggest reason; that crown goes to something else however…

Hacking Together Physics and Collision

This was a massive oversight on my part. At the time of the game jam, my framework had no concept of physics or collision between objects and unfortunately I decided to make a game that rather heavily relied on both to be playable. The player required gravity and friction to allow them to fall and move around the world in a fluid way, but they also required the ability to collide with a constantly updating terrain. Further to this, the terrain needed to bounce the player upwards depending on the velocity of the current block the player was standing on. Let’s draw this up in a list to simplify things:

  • 1. The player required gravity to fall back down onto the terrain
  • 2. The player required acceleration and friction so that horizontal movement felt smooth
  • 3. The player required the ability to have forces applied to them by the terrain so that they can be flung into the air
  • 4. The player had to properly collide with the terrain so that they never go inside of it from either above or from the side

The solution to all of these problems was a very hacky and bespoke physics and collision system. The system, by far, took the largest chunk of development time and was rather tedious when compared to working on the rendering. It is also worth noting that the ray marcher and the physics and collision system were working on two different devices; the GPU and CPU. This meant that the physics and collision system also had to be synced up properly with whatever the ray marcher was producing.

What Went Right

Those were the main challenges involved with making the game, so let’s talk about what went right during development. This section details parts of the development that I personally felt I pulled off well!

It Actually Worked

I do not feel like I am overstating when I say I am amazed that it actually worked. My genuine expectation was to fall flat on my face and buried under the long list of problems that were surely going to arise (and that actually did). Although I had plenty of previous experience with a ray marcher and knew the pitfalls that resulted in a terrible frame rate, I had never made a game with one and I didn’t know in the slightest whether keeping a stable and high frame rate was possible given the absolute freedom of movement a player is granted. Basically, I expected it to run like shit regardless of what I did. Fortunately, I found ways to cut corners and keep the frame rate high (or at least keep it high when it mattered…)

I Managed to Create an Engaging Environment

The environment was another one of my biggest worries. Ray marchers are very restrictive in what you can produce in a small amount of time and with a good frame rate. However I couldn’t just bottle it and render everything with bitmaps - what is the point in using a ray marcher otherwise? I needed to show it off! Fortunately, the height map idea was pretty brilliant in that not only did it mean I could create an infinitely spreading environment with interesting details quite easily, but I could also use it to aid the physics and collision system.

It Looks Pretty Gorgeous In Motion

One of the biggest things I am proud of is how good it looks despite having to scrap the lighting model. I deliberately picked a very distinct colour palette that was bright and fun along with a careful selection of visual effects to enhance it. The combination of these meant that proper lighting was not needed and different objects could be easily distinguished. One of the hardest things to do as an artist sometimes is to discard certain aspects of a creation, so I am glad that it worked out well in the end.

It Felt Good to Play

Although the physics were super hacky, they actually felt pretty good. The gravity had a good balance between being floaty and weighty, in that the player could glide through the air but also make a strong impact when hitting the ground. The ability to boost through the air also felt impactful when combined with an apt sound and barrel blurring visual effect.

Screenshot of the player boosting through the air.

What Went Wrong

Of course, the final product was not even close to perfection. These are the things that went wrong and that I didn’t manage to solve in the given time limit.

I Ran Out of Time

With the long list of problems that arose during development, running out of time was rather inevitable. I managed to make the actual game section pretty polished, but the story and ending portions of the game lacked in quality. For instance, the cutscene at the beginning of the game relied heavily on text dialog and lacked interesting animations and visuals to keep the player amused. This meant that the introduction also didn’t really show off what a ray marcher could do, which is a bit of a regret since that was a main objective of mine.

There was also plenty that I wanted to do with the ending of the game that I had to entirely forget about implementing. Instead, the ending consists of a very simple game over screen and the player’s score is reported in the title of the window.

There Was No Way of Restarting the Game

Upon death, the player had to completely close and repon the game to play again. This is very poor design but I just had no time to implement a proper replay loop. To get around this while demonstrating my game at the end of the game jam, I created two versions; one with the introduction and one without. This meant that people did not have to sit and wait through the introduction every time they wanted to play again.

The Game Was Very Simple

I had plenty of ideas for where I could take the actual gameplay, but had absolutely no time to implement any of them. I did attempt to implement one of these ideas but it proved buggy and game breaking. Therefore I ended up removing it in favour of having something playable. This meant that the game ended up being both simple and pretty random with how well you performed. Players could very easily lose interest upon realising this.

Conclusion

Screenshot of the player looking down upon the terrain.

Although the game was not everything that I wanted it to be, I am still very proud of what I managed to produce given the long list of constraints and problems I restricted myself with. It was an extremely good trial by fire for my framework, giving me plenty of ideas on how to improve it for (possibly?) next time. The game requires a bunch of pre-requisites to actually run smoothly on a system, so I might leave the video as the only proof that it actually exists. Thanks for reading!