Project N5 Progress Update: 2025-03-16

» Refactoring


I've been making a lot of progress in a lot of different areas, so I won't be able to elaborate on every little detail, but I'll focus on more major things. Excited to share what I've been working on!

Introducing: Laura

Laura is finally, FINALLY a playable character in the game!! I cannot overstate how cool this is. To finally see the character I've been creating for actual MONTHS in my game is HUGE.

As you can see in the screenshot above, Laura has a toon shader applied – it's this one again.

With the implementation of Laura came some other changes as well. The over-the-shoulder camera had already been adjusted to fly over the character's left shoulder, but now Laura also holds the weapon in her left hand. Plus, the camera was changed, because Laura is smaller than the chunky robot I had in her place before.

I even added swooshy hair using the JiggleBones plugin, though I've already removed that plugin from the project, which I'll elaborate on later.

I was also able to implement LookAtModifier3D to make Laura look at any enemy she's targetting. In the video, however, you can also notice that Laura's irises don't follow her head. That's a bug and it'll be fixed soon-ish.

...and I'm not happy about it?

I want to change Laura.

While I'm super happy that I was able to create a relatively decent mesh (topology-wise) that even animates fairly alright, I think Laura in her current form is boring. She is meant to be a 'regular girl' just being thrown into this dystopian world and unfamiliar (combat) situations, but... it doesn't have to mean that she has to look boring. Consider her clothes in particular; right now, her clothes are straight, clean, uneventful, and it's even worse on the back (where you, as the player, will consistently see her), since I've primarily focussed on modelling her from the front. There's nothing interesting in the back, by which I mean something akin to Ratchet carrying Clank on his back, Banjo carrying Kazooie, or even just a neat backpack or belt.

I think Laura (being born in the 28th century) should look more futuristic, more interesting, and just overall more unique! I also want to make changes to aspects such as her hair, because while I have found out how to animate it in-game, it looks pretty unappealing. Plus, laying the back hair was kind of difficult; making it follow the flow of her shoulders meant that it would not deform properly when running. Making it straight would mean it clips through her torso when standing still. I do have an idea for how to fix that – by modelling it straight and then placing a capsule as collision shape for the SpringBoneSimulator3D – but this didn't even exist when I modelled Laura.

Also, I think I want to go with tied-up hair instead. Not only does it animate much easier without clipping, but it'll give Laura a more unique silhouette, I believe!

I've been doing some sketching in a new B5-sized (much better size than A5 for sketches, I reckon) notebook, and I'm quite excited for this.

While I do wonder whether I'll be able to successfully execute upon my ideas, I believe that I'll be able to create something quite cool. Not only do I now have plenty of experience creating a character, but I'm also not creating one from literally nothing anymore. I have the current Laura model as a base to work off of – though I likely will not recycle many parts, since I want to make improvements to the mesh and loop cuts for better bends. I also have ideas! I was struggling so hard to come up with ideas for Laura before, especially concerning her clothes!

I am confident that Laura 2.0 will be awesome.

New Firepower

I added two new weapons to the game! Neither one currently has a proper model, being relegated to primitive shapes, so they're not worth showing, BUT I'm quite happy about the fact I've been able to implement their basic functionality already.

Igniter / Flamethrower

The Igniter is a flamethrower with a rapid firing rate. Here is it in action:

The particle effect is a single .webp that was originally meant to have a blur effect, but I used Alpha Scissoring as the transparency mode in the StandardMaterial3D and kind of liked the effect, so I kept it. The fire effect is BY NO MEANS finished though.

I was initially writing custom logic for the Igniter, which, as you will see, I wasn't super fond of, though I later was able to reel back the project and integrate it into automatic3.gd quite nicely. There's still a remainder of custom logic for the sfx, since the audio for the Igniter loops instead of one-off firing, but I think that can be integrated into the regular sfx script as well.

I've been meaning to implement the Igniter for a while, because I thought a flamethrower could be a neat addition to the roster, but given the direction I've been meaning to take the game's story, I think a flamethrower is unsuitable and overly brutal, especially considering that Laura's is supposed to be a 'regular girl' thrown into this ruined world. Expecting her to use a flamethrower doesn't match her character, I find.

Then again, you could say the same thing about the other weapons, but I think they can work better as strategic items rather than merciless killing devices.

This, by the way, also means that the arena will likely not make it into the final game, unless I integrate it on the premise of, for example, it serving as a colosseum of sorts where Laura can become a gladiator and risk her life for a reward.

Unnamed Rifle

The second weapon I've added is a rifle-type weapon! Whether it'll just be a rifle or a sniper rifle, I haven't decided yet.

This rifle, unlike the Igniter, fits the ideas I've had for the story much better. I can imagine Laura using this as a long-range weapon from behind covers, possibly paired with a sliding mechanic that allows her to quickly and stealthily move between hiding spots, leaning over them to take shots... could be cool.

The projectile ray takes a while to spawn after pressing the fire button. This happens because the projectile uses a RayCast3D to register a collision with a prop or an enemy so that the projectile stops exactly where the hit occurred instead of extending further. The RayCast3D, however, takes a while to process collisions after being moved, so the projectile overall has 3 frames of buffer time between being created and visibly appearing to calculate its end position. This creates a short delay. Not sure 1. whether I'll fix it, and 2. how I'd fix it, though I assume it would require some reworking and potentially scrapping the RayCast3D idea.

The projectile also... doesn't exactly hit where the crosshair is pointing. I'm pretty sure this has to do with the RayCast3D responsible for finding the collision point being attached to the player instead of the camera (which I've intentionally changed very recently – it used to be attached to the camera!), so it doesn't actually point where the crosshair is pointing. I'll get around to it eventually.

The good news: it has nothing to do with the rifle, so the rifle isn't broken. The bad news: it affects every weapon, so technically, all weapons are broken.

Item Preview Window

I upgraded the item preview window slightly. Previously, the weapons just spun aimlessly, but now they can be tilted using the right analogue stick or the mouse to gaze upon them better! It's a small change but I'm proud of it, so here it is:

I also fixed a long-running bug where the DirectionalLight3D of this preview would cast light on the gameplay world. This was caused by the preview being in the same physical space as the rest of the world (unavoidable) and being on the same visual layer (totally avoidable). I changed the layers, adjusted the light so that it doesn't contribute to the sky (very important with a shader that takes the scene's main light into consideration!), and it relieved a great headache that caused oddities such as two specular highlights on every model that received light.

Please Appreciate These Wonderful Temporary Weapon Icons

Grand Code Overhaul

In (re)starting work on my game, I've been confronted with a lot of... legacy code? Lots of code that I was unhappy with, at the very least.

I've found that a lot of the code I've written – which at this point is up to 1.5 years old – isn't really up to par with what I want to write. It's inflexible, verbose, doesn't always follow standards and best practices, and overall really needed some overhauling. So, I've been doing just that.

I simplified logic, standardised scenes and code for game objects that share logic, implemented both inheritance and component-based designs where appropriate, and just yesterday, I've moved the code for fading in/out a black screen as well as the message handler displaying text such as "Collected 12 N5 Blaster ammo" and "Open vendor" into autoloads – I learned this morning that autoloads can be full scenes (.tscn) instead of just code (.gd). It makes a lot of sense, retrospectively, but now I'm just happy to have simplified some areas where I was unnecessarily passing references. For instance, displaying a text such as "Collected ammo" required the node response for collecting that ammo to have had a reference to the player, who in turn had a reference to the message handler and thus could display messages. This approach was overly convoluted.

Godot 4.4 Changes

If you haven't heard, Godot 4.4 is out! And that meant quite a few changes for my game:

$

Yesterday, I replaced a lot of $ node references with @export properties for performance reasons. I watched this video on node retrieval, where I found out that $ references are inefficient. I then thought about this, and... yeah, that makes sense. $ is just a short-hand for get_node(), which means that, in a _process() context, I'm calling get_node() potentially 60 times a second – every time I use it. Considering this massive performance implication, I refactored a lot of code and created loads more @export references. They're easier to manage in case of moving or renaming nodes, anyway.

Weapon Code

The weapons received some of the biggest changes. Previously, I had a bunch of different classes for a base weapon, semiauto, automatic, and thrower weapon (the last one being a semiauto weapon that fires in an arc), and they all kind of did similar things. I first used inheritance, then switched to a component-based design, where I still needed more boilerplate than I was comfortable with. The thrower in particular copied all the code from the other weapon types, just with changed logic for the projectile path.

It was a mess. It's all overhauled now.

There's weapon3.gd, which is the base weapon class for all weapons, inheriting from item.gd. Then, there are semiauto3.gd and automatic3.gd, which implement only the functions to determine what happens when the player presses and releases the shoot button – one of them fires once, the other one repeatedly.

Notice there's no thrower3.gd? It's unnecessary. The logic for the arc has moved into the projectile. Why would the weapon be responsible, I asked myself, considering that the throwers otherwise acted identically to the semiauto weapons. I also moved a lot more properties away from the weapons; damage and speed, among other things, have been moved to the projectile. AoE damage and radius, for example, have been moved into the explosion that's spawned by the projectile upon impact. I've generally moved properties to where they're needed instead of bunching them all up at the weapon and then sending them over via long and unnecessary functions. Like, for example, a function that spawned the projectile, which used to look like this: start_moving(direction: Vector3, ramp_up_speed: float, damage: float, explosion_resource: PackedScene) -> void

My Enemies Follow Me Wherever I Go

The enemies have pathfinding now implemented! I used Godot's NavigationRegion to create a mesh the enemies can traverse. Since they all inherit from StairsCharacter – a class I once downloaded to deal with stair stepping for CharacterController3Ds – they can traverse the world about as easily as the player. It works super well! I was able to piece it together quite quickly, after a friend of mine figured out how to implement navigation in another game we're working on together.

Story Changes

I have some minor ideas for where I want the story to head in.

Where the Game is Headed Gameplay-Wise

When I showed the Laura model to a friend recently, they noted how she doesn't look like she belongs in a shooter, but more of a puzzle-type game. I think that incorporating some elements of that sort could be quite cool, actually; solving problems to uncover the mystery of what happened to Laura's world.

That's the general idea.

How (Many) Weapons Will Play Into It

Heading into this direction means that a large arsenal makes less sense. While I do still want to have combat elements, I've considered reducing the amount of weapons from 12 (which was even as high as 16 way earlier) to 8 or even just 4.

The amount of weapons in the game also impacts UI: having 8 weapons total would warrant a quick select, like the one currently implemented – though I'd probably make it look a bit more similar to Ratchet: Gladiator, where it is displayed in the upper left corner of the screen. 4 weapons total might instead be served through selection via the d-pad (or numbers 1-4 on the keyboard), though.

A Notebook for My Thoughts

I bought a new notebook recently! While I had a notebook before – a green A5 notebook with dotted pages by Share – it was filling up with notes from university, internships, and other miscellaneous things I didn't want to clutter my project notebook with.

I switched to a black B5 notebook, also with dotted pages, by Plan A. This cost me a lot less than a Leuchtturm1917 B5 notebook (like 60% cheaper) and still totally serves my needs. I like the B5 format, it's just a fantastic size. It's bigger than A5, which allows for more expression, details, and overall just breathing space on the pages, but it's also not as big as A4, which would be unwieldy. B5 is a superb format for my sketch notebooks; can recommend.

Bluesky

I have a Bluesky account now!

I've been eyeing the platform for a while now, but lately I've noticed that quite a few people I enjoy following have Bluesky presences. Plus there are other cool people there, as well as the Feed feature where I can, for example, see all Godot-related content. I've created an account with the idea of potentially posting some of my gamedev progress on there, though I have not yet shared anything. Still figuring out social media; while I grew up during the rise of social media (on mobile phones in particular), I've never really been into them quite as much as others have.

Maybe this'll be different though, seen as I have a relatively specific goal here. We'll see!

Addendum

Sorry for the walls of text! I've really just been working more on backend stuff than visually interesting things, mostly to clean up the project, but also because I feel that's my strength. I'm super good at programming expandable, relatively easy to maintain code, at least in comparison to my artistic skills. However, I'm absolutely working on story, visuals, more weapon, and of course Laura 2.0, so hopefully I'll have more to show for in the coming weeks and months!!