Cometa: Physics Based Asteroids
April 2023
This post describes some of the features of a game developed by Piotr and me. It can be played in your web browser here, or downloaded on the Android store (pending). The source code is visible on my GitHub here. The game is associated with our "studio" Honey Badger Attitude. This blog gives a bit of a flavour of how this game works and some of the gameplay aspects we implemented.
Asteroids: The inspiration
Figure 1: A sample of gameplay of Asteroids, showing moving, shooting, and screen wrapping.
Figure 2: Screen wrapping in Asteroids
Asteroids was a popular Atari game released in 1979. I am sure you have come across this game before, as it was intensly popular and remains well known, even 44 years later. If you want a refresher, you can play an emulated version of Asteroids here. Figure 1 shows a sample of gameplay, including the spaceship dynamics and destruction of asteroids. You get points for shooting objects, and actually get extra points the smaller they are. This is because smaller asteroids have less of a cross section to shoot at. The asteroids do not interact with eachother, but destroy the player on touch.
Although a simple gameplay loop, the game is surprisingly fun. I wanted to create a variant on the game's theme, but incorporating more physics. In the game there is no real concept of momentum or conservation thereof. Mass also disappears (one large asteroid splits into two half sized ones rather than four), and most objects do not collide.
One interesting element of it to consider is the "screen wrapping" (look at Figure 2). This means that when an object (including the player) disappears off one side of the display, it then reappears on the opposite side. However it can never actually be on both sides at once, so there is effectively an invisible "buffer zone" around the screen in which all objects are non-interacting. Removing this buffer zone was also put on my list of "improvements"!
Cometa: Asteroids revisited
Figure 3: A snippet of gameplay on the PC version.
Game Structure
The basic idea behind this game is to create something which captures the action and danger of a movie style asteroid field. This means that there should be many asteroids ricocheting and splintering on the screen. We want to have a lot going on, and the presence of both primary (player-asteroid) and secondary (asteroid-asteroid) interactions.
From a gameplay perspective, the issue with having asteroids everywhere is in making it too difficult for a player. Therefore the player will be given a shield. And of course the final feature will be the weapon systems the player needs to destroy asteroids and score points. This will be both a "gun" and missiles.
Screen wrapping
Screen wrapping is a familiar concept in games. In the implementation in the original asteroids, an object simply leaves the screen on one side and then teleports to the far side. However, I wanted a system in which each object could be half and half wrapped across the screen, with interactions occuring on each side. One way of ding this would be to split the object polygons across the boundary. This could be quite efficient, but I was worried about how various animations would function.
The way this has been implemented was to simply have nine copies of every object. This is one "primary object" with eight "secondary" objects position locked to the first. Figure 4 shows how this looks in practice. Once the primary object reaches the edge of its bounding box they all teleport over by the size of the screen. This system works well, and looks seamless once you cover up the secondary objects. All interactions are funneled through the "master" data class, to allow any primary-secondary object pair to interact.
The really tricky part of this system is the spawning of new objects. When they appear, the secondary objects are deactivated and they fly in from one side. The question is what happens if one gets half on, and then gets nocked off. Or an object "follows" a half spawned asteroid over the wrapping. There is some (admittidly gnarly) decision trees to handle these edgecases.
Figure 4: Footage of the editor backend with the screen windowing removed. You can see that there are nine versions of every object, which are spaced one screen width apart.
Physical rules
The two main concepts we wanted to implement in this game were conservation of mass and momentum. In gameplay terms, this means that all objects bounce and spin (atually including missiles although it is hard to tell). Explosions push all nearby objects with a 1/x relationship. The player shield also works on a momentum basis, looking at how much overlap another object has on it and pushing both away from eachother.
For mass, the main consideration is the destruction of asteroids. Each of the bullets and rockets has an explosion radius. When they explode, they remove the mass in their radius. The remaining asteroid then has a certain probability of splitting apart depending on the damage and impact. Importantly, when it does so all the chunks are conserved from the shape of the original asteroid. This is not trivial as the new asteroid is comprised of completely new objects.
To give a framework for the asteroids that was both easily workable and aesthetically pleasing we went for a square grid of unit asteroids. An asteroid is a data frame containing all of the smaller component units. This would allow us to give each sub cube health or other characteristics, but the basic concept performed well enough to preclude the need for this.
The one deviation from the basic concepts outlined above is that we cheat with mass conservation. The issue was that the screen tended to fill up with many tiny asteroids. These get cleaned up therefore when a sufficient velocity impact occurs with the player shield, or proabilistically, with a larger asteroid. Playing with probabilities allows you to tune to the gameplay desired.
Figure 5: The destruction of an asteroid by bullet (let) and rocket (right). You can see that in both cases the asteroid is split into four, but the rocket also removes a lot of mass.
Adding "juice" to the gameplay
Once all of the game structures and features were implemented, what was needed was "juice". This is my term for all of the details that make it more visually appealing and give positive reinforcement to the player. This is especially important for a shooter which is all about how fun it feels to destroy things. There were two key components to the juice for this game, the sound (unfortunately not in the gifs), and the animations.
When the player destroys asteroids to score points for instance, a gold number appears with a size proportional to the number of points scored. This then floats away and fades, while also pulsating. This is accompanied by a "coins" sound. All of these taken together adds to the positive feedback the player gets, it should just feel satisfying to perform the core gameplay mechanic.
Another important element of the game feel comes from adding "weight" to certain actions. The rockets are the big weapon, and special attenton was added to these. As they fire there is a deep jet engine thrum as they propel. This prepares the player for the explosion, which additionally shakes the whole screen.
These elements overall both help with the game feel, and provide important feedback to the player about what is going on in the relatively visually confusing game.
Figure 6: A rocket impact showing some of the features added to aid the visual impact.
Verdict
The goal of this project from the start was to use a relatively simple game concept for us to learn about how to actually polish and prepare a game for release. In our previous projects we had just enjoyed adding features, which made the games feel a bit more disconnected and also very hard to complete. This game had a clear vision from the start, and we were very careful to bound the scope of features we would add.
Taken together this has allowed us to package this as a reasonable self contained "thing", with the added bonus of porting it to mobile making it easy to show off. Seeing how the core features added early on (for example the screen wrapping) had to be modified and used as the game progressed has really helped calibrate how we should approach scalability of the codebase in future. The lesson in implementing polish also helped me to learn the difference between implementing a feature, and implementing a feature in a way which would be robust enough to release.
So as a project I thought it was a great success and I learnt a lot! But is it fun? It is not as addictivly compelling as it could be, but I think it does ok. A core issue with the gameplay is that conservation of momentum tends to lead to all objects moving across the screen together. However, some of what we implemented is really quite good, and could be shared across to our next project.