Project N5 Progress Update: 2024-04-01

» The Behind-the-Scenes Update


This is my final update before the next semester begins! I'm actually quite sad about this. For the past few days, I've been really motivated to work on my game. The free time that I had after I finished my last few submissions for university gave me enough room to spend significant time developing. But now that the next semester is about to begin, I fear that university will rob me of a significant amount of my time, and that I will not be able to spend the rest of my time productively.

I do hope that I'll manage, though. A loose goal of mine is to work on my project every single day. I don't know if I'll succeed, but I think it would be beneficial. If I continue work on my game, I'll continue making progress. This progress will motivate me to work on my game, thus progressing development further. We'll see if it works out!

This progress update is going to be interesting. I have made quite a bit of progress, but there aren't that many visual changes to show off! A lot of the changes I've implemented are behind-the-scenes stuff.

Skip to the interesting stuff

Component-based design

Like for example, I started implementing a composition-based approach for certain game functions. I've been meaning to implement this for a long time, but I've never really gotten around to it, until I had this video by Bitlytic recommended to me today.

In short, composition means that you have certain components – e.g. health, hitboxes, etc. – that you can attach to any entity that needs them. This is especially useful because it allows for combining components freely without needing to repeat lines of code!

So for example, I have my player and my enemies. They are based on different scripts, but they should both have hitboxes and health handling. What I'm doing now is attaching the components HealthComponent and HitboxComponent to handle these functions.

I hesitated to implement this design approach in my game because I wasn't sure how, but the video I linked above really helped with its code examples. I took them, modified them (somewhat significantly), and edited a few other elements of my game to make them fit, and now they work quite nicely! On the note of editing other elements,

Refactoring

There's no point working on my game if I inevitably end up losing track of the entire project! So, every now and then, I refactor functions, separating things out, and keeping general order. Part of this has been solved through composition, but other things have to be fixed in other ways. For example, a relic of my first few weeks of programming my game was that the HealthBar was handling not only the visual element of showing a health bar on the screen, but it was also responsible for keeping track of how much health the player had, registering healing processes and damage taken. This... didn't make much sense, as the HealthBar was pulling double duty. With the HealthComponent implemented, there was no need for HealthBar to keep track of health anymore, so it was refactored to only handle the displaying of health, simplifying its function significantly.

Loading optimisations

I replaced a few load() calls with preload(). This is significant insofar that the use of preload() reduces runtime loads – and therefore load spikes – significantly, as resources are pre-loaded (hence the name) and only have to be instantiated at runtime. This yielded a massive performance improvement in the arena, for example, when a dozen enemies have to be spawned at once. Here's an example:

var enemies = ["path-to-enemy-0", "path-to-enemy-1", ...]

...

for enemy_path in enemies {
    enemy = load(enemy_path).instantiate()
}

This was my old approach: enemies are declared as path strings and both loaded into memory as well as instantiated at runtime. This meant that, in a round of 12 enemies, the enemy resource(s) had to be loaded 12 times at exactly the moment the last enemy of the previous round died – which is to say, in the middle of gameplay. This caused significant lag. Here's the more optimised solution:

var enemy0 = preload("path-to-enemy-0")
var enemy1 = preload("path-to-enemy-1")

var enemies = [enemy0, enemy0, enemy1, ...]

...

for enemy_resource in enemies {
    enemy = enemy_resource.instantiate()
}

This yielded a great performance boost, as the preloads meant that the enemies were loaded much in advance. These resources could also be used manifold, as they aren't references to instantiated scenes – this only happens with the instantiate() call. So in this case, I could have 6 enemy0 and 6 enemy1; both types would be preloaded once (so, two loads in total), and then they could be instantiated afterwards. Lag spikes be gone.

There's more stuff I did: I fixed some memory leaks, visual mistakes, behavioural errors, etc., but writing this only makes me realise that it's probably more interesting to write than to read, so I'll continue with a few (hopefully) more visually appealing points of discussion.

The Venom

Something visual to intersperse the dry code explanations:

An image of an untextured work-in-progress 3D model of a blaster

This is an image for a weapon I've come up recently! It's supposed to be a slow-firing but strong blaster, contrasting the rapid-firing but weaker N5 Blaster (which recently changed to an automatic firing mode). The Venom originated from sketches like this, by the way:

A REALLY crude sketch of a blaster. A crude sketch of a blaster resembling the 3D model shown above.

The bolt visible in the first sketch actually makes me consider using the model I showed off recently as the v2 for the Venom (which I would call Antidote by the way, in reference to this song).

N5 Blaster glow!

The N5 Blaster got some visual flair! The lights now glow slightly differently, a bit dimmer than before. When the N5 Blaster is fired, its lights glow brightly for a split second, indicating that a shot has been fired! And when the gun is empty, the lights go out and the icosphere (which is meant to be the power source of the gun) is only dimly lit! I really like the effect.

An image of the N5 Blaster. Its lights are turned off, and the icosphere in the middle is dimly glowing.

Sorry about the sparse delivery of visually pretty things, but I hope the cool effects on the N5 Blaster make up for it somewhat! I can say for sure though that I'm progressing quite well, and I'm having fun doing so, even if this progress can't really be showed off in the same way I could show off a 3D model or a new enemy. There's lots to come in the future though, especially since I still have to design most of the 12 × 2 = 24 weapon models, a tonne of enemies, the player, and all the levels. There'll be lots to gawk at (hopefully)!