converted all devlog pages to markdown
@@ -9,6 +9,7 @@
|
||||
|
||||
let idCounter: number = 0;
|
||||
|
||||
let root: HTMLElement;
|
||||
let container: HTMLElement;
|
||||
|
||||
onMount(() => {
|
||||
@@ -21,6 +22,11 @@
|
||||
element.innerHTML = `${(header as HTMLElement).innerHTML}`;
|
||||
container.appendChild(element);
|
||||
});
|
||||
|
||||
// Hide table of contents if no valid entries have been found
|
||||
if (headers.length == 0) {
|
||||
root.style.display = "none";
|
||||
}
|
||||
});
|
||||
|
||||
let getHeaders = function(): NodeList {
|
||||
@@ -54,11 +60,11 @@
|
||||
</script>
|
||||
|
||||
{#if disableStickyScrolling}
|
||||
<div class="toc-container notched">
|
||||
<div class="toc-container notched" bind:this={root}>
|
||||
{@render tocList()}
|
||||
</div>
|
||||
{:else}
|
||||
<div class="toc-container notched sticky-toc">
|
||||
<div class="toc-container notched sticky-toc" bind:this={root}>
|
||||
{@render tocList()}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -165,7 +165,7 @@
|
||||
|
||||
code, .code-block {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 1.0em;
|
||||
font-size: 0.8em;
|
||||
font-weight: 500;
|
||||
background-color: var(--color-background-highlight);
|
||||
/* color: var(--color-background); */
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
|
||||
<BannerTitleAlt
|
||||
title="Project N5; Development Log"
|
||||
banner="/projects/projectn5/devlog/2024/0323/unity_overview.webp"
|
||||
banner="/projects/projectn5/devlog/20240323/unity_overview.webp"
|
||||
wide
|
||||
/>
|
||||
|
||||
|
||||
@@ -1,105 +0,0 @@
|
||||
<script>
|
||||
import BannerTitle from "$lib/banner-title.svelte";
|
||||
import Content from "$lib/content.svelte";
|
||||
import TableOfContents from "$lib/table-of-contents.svelte";
|
||||
import Video from "$lib/video.svelte";
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>2023-09 | denizk0461</title>
|
||||
</svelte:head>
|
||||
|
||||
<Content>
|
||||
<BannerTitle
|
||||
title="Project N5 Progress Update: 2023-09"
|
||||
subtitle=""
|
||||
banner="../../previews/2023/09.webp"
|
||||
bannerAlt="Ratchet from Ratchet: Gladiator and Sans from Undertale t-posing"
|
||||
/>
|
||||
|
||||
<p>My progress in September 2023. Updates are shown in chronological order.</p>
|
||||
|
||||
<TableOfContents disableStickyScrolling={true} />
|
||||
|
||||
<h2>One Small Step</h2>
|
||||
<p>A character has been added and the player can control them! It's influenced by gravity too, although it falls at an unnaturally rapid rate when thrown off the edge. This is because the downward velocity kept increasing even when grounded, and is fixed in a later version. Also, the character faces the wrong direction; moving forward results in the character facing the camera instead of forward. This is fixed once I replaced the character model with one where it's more obvious which side is forward.</p>
|
||||
<Video src="2023-09-16_00.mp4" />
|
||||
|
||||
<h2>Gravity Functions As It Should</h2>
|
||||
<p>Gravity is fixed, and the camera angle has been adjusted, though not fixed to the character yet. It's kind of funny watching this little character move around.</p>
|
||||
<Video src="2023-09-16_01.mp4" />
|
||||
|
||||
<h2>Look Where You're Jumping!</h2>
|
||||
<p>The character can jump! Jump height is set unnaturally high as a test. The player can double jump, but only from a grounded state; falling off a cliff counts as the first jump, thus only allowing the player to jump once. Also, gravity is broken again. Also, a player-controllable camera! This was implemented with a custom third person camera plugin, which proved to be a bit jumpy.</p>
|
||||
<Video src="2023-09-16_02.mp4" />
|
||||
|
||||
<h2>A Better Camera</h2>
|
||||
<p>The camera system has been replaced! This implementation simply uses <code>SpringArm3D</code> with a <code>Camera3D</code> as its child. This allows for the camera to not clip into walls (though it really likes clipping into the floor for some reason), and overall feels much more responsive. Not just that though – the player's movement input is now adjusted to where the camera points! When the player presses forward, they are now moving in the direction the camera is pointing. Previously, movement was independent from the camera's rotation, which of course wouldn't make sense for a game like this.</p>
|
||||
<Video src="2023-09-16_03.mp4" />
|
||||
|
||||
<h2>Helicopter Ratchet</h2>
|
||||
<p>character go spinny</p>
|
||||
<p>The pause menu also makes a brief cameo! It's designed in a very simple way, and meant to replicate the pause menu from Ratchet & Clank 2002 while being legally distinct!</p>
|
||||
<Video src="2023-09-23_00.mp4" />
|
||||
<img src="2023-09-23_01.webp" alt="Close-up of the new pause menu">
|
||||
|
||||
<h2>A Gun</h2>
|
||||
<p>The gun can shoot! Or can it? Well, the bullet doesn't exactly move…</p>
|
||||
<Video src="2023-09-24_00.mp4" />
|
||||
<p>Bullets have been converted into <code>RigidBody3D</code> which is great for collision but unfortunately initialises the bullets to be affected by gravity. Since the bullets are also parented to the player, it means that the fallen bullets move with the player. I don't think that's how guns are supposed to work.</p>
|
||||
<Video src="2023-09-24_01.mp4" />
|
||||
<p>The gun now shoots properly! Not only do the bullets fly, but they fly in the correct direction as well! This is possible thanks to simple vector math, as the only thing needed to calculate a velocity vector for the bullet is to put two nodes on the gun, one at the front (where the bullet will fly from) and one further back, and calculate a vector between the two nodes!</p>
|
||||
<Video src="2023-09-24_02.mp4" />
|
||||
<img src="2023-09-24_03.webp" alt="Diagram for the bullet trajectory calculation">
|
||||
|
||||
<h2>Dialogue</h2>
|
||||
<p>The game now supports talking with NPCs. I only implemented this because I thought of something funny and I wanted to put it in the game.</p>
|
||||
<Video src="2023-09-25.mp4" />
|
||||
|
||||
<h2>Conversation Camera</h2>
|
||||
<p>There's now a special camera angle for conversations with NPCs! Unfortunately, as the camera is bound to the player, and the player's position is unmodified when entering a conversation, this can result in blocking the NPC, or even facing a different direction entirely – how rude!</p>
|
||||
<Video src="2023-09-28.mp4" />
|
||||
|
||||
<h2>Don't Waste Your Ammo!</h2>
|
||||
<p>Guns now have ammo counters! They can only fire for as long as they have ammunition left – as it should be. Unfortunately, unloading bullets unto Sans does nothing.</p>
|
||||
<Video src="2023-09-29_00.mp4" />
|
||||
|
||||
<h2>Smooth Player Movement</h2>
|
||||
<p>Using <code>lerp()</code> as well as <code>lerp_rotation()</code>, the player's movements are now smoother than before! The character rotates smoothly whenever pointing in a given direction and when strafing. Furthermore, the character now has a slight acceleration and deceleration in their movement.</p>
|
||||
<Video src="2023-09-29_01.mp4" />
|
||||
|
||||
<h2>Language Options</h2>
|
||||
<p>The game now supports English and German as language options! Godot makes this very easy. All that's needed is to create a table with keys and the corresponding translations, export it as CSV, add them to the game (and don't forget to add the generated translation files in the project settings as well!), and then use <code>TranslationServer.setLocale(locale)</code> to set the language whenever needed – game defaults to English <code>en</code>. For UI elements, supplying the key in the text field suffices, and for strings in script, use <code>tr(key)</code>. Easy as that!</p>
|
||||
<Video src="2023-09-30_00.mp4" />
|
||||
|
||||
<h2>Imposing dominance</h2> <!-- get it? -->
|
||||
<img src="2023-09-29.webp" alt="Ratchet from Ratchet: Gladiator and Sans from Undertale t-posing">
|
||||
|
||||
<h2>Learning to Model and Rig a Character</h2>
|
||||
<p>today's task: modelling and rigging a character from scratch</p>
|
||||
<img src="2023-09-30_01.webp" alt="A wiremesh of a mesh with a wiremesh of Ratchet from Ratchet: Gladiator in the background as reference">
|
||||
<p>(Ratchet for scale)</p>
|
||||
<p>whaddya lookin at pinhead</p>
|
||||
<img src="2023-09-30_02.webp" alt="The previous head but with a very long neck">
|
||||
<p>is it a bird? is it a plane? no, it's arms</p>
|
||||
<img src="2023-09-30_03.webp" alt="The head attached to a set of shoulders and arms in t-pose">
|
||||
<p>*Mii Maker theme intensifies*</p>
|
||||
<img src="2023-09-30_04.webp" alt="The head and arms with a torso added, standing next to Ratchet from Ratchet: Gladiator">
|
||||
<p>feet are difficult</p>
|
||||
<img src="2023-09-30_05.webp" alt="A close-up of rectangular feet">
|
||||
<p>yoooo actually, not half bad</p>
|
||||
<img src="2023-09-30_06.webp" alt="A close-up of the rounded-out feet">
|
||||
<p>that one might hurt</p>
|
||||
<img src="2023-09-30_07.webp" alt="The left arm of the character, with a face twisted to suggest that the arm has been broken">
|
||||
<p>we have a character!!</p>
|
||||
<img src="2023-09-30_08.webp" alt="A full-body shot of the newly-modelled character">
|
||||
<p><i>we've been rigged!</i></p>
|
||||
<Video src="2023-09-30_09.mp4" />
|
||||
<p><code>we come in peace</code></p>
|
||||
<img src="2023-09-30_10.webp" alt="The new character with its skeleton on the left, and its skeleton without the mesh on the right">
|
||||
<p>brief texture troubles</p>
|
||||
<img src="2023-09-30_11.webp" alt="The textured character on the right and the texture of the character on the left">
|
||||
<p>my character is now a playable character</p>
|
||||
<img src="2023-09-30_12.webp" alt="The newly-textured character holding a purple blaster in-game">
|
||||
<img src="2023-09-30_13.webp" alt="The Buzz Lightyear meme where he says: 'hmm yes the character here is made out of character'">
|
||||
</Content>
|
||||
@@ -1,74 +0,0 @@
|
||||
<script>
|
||||
import BannerTitle from "$lib/banner-title.svelte";
|
||||
import Content from "$lib/content.svelte";
|
||||
import TableOfContents from "$lib/table-of-contents.svelte";
|
||||
import Video from "$lib/video.svelte";
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>2023-10 | denizk0461</title>
|
||||
</svelte:head>
|
||||
|
||||
<Content>
|
||||
<BannerTitle
|
||||
title="Project N5 Progress Update: 2023-10"
|
||||
subtitle=""
|
||||
banner="../../previews/2023/10.webp"
|
||||
bannerAlt="Red protagonist lying on the floor, holding a purple blaster"
|
||||
/>
|
||||
|
||||
<p>My progress in October 2023. Updates are shown in chronological order.</p>
|
||||
|
||||
<TableOfContents disableStickyScrolling={true} />
|
||||
|
||||
<h2>Implementing RigidBody3D Character Movement</h2>
|
||||
<p>Today's task: reimplementing my player character as a <code>RigidBody3D</code>. In the example below, it is using <code>CharacterController3D</code>. I wanted to make this change to get more natural feeling movement and physics, particularly in carrying momentum.</p>
|
||||
<Video src="2023-10-03_00.mp4" />
|
||||
<p>oops i've had a bit of a tumble</p>
|
||||
<Video src="2023-10-03_01.mp4" />
|
||||
<p>This is the result of the <code>RigidBody3D</code> implementation in my character. I used a script from the following video, which served as a great base – the only good one I could find, in fact. Most people on the internet seem to want others to use <code>CharacterController3D</code>, and for good reasons; it's simple, it works, and it's easy to adjust and tweak, unlike a <code>RigidBody3D</code>. And so I had to admit: I wasn't happy with my implementation. I changed the script in large parts, only keeping a few segments, but it never felt quite like I wanted to. It felt too loose.</p>
|
||||
<p><a href="https://www.youtube.com/watch?v=ZLTYlZgZc-0&t=986s">Godot 4.0: I solved my CharacterBody3d issues by using RigidBody3d for character movement!</a></p>
|
||||
<Video src="2023-10-03_02.mp4" />
|
||||
<p><code>RigidBody3D</code> also greeted me with some bugs I had encountered in Unity but was initially spared from when I switched to Godot and its <code>CharacterController3D</code> implementation. A significant issue was the double jump; the character would often not be able to recognise that it had been grounded, and thus it would not allow the player to jump again. Another issue was glitching; the video shows how the character sinks into the ground briefly before jumping up. I have no idea why this happened.</p>
|
||||
<Video src="2023-10-03_03.mp4" />
|
||||
<p>Using a momentum-based character also introduces the issue of sliding up slopes and ramps with the carried momentum a little more than I would like.</p>
|
||||
<Video src="2023-10-03_04.mp4" />
|
||||
<p>And so, after 10 hours of implementing RigidBody3D, I decided to go back to CharacterController3D. I played a bit of Ratchet & Clank for reference, and decided that they might be using a <code>RigidBody</code> implementation (did a <code>CharacterController</code> even exist back then? Did their engine support that even?), but I could get closer to their movement more easily using a <code>CharacterController</code> and emulating a few momentum-based movements using <code>lerp</code>s.</p>
|
||||
<p>The effort was not in vain, however! I implemented the ground <code>RayCast</code> that was necessary for my <code>RigidBody3D</code> implementation in my <code>CharacterController</code>, which, together with a plane calculation, allows for adjusting the character movement velocity when moving on slopes! This corrects the player's uphill speed, and it also prevents jumpy movement when running down a slope! It's currently a little glitch-prone though, crashing the game when standing on Sans, for example, but I'll fix that soon.</p>
|
||||
<h2>Healthy</h2>
|
||||
<p>We now have health points! As it is currently set up, the health bar supports up to 8 health points. For testing purposes, I set up the melee attack to drain health, and the gunshot to heal the player.</p>
|
||||
<Video src="2023-10-07_00.mp4" />
|
||||
<p>The health bar even aligns properly for 5 and 6 max health points, reducing the max points displayed per line from 4 to 3!</p>
|
||||
<div class="horizontally-centre-aligned">
|
||||
<img src="2023-10-07_01.webp" alt="Five health points in the shape of plusses">
|
||||
<img src="2023-10-07_02.webp" alt="Six health points in the shape of plusses">
|
||||
</div>
|
||||
|
||||
<h2>What Are the Controls??</h2>
|
||||
<p>We have a controls screen! This task would have been easier if the game was specific to a console, thus necessitating only one controller layout. Instead, I used Godot's <code>Input.get_joy_name()</code> function to retrieve the first connected controller's name, and use that to display an appropriate screen. Current options are PlayStation (DualSense), Xbox (Series X/S), and Nintendo (Switch Pro Con). Keyboard/Mouse layout will follow soon(ish).</p>
|
||||
<p>Specifying controller layouts for different controllers is difficult though, since I don't know the controller's names (I currently only have the following strings: “PS5 Controller”, “XInput Gamepad” (through emulation using DS4Windows), and “Nintendo Switch Pro Controller”).</p>
|
||||
<p>Another difficulty is figuring out which controller layout to show if multiple controllers are connected, or when KBM is used even though a controller is connected. I currently check for the first connected controller, which means that, if multiple controllers are connected, the layout shown may be wrong. Furthermore, connecting a controller always overrides the KBM layout, since KBM is currently the default. A solution to this may be to check which controller last sent an input, and retrieving that controller's name.</p>
|
||||
<img src="2023-10-10_00.webp" alt="Controls screen displaying a DualSense controller">
|
||||
<img src="2023-10-10_01.webp" alt="Controls screen displaying a Nintendo Switch Pro controller">
|
||||
<img src="2023-10-10_02.webp" alt="Controls screen displaying an Xbox Series controller">
|
||||
|
||||
<h2>Quick Select</h2>
|
||||
<p>I've done some work on the quick select menu to get it functional. The goal is to emulate its behaviour in the Ratchet & Clank games (duh). Current functionality is as follows:</p>
|
||||
<p>The Quick Select menu opens when the E key (keyboard) or the North face button (controller) is pressed, and closes once the button is released. Using the Keyboard/Mouse control layout, the player is able to pick a weapon by hovering over it. The focussed weapon is equipped once the Quick Select menu is closed. Controller users point the left stick in the desired direction to focus on an item.</p>
|
||||
<Video src="2023-10-14.mp4" />
|
||||
|
||||
<h2>Heavy Weaponry</h2>
|
||||
<p>In order to get started with the 3D models I'll need to create for the game, I attempted to begin the process of modelling the weapon of the protagonist! It's supposed to become a battle axe, though I have not yet finalised whether I'll keep with the idea.</p>
|
||||
<div class="horizontally-centre-aligned width-restricted">
|
||||
<img src="2023-10-22_02.webp" alt="Top view of the battle axe with a flat blade">
|
||||
<img src="2023-10-22_04.webp" alt="Top view of the battle axe with a thickened blade">
|
||||
<img src="2023-10-22_05.webp" alt="Side view of the battle axe">
|
||||
</div>
|
||||
|
||||
<h2>Hot, Fresh Quality</h2>
|
||||
<p>In order to test animation and rigging of arbitrary 3D models, I created these bread-centred animations. This obsession with toast came to me after a friend of mine and I took a test that determined <a href="https://www.buzzfeed.com/mathewguiver/which-type-of-bread-are-you">which type of bread we are</a>. Despite vastly different answers, our end results were both 'vegan biscuit.'</p>
|
||||
<Video src="2023-10-25_00.mp4" />
|
||||
<Video src="2023-10-25_01.mp4" />
|
||||
<p>I like my bread with bones, <i>thank you very much.</i></p>
|
||||
<img src="2023-10-25_02.webp" alt="A rigged slice of toast in front of a toaster reading 'Deniz' Quality Toasters'">
|
||||
</Content>
|
||||
@@ -1,79 +0,0 @@
|
||||
<script>
|
||||
import BannerTitle from "$lib/banner-title.svelte";
|
||||
import Content from "$lib/content.svelte";
|
||||
import TableOfContents from "$lib/table-of-contents.svelte";
|
||||
import Video from "$lib/video.svelte";
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>2023-11 | denizk0461</title>
|
||||
</svelte:head>
|
||||
|
||||
<Content>
|
||||
<BannerTitle
|
||||
title="Project N5 Progress Update: 2023-11"
|
||||
subtitle=""
|
||||
banner="../../previews/2023/11.webp"
|
||||
bannerAlt="A side view of the N5 Blaster"
|
||||
/>
|
||||
|
||||
<p>My progress in November 2023. Updates are shown in chronological order.</p>
|
||||
|
||||
<TableOfContents disableStickyScrolling={true} />
|
||||
|
||||
<h2>Gearing Up</h2>
|
||||
<p>Lots of progress on the 3D models! I modelled the first weapon for the game, the N5 Blaster, from start to finish!</p>
|
||||
<p>The earliest version was based on an 8-sided cylinder. After some feedback from friends, I remade the weapon, using a 16-sided cylinder, and also adding more details to the weapon overall. More attention went into the grip, which now resembled a weapon grip more so than a stick.</p>
|
||||
<div class="horizontally-centre-aligned">
|
||||
<img src="2023-11-05_00.webp" alt="N5 Blaster v1 made from an 8-sided cylinder">
|
||||
<img src="2023-11-03_01.webp" alt="N5 Blaster v2 made from a 16-sided blaster and with additional lights on the grip">
|
||||
<img src="2023-11-05_03.webp" alt="N5 Blaster v3 with additional lights on the body">
|
||||
</div>
|
||||
<p>Here's an overview of the first model.</p>
|
||||
<Video src="2023-11-03_00.mp4" />
|
||||
<p>The final version of the weapon layers a black wireframe on top of the icosphere, so that in the game it's a bit more clearly visible that it rotates, and it uses smooth shading. I was against using smooth shading initially, as I wanted to go for a low-poly artstyle, but I think that approach just looked a bit cheap, considering my 3D models aren't exactly high-quality by themselves. Smooth shading gives the impression of smooth, high-poly models at a significant reduction in vertices.</p>
|
||||
<img src="2023-12-11.webp" alt="Close-up of smoothly-shaded N5 Blaster v3">
|
||||
<p>Here's the icon for the N5 Blaster that's to be used in the quick select menu, the item menu, and the HUD. The icon will be tinted in different colours when the weapon has been levelled up.</p>
|
||||
<p>In my first attempt at creating this icon, I took a picture of the wireframed icosphere that's in the weapon, and I tried to vectorise it using Inkscape. That didn't work the way I wanted, so I hand-traced all the lines from the icosphere. I was confused as to why it's not symmetrical, but I later realised that that's just how the icosphere looks.</p>
|
||||
<img src="n5blaster_icon.webp" alt="N5 Blaster icon">
|
||||
<p>I also continued work on the battle axe, giving it more character. It's still not close to being finished, but it's now a bit less of a rough draft.</p>
|
||||
<div class="horizontally-centre-aligned">
|
||||
<img src="2023-11-01_01.webp" alt="Battle axe with a hollowed-out blade">
|
||||
<img src="2023-11-01_06.webp" alt="Battle axe with a stabilising pattern in the blade">
|
||||
<img src="2023-11-01_09.webp" alt="Battle axe with two blades">
|
||||
</div>
|
||||
<p>I will admit though that I'm unsure whether I'll actually stick with the battle axe as the protagonist's main melee weapon.</p>
|
||||
<p>Another idea, though more as an unlockable extra, is Derek the crowbar.</p>
|
||||
<img src="2023-11-06_02.webp" alt="A crowbar">
|
||||
<p>I also worked on the upgrade for the N5 Blaster, the N5 Cannon. Progress on that one has been a bit slow, since I have yet to figure out what kind of weapon I want the upgraded version to be.</p>
|
||||
<div class="horizontally-centre-aligned">
|
||||
<img src="2023-11-12_04.webp" alt="N5 Cannon body">
|
||||
<img src="2023-11-12_02.webp" alt="N5 Cannon Body next to the N5 Blaster">
|
||||
</div>
|
||||
<p>And, as a bonus, here's the discarded, very-early-WIP draft I created for a rifle-type weapon. I don't think this type of weapon fits the type of game I'm making.</p>
|
||||
<img src="2023-11-12_00.webp" alt="Untextured body and scope of a rifle">
|
||||
<p>And a draft of a rocket launcher with 9 barrels! This is heavily inspired by the <a href="https://ratchetandclank.fandom.com/wiki/R.Y.N.O._(2002_game)">R.Y.N.O. from Ratchet & Clank</a>. It's coloured blue because I was investigating issues with the mesh's normals at the time.</p>
|
||||
<img src="2023-11-02_01.webp" alt="Front of a 9-barrel rocket launcher with visualised normals">
|
||||
|
||||
<h2>A Star is Born</h2>
|
||||
<p>I begun modelling my protagonist! I didn't progress far, as I currently lack a vision for where I really want my character to go in detail. I have slight ideas – inspirations are, for example, <a href="https://hero.fandom.com/wiki/Merc_and_Green">Merc & Green from Ratchet: Gladiator</a>, and <a href="denholm.webp">Denholm Reynholm</a>. I quite liked the idea of having glowing tubes on the character's back; I got the inspiration from a Blender tutorial that was randomly recommended to me one morning.</p>
|
||||
<div class="horizontally-centre-aligned">
|
||||
<img src="2023-11-11_05.webp" alt="Tubes for the back of the protagonist">
|
||||
<img src="2023-11-12_01.webp" alt="Glowing tubes attached to a torso block">
|
||||
</div>
|
||||
<p>i love</p>
|
||||
<Video src="2023-11-11_09.mp4" />
|
||||
|
||||
<h2>Real-World Testing</h2>
|
||||
<p>On a whim, I decided to import the N5 Blaster's model into my game. Doing that was honestly quite the motivational boost at the time, as it visualised my progress. I could actually play <i>my game</i> with <i>my weapon!</i> It's not finished at all, it has no proper mechanics implemented other than the shooting copied from the Purple Gun, and the glass is also not actually transparent.</p>
|
||||
<Video src="2023-11-21.mp4" />
|
||||
|
||||
<h2>Inventory System</h2>
|
||||
<p>I implemented an inventory system somewhat akin to Ratchet & Clank's. It shows the weapons the player has acquired, previewing the model in a 3D sub-viewport. Later, it will also show the weapon's name, remaining ammo, perhaps statistics such as damage, and a description. But that's a task for later.</p>
|
||||
<p>The only reason that the Purple Gun as well as the N5 Blaster show up multiple times is because I wanted to test all inventory slots, and I didn't have any weapons other than those two implemented.</p>
|
||||
<Video src="2023-11-24.mp4" />
|
||||
|
||||
<h2>My Best Friend JSON</h2>
|
||||
<p>It might seem simple (or look complicated), but I came up with the idea of creating a JSON-based lookup table for the weapon metadata. Using this, it's quite easy to retrieve any kind of information about any kind of weapon without needing to hardcode it into the weapon itself. Here's an early screenshot of the lookup table.</p>
|
||||
<img src="2023-11-25.webp" alt="A screenshot of the weapon lookup table JSON">
|
||||
</Content>
|
||||
@@ -1,77 +0,0 @@
|
||||
<script>
|
||||
import BannerTitle from "$lib/banner-title.svelte";
|
||||
import Content from "$lib/content.svelte";
|
||||
import TableOfContents from "$lib/table-of-contents.svelte";
|
||||
import Video from "$lib/video.svelte";
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>2023-12 | denizk0461</title>
|
||||
</svelte:head>
|
||||
|
||||
<Content>
|
||||
<BannerTitle
|
||||
title="Project N5 Progress Update: 2023-12"
|
||||
subtitle=""
|
||||
banner="../../previews/2023/12.webp"
|
||||
bannerAlt="White protagonist holding the N5 Blaster"
|
||||
/>
|
||||
|
||||
<p>My progress in December 2023. Updates are shown in chronological order.</p>
|
||||
|
||||
<TableOfContents disableStickyScrolling={true} />
|
||||
|
||||
<h2>Identity Crisis</h2>
|
||||
<p>I started creating a logo for my game! I settled on the name <b>Project N5</b> as a working title, and perhaps as a final title for the game as well. Here's all the logos I created thus far:</p>
|
||||
<p>Logo #0 is just an outline using <a href="https://fonts.google.com/specimen/Kanit">Kanit</a>. This is the font I also decided on for all of the in-game menus and text. The 5 is special though; it is based on a part salvaged from a hard drive. On a slow day, my coworker disassembled some defective mechanical hard drives, and I got to keep the parts. I thought it would look quite cool as a highlight for the game's logo, and perhaps function as a part of the in-game antagonist company that I'm planning to write the story around.</p>
|
||||
<img class="image-block centred width-restricted light-background" src="projectn5-logo-outline.webp" alt="Outlined Project N5 logo">
|
||||
<img src="hdd.webp" alt="C-shaped hard drive component">
|
||||
<p>Logo #1 gained a fill, wider stroke, and a pattern fill that's straight outta Inkscape.</p>
|
||||
<img class="image-block centred width-restricted light-background" src="projectn5-logo-fill-v1.webp" alt="Outlined Project N5 logo with grey infill">
|
||||
<p>#2 reserves the pattern fill for the N5 part and colours the 5 in the game's main yellow colour, #D4AB49. It's also much thicker.</p>
|
||||
<img src="projectn5-logo-v2.webp" alt="Project N5 logo with thicker letter strokes">
|
||||
<p>Version 3 is a complete overhaul, still using Kanit for the N, keeping the custom 5, but changing the font of the word 'Project' to <a href="https://www.collletttivo.it/typefaces/apfel-grotezk">Apfel Grotezk</a>. Unfortunately, that font doesn't really work well in all-caps. The J just stood out too poorly for my liking, and friends confirmed it.</p>
|
||||
<p>The hexagonal background behind the N5 actually was a fairly random addition, but I liked it so much that it continued to stick. I think this could also serve as part of the player's HUD. Maybe as an element that shows the level of the currently equipped weapon? I love when ideas sprout from random decisions like this!</p>
|
||||
<img src="projectn5-logo-v3.webp" alt="Project N5 logo typeset in Apfel Grotezk and with the C-shaped hard drive component integrated into the 5">
|
||||
<p>I also tried <a href="https://fonts.google.com/specimen/Lato">Lato</a>, but that looked too standard, and not quite as expressive as I wanted it to. Relatively speaking, considering we're talking about regular sans-serif fonts, of course.</p>
|
||||
<p>A friend also suggested I cut apart the top part of the 5, leaving a gap, and I think that looked quite cool! I continued that trend for the HDD-inspired bits on the lower part of the 5, simplifying them, detaching them from the main bottom part, and even removing one element. The element that was removed actually served as the part that sticks out in the upper part of the lower part – if that makes sense. It's now located near the cutting point between the upper and lower parts of the digit.</p>
|
||||
<p>I also tore apart the N on my own volition. Thought it looked cool.</p>
|
||||
<img src="projectn5-logo-v4.webp" alt="Project N5 logo typeset in Lato. Slices have been added to the N and 5">
|
||||
<p>This logo uses <a href="https://fonts.google.com/specimen/Montserrat">Monserrat ExtraBold</a>. I actually quite liked this font; it looked unified, bold, and actually quite fitting for my vision!</p>
|
||||
<img src="projectn5-logo-v5.webp" alt="Project N5 logo typeset in Monserrat">
|
||||
<p>Then I inset the C into the T, creating a neat little cutout effect.</p>
|
||||
<img src="projectn5-logo-v6.webp" alt="Project N5 logo with a cutout in the T">
|
||||
<p>I then decided to put a splash of colour behind the 'Project' wordmark, and highlighting the background with two hexagons.</p>
|
||||
<p>Do you think the comment is right? I'm unsure. Amongst all the people I've shown this logo to, the decision has been split 50/50. I just don't want people to consider this the 'dick logo.'</p>
|
||||
<p>I've also received comments from some people who are irked by the T in 'Project' overlapping with the background of the N5. I actually quite like that feature, but I'll take it into consideration, and maybe change it in the near future.</p>
|
||||
<img src="projectn5-logo-v7.webp" alt="Project N5 logo with a golden background and a note on top that reads 'TODO this looks like a dick'">
|
||||
<p>And lastly, a little draft logo I created, based on #7, in <a href="https://www.getpaint.net/">Paint.net</a>, which is why it doesn't look as clean as the other ones, which are all vector-based logos created in Inkscape.</p>
|
||||
<p>I want my work to be transferrable and easily scale-able after all, you know?</p>
|
||||
<img src="projectn5-logo-v7-sketch.webp" alt="Project N5 logo with golden letters">
|
||||
|
||||
<h2>Glowing Weaponry</h2>
|
||||
<p>I was struggling for SO LONG to get this weapon to glow. Using a <code>WorldEnvironment</code> node just wouldn't work, the weapon never glowed. Then, I figured out that, at some point, I disabled glow in the entire scene... and after changing that – and trying other things for 1.5 hours before that point – the weapon was glowing! Not quite the way I want it to, but that's easy to tweak. Only downside is that my character started glowing as well, for some reason, but I'll figure that out another time.</p>
|
||||
<img src="2023-12-08.webp" alt="N5 Blaster on the floor and Sans t-posing in the background">
|
||||
|
||||
<h2>Character II</h2>
|
||||
<p>For testing animations, I created a new rigged character. This character is segmented, using separate objects for its arms, fingers, legs, etc. The final protagonist will use completely separate objects, since the character will be a robot. This will also reduce the work I will need to do in weight painting, and make mesh bends trivial – which is to say, not necessary.</p>
|
||||
<img src="2023-12-12_00.webp" alt="A new rigged character model">
|
||||
<p>Rigging remains as difficult as ever. The final model – which won't be based on this model but use a similar rig, hopefully the same so that animations can be carried over 1:1 – will have separate segments for the fingers, so that bends like this will never occur.</p>
|
||||
<p>Notice that the character only has four fingers per hand. This should reduce animation work somewhat. Also, I came to realise – why even put five fingers on a robot? It's not like we as humans even utilise our five fingers very efficiently. I've found myself struggling to keep my pinky out of my way countless times.</p>
|
||||
<Video src="2023-12-12_01.mp4" />
|
||||
<p><code>hello world! nice to meet you</code></p>
|
||||
<p>This uses 1-frame animations to achieve posing. My first attempt at using animations in Godot! Worked really well, actually. All I fear now is playing multiple animations at once. Is that even possible? I don't know yet.</p>
|
||||
<Video src="2023-12-12_02.mp4" />
|
||||
<p>And finally, a shot of the character holding the weapon correctly. This was actually super easy to achieve. The weapon is parented to a node that's attached to the right hand bone of the model. This makes posing and animations loads easier, since the equipped item does not have to be moved manually.</p>
|
||||
<img src="2023-12-12_03.webp" alt="The new character model in front of a brick wall, holding the N5 Blaster">
|
||||
|
||||
<h2>Worldbuilding – Toasters</h2>
|
||||
<p>Adapted from the early animations, I present: Deniz' Quality Toasters! A fictitious toaster manufacturing company bearing my name – maybe they manufacture more than just toasters? The logo is using the font <a href="https://fonts.google.com/specimen/Pacifico">Pacifico</a>.</p>
|
||||
<img src="dqt.webp" alt="Wordmark for Deniz' Quality Toasters">
|
||||
<p>I don't actually know whether I'll use this in any way, I just wanted to create this logo for the sake of it.</p>
|
||||
|
||||
<h2>Simultaneous Animations</h2>
|
||||
<p>I managed to implement the ability to play multiple animations at a time! The character can now walk + point its gun, or keep its arms down. There's no animation for standing still yet, so it perpetually walks, but this is huge progress, and more importantly, a huge fear of mine alleviated! I was really concerned that implementing multiple animations would be a tedious task, but with Godot's <code>AnimationTree</code> node, it's actually rather trivial.</p>
|
||||
<p>I followed <a href="https://www.youtube.com/watch?v=WY2cN9uG6W8">this</a> extremely useful and concise tutorial.</p>
|
||||
<Video src="simultaneous-animations.mp4" />
|
||||
</Content>
|
||||
93
src/routes/projects/projectn5/devlog/202309.md
Normal file
@@ -0,0 +1,93 @@
|
||||
---
|
||||
title: 'Progress Update #1'
|
||||
date: '2023-09'
|
||||
tag: '202309'
|
||||
bannerAlt: 'Ratchet from Ratchet: Gladiator and Sans from Undertale t-posing'
|
||||
---
|
||||
<script lang="ts">
|
||||
import Video from "$lib/video.svelte";
|
||||
</script>
|
||||
|
||||
My progress in September 2023. Updates are shown in chronological order.
|
||||
|
||||
## One Small Step
|
||||
A character has been added and the player can control them! It's influenced by gravity too, although it falls at an unnaturally rapid rate when thrown off the edge. This is because the downward velocity kept increasing even when grounded, and is fixed in a later version. Also, the character faces the wrong direction; moving forward results in the character facing the camera instead of forward. This is fixed once I replaced the character model with one where it's more obvious which side is forward.
|
||||
<Video src="2023-09-16_00.mp4" />
|
||||
|
||||
## Gravity Functions As It Should
|
||||
Gravity is fixed, and the camera angle has been adjusted, though not fixed to the character yet. It's kind of funny watching this little character move around.
|
||||
<Video src="2023-09-16_01.mp4" />
|
||||
|
||||
## Look Where You're Jumping!
|
||||
The character can jump! Jump height is set unnaturally high as a test. The player can double jump, but only from a grounded state; falling off a cliff counts as the first jump, thus only allowing the player to jump once. Also, gravity is broken again. Also, a player-controllable camera! This was implemented with a custom third person camera plugin, which proved to be a bit jumpy.
|
||||
<Video src="2023-09-16_02.mp4" />
|
||||
|
||||
## A Better Camera
|
||||
The camera system has been replaced! This implementation simply uses `SpringArm3D` with a `Camera3D` as its child. This allows for the camera to not clip into walls (though it really likes clipping into the floor for some reason), and overall feels much more responsive. Not just that though – the player's movement input is now adjusted to where the camera points! When the player presses forward, they are now moving in the direction the camera is pointing. Previously, movement was independent from the camera's rotation, which of course wouldn't make sense for a game like this.
|
||||
<Video src="2023-09-16_03.mp4" />
|
||||
|
||||
## Helicopter Ratchet
|
||||
character go spinny
|
||||
The pause menu also makes a brief cameo! It's designed in a very simple way, and meant to replicate the pause menu from Ratchet & Clank 2002 while being legally distinct!
|
||||
<Video src="2023-09-23_00.mp4" />
|
||||
<img src="2023-09-23_01.webp" alt="Close-up of the new pause menu">
|
||||
|
||||
## A Gun
|
||||
The gun can shoot! Or can it? Well, the bullet doesn't exactly move…
|
||||
<Video src="2023-09-24_00.mp4" />
|
||||
Bullets have been converted into `RigidBody3D` which is great for collision but unfortunately initialises the bullets to be affected by gravity. Since the bullets are also parented to the player, it means that the fallen bullets move with the player. I don't think that's how guns are supposed to work.
|
||||
<Video src="2023-09-24_01.mp4" />
|
||||
The gun now shoots properly! Not only do the bullets fly, but they fly in the correct direction as well! This is possible thanks to simple vector math, as the only thing needed to calculate a velocity vector for the bullet is to put two nodes on the gun, one at the front (where the bullet will fly from) and one further back, and calculate a vector between the two nodes!
|
||||
<Video src="2023-09-24_02.mp4" />
|
||||
<img src="2023-09-24_03.webp" alt="Diagram for the bullet trajectory calculation">
|
||||
|
||||
## Dialogue
|
||||
The game now supports talking with NPCs. I only implemented this because I thought of something funny and I wanted to put it in the game.
|
||||
<Video src="2023-09-25.mp4" />
|
||||
|
||||
## Conversation Camera
|
||||
There's now a special camera angle for conversations with NPCs! Unfortunately, as the camera is bound to the player, and the player's position is unmodified when entering a conversation, this can result in blocking the NPC, or even facing a different direction entirely – how rude!
|
||||
<Video src="2023-09-28.mp4" />
|
||||
|
||||
## Don't Waste Your Ammo!
|
||||
Guns now have ammo counters! They can only fire for as long as they have ammunition left – as it should be. Unfortunately, unloading bullets unto Sans does nothing.
|
||||
<Video src="2023-09-29_00.mp4" />
|
||||
|
||||
## Smooth Player Movement
|
||||
Using `lerp()` as well as `lerp_rotation()`, the player's movements are now smoother than before! The character rotates smoothly whenever pointing in a given direction and when strafing. Furthermore, the character now has a slight acceleration and deceleration in their movement.
|
||||
<Video src="2023-09-29_01.mp4" />
|
||||
|
||||
## Language Options
|
||||
The game now supports English and German as language options! Godot makes this very easy. All that's needed is to create a table with keys and the corresponding translations, export it as CSV, add them to the game (and don't forget to add the generated translation files in the project settings as well!), and then use `TranslationServer.setLocale(locale)` to set the language whenever needed – game defaults to English `en`. For UI elements, supplying the key in the text field suffices, and for strings in script, use `tr(key)`. Easy as that!
|
||||
<Video src="2023-09-30_00.mp4" />
|
||||
|
||||
## Imposing dominance <!-- get it? -->
|
||||
<img src="2023-09-29.webp" alt="Ratchet from Ratchet: Gladiator and Sans from Undertale t-posing">
|
||||
|
||||
## Learning to Model and Rig a Character
|
||||
today's task: modelling and rigging a character from scratch
|
||||
<img src="2023-09-30_01.webp" alt="A wiremesh of a mesh with a wiremesh of Ratchet from Ratchet: Gladiator in the background as reference">
|
||||
(Ratchet for scale)
|
||||
whaddya lookin at pinhead
|
||||
<img src="2023-09-30_02.webp" alt="The previous head but with a very long neck">
|
||||
is it a bird? is it a plane? no, it's arms
|
||||
<img src="2023-09-30_03.webp" alt="The head attached to a set of shoulders and arms in t-pose">
|
||||
*Mii Maker theme intensifies*
|
||||
<img src="2023-09-30_04.webp" alt="The head and arms with a torso added, standing next to Ratchet from Ratchet: Gladiator">
|
||||
feet are difficult
|
||||
<img src="2023-09-30_05.webp" alt="A close-up of rectangular feet">
|
||||
yoooo actually, not half bad
|
||||
<img src="2023-09-30_06.webp" alt="A close-up of the rounded-out feet">
|
||||
that one might hurt
|
||||
<img src="2023-09-30_07.webp" alt="The left arm of the character, with a face twisted to suggest that the arm has been broken">
|
||||
we have a character!!
|
||||
<img src="2023-09-30_08.webp" alt="A full-body shot of the newly-modelled character">
|
||||
<i>we've been rigged!</i>
|
||||
<Video src="2023-09-30_09.mp4" />
|
||||
`we come in peace`
|
||||
<img src="2023-09-30_10.webp" alt="The new character with its skeleton on the left, and its skeleton without the mesh on the right">
|
||||
brief texture troubles
|
||||
<img src="2023-09-30_11.webp" alt="The textured character on the right and the texture of the character on the left">
|
||||
my character is now a playable character
|
||||
<img src="2023-09-30_12.webp" alt="The newly-textured character holding a purple blaster in-game">
|
||||
<img src="2023-09-30_13.webp" alt="The Buzz Lightyear meme where he says: 'hmm yes the character here is made out of character'">
|
||||
96
src/routes/projects/projectn5/devlog/202310.md
Normal file
@@ -0,0 +1,96 @@
|
||||
---
|
||||
title: 'Progress Update #2'
|
||||
date: '2023-10'
|
||||
tag: '202310'
|
||||
bannerAlt: Red protagonist lying on the floor, holding a purple blaster
|
||||
---
|
||||
<script lang="ts">
|
||||
import Video from "$lib/video.svelte";
|
||||
</script>
|
||||
|
||||
My progress in October 2023. Updates are shown in chronological order.
|
||||
|
||||
## Implementing RigidBody3D Character Movement
|
||||
|
||||
Today's task: reimplementing my player character as a `RigidBody3D`. In the example below, it is using `CharacterController3D`. I wanted to make this change to get more natural feeling movement and physics, particularly in carrying momentum.
|
||||
|
||||
<Video src="2023-10-03_00.mp4" />
|
||||
|
||||
oops i've had a bit of a tumble
|
||||
|
||||
<Video src="2023-10-03_01.mp4" />
|
||||
|
||||
This is the result of the `RigidBody3D` implementation in my character. I used a script from the following video, which served as a great base – the only good one I could find, in fact. Most people on the internet seem to want others to use `CharacterController3D`, and for good reasons; it's simple, it works, and it's easy to adjust and tweak, unlike a `RigidBody3D`. And so I had to admit: I wasn't happy with my implementation. I changed the script in large parts, only keeping a few segments, but it never felt quite like I wanted to. It felt too loose.
|
||||
[Godot 4.0: I solved my CharacterBody3d issues by using RigidBody3d for character movement!](https://www.youtube.com/watch?v=ZLTYlZgZc-0&t=986s)
|
||||
|
||||
|
||||
<Video src="2023-10-03_02.mp4" />
|
||||
|
||||
`RigidBody3D` also greeted me with some bugs I had encountered in Unity but was initially spared from when I switched to Godot and its `CharacterController3D` implementation. A significant issue was the double jump; the character would often not be able to recognise that it had been grounded, and thus it would not allow the player to jump again. Another issue was glitching; the video shows how the character sinks into the ground briefly before jumping up. I have no idea why this happened.
|
||||
|
||||
<Video src="2023-10-03_03.mp4" />
|
||||
|
||||
Using a momentum-based character also introduces the issue of sliding up slopes and ramps with the carried momentum a little more than I would like.
|
||||
|
||||
<Video src="2023-10-03_04.mp4" />
|
||||
|
||||
And so, after 10 hours of implementing RigidBody3D, I decided to go back to CharacterController3D. I played a bit of Ratchet & Clank for reference, and decided that they might be using a `RigidBody` implementation (did a `CharacterController` even exist back then? Did their engine support that even?), but I could get closer to their movement more easily using a `CharacterController` and emulating a few momentum-based movements using `lerp`s.
|
||||
|
||||
The effort was not in vain, however! I implemented the ground `RayCast` that was necessary for my `RigidBody3D` implementation in my `CharacterController`, which, together with a plane calculation, allows for adjusting the character movement velocity when moving on slopes! This corrects the player's uphill speed, and it also prevents jumpy movement when running down a slope! It's currently a little glitch-prone though, crashing the game when standing on Sans, for example, but I'll fix that soon.
|
||||
|
||||
## Healthy
|
||||
|
||||
We now have health points! As it is currently set up, the health bar supports up to 8 health points. For testing purposes, I set up the melee attack to drain health, and the gunshot to heal the player.
|
||||
|
||||
<Video src="2023-10-07_00.mp4" />
|
||||
|
||||
The health bar even aligns properly for 5 and 6 max health points, reducing the max points displayed per line from 4 to 3!
|
||||
|
||||
<div class="horizontally-centre-aligned">
|
||||
<img src="2023-10-07_01.webp" alt="Five health points in the shape of plusses">
|
||||
<img src="2023-10-07_02.webp" alt="Six health points in the shape of plusses">
|
||||
</div>
|
||||
|
||||
## What Are the Controls??
|
||||
|
||||
We have a controls screen! This task would have been easier if the game was specific to a console, thus necessitating only one controller layout. Instead, I used Godot's `Input.get_joy_name()` function to retrieve the first connected controller's name, and use that to display an appropriate screen. Current options are PlayStation (DualSense), Xbox (Series X/S), and Nintendo (Switch Pro Con). Keyboard/Mouse layout will follow soon(ish).
|
||||
|
||||
Specifying controller layouts for different controllers is difficult though, since I don't know the controller's names (I currently only have the following strings: “PS5 Controller”, “XInput Gamepad” (through emulation using DS4Windows), and “Nintendo Switch Pro Controller”).
|
||||
|
||||
Another difficulty is figuring out which controller layout to show if multiple controllers are connected, or when KBM is used even though a controller is connected. I currently check for the first connected controller, which means that, if multiple controllers are connected, the layout shown may be wrong. Furthermore, connecting a controller always overrides the KBM layout, since KBM is currently the default. A solution to this may be to check which controller last sent an input, and retrieving that controller's name.
|
||||
|
||||
<img src="2023-10-10_00.webp" alt="Controls screen displaying a DualSense controller">
|
||||
|
||||
<img src="2023-10-10_01.webp" alt="Controls screen displaying a Nintendo Switch Pro controller">
|
||||
|
||||
<img src="2023-10-10_02.webp" alt="Controls screen displaying an Xbox Series controller">
|
||||
|
||||
## Quick Select
|
||||
|
||||
I've done some work on the quick select menu to get it functional. The goal is to emulate its behaviour in the Ratchet & Clank games (duh). Current functionality is as follows:
|
||||
|
||||
The Quick Select menu opens when the E key (keyboard) or the North face button (controller) is pressed, and closes once the button is released. Using the Keyboard/Mouse control layout, the player is able to pick a weapon by hovering over it. The focussed weapon is equipped once the Quick Select menu is closed. Controller users point the left stick in the desired direction to focus on an item.
|
||||
|
||||
<Video src="2023-10-14.mp4" />
|
||||
|
||||
## Heavy Weaponry
|
||||
|
||||
In order to get started with the 3D models I'll need to create for the game, I attempted to begin the process of modelling the weapon of the protagonist! It's supposed to become a battle axe, though I have not yet finalised whether I'll keep with the idea.
|
||||
|
||||
<div class="horizontally-centre-aligned width-restricted">
|
||||
<img src="2023-10-22_02.webp" alt="Top view of the battle axe with a flat blade">
|
||||
<img src="2023-10-22_04.webp" alt="Top view of the battle axe with a thickened blade">
|
||||
<img src="2023-10-22_05.webp" alt="Side view of the battle axe">
|
||||
</div>
|
||||
|
||||
## Hot, Fresh Quality
|
||||
|
||||
In order to test animation and rigging of arbitrary 3D models, I created these bread-centred animations. This obsession with toast came to me after a friend of mine and I took a test that determined [which type of bread we are](https://www.buzzfeed.com/mathewguiver/which-type-of-bread-are-you). Despite vastly different answers, our end results were both 'vegan biscuit.'
|
||||
|
||||
<Video src="2023-10-25_00.mp4" />
|
||||
|
||||
<Video src="2023-10-25_01.mp4" />
|
||||
|
||||
I like my bread with bones, <i>thank you very much.</i>
|
||||
|
||||
<img src="2023-10-25_02.webp" alt="A rigged slice of toast in front of a toaster reading 'Deniz' Quality Toasters'">
|
||||
99
src/routes/projects/projectn5/devlog/202311.md
Normal file
@@ -0,0 +1,99 @@
|
||||
---
|
||||
title: 'Progress Update #3'
|
||||
date: '2023-11'
|
||||
tag: '202311'
|
||||
bannerAlt: A side view of the N5 Blaster
|
||||
---
|
||||
<script lang="ts">
|
||||
import Video from "$lib/video.svelte";
|
||||
</script>
|
||||
|
||||
My progress in November 2023. Updates are shown in chronological order.
|
||||
|
||||
## Gearing Up
|
||||
|
||||
Lots of progress on the 3D models! I modelled the first weapon for the game, the N5 Blaster, from start to finish!
|
||||
|
||||
The earliest version was based on an 8-sided cylinder. After some feedback from friends, I remade the weapon, using a 16-sided cylinder, and also adding more details to the weapon overall. More attention went into the grip, which now resembled a weapon grip more so than a stick.
|
||||
|
||||
<div class="horizontally-centre-aligned">
|
||||
<img src="2023-11-05_00.webp" alt="N5 Blaster v1 made from an 8-sided cylinder">
|
||||
<img src="2023-11-03_01.webp" alt="N5 Blaster v2 made from a 16-sided blaster and with additional lights on the grip">
|
||||
<img src="2023-11-05_03.webp" alt="N5 Blaster v3 with additional lights on the body">
|
||||
</div>
|
||||
|
||||
Here's an overview of the first model.
|
||||
|
||||
<Video src="2023-11-03_00.mp4" />
|
||||
|
||||
The final version of the weapon layers a black wireframe on top of the icosphere, so that in the game it's a bit more clearly visible that it rotates, and it uses smooth shading. I was against using smooth shading initially, as I wanted to go for a low-poly artstyle, but I think that approach just looked a bit cheap, considering my 3D models aren't exactly high-quality by themselves. Smooth shading gives the impression of smooth, high-poly models at a significant reduction in vertices.
|
||||
|
||||
<img src="2023-12-11.webp" alt="Close-up of smoothly-shaded N5 Blaster v3">
|
||||
|
||||
Here's the icon for the N5 Blaster that's to be used in the quick select menu, the item menu, and the HUD. The icon will be tinted in different colours when the weapon has been levelled up.
|
||||
|
||||
In my first attempt at creating this icon, I took a picture of the wireframed icosphere that's in the weapon, and I tried to vectorise it using Inkscape. That didn't work the way I wanted, so I hand-traced all the lines from the icosphere. I was confused as to why it's not symmetrical, but I later realised that that's just how the icosphere looks.
|
||||
|
||||
<img src="n5blaster_icon.webp" alt="N5 Blaster icon">
|
||||
|
||||
I also continued work on the battle axe, giving it more character. It's still not close to being finished, but it's now a bit less of a rough draft.
|
||||
|
||||
<div class="horizontally-centre-aligned">
|
||||
<img src="2023-11-01_01.webp" alt="Battle axe with a hollowed-out blade">
|
||||
<img src="2023-11-01_06.webp" alt="Battle axe with a stabilising pattern in the blade">
|
||||
<img src="2023-11-01_09.webp" alt="Battle axe with two blades">
|
||||
</div>
|
||||
|
||||
I will admit though that I'm unsure whether I'll actually stick with the battle axe as the protagonist's main melee weapon.
|
||||
|
||||
Another idea, though more as an unlockable extra, is Derek the crowbar.
|
||||
|
||||
<img src="2023-11-06_02.webp" alt="A crowbar">
|
||||
|
||||
I also worked on the upgrade for the N5 Blaster, the N5 Cannon. Progress on that one has been a bit slow, since I have yet to figure out what kind of weapon I want the upgraded version to be.
|
||||
|
||||
<div class="horizontally-centre-aligned">
|
||||
<img src="2023-11-12_04.webp" alt="N5 Cannon body">
|
||||
<img src="2023-11-12_02.webp" alt="N5 Cannon Body next to the N5 Blaster">
|
||||
</div>
|
||||
|
||||
And, as a bonus, here's the discarded, very-early-WIP draft I created for a rifle-type weapon. I don't think this type of weapon fits the type of game I'm making.
|
||||
|
||||
<img src="2023-11-12_00.webp" alt="Untextured body and scope of a rifle">
|
||||
|
||||
And a draft of a rocket launcher with 9 barrels! This is heavily inspired by the [R.Y.N.O. from Ratchet & Clank](https://ratchetandclank.fandom.com/wiki/R.Y.N.O._(2002_game)). It's coloured blue because I was investigating issues with the mesh's normals at the time.
|
||||
|
||||
<img src="2023-11-02_01.webp" alt="Front of a 9-barrel rocket launcher with visualised normals">
|
||||
|
||||
## A Star is Born
|
||||
|
||||
I begun modelling my protagonist! I didn't progress far, as I currently lack a vision for where I really want my character to go in detail. I have slight ideas – inspirations are, for example, [Merc & Green from Ratchet: Gladiator](https://hero.fandom.com/wiki/Merc_and_Green), and [Denholm Reynholm](denholm.webp). I quite liked the idea of having glowing tubes on the character's back; I got the inspiration from a Blender tutorial that was randomly recommended to me one morning.
|
||||
|
||||
<div class="horizontally-centre-aligned">
|
||||
<img src="2023-11-11_05.webp" alt="Tubes for the back of the protagonist">
|
||||
<img src="2023-11-12_01.webp" alt="Glowing tubes attached to a torso block">
|
||||
</div>
|
||||
|
||||
i love
|
||||
|
||||
<Video src="2023-11-11_09.mp4" />
|
||||
|
||||
## Real-World Testing
|
||||
|
||||
On a whim, I decided to import the N5 Blaster's model into my game. Doing that was honestly quite the motivational boost at the time, as it visualised my progress. I could actually play *my game* with *my weapon!* It's not finished at all, it has no proper mechanics implemented other than the shooting copied from the Purple Gun, and the glass is also not actually transparent.
|
||||
|
||||
<Video src="2023-11-21.mp4" />
|
||||
|
||||
## Inventory System
|
||||
|
||||
I implemented an inventory system somewhat akin to Ratchet & Clank's. It shows the weapons the player has acquired, previewing the model in a 3D sub-viewport. Later, it will also show the weapon's name, remaining ammo, perhaps statistics such as damage, and a description. But that's a task for later.
|
||||
|
||||
The only reason that the Purple Gun as well as the N5 Blaster show up multiple times is because I wanted to test all inventory slots, and I didn't have any weapons other than those two implemented.
|
||||
|
||||
<Video src="2023-11-24.mp4" />
|
||||
|
||||
## My Best Friend JSON
|
||||
|
||||
It might seem simple (or look complicated), but I came up with the idea of creating a JSON-based lookup table for the weapon metadata. Using this, it's quite easy to retrieve any kind of information about any kind of weapon without needing to hardcode it into the weapon itself. Here's an early screenshot of the lookup table.
|
||||
|
||||
<img src="2023-11-25.webp" alt="A screenshot of the weapon lookup table JSON">
|
||||
110
src/routes/projects/projectn5/devlog/202312.md
Normal file
@@ -0,0 +1,110 @@
|
||||
---
|
||||
title: 'Progress Update #4'
|
||||
date: '2023-12'
|
||||
tag: '202312'
|
||||
bannerAlt: White protagonist holding the N5 Blaster
|
||||
---
|
||||
<script lang="ts">
|
||||
import Video from "$lib/video.svelte";
|
||||
</script>
|
||||
|
||||
My progress in December 2023. Updates are shown in chronological order.
|
||||
|
||||
## Identity Crisis
|
||||
|
||||
I started creating a logo for my game! I settled on the name <b>Project N5
|
||||
as a working title, and perhaps as a final title for the game as well. Here's all the logos I created thus far:
|
||||
|
||||
Logo #0 is just an outline using [Kanit](https://fonts.google.com/specimen/Kanit). This is the font I also decided on for all of the in-game menus and text. The 5 is special though; it is based on a part salvaged from a hard drive. On a slow day, my coworker disassembled some defective mechanical hard drives, and I got to keep the parts. I thought it would look quite cool as a highlight for the game's logo, and perhaps function as a part of the in-game antagonist company that I'm planning to write the story around.
|
||||
|
||||
<img class="image-block centred width-restricted light-background" src="projectn5-logo-outline.webp" alt="Outlined Project N5 logo">
|
||||
|
||||
<img src="hdd.webp" alt="C-shaped hard drive component">
|
||||
|
||||
Logo #1 gained a fill, wider stroke, and a pattern fill that's straight outta Inkscape.
|
||||
|
||||
<img class="image-block centred width-restricted light-background" src="projectn5-logo-fill-v1.webp" alt="Outlined Project N5 logo with grey infill">
|
||||
|
||||
#2 reserves the pattern fill for the N5 part and colours the 5 in the game's main yellow colour, #D4AB49. It's also much thicker.
|
||||
|
||||
<img src="projectn5-logo-v2.webp" alt="Project N5 logo with thicker letter strokes">
|
||||
|
||||
Version 3 is a complete overhaul, still using Kanit for the N, keeping the custom 5, but changing the font of the word 'Project' to [Apfel Grotezk](https://www.collletttivo.it/typefaces/apfel-grotezk). Unfortunately, that font doesn't really work well in all-caps. The J just stood out too poorly for my liking, and friends confirmed it.
|
||||
|
||||
The hexagonal background behind the N5 actually was a fairly random addition, but I liked it so much that it continued to stick. I think this could also serve as part of the player's HUD. Maybe as an element that shows the level of the currently equipped weapon? I love when ideas sprout from random decisions like this!
|
||||
|
||||
<img src="projectn5-logo-v3.webp" alt="Project N5 logo typeset in Apfel Grotezk and with the C-shaped hard drive component integrated into the 5">
|
||||
|
||||
I also tried [Lato](https://fonts.google.com/specimen/Lato), but that looked too standard, and not quite as expressive as I wanted it to. Relatively speaking, considering we're talking about regular sans-serif fonts, of course.
|
||||
|
||||
A friend also suggested I cut apart the top part of the 5, leaving a gap, and I think that looked quite cool! I continued that trend for the HDD-inspired bits on the lower part of the 5, simplifying them, detaching them from the main bottom part, and even removing one element. The element that was removed actually served as the part that sticks out in the upper part of the lower part – if that makes sense. It's now located near the cutting point between the upper and lower parts of the digit.
|
||||
|
||||
I also tore apart the N on my own volition. Thought it looked cool.
|
||||
|
||||
<img src="projectn5-logo-v4.webp" alt="Project N5 logo typeset in Lato. Slices have been added to the N and 5">
|
||||
|
||||
This logo uses [Monserrat ExtraBold](https://fonts.google.com/specimen/Montserrat). I actually quite liked this font; it looked unified, bold, and actually quite fitting for my vision!
|
||||
|
||||
<img src="projectn5-logo-v5.webp" alt="Project N5 logo typeset in Monserrat">
|
||||
|
||||
Then I inset the C into the T, creating a neat little cutout effect.
|
||||
|
||||
<img src="projectn5-logo-v6.webp" alt="Project N5 logo with a cutout in the T">
|
||||
|
||||
I then decided to put a splash of colour behind the 'Project' wordmark, and highlighting the background with two hexagons.
|
||||
|
||||
Do you think the comment is right? I'm unsure. Amongst all the people I've shown this logo to, the decision has been split 50/50. I just don't want people to consider this the 'dick logo.'
|
||||
|
||||
I've also received comments from some people who are irked by the T in 'Project' overlapping with the background of the N5. I actually quite like that feature, but I'll take it into consideration, and maybe change it in the near future.
|
||||
|
||||
<img src="projectn5-logo-v7.webp" alt="Project N5 logo with a golden background and a note on top that reads 'TODO this looks like a dick'">
|
||||
|
||||
And lastly, a little draft logo I created, based on #7, in [Paint.net](https://www.getpaint.net/), which is why it doesn't look as clean as the other ones, which are all vector-based logos created in Inkscape.
|
||||
|
||||
I want my work to be transferrable and easily scale-able after all, you know?
|
||||
|
||||
<img src="projectn5-logo-v7-sketch.webp" alt="Project N5 logo with golden letters">
|
||||
|
||||
## Glowing Weaponry
|
||||
|
||||
I was struggling for SO LONG to get this weapon to glow. Using a `WorldEnvironment` node just wouldn't work, the weapon never glowed. Then, I figured out that, at some point, I disabled glow in the entire scene... and after changing that – and trying other things for 1.5 hours before that point – the weapon was glowing! Not quite the way I want it to, but that's easy to tweak. Only downside is that my character started glowing as well, for some reason, but I'll figure that out another time.
|
||||
|
||||
<img src="2023-12-08.webp" alt="N5 Blaster on the floor and Sans t-posing in the background">
|
||||
|
||||
## Character II
|
||||
|
||||
For testing animations, I created a new rigged character. This character is segmented, using separate objects for its arms, fingers, legs, etc. The final protagonist will use completely separate objects, since the character will be a robot. This will also reduce the work I will need to do in weight painting, and make mesh bends trivial – which is to say, not necessary.
|
||||
|
||||
<img src="2023-12-12_00.webp" alt="A new rigged character model">
|
||||
|
||||
Rigging remains as difficult as ever. The final model – which won't be based on this model but use a similar rig, hopefully the same so that animations can be carried over 1:1 – will have separate segments for the fingers, so that bends like this will never occur.
|
||||
|
||||
Notice that the character only has four fingers per hand. This should reduce animation work somewhat. Also, I came to realise – why even put five fingers on a robot? It's not like we as humans even utilise our five fingers very efficiently. I've found myself struggling to keep my pinky out of my way countless times.
|
||||
|
||||
<Video src="2023-12-12_01.mp4" />
|
||||
|
||||
`hello world! nice to meet you`
|
||||
|
||||
This uses 1-frame animations to achieve posing. My first attempt at using animations in Godot! Worked really well, actually. All I fear now is playing multiple animations at once. Is that even possible? I don't know yet.
|
||||
|
||||
<Video src="2023-12-12_02.mp4" />
|
||||
|
||||
And finally, a shot of the character holding the weapon correctly. This was actually super easy to achieve. The weapon is parented to a node that's attached to the right hand bone of the model. This makes posing and animations loads easier, since the equipped item does not have to be moved manually.
|
||||
|
||||
<img src="2023-12-12_03.webp" alt="The new character model in front of a brick wall, holding the N5 Blaster">
|
||||
|
||||
## Worldbuilding – Toasters
|
||||
|
||||
Adapted from the early animations, I present: Deniz' Quality Toasters! A fictitious toaster manufacturing company bearing my name – maybe they manufacture more than just toasters? The logo is using the font [Pacifico](https://fonts.google.com/specimen/Pacifico).
|
||||
|
||||
<img src="dqt.webp" alt="Wordmark for Deniz' Quality Toasters">
|
||||
|
||||
I don't actually know whether I'll use this in any way, I just wanted to create this logo for the sake of it.
|
||||
|
||||
## Simultaneous Animations
|
||||
|
||||
I managed to implement the ability to play multiple animations at a time! The character can now walk + point its gun, or keep its arms down. There's no animation for standing still yet, so it perpetually walks, but this is huge progress, and more importantly, a huge fear of mine alleviated! I was really concerned that implementing multiple animations would be a tedious task, but with Godot's `AnimationTree` node, it's actually rather trivial.
|
||||
|
||||
I followed [this](https://www.youtube.com/watch?v=WY2cN9uG6W8) extremely useful and concise tutorial.
|
||||
|
||||
<Video src="simultaneous-animations.mp4" />
|
||||
@@ -1,47 +0,0 @@
|
||||
<script>
|
||||
import BannerTitle from "$lib/banner-title.svelte";
|
||||
import Content from "$lib/content.svelte";
|
||||
import Video from "$lib/video.svelte";
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>2024-02-10 | denizk0461</title>
|
||||
</svelte:head>
|
||||
|
||||
<Content>
|
||||
<BannerTitle
|
||||
title="Project N5 Progress Update: 2024-02-10"
|
||||
subtitle=""
|
||||
banner="../../previews/2024/0210.webp"
|
||||
bannerAlt="Panorama of the environment"
|
||||
/>
|
||||
|
||||
<p>My apologies for the lack of updates lately! Between being hard at work on the game's progress, lacking motivation, and university exams, I really didn't have the time to write a proper update. Instead, I figured it would now be a great time to do a bundled progress update, since I really did get a lot done that takes the game quite a few steps further!</p>
|
||||
<p>The most apparent change may be the new character! It's a temporary character once again – character number 3, to be exact – but this time it's rigged properly. There are no bends in the character, which sounds PS1-esque but is actually on purpose because the final character is supposed to be a robot.</p>
|
||||
<p>There are also new animations! Nothing finished, of course, but I created them to play around with Godot's <code>AnimationTree</code> and <code>Blend2D</code>, which worked very well to lay out and play even multiple animations at once. There are now animations for walking, standing still, pointing a gun, single jumping, and double jumping! What's missing is a falling animations, but that will be implemented once I figure out how to import NLA tracks instead of needing to re-import the entire character for every animation change.</p>
|
||||
<Video src="animations.mp4" />
|
||||
<p>The game also now has a proper sky! I used this <a href="https://godotshaders.com/shader/stylized-sky-with-procedural-sun-and-moon/">Procedural Sky with Procedural Sun and Moon shader</a> by krzmig and tweaked the colours and light to get the current look. I don't expect this to be final necessarily, but I'll definitely at the very least use this as a base. I do like the look though, so it might remain final after all!</p>
|
||||
<img src="sky.webp" alt="Panorama shot of the scene and the orange-to-pink sky with the character in front">
|
||||
<p>I fixed the glowing issues in the game at one point, but then screwed up again because glow wasn't working <i>at all</i> anymore. Only after over an hour of troubleshooting did I realise that I disabled glow in the <code>WorldEnvironment</code> node...</p>
|
||||
<p>In tweaking the <code>WorldEnvironment</code>, I even got shadows to work!</p>
|
||||
<img src="shadows.webp" alt="The character standing next to a new enemy">
|
||||
<p>That red thing in the top right is an enemy. It doesn't move yet, and it can't take damage either (thus making it invulnerable), but it can be targetted, and it can damage the player too!</p>
|
||||
<p>It can be <i>targetted?</i> Yes! There's now an <code>AutoAimAgent</code> component available for all weapons that targets the nearest enemy that's inside a collision cone attached to the weapon. Once an enemy is inside this collision zone, a target is shown to let the player know which enemy is targetted, and the weapon fires in the precise direction of the enemy.</p>
|
||||
<img src="target.webp" alt="The character aiming the N5 Blaster at an enemy. A crosshair is displayed on top of the enemy">
|
||||
<p>The weapons received more updates! There's now a quick change function that allows for quickly switching between the 3 most recently used weapons by pressing the Quick Select button quickly.</p>
|
||||
<img src="quickchange.webp" alt="The weapons UI displaying the equipped weapon and two extra weapons accessible via quick change">
|
||||
<p>That sperm rocket you're seeing in the picture above is the new rocket launcher. I wanted to implement the rocket launcher as a weapon type already, so I quickly whipped by a temporary model for launcher and rockets, and implemented the functionality. And it works! It even has particle effects for the rockets!</p>
|
||||
<p>overcompensation be like</p>
|
||||
<img src="rocketlauncher.webp" alt="The character holding a massive rocket launcher">
|
||||
<Video src="rockets.mp4" />
|
||||
<p>I really feared GPU particles because I figured they would be insanely difficult to implement, but Godot really made this a breeze. Now, making them look <i>good</i> is a different story, but that's more so due to my lacking creativity and skill.</p>
|
||||
<p>What you don't possess, you can buy. And what do you need to buy those things? Money.</p>
|
||||
<img src="money.webp" alt="Golden bolts arranged in a line on the floor">
|
||||
<p>Aside from increasing a counter upon being collected, these totally-not-bolts don't do anything at the moment. But it's a start! In the future, the money can be used to buy things at the vendor that also already exists! But interacting with it only yields a blank menu at the moment.</p>
|
||||
<img src="vendor.webp" alt="The character standing next to the vendor object">
|
||||
<p>There's more that I can't really show visually though. I made huge progress with the character, for instance. Or rather, <i>I fixed some of the issues my own script caused.</i> I used to use a custom solution based on someone else's code to handle movement speed and sliding on slopes, but this introduced two massive issues. For one, stepping onto a steep slope while still half-standing on a surface that can be walked on caused the character to lose the ability to move until jumping, thus getting stuck. The other issue was that some abrupt slope angle changes caused the entire game to crash, probably caused by a faulty <code>RayCast</code> check.</p>
|
||||
<p>Now, how did I fix these issues? Well, I found out that Godot already offers these functions in the default <code>CharacterController3D</code>. Hence, I ripped out all the custom code, I essentially checked two boolean flags, and I had the same behaviour, minus the game-breaking bugs. Despite my stupidity, I felt very happy to have discovered that. My player script is now a lot cleaner!</p>
|
||||
<p>And so are other scripts! I cleaned up a few scripts, most recently the Inventory script. There used to be a lot of redundant function calls that essentially did the same thing except with one check that could be performed more centrally. I also double-checked item IDs unnecessarily. All gone now! Inventory is much more streamlined now.</p>
|
||||
<p>My next goals are to implement enemy health as well as a level travelling mechanic. To be able to test weapons, enemy movement, and balancing, I want to add an arena world with test challenges. Adding an arena is convenient anyways, since I aim to have an arena in the final game anyway, so I can feel free to dedicate more resources into the arena than if it only were for testing.</p>
|
||||
<p>Let's see how long it'll take me to get these things done! I really do love working on my game, but I often lack the motivation to <i>start</i> working on it. Once I'm in the flow, I can get a lot done, but getting into that flow, just getting out of bed to start something that can be considered "work" – that's the difficult part.</p>
|
||||
</Content>
|
||||
@@ -1,63 +0,0 @@
|
||||
<script>
|
||||
import BannerTitle from "$lib/banner-title.svelte";
|
||||
import Content from "$lib/content.svelte";
|
||||
import TableOfContents from "$lib/table-of-contents.svelte";
|
||||
import Video from "$lib/video.svelte";
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>2024-03-12 | denizk0461</title>
|
||||
</svelte:head>
|
||||
|
||||
<Content>
|
||||
<BannerTitle
|
||||
title="Project N5 Progress Update: 2024-03-12"
|
||||
subtitle=""
|
||||
banner="../../previews/2024/0312.webp"
|
||||
bannerAlt="Protagonist pointing the N5 Blaster into the sky"
|
||||
/>
|
||||
|
||||
<TableOfContents disableStickyScrolling={true} />
|
||||
|
||||
<p>I've unfortunately not gotten a lot done lately. Both an internship and many university courseworks had robbed me of much time, while the remainder of my free time had been taken up by a lack of motivation for working on my game. Despite this, I've still made a little bit of progress that I'm quite happy to share here!</p>
|
||||
|
||||
<h2 id="titlescreen">Back to Title Screen</h2>
|
||||
<p>I needed a means to launch different levels quickly, so I created a basic title screen for the game! Behind this is a basic custom level manager that allows for launching and switching between different levels. Currently, there exist two of them – Unity and Arena. Unity is the original level that's been in the game since day 1, using Unity's (old) logo as a floor plane, mostly as a joke because I switched from Unity to Godot.</p>
|
||||
<img src="titlescreen.webp" alt="The title screen displaying two levels: Unity and Arena">
|
||||
|
||||
<h2 id="arena">Level 2: Arena</h2>
|
||||
<p>The arena level is a new addition, everyone welcome the arena! While I do intend to design a proper arena for the final game, this arena is intended to test enemies and the arena menu.</p>
|
||||
<img src="arena.webp" alt="A panorama of the arena with a blue sky, white clouds, and an arena terminal">
|
||||
<span class="image-subtitle">the blue sky gives the level such a different feel. the clouds move really quickly here compared to Unity's clouds, suggesting a stormy atmosphere on this planet.</span>
|
||||
<p>The computer over there is the arena terminal. By interacting with it, you can select an arena challenge. Currently, it doesn't work. The menu does work! But the buttons don't do anything so far.</p>
|
||||
<img src="arena-terminal.webp" alt="Three arena challenges displayed in the arena terminal UI">
|
||||
|
||||
<h2 id="thirdperson">Talking about yourself in the 3rd person</h2>
|
||||
<p>I discovered this great plugin for Godot called <a href="https://phantom-camera.dev/">Phantom Camera</a>. It's a plugin that allows you to use agents to control the game camera smoothly, efficiently, and hassle-free. In order to implement it in my game, I only had to do the totally easy task of ripping out my entire camera system. It totally didn't almost make me restart the project from scratch. But it works flawlessly now!</p>
|
||||
<img src="shoulder.webp" alt="An over-the-shoulder view of the protagonist aiming the N5 Blaster">
|
||||
<p>It wasn't quite flawless from the start though. I had issues with the camera facing my character's front instead of their back. Turns out though, that's not the camera's fault; Phantom Camera's agent was specifically designed to look at the character's back – only problem was that my character model was facing the wrong way! Fixing that took a little bit of time, but I got it done, and now the camera works pretty decently. I even added two more fancy camera gizmos: the first one is a level overview camera, like in Ratchet & Clank! It shows an overview of the level when you enter it. It smootly transitions to the player once any input is made.</p>
|
||||
<img src="overview.webp" alt="A panorama shot of the Unity level with the brick wall filling the entire left half">
|
||||
<p>The other is an over-the-shoulder camera! This one allows for (allegedly) more precise aiming. Come to think of it, I should actually turn down the camera sensitivity when the player is in this mode...</p>
|
||||
<Video src="shoulder.mp4" />
|
||||
<p>Funnily, due to initial collision issues, I first accidentally turned my game into a first person shooter. Actually looks kind of cool, I have to say. Maybe I'll implement a first person view as an alternative option to the over-the-shoulder view.</p>
|
||||
<Video src="firstperson.mp4" />
|
||||
|
||||
<h2 id="sketches">Can I offer you a nice sketch in this trying time?</h2>
|
||||
<p>When I'm not developing, I'm often doing something else related to my game. Sometimes, I sketch!</p>
|
||||
<p>I am by NO MEANS a skilled sketch artist, but it really helps to note down ideas to remember them, visualise them, and expand on them.</p>
|
||||
<img src="sketches.webp" alt="Sketches of the protagonist as well as their armour and weapons">
|
||||
<span class="image-subtitle">don't judge</span>
|
||||
|
||||
<h2 id="kanban">Kanban for my TODOs</h2>
|
||||
<p>Perhaps as a small insight into my project management process: I'm using <a href="https://obsidian.md/">Obsidian</a>, a markdown editor, as my means of collecting and managing my projects' notes and ideas. Recently, I've also tried using the Kanban plugin to organise my TODOs (I have <i>a lot</i> of them), which is working quite well! I often create small notes on this board, saving sparks of ideas that I occasionally have, and I like adding extra information that will help me remember in the long term what those ideas were about.</p>
|
||||
<img src="kanban.webp" alt="The kanban board housing all TODOs for the game">
|
||||
<p>I can only recommend it – both Kanban as a means of project management as well as Obsidian as a note vault!</p>
|
||||
|
||||
<h2 id="future">in hopes of more to come</h2>
|
||||
<p>Progress has been slow lately, but I have not stopped thinking about my game. I have big ambitions for this title – of course bearing in mind that I am only one person, and that this is also my first proper attempt at making a video game. Still, I think that, with enough time and dedication, I can pull off developing something that I will be quite proud of. Even right now, I am already proud of what I've accomplished. I have a large chunk of the basic game mechanics down already, and I did it all on my own (with the help of online documentation and a few tutorials, of course)!</p>
|
||||
<p>After every day of working on my game, I ask myself: "did I really accomplish much today?" Often, my immediate response is "no", but my second response is "of course I did!" Because while a lot of things that take me quite a bit of time are children's play for another person most likely, the fact that I worked through it and managed to successfully create or implement something is huge. I'm always quite happy once I realise this.</p>
|
||||
<p>And so, while my day-to-day motivation for working on my game directly is rather low, this is only a symptom of a general lack of motivation for anything. In the long term, I think I am quite dedicated to this game. When I'm not coding something, I'm coming up with ideas. I'm managing my notes. I'm designing something. Maybe I'm talking to someone about my ideas. That last point is actually something I would love to do more, but I don't really know any person that would enjoy listening to my ramblings.</p>
|
||||
<p>Let's see how far we get.</p>
|
||||
<img src="alone.webp" alt="Protagonist staring longingly into the distance, pointing the N5 Blaster thereto">
|
||||
<span class="image-subtitle">staring longingly into the sunset</span>
|
||||
</Content>
|
||||
@@ -1,142 +0,0 @@
|
||||
<script>
|
||||
import BannerTitle from "$lib/banner-title.svelte";
|
||||
import Content from "$lib/content.svelte";
|
||||
import TableOfContents from "$lib/table-of-contents.svelte";
|
||||
import Video from "$lib/video.svelte";
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>2024-03-23 | denizk0461</title>
|
||||
</svelte:head>
|
||||
|
||||
<Content>
|
||||
<BannerTitle
|
||||
title="Project N5 Progress Update: 2024-03-23"
|
||||
subtitle=""
|
||||
banner="../../previews/2024/0323.webp"
|
||||
bannerAlt="A red enemy being blown up by an incoming rocket"
|
||||
/>
|
||||
|
||||
<TableOfContents disableStickyScrolling={true} />
|
||||
|
||||
<p>I have quite a bit of free time on my hands until the next semester starts (in a few days...), and this leisure time has allowed me to continue working on my game a lot more than usual! I made quite a bit of progress that makes this game prototype feel slightly more polished and I'm really happy to share it here and now.</p>
|
||||
|
||||
<h2 id="attraction">Attraction <3</h2>
|
||||
<p>Collectibles are now attracted by the player once they're within a certain range (specified by a spherical <code>CollisionShape3D</code>) and are collected once they get close enough to the player – which is to say, once they collide with another, smaller spherical <code>CollisionShape3D</code>. The first try didn't work out amazingly, as the collectibles didn't want my character to intrude on their personal space though...</p>
|
||||
<Video src="personalspace.mp4" />
|
||||
|
||||
<p>I fixed that issue, and lowered the attraction velocity to test, but that resulted in a spooky haunting effect.</p>
|
||||
<Video src="haunting.mp4" />
|
||||
|
||||
<p>Here's another demonstration of that! I played around with PhantomCamera's dampening, which makes the haunting effect more evident. Also something I only came to notice then: my player jumps INSANELY high. Like 8x their height. This will be fixed later.</p>
|
||||
<Video src="high.mp4" />
|
||||
|
||||
<p>After tweaking the speed, I got some nice attracted collectibles.</p>
|
||||
<Video src="attraction_stuck.mp4" />
|
||||
|
||||
<p>One issue still remains though: when moving, the collectibles don't attract all the way into the player, therefore they don't get collected and fly next to the player until they stop moving.</p>
|
||||
<p>I learned that <code>lerp()</code> was at fault (no offense!) – <code>lerp()</code> would work perfectly fine if the player were standing still, but since the player – and therefore, the target position – is moving, <code>lerp()</code> calculates a speed that cannot overcome the difference between the collectible position and the player.</p>
|
||||
<p>I overcame this issue by increasing the weight of <code>lerp()</code> on every frame, thus increasing the speed linearly. This resulted in a very smooth attraction transition.</p>
|
||||
|
||||
<Video src="attraction_smooth.mp4" />
|
||||
|
||||
<h2 id="rockets">rocket go boom</h2>
|
||||
<p>I finally implemented enemy health – they can now take damage from weapons and die. But it felt so hollow without any impact. I wanted my rockets to explode. So I started working on that.</p>
|
||||
|
||||
<h3 id="rockets-1">Stage 1: Experimentation</h3>
|
||||
|
||||
<p>I first implemented a fairly basic particle effect using cube meshes. Not exactly photorealistic, but it gets the message across.</p>
|
||||
|
||||
<Video src="explosion_0.mp4" />
|
||||
<span class="image-subtitle">boom</span>
|
||||
|
||||
<h3 id="rockets-2">Stage 2: Struggle Colliding</h3>
|
||||
|
||||
<p>I struggled EXTREMELY with getting the rockets to collide with the floor and walls. Oddly enough, they collided perfectly fine with the enemies! I was particularly confused because both the walls/floors and the enemies were types of <code>body</code> nodes, thus using the same piece of code to register a collision.</p>
|
||||
|
||||
<p>I looked up the issue online, to no avail, really, until I stumbled upon a thread about a completely different problem where someone advised to change the physics engine. I am, in fact, using a different physics engine – Jolt. So I figured, I'll go into the settings, and I'll change it, just to see what happens.</p>
|
||||
|
||||
<p>I briefly checked out Jolt's settings page... and then I saw something.</p>
|
||||
|
||||
<img src="joltsettings.webp" alt="Screenshot of the game's Jolt configuration, the option 'Areas Detect Static Bodies' is enabled and highlighted">
|
||||
|
||||
<p>"Areas Detect Static Bodies." This setting was OFF by default. This could actually apply, I figured, because my rockets are <code>Area3D</code>s and the walls/floors are <code>StaticBody3D</code> nodes. I turned it on, and... my issue was solved. Slightly frustrated, but more so amused and relieved, I continued work, happy that my code was fine and my solution worked.</p>
|
||||
|
||||
<p>I introduced an exported property that allows for setting the amount of collisions a projectile may experience before it despawns, thus allowing, for example, for the rocket to explode through a wall! I might use this in the future for the v3 rocket laucher.</p>
|
||||
|
||||
<Video src="explosion_wall.mp4" />
|
||||
|
||||
<h3 id="rockets-3">Stage 3: Style</h3>
|
||||
|
||||
<p>One day after that, I was motivated to create a more convincing explosion. I watched a YouTube tutorial, and ultimately got something that looks quite nice:</p>
|
||||
|
||||
<Video src="explosion_test.mp4" />
|
||||
|
||||
<Video src="explosion_1.mp4" />
|
||||
|
||||
<p>Interesting observation: in Godot, you can use the "RAW" tab when picking a colour to set values above 100%. The explosions, for example, use red values between 300% and 500%, which, with my <code>WorldEnvironment</code> light setup, produces a glowing effect that's just perfect for explosions!</p>
|
||||
|
||||
<p>I also messed up my lighting setup in configuring this, which results in my character being extra shiny and the N5 Blaster to glow excessively, but that's ok, we can fix that later.</p>
|
||||
|
||||
<p>In a strange coincidence, <a href="https://youtu.be/rXwo0qcKJDk">Masahiro Sakurai released a video</a> about particle effects and the "right level of detail" just one day after I had started working on my explosion particle effects. Interesting video, by the way – I was not aware of how important scale is when designing VFX.</p>
|
||||
|
||||
<h2 id="shake">Camera Shake</h2>
|
||||
|
||||
<p>Anyway, I got to work on camera shake! Through a tiny bug that has already been fixed, I briefly got to experience something resembling a camera shake in my game while I was firing a rocket. I thought that was super cool, so I looked up camera shake and implemented it.</p>
|
||||
|
||||
<p>The tutorial I followed (a 2D tutorial, btw) used a strength value of 30. I figured that'd be too much, so I set it to 20, just in case.</p>
|
||||
|
||||
<Video src="shake_0.mp4" />
|
||||
|
||||
<p>...I later set down the strength value to about 0.35.</p>
|
||||
|
||||
<p>I also implemented distance fade for the camera shake strength! The strength now depends on how close the player is to the explosion origin. An explosion far away won't shake the camera, but one close up has much more impact!</p>
|
||||
|
||||
<Video src="shake_impact.mp4" />
|
||||
|
||||
<h2 id="new-weapon">A new weapon is in the works!</h2>
|
||||
|
||||
<p>I had a random burst inspiration recently while I was on the bus, and once I got home, I started modelling it. Introducing: a weapon that is unfinished and has no (finalised) name yet, but I'm still fairly proud of:</p>
|
||||
|
||||
<img src="venom_front.webp" alt="Front view at a new weapon with two barrels, a golden lead-up to the top barrel, and a bolt in the back">
|
||||
<img src="venom_back.webp" alt="Back view of the previously-described weapon">
|
||||
|
||||
<p>I'm thinking this could be a blaster of types, maybe similar to an N5 Blaster upgrade – two-handed. Though I think it should be separate from the N5 Blaster. It could also be a flamethrower, though I want the flamethrower to look a bit different, especially at the gun barrel.</p>
|
||||
|
||||
<p>I quite like the bolt at the back as well as the yellow gunmetal-ish colour of the bolt and the gun barrel. The body is far from finalised – I still have to figure out a fitting one. I do like the cutouts in the shape, however, so I'll probably keep them for the final body shape.</p>
|
||||
|
||||
<h2 id="camera">Camera Adjustments</h2>
|
||||
|
||||
<p>I also worked quite a bit on the camera, specifically how it moves! This is the main thing that, in my opinion, makes the current build feel just a bit more polished than the previous ones – relatively speaking, of course.</p>
|
||||
|
||||
<p>The camera now moves quicker and more smoothly in and out of the precision aiming mode, for example:</p>
|
||||
|
||||
<Video src="camera_precision.mp4" />
|
||||
|
||||
<p>The level overview camera also moves in a much cooler way, using a quint transition type instead of the previous linear transition. I think using quint improves the look significantly.</p>
|
||||
|
||||
<Video src="camera_overview.mp4" />
|
||||
|
||||
<p>Look at how smoothly the camera follows the player, even when the player jumps up a platform or falls down from one!</p>
|
||||
|
||||
<Video src="camera_smooth.mp4" />
|
||||
|
||||
<p>The camera now sticks to the ground briefly when the player jumps, but it returns to the player once the player exceeds a certain height above the jump origin or falls lower than the starting point.</p>
|
||||
|
||||
<p>Also notice how, at the end of the video, I struggle to jump up the (admittedly massive) wall, but ultimately make it. Why is that? It's because I:</p>
|
||||
|
||||
<ol>
|
||||
<li>Adjusted the jump height to much more sensible values</li>
|
||||
<li>Implemented variable jump height, letting the player jump heigher the longer the jump button is pressed</li>
|
||||
</ol>
|
||||
|
||||
<p>Of course, obligatory <i>I accidentally turned my game into a first-person shooter</i>, again. This view of the N5 Blaster actually reminds me of Metroid.</p>
|
||||
|
||||
<img src="firstperson.webp" alt="Erroneous first-person view">
|
||||
|
||||
<h2 id="unity">Looking down upon the mess I've created</h2>
|
||||
|
||||
<p>I'm really happy with my progress. As a bonus, here's an overview of my current testing level Unity.</p>
|
||||
|
||||
<img src="unity_overview.webp" alt="Bird's eye perspective overview at the Unity level">
|
||||
</Content>
|
||||
@@ -1,109 +0,0 @@
|
||||
<script>
|
||||
import BannerTitle from "$lib/banner-title.svelte";
|
||||
import Content from "$lib/content.svelte";
|
||||
import TableOfContents from "$lib/table-of-contents.svelte";
|
||||
import Video from "$lib/video.svelte";
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>The Arena Update | denizk0461</title>
|
||||
</svelte:head>
|
||||
|
||||
<Content>
|
||||
<BannerTitle
|
||||
title="Project N5 Progress Update: 2024-03-24"
|
||||
subtitle="The Arena Update"
|
||||
banner="../../previews/2024/0324.webp"
|
||||
bannerAlt="Protagonist being swamped by many monkey enemies"
|
||||
/>
|
||||
|
||||
<TableOfContents disableStickyScrolling={true} />
|
||||
|
||||
<p>A new update <i>so</i> soon‽ Yes! I have things to share that I'm really excited about!</p>
|
||||
|
||||
<h2 id="what">What did I actually do?</h2>
|
||||
|
||||
<p>Today, while I was standing in the shower, I set out a goal for myself: implement the arena mechanic. This was actually a goal that I had set out for myself to complete months ago, and my ultimate goal was to have it done by April. A few weeks ago, I thought to myself that I had postponed it too much, and that I wouldn't be able to get it done by April anymore – especially concerning the lacking motivation I had back then.</p>
|
||||
|
||||
<p>So, did I actually get done what I had set out to do? Also yes! I worked on my game (with breaks in-between, even one I used to bake a small cake) for a whole 10 hours today, and I actually worked out a decent, modular arena challenge system.</p>
|
||||
|
||||
<h2 id="product">The Finished Product</h2>
|
||||
|
||||
<Video src="demonstration.mp4" />
|
||||
|
||||
<h2 id="good">The Good</h2>
|
||||
|
||||
<ul>
|
||||
<li>Arenas are fully functional; challenges can be selected, enemies fought, and rounds finished</li>
|
||||
<li>The arena terminal automatically receives all arena challenges and creates an interactable menu with clickable buttons that can be used to start challenges</li>
|
||||
<li>Lots of components are easily reusable and meshes are able to be replaced with finished products with ease once the time comes</li>
|
||||
<li>Finishing a challenge successfully yields a monetary reward</li>
|
||||
<li>A new test enemy type has been added that can more appropriately attack the player and even move towards them, thus laying the groundwork for a general-purpose enemy behaviour script</li>
|
||||
<li>Adding new challenges to the arena terminal is insanely easy and intuitive</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="enemy">The New Enemy, Suzanne Cylinder</h3>
|
||||
|
||||
<img src="suzannecylinder.webp" alt="Suzanne cylinder; an enemy made from a few cylinders and Blender's default 'Suzanne' monkey head">
|
||||
|
||||
<p>Suzanne cylinder (called "test_monkey" in the game) is the first enemy that has movement code implemented, able to follow the player once close enough and attack once the player gets too close. Without gravity holding Suzanne cylinder to the ground, though, the situation gets spooky quickly.</p>
|
||||
|
||||
<Video src="haunted.mp4" />
|
||||
|
||||
<p>Initial movement tests were quite funny, because <code>look_at()</code> adjusts rotation on both the y axis (left-right rotation) as well as the x-axis (up-down rotation), which meant that the enemy kept looking up when the player was at a higher elevation than it.</p>
|
||||
|
||||
<img src="lookingup.webp" alt="Suzanne cylinder staring up at the protagonist from beneath a ramp">
|
||||
<span class="image-subtitle">send help</span>
|
||||
|
||||
<h3 id="challenges">Developing Arena Challenges</h3>
|
||||
|
||||
<p>To expand on the last point: I'm actually quite proud of the solution I implemented for creating arena challenges. The way this works right now is that the arena terminal contains a dictionary which stores all arena challenges, including any information that needs to be associated with them: round and enemy count and types, rewards, etc.</p>
|
||||
|
||||
<p>All that information looks a little like this:</p>
|
||||
|
||||
<pre class="code-block">
|
||||
const arena_challenges = {
|
||||
1099: {
|
||||
"reward": 7382,
|
||||
"rounds": [
|
||||
{
|
||||
"type": "regular",
|
||||
"spawner_count": 3,
|
||||
"enemies": [
|
||||
ENEMY_MONKEY,
|
||||
ENEMY_MONKEY,
|
||||
ENEMY_MONKEY,
|
||||
...
|
||||
],
|
||||
},
|
||||
...
|
||||
],
|
||||
},
|
||||
}</pre>
|
||||
|
||||
<p><code>1099</code> is the unique ID by which the challenge is identified; this can later be used to save which challenges the player has already successfully completed. The ID is also used to fetch strings, such as the title of the challenge, and later the description and perhaps other useful information that could be displayed to the player in the arena terminal GUI.</p>
|
||||
|
||||
<p><code>reward</code> is the money count that is rewarded after completing a challenge; the option to receive items could be implemented later. A reward for completions after the first one should also be added later, so that the player doesn't receive an insane amount of money for completing the same challenge over and over again!</p>
|
||||
|
||||
<p><code>rounds</code> is an array that contains <code>round</code> objects which store the <code>type</code> of round – which is currently unused, but could be used later for boss rounds –, the <code>spawner_count</code>, defining how many of the current total of 8 spawners should be used for spawning enemies, and of course, <code>enemies</code>, which defines what types of enemies and how many should be spawned in the given round. <code>enemies</code> are defined simply by entering the string paths to their scene file (here, <code>ENEMY_MONKEY</code> is a constant string pointing to the enemy's <code>enemy.tscn</code> file).</p>
|
||||
|
||||
<p>This system is actually super easy to use; by defining a <code>spawner_count</code> and <code>enemies</code>, the arena script can figure out how many enemies should be spawned per spawner in order to balance out the spread of enemies. Spawners are picked at random, and enemies are shuffled before being spawned, so that the order entered in the challenge definition doesn't produce same results every time.</p>
|
||||
|
||||
<p>A challenge ends once all rounds have been cleared; a round ends once all enemies in a given round have been defeated.</p>
|
||||
|
||||
<h2 id="bad">The Bad</h2>
|
||||
|
||||
<ul>
|
||||
<li>I have yet to implement handling for when the player dies during the challenge</li>
|
||||
<li>It all still looks a little janky – although that's to be expected, since I implemented this entire system just a few hours ago, as of writing this webpage</li>
|
||||
<li>It's a bit annoying to fight the enemies with the current, primitive roster of weapons</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="verdict">Verdict</h2>
|
||||
|
||||
<p>Very happy with my progress today – I got so much done. This was my most productive day in a <i>very</i> long time.</p>
|
||||
|
||||
<p>The great thing is that, now that there's an arena challenge, and with it, a constantly spawning stream of enemies attacking the player, the game actually has a proper gameplay loop, in some way! In other words – there's actually something to do now!!</p>
|
||||
|
||||
<p>I think that's pretty <a href="https://youtu.be/DrQqajtiRt4">neat</a>.</p>
|
||||
</Content>
|
||||
@@ -1,98 +0,0 @@
|
||||
<script>
|
||||
import BannerTitle from "$lib/banner-title.svelte";
|
||||
import Content from "$lib/content.svelte";
|
||||
import TableOfContents from "$lib/table-of-contents.svelte";
|
||||
import Video from "$lib/video.svelte";
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>The Behind-the-Scenes Update | denizk0461</title>
|
||||
</svelte:head>
|
||||
|
||||
<Content>
|
||||
<BannerTitle
|
||||
title="Project N5 Progress Update: 2024-04-01"
|
||||
subtitle="The Behind-the-Scenes Update"
|
||||
banner="../../previews/2024/0401.webp"
|
||||
bannerAlt="N5 Blaster with its lights turned off"
|
||||
/>
|
||||
|
||||
<TableOfContents disableStickyScrolling={true} />
|
||||
|
||||
<p>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.</p>
|
||||
|
||||
<p>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!</p>
|
||||
|
||||
<p>This progress update is going to be interesting. I <i>have</i> 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.</p>
|
||||
|
||||
<p>↠ <a href="#venom">Skip to the interesting stuff</a> ↞</p>
|
||||
|
||||
<h2 id="components">Component-based design</h2>
|
||||
|
||||
<p>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 <a href="https://youtu.be/74y6zWZfQKk">this video by Bitlytic</a> recommended to me today.</p>
|
||||
|
||||
<p>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!</p>
|
||||
|
||||
<p>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 <code>HealthComponent</code> and <code>HitboxComponent</code> to handle these functions.</p>
|
||||
|
||||
<p>I hesitated to implement this design approach in my game because I wasn't sure <i>how</i>, 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,</p>
|
||||
|
||||
<h2 id="refactoring">Refactoring</h2>
|
||||
|
||||
<p>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 <code>HealthBar</code> 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 <code>HealthBar</code> was pulling double duty. With the <code>HealthComponent</code> implemented, there was no need for <code>HealthBar</code> to keep track of health anymore, so it was refactored to only handle the displaying of health, simplifying its function significantly.</p>
|
||||
|
||||
<h2 id="preloading">Loading optimisations</h2>
|
||||
|
||||
<p>I replaced a few <code>load()</code> calls with <code>preload()</code>. This is significant insofar that the use of <code>preload()</code> 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:</p>
|
||||
|
||||
<pre class="code-block">
|
||||
var enemies = ["path-to-enemy-0", "path-to-enemy-1", ...]
|
||||
|
||||
...
|
||||
|
||||
for enemy_path in enemies {
|
||||
enemy = load(enemy_path).instantiate()
|
||||
}</pre>
|
||||
|
||||
<p>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:</p>
|
||||
|
||||
<pre class="code-block">
|
||||
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()
|
||||
}</pre>
|
||||
|
||||
<p>This yielded a great performance boost, as the <code>preload</code>s 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 <code>instantiate()</code> call. So in this case, I could have 6 <code>enemy0</code> and 6 <code>enemy1</code>; both types would be preloaded once (so, two loads in total), and then they could be instantiated afterwards. Lag spikes be gone.</p>
|
||||
|
||||
<p>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.</p>
|
||||
|
||||
<h2 id="venom">The Venom</h2>
|
||||
|
||||
<p>Something visual to intersperse the dry code explanations:</p>
|
||||
|
||||
<img alt="An untextured work-in-progress 3D model of a blaster" src="venom.webp">
|
||||
|
||||
<p>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:</p>
|
||||
|
||||
<div class="horizontally-centre-aligned">
|
||||
<img alt="A REALLY crude sketch of a blaster." src="dual_venom_sketch.webp">
|
||||
<img alt="A crude sketch of a blaster resembling the 3D model shown above." src="venom_sketch.webp">
|
||||
</div>
|
||||
|
||||
<p>The bolt visible in the first sketch actually makes me consider using <a href="/projects/projectn5/devlog/2024/0323/#new-weapon">the model I showed off recently</a> as the v2 for the Venom (which I would call Antidote by the way, in reference to <a href="https://youtu.be/fbafd6UV3w4">this song</a>).</p>
|
||||
|
||||
<h2 id="n5-glow">N5 Blaster glow!</h2>
|
||||
|
||||
<p>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.</p>
|
||||
|
||||
<Video src="n5-glow.mp4" />
|
||||
<img alt="The N5 Blaster. Its lights are turned off, and the icosphere in the middle is dimly glowing." src="n5-dim.webp">
|
||||
|
||||
<p>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)!</p>
|
||||
</Content>
|
||||
@@ -1,42 +0,0 @@
|
||||
<script>
|
||||
import BannerTitle from "$lib/banner-title.svelte";
|
||||
import Content from "$lib/content.svelte";
|
||||
import Video from "$lib/video.svelte";
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>The WHERE HAVE I BEEN?? Update | denizk0461</title>
|
||||
</svelte:head>
|
||||
|
||||
<Content>
|
||||
<BannerTitle
|
||||
title="Project N5 Progress Update: 2024-07-13"
|
||||
subtitle="The WHERE HAVE I BEEN?? Update"
|
||||
banner="../../previews/2024/0713.webp"
|
||||
bannerAlt="Protagonist staring longingly into the distance, pointing the N5 Blaster thereto"
|
||||
/>
|
||||
|
||||
<p>University.</p>
|
||||
|
||||
<p>Things have been busy. I had more responsibilities than I assumed this semester. More importantly perhaps, I had more exams <i>during</i> the semester than I assumed. It robbed me of a lot of time and I have virtually not progressed with Project N5 or any other project of mine in the past 3 months.</p>
|
||||
|
||||
<p>I can't express how much I loathe it – I'd much rather work on meaningful, creative tasks than these worthless university submissions and exams, especially considering that I don't feel my university courses contribute anything of value to my education, at least in regards to my future job. In fact, I believe that my lack of time to work on creative projects might have made me forget how rewarding those can be, which in turn has robbed me of motivation to do just that.</p>
|
||||
|
||||
<p>The semester has wrapped up, and all that's left is an exam next week (for which I am supposed to study right now – I am currently procrastinating), an oral exam in 3½ weeks, and two submissions due at the start of August and mid-September, respectively. Not exactly fulfilling tasks, I have to admit, but I'll have to push through.</p>
|
||||
|
||||
<p>If there's one positive thing I can report back with, it's that I've been doing pretty well in my exams. I've yet to receive a grade lower than 2.0 this semester (which likely will change once I receive my geography didactics exam grade, but still), and that's despite the fact that I've really not put in the appropriate amount of work for it. Just as my motivation for my creative projects has been dwindling, I've been procrastinating on all my university tasks hardcore.</p>
|
||||
|
||||
<Video src="procrastination.mp4" />
|
||||
|
||||
<p>Project N5 is not cancelled, though! I'm still confident that work will commence soon! I just have to gather the motivation to actually start working on it again (which is much easier said than done).</p>
|
||||
|
||||
<p>Part of my problem, I think, is that I want to start with story and artistic content. For instance, I want to actually create my protagonist! I want to create the character so I can create animations, set up the proper node hierarchy, and just to take cool presentable screenshots of my work. Would it not be a lot cooler if all my devlog screenshots had a fully fleshed-out, poseable character instead of the T-posing temporary character?</p>
|
||||
|
||||
<p>For what it's worth, here's a picture of something I printed a few weeks ago. It's an N5 Blaster magnet that's hanging on my PC! I printed it myself, using my new <a href="https://eu.store.bambulab.com/products/a1-mini?variant=49003631083868">Bambu A1 mini 3D printer</a>, and the filament I used is <a href="https://eu.store.bambulab.com/products/pla-galaxy?variant=47730388107612">PLA Galaxy green</a>.</p>
|
||||
|
||||
<img alt="A 3D-printed half of an N5 Blaster that's hanging on the side wall of a PC" src="3dprint.webp">
|
||||
|
||||
<p>I'd love to 3D print more Project N5 weapons – though for that I'll have to design the weapons first!! And in order to do <i>that</i>, I'll have to come up with the ideas for the weapons, which is also proving difficult. A friend suggested to me a while back that I should consider which types of weapons <i>I</i> like in games, and which types I find fun to use.</p>
|
||||
|
||||
<p>As for now, I should get started with my studies – I'll write my next update once I have more things to present from Project N5, which will (hopefully) be in less than 3 months! Until then~</p>
|
||||
</Content>
|
||||
@@ -1,95 +0,0 @@
|
||||
<script>
|
||||
import BannerTitle from "$lib/banner-title.svelte";
|
||||
import Content from "$lib/content.svelte";
|
||||
import TableOfContents from "$lib/table-of-contents.svelte";
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>The Returnal Update | denizk0461</title>
|
||||
</svelte:head>
|
||||
|
||||
<Content>
|
||||
<BannerTitle
|
||||
title="Project N5 Progress Update: 2024-10-12"
|
||||
subtitle="The Returnal Update"
|
||||
banner="../../previews/2024/1012.webp"
|
||||
bannerAlt="Protagonist aiming at two monkeys"
|
||||
/>
|
||||
|
||||
<TableOfContents disableStickyScrolling={true} />
|
||||
|
||||
<p>I'M BACK!!!!</p>
|
||||
|
||||
<p>For real this time!! I've been busy with university, then I started working on other projects including 3D prints, electronics, a different game, then got busy with university again, and now I FINALLY started work on Project N5 again. And, as I promised in <a href="/projects/projectn5/devlog/2024/0713/">my last update</a>, it would not take me another 3 months to get back to development – in fact, I undercut that deadline by a whole 24 hours!</p>
|
||||
|
||||
<p>Since even though Project N5 was stalled, I gained some more knowledge about and mostly confidence with Godot through another game project I'm working on in parallel with friends, I've kicked off Project N5 development by restructuring a few things. This means there's not that much visual stuff to show so far, but there are some sorely needed mechanical and programmatical under-the-hood improvements.</p>
|
||||
|
||||
<h2 id="aim-helper">New 2D-Based Aim Helper</h2>
|
||||
|
||||
<p>I overhauled the auto aim mechanism (which is now called aim helper). Previously, the aim helper worked by putting a 3D collision shape in front of the gun, registering all collisions within this cone, and determining a target by calculating the shortest distance between the player and the enemies. Here's a visual of the old cone at the tip of the N5 Blaster:</p>
|
||||
|
||||
<img src="cone.webp" alt="The protagonist pointing the N5 Blaster, which is emitting a wiremeshed cone shape">
|
||||
|
||||
<p>This was a good solution, because it allowed for targetting enemies without much effort – add an enemy to the 'targetable' group and let the aim helper script take care of it. However, customisation proved difficult. Since the collider was a 3D shape, a new 3D shape would have to be created for every weapon and every upgrade that demanded a unique shape. While this offered flexibility, it proved cumbersome in execution. Cones could only be changed in scale uniformally, which means that, while they can be changed in size, no single dimension could be changed without causing bugs. Keeping X and Y while increasing the Z distance would mandate a whole new shape. Furthermore, the cone would have to be manually rotated and positioned in front of the gun every frame, which wasn't particularly elegant.</p>
|
||||
|
||||
<p>Thus, a new solution was born: a 2D approach to the aim helper!</p>
|
||||
|
||||
<img src="aim_helper.webp" alt="A 2D circle on the screen aiming at an enemy, which is displayed as a target via crosshair">
|
||||
|
||||
<p>The way the new aim helper works is by putting a 2D collision shape on the screen of the player. All enemies contain a 2D shape as well, which is unprojected onto the screen by the player camera. This means that the 2D shapes are positioned on top of the 3D characters. As soon as the player's collision shape collides with one of the enemies', it's added to the list of collisions and the shortest distance is calculated. This procedure hasn't changed between the 3D and 2D approaches.</p>
|
||||
|
||||
<p>Using this 2D shape is a lot simpler, however, because it allows for much easier changes of the collision shape. Using just a circle, the diameter can be changed by just changing one variable, and the max distance can be changed with another variable – much more easily configurable than modelling new cones! And new shapes can easily be created using 1-bit (black and white) bitmaps instead of 3D shapes.</p>
|
||||
|
||||
<p>There's also a blue line shooting out of the gun in the picture above. That's a raycast spanning from the player to the targetted enemy, checking whether a wall is obstructing line of sight. Enemies can no longer be targetted if they're behind a wall or similar.</p>
|
||||
|
||||
<h2 id="n5-icons">Overhauled N5 Weapon Icons</h2>
|
||||
|
||||
<p>The N5 Blaster received an overhauled icon. The soon-to-be-implemented N5 Bomb Launcher also received its own icon!</p>
|
||||
|
||||
<div class="horizontally-centre-aligned">
|
||||
<img src="n5-blaster-icon.webp" alt="N5 Blaster logo made from an icosphere and two handles">
|
||||
<img src="n5-bomb-launcher-icon.webp" alt="N5 Bomb Launcher logo made from an icosphere and waves">
|
||||
</div>
|
||||
|
||||
<p>I changed the icosphere by tracing its 3D counterpart (the ball inside the N5 Blaster's glass tube) from a different point of view. It wasn't symmetrical before – it is now.</p>
|
||||
|
||||
<p>Admittedly, seeing the two icons side-by-side... they look damn similar. I think they might be difficult to tell apart in-game. One of these icons will be changed most likely. I'm also considering using the right icon for the N5 Blaster instead, maybe.</p>
|
||||
|
||||
<p>The idea with these weapons is that they're both N5 series weapons – they are supposed to be similar in style to the protagonist and be default gear. Perhaps both of them will be available from the start of the game. They're basic weapons like the Lancer and Gravity Bomb in Ratchet & Clank 2, for instance.</p>
|
||||
|
||||
<h2 id="minor-changes">Minor Changes</h2>
|
||||
|
||||
<h3 id="signal-bus">Hopping on the Signal Bus</h3>
|
||||
|
||||
<p>Minor change, but I overhauled the inventory by removing complicated signal lines and simplifying them through a <code>SignalBus</code> singleton.</p>
|
||||
|
||||
<p>Previously, in order to change weapons, the quick select menu would directly interact with the inventory; the weapons menu would signal to the pause menu, and the pause menu would thus interact with the inventory. This was unnecessarily complicated.</p>
|
||||
|
||||
<p>Instead, I'm now using a <code>SignalBus</code> containing a signal <code>on_player_equip()</code> that can easily be triggered by the quick select and weapons menus without a direct connection to the inventory. In order to receive these signals, the inventory connects one of its functions to the signal in <code>SignalBus</code>, consolidating functions such as <code>on_quick_select_item_equipped()</code>, <code>on_weapons_menu_item_equipped()</code>, etc.</p>
|
||||
|
||||
<p>This <code>SignalBus</code> isn't even new in my game; I've previously already used it for the aim helper described above! Using such a bus is genuinely useful for any kind of Godot game that needs to allow communication between nodes that have no direct connection to one another. It's much more convenient – and safe! – than fetching nodes directly by their path, like <code>get_node("/root/Main/Level/Player/CharacterBody3D/Inventory")</code>. Imagine you change just one of these nodes' names a few weeks down the line. Nightmare to debug.</p>
|
||||
|
||||
<h3 id="strafing">Strafing Like a Gladiator</h3>
|
||||
|
||||
<p>Another minor change that affects gameplay more so than code: the player now strafes automatically when having a weapon equipped. This emulates the strafing behaviour in Ratchet: Gladiator, which may have been influenced by the fact that I've been playing this game a bunch these past few days... on Exterminator difficulty, no less. Not easy, but really fun.</p>
|
||||
|
||||
<p>Conveniently, forcing strafing when holding a weapon elminiates the need to fix bugs related to strafing – for example, if the player doesn't strafe, or doesn't stop strafing. Though I may need to change this behaviour again if I decide to introduce gadgets.</p>
|
||||
|
||||
<h2 id="whats-next">What's Next?</h2>
|
||||
|
||||
<p>It's not quite certain, but I have ideas. Next on my agenda is, for example, continuing to clean up the project. I think there's a lot of streamlining I can do using signals, the <code>SignalBus</code>, and overall just writing more cohesive code. I've come a long way since I started this game project 13 or so months ago, after all.</p>
|
||||
|
||||
<p>I also want to implement more visual things. I've been meaning to 3D model again, creating crates, a new ammo pickup, and even some weapons. Of course, I'd also love to create a new, more final protagonist, but ideas are slow to come. Still, there are some I've newly come up with or written down. The N5 Bomb Launcher especially is something I want to implement soon. Since it's a thrower-type weapon, meaning it fires its shots in an arch and targetting the floor, there's a little bit of work involved to make that happen. I've been thinking about possible approaches to this lately, and I think I might settle on a pre-baked curve/collision mesh, because I think the PS2 Ratchet & Clank games may be using a similar approach.</p>
|
||||
|
||||
<p>Here's a sneak peek at an ammo pickup I started working on recently:</p>
|
||||
|
||||
<img src="ammo.webp" alt="An ammo canister with a question mark at its front">
|
||||
|
||||
<p>And of course, there's always the struggle of motivation. With my new game project, I have the fortune of working with two other people who also do work. We can motivate one another, since we're all interested in developing the game further. I don't have this with Project N5. At least as far as I know, I'm the only one who's really interested in seeing this game flourish, so there's no real option for me to gain motivation through other people. It's difficult, and I don't quite know how to deal with it. I've also considered uploading snippets onto my Instagram, but even disregarding my dislike for the platform, I don't think anyone would really care – I've uploaded snippets in the past already, to little resonance. I don't blame other people, but it just illustrates that I need to have intrinsic motivation to continue work on Project N5.</p>
|
||||
|
||||
<p>That's where my idea of adding visual things came from, by the way. By making visually (or sonically, for that matter) distinct changes, such as through introducing new meshes and models, I could <i>see</i> my progress much more clearly than I can now. Perhaps by gauging my progress through visuals, I could lift my motivation?</p>
|
||||
|
||||
<p>Then again, in order to create visual things, I'll have to have motivation from the start, so we're in a bit of a pickle here.</p>
|
||||
|
||||
<p>I can do this.</p>
|
||||
</Content>
|
||||
@@ -1,153 +0,0 @@
|
||||
<script>
|
||||
import BannerTitle from "$lib/banner-title.svelte";
|
||||
import Content from "$lib/content.svelte";
|
||||
import TableOfContents from "$lib/table-of-contents.svelte";
|
||||
import Video from "$lib/video.svelte";
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>The Visual Update | denizk0461</title>
|
||||
</svelte:head>
|
||||
|
||||
<Content>
|
||||
<BannerTitle
|
||||
title="Project N5 Progress Update: 2024-11-03"
|
||||
subtitle="The Visual Update"
|
||||
banner="../../previews/2024/1103.webp"
|
||||
bannerAlt="Two N5 Blaster side-to-side"
|
||||
/>
|
||||
|
||||
<TableOfContents disableStickyScrolling={true} />
|
||||
|
||||
<p>As promised, I've been working on a few visual things! There's not <i>that</i> much to show yet, but I have a model or two to show, plus a lot more to talk about in terms of where I want to take the game.</p>
|
||||
|
||||
<p>Before this, though, here's some progress in the coding department (that's where I'm best at):</p>
|
||||
|
||||
<h2 id="node-chains">Simplifying Node Chains</h2>
|
||||
|
||||
<p>Behind-the-scenes, I've been steadily working at overhauling and refactoring some of my code. I wrote the majority of my game's scripts 6 to 12 months ago, and some of it hasn't aged that well. Complicated code structures and wonky node paths such as <code>get_node("/root/Main/LevelParent/Level/Camera/AimRayCastContainer/AimRayCast3D")</code> aren't things I want to maintain, so I'm trying my best to implement more best-practices – or at least better-practices.</p>
|
||||
|
||||
<p>One challenge I faced was referencing a node that has no clear direct relationship to the one I'm calling it from. Picture this node chain:</p>
|
||||
|
||||
<img src="node_chain.webp" alt="A very long node chain displayed using Obsidian's canvas feature">
|
||||
|
||||
<p>Say, for example, that I'm writing a script in <code>Automatic</code> – that's the node that handles projectile spawning and their direction in automatic weapons, among other things – and I need to reference <code>AimRayCast3D</code> to determine in which direction the projectile needs to be fired. Reasonable use case, seen as the <code>RayCast3D</code> is attached to the <code>Camera3D</code> to point exactly where the player is facing – except there's no real path I can follow to get to that node. Their closest relative is <code>Level</code>, which is the root node of the level, and no less than <b>eight nodes away</b> from <code>Automatic</code>! It's possible to retrieve the node in this way, starting from <code>Automatic</code>, but it's not pretty...</p>
|
||||
|
||||
<p><code>var _ray_cast = get_node("../../../../../../../../Camera/AimRayCastContainer/AimRayCast3D")</code></p>
|
||||
|
||||
<p>Imagine if any of these nodes has their name changed – or worse, if the order of nodes is changed. It <i>could</i> spell disaster. This method grabs the node relative to <code>Automatic</code>, which means it relies on this specific count of nodes as well as the names of the nodes, starting at <code>Camera</code>. We could switch this around:</p>
|
||||
|
||||
<p><code>var _ray_cast = get_node("/root/Main/LevelParent/Level/Camera/AimRayCastContainer/AimRayCast3D")</code></p>
|
||||
|
||||
<p>...but now we're reliant on the order starting from the root node (from the top), plus we now have to be wary of even more node names, so this is no good either. For quick testing, sure, but not to be implemented in a production release – hopefully. How do we fix this? I thought of using a singleton script that holds references to the most important nodes (level parent, player, camera) to retrieve nodes relative to them:</p>
|
||||
|
||||
<p><code>var _ray_cast = GlobalReferences.camera.get_node("AimRayCastContainer/AimRayCast3D")</code></p>
|
||||
|
||||
<p>This <i>is</i> a lot more streamlined, but... it doesn't work. You need to initialise the <code>camera</code> variable at some point after the level has loaded, but before the variable is used. If you use the variable in any <code>_ready()</code> call, then you're hosed, because you must initialise the variables in the level's <code>_ready()</code> and you cannot be certain that the level has its <code>_ready()</code> function called in time for the other node to retrieve a proper reference in <code>camera</code> instead of <code>null</code>.</p>
|
||||
|
||||
<p>Instead, we can use the function <code>get_first_node_in_group()</code> on the <code>SceneTree</code> to retrieve <i>any</i> node! We just have to make sure that the node has a group name that is unique to it within the <code>SceneTree</code> – in the case of a level camera, that's a given. Having multiple nodes with this group name is also possible by using <code>get_nodes_in_group()</code> and then filtering the returned array by, for example, checking its class name.</p>
|
||||
|
||||
<p><code>var _ray_cast = get_tree().get_first_node_in_group("level_camera").get_node("AimRayCastContainer/AimRayCast3D")</code></p>
|
||||
|
||||
<p>Almost there! We can pretty this up by adding two more things:</p>
|
||||
|
||||
<ul>
|
||||
<li>Turn <code>"level_camera"</code> into a constant. I did this by creating a global class called <code>Groups</code> and adding:<br><code>const LEVEL_CAMERA: String = "level_camera"</code><br>This simplifies changing group names, though keep in mind that this constant cannot be used inside the node's group assignment, meaning that, if you do change the name, you will have to change it in at least two places (the node and the constant).</li>
|
||||
<li>Remove the <code>get_node("AimRayCastContainer/AimRayCast3D")</code> call and replace it with a variable call. Inside the camera's script, we can add a variable referencing <code>AimRayCast3D</code> quite easily because it's a child of the camera. Add to the camera script: <br><code>@onready var aim_ray_cast: RayCast3D = $AimRayCastContainer/AimRayCast3D</code><br>And then use <code>camera.aim_ray_cast</code> to retrieve it. Remember to add <code>@onready</code> because the node cannot be retrieved before <code>_ready()</code> is called.</li>
|
||||
</ul>
|
||||
|
||||
<p>In the end, we have the following statement:</p>
|
||||
|
||||
<p><code>var _ray_cast = get_tree().get_first_node_in_group(Groups.LEVEL_CAMERA).aim_ray_cast</code></p>
|
||||
|
||||
<p>We can use this <i>anywhere</i> in our game to retrieve the node, as long as it exists within the scene tree!</p>
|
||||
|
||||
<h2 id="buttmuncher7">ButtMuncher7's Approach to Projectiles</h2>
|
||||
|
||||
<p>A while back, ButtMuncher7 on YouTube uploaded a video on <a href="https://youtu.be/0rTI_UUfB-E?t=89">projectiles in video games</a>. They use the Godot engine as well, so anything they implement, I can implement as well. The issue they faced was that projectiles often fly through walls a bit before colliding, since they may move past an object's surface between frames. I finally got around to implementing their solution, which worked quite well: you add a raycast to the projectile pointing from its current location to its last location, see if collides with anything, and if it does, you move the projectile to that position. It's quite a neat solution!</p>
|
||||
|
||||
<h2 id="sky">Lighten the Mood</h2>
|
||||
|
||||
<img src="sky.webp" alt="A bright blue sky and procedually generated white clouds">
|
||||
|
||||
<p>I changed the sky to be brighter and more friendly in the Unity test level. This doesn't serve the game in its final form in any way, it's just a measure I took to <a href="/projects/projectn5/devlog/2024/1012/#whats-next">give myself the impression that a lot has changed</a>, since the game has visually changed.</p>
|
||||
|
||||
<p>Interestingly though, this did give me ideas. This sky shader has a setting for cloud fuzziness, which, when turned down, gives the clouds a more toon-like aesthetic (pictured here). This is great, because this is actually an aesthetic direction I had recently decided to pursue with Project N5.</p>
|
||||
|
||||
<h2 id="planets">Create New World</h2>
|
||||
|
||||
<p>I discovered this <a href="https://deep-fold.itch.io/pixel-planet-generator">insanely cool planet generator</a> by Deep-Fold on itch.io. It's a <i>pixel</i> planet generator, strictly speaking, but since its output is just determined by generated noise (I think), the resolution can be increased much further to create sharp toon-like planets. Here's one I generated that I quite liked:</p>
|
||||
|
||||
<Video src="planet.mp4" />
|
||||
|
||||
<p>This shader made me think that I really do want planets to be present in my game similar to how Ratchet & Clank does it – on the starmap as well as when flying towards the planets. Maybe you could even see a planet if you look into the sky from another planet's surface?</p>
|
||||
|
||||
<p>I'm unsure how I feel about using someone else's generator in my own game, though, so I followed a <a href="https://docs.godotengine.org/en/stable/tutorials/shaders/using_viewport_as_texture.html">tutorial</a> I found in the Godot documentation by coincidence – I wanted to look up something for an entirely different game. The result:</p>
|
||||
|
||||
<img src="planet-mine.webp" alt="A sphere with green and purple noise artifacts representing land and potentially poisonous liquid">
|
||||
|
||||
<p>...it's a work-in-progress. A relatively decent start though! I think there's potential.</p>
|
||||
|
||||
<p>The debate of "should I use someone else's work in my own?" is one I find myself debating frequently, actually. It's always been a problem with me, and I think it started with using other people's samples and synth patches in my music, which I did do, but tried to avoid rather frequently. This sentiment still holds true to this day, whether it's in music, 3D modelling, or... literally any of the rubbish generated by AI these days. I think a healthy dose of attempting to create things on your own is good though, because it allows you to both expand your own skillset and adapt the work to your own vision much more easily than if you had to modify an existing work you didn't create.</p>
|
||||
|
||||
<p>No harm in studying other people's work though – in fact, I'd say that's super beneficial! Don't fall into the trap of "good artists copy, great artists steal"; go for "great artists are inspired by other people's works and incorporate this into their own works" instead. Doesn't roll off the tongue quite as nicely though.</p>
|
||||
|
||||
<h2 id="remeshing">Remeshing</h2>
|
||||
|
||||
<p>Continuing the streak of visual elements, I worked on the N5 Blaster... again. This time I didn't tweak its visuals much, however; I modelled it from scratch to fix its terrible meshes.</p>
|
||||
|
||||
<p>Back when I modelled the N5 Blaster around a year ago, I didn't have much experience in using Blender. Thus, it wasn't modelled very well. The model consisted of 8 parts for the body, 3 or 4 parts for the grip, and the icosphere spinning in the middle of the gun. My goal today was to recreate the N5 Blaster with a more streamlined mesh, and I must say, I achieved my goal quite well: the gun now consists of one mesh for the body, one for the grip, and another for the icosphere.</p>
|
||||
|
||||
<img src="101-comparison.webp" alt="The remeshed N5 Blaster on the left compared to the old N5 Blaster on the right">
|
||||
<span class="image-subtitle">left: new, right: old</span>
|
||||
|
||||
<p>With this change, I also adjusted the material slightly. The gun has a more matte look and the grip is more rounded. I should say that the blue glass is only a temporary material I assigned within Blender; it's transparent in-engine to display the icosphere hiding within.</p>
|
||||
|
||||
<p>Also of note is the reduced tri count I achieved by optimising the model: I managed to push the tris down from 2,520 to... 2,510. Of course, reducing tri count wasn't the primary objective, I just thought this minuscule reduction was somewhat amusing.</p>
|
||||
|
||||
<p>Oh and, with this change, I think I decided on the upgraded version of the N5 Blaster: instead of changing into a bigger weapon, I think it'd be neat if the character would use two of the blasters when upgraded. I like the look of the two blasters side-by-side in the picture above.</p>
|
||||
|
||||
<img src="101-profile.webp" alt="The N5 Blaster from an orthogonal side view">
|
||||
|
||||
<h2 id="canister">Need Some Ammo?</h2>
|
||||
|
||||
<p>After I introduced a <a href="/projects/projectn5/devlog/2024/1012/#whats-next">new ammo crate in the last devlog</a>, I completely overhauled its look. It's now quite different, more simplistic in its mesh, and it's so round, I stopped calling it crate and started naming it canister.</p>
|
||||
|
||||
<img src="canister.webp" alt="A new 8-sided ammo canister with the N5 Bomb Launcher logo on its sides">
|
||||
|
||||
<p>It's simple! But I kinda like it that way. Plus, neat feature: the canister displays the icon of the weapon for which it holds ammo! So far, only the N5 Bomb Launcher's icon is implemented, but others are easy to put in once I create icons for more weapons.</p>
|
||||
|
||||
<h2 id="bomblauncher">A New Weapon</h2>
|
||||
|
||||
<p>Introducing: the N5 Bomb Launcher.</p>
|
||||
|
||||
<img src="102-profile.webp" alt="A side view of the N5 Bomb Launcher, depicted using two cuboids and an icosphere in the front">
|
||||
|
||||
<p>Okay, it's not exactly a looker at this stage, but it's functionally largely implemented. This is an, as the name implies, bomb-launching device with ground targetting. This sets it apart from other weapons, and is the reason for why I was so hesitant to imlpement it: it meant I had to change my existing code to accommodate for this.</p>
|
||||
|
||||
<p>It also meant that I had to figure out how the projectile will fly. The problem: I wanted a projectile that follows a predictable curve and has ground targetting so that you can see where the bomb will land. I achieved the former through using a <a href="https://docs.godotengine.org/en/stable/classes/class_path3d.html"><code>Path3D</code></a> node and modelling a curve into it. The latter still proves a challenge, however; how do I retrieve a collision where the projectile is projected to land? I have not implemented anything of the sort yet. An idea solution would be a curved raycast, but that doesn't exist. Maybe a <code>ShapeCast3D</code> and retrieving the collision closest to the player? We'll see.</p>
|
||||
|
||||
<p>I've been playing around with the explosion as well:</p>
|
||||
|
||||
<img src="102-explosion.webp" alt="An icosphere-based explosion effect with white streaks in the middle of it">
|
||||
|
||||
<p>I like the idea of the explosion looking 'technical', if that makes sense. A quick explosion with a large wireframe icosphere. The colour definitely needs changing; I'm even considering changing it to blue, even if that doesn't match the N5 colours. Maybe for the V2 upgrade of the weapon.</p>
|
||||
|
||||
<p>The white stripes are strongly inspired by the art to Jaron's track <a href="https://youtu.be/M7Ng0hIzsIg">ONCE</a>. Looking at the art again, I actually quite like the colourshift effect, I <i>might</i> try to incorporate that as well. Then again, maybe the two effects (stripes and icosphere) don't match quite so well. I'll figure something out.</p>
|
||||
|
||||
<h2 id="inspiration">Character Inspiration</h2>
|
||||
|
||||
<p>In an effort to gain more inspiration for my project's visual direction, I've turned to a place I never thought I would voluntarily step foot in: Pinterest. Turns out, Pinterest is not only good for fashion and home furnishing inspo (though I also like it for that), but it has a slew of game art as well. I only created my account 10 hours ago, and I've already collected quite a lot of cool art <a href="https://de.pinterest.com/denizk0461/character-design/">here</a>!</p>
|
||||
|
||||
<p>Using Pinterest for this purpose allows me to visually see lots of different options I could go for with my character, which is a huge improvement over just... trying to come up with something exclusively on my own.</p>
|
||||
|
||||
<p>Seeing all of this art gives me ideas for how I could design a robot character, for instance. It allows me to decide on a shading style – there's a pin of a <a href="https://de.pinterest.com/pin/999165867324583246/">toon-shaded character</a> in there that I quite like. It also makes me contemplate the direction of the character's identity. With designing a robot character, I find that falling into the stereotype of 'cool and strong male robot' is too easy. I've done it myself. Why does it have to be a <i>male</i>-looking robot, anyway? What made me reevaluate my ideas was <a href="https://de.pinterest.com/pin/999165867324583524/">this pin</a>. It's not of robots, but I like the aesthetic of those outfits and hope to integrate some of that into my character somehow. The idea from the start was to create relatively non-binary robots anyway; after all, they're robots living 600 years in the future, why should they confine to humanity's societal standards?</p>
|
||||
|
||||
<h2 id="retro">Retrospective</h2>
|
||||
|
||||
<p>It's been almost 14 months of working on Project N5 – sometimes actively, with occasional breaks in-between. Can you believe that this game started from <i>this?</i> (video from <a href="/projects/projectn5/devlog/2023/09/#header-0">2023-09-16</a>)</p>
|
||||
|
||||
<Video src="../../2023/09/2023-09-16_00.mp4" />
|
||||
|
||||
<p>Logically speaking, of course, that makes complete sense. I had to start from somewhere. But it's the fact that I managed to get so far already, working on my own, that I find crazy. I've already managed to implement many basics of this game, slowly but surely realising my vision. I think this really has potential. I should keep up the work.</p>
|
||||
</Content>
|
||||
@@ -1,109 +0,0 @@
|
||||
<script>
|
||||
import BannerTitle from "$lib/banner-title.svelte";
|
||||
import Content from "$lib/content.svelte";
|
||||
import TableOfContents from "$lib/table-of-contents.svelte";
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>The Making of a Protagonist, Part I | denizk0461</title>
|
||||
</svelte:head>
|
||||
|
||||
<Content>
|
||||
<BannerTitle
|
||||
title="Project N5 Progress Update: 2024-11-27"
|
||||
subtitle="The Making of a Protagonist, Part I"
|
||||
banner="../../previews/2024/1127.webp"
|
||||
bannerAlt="Multiple iterations of untextured hand 3D models"
|
||||
/>
|
||||
|
||||
<TableOfContents disableStickyScrolling={true} />
|
||||
|
||||
<p>I've been busy at work on this game! I've not done any programming work lately – which I feel a bit guilty about – <i>however!</i> I've been improving in the 3D modelling department. I started modelling a humanoid character, based on references and my personal ideas, to become my new protagonist for Project N5. Here's what I've been able to do so far, and how I managed to get to this point.</p>
|
||||
|
||||
<h2 id="laura">Laura</h2>
|
||||
|
||||
<p>My new protagonist is called Laura. This is a change from my original idea, where I would have a robot protagonist, but more on that further down.</p>
|
||||
|
||||
<p>Laura is a 20-something year old human girl fitted with a mechanical right arm. This is supposed to affect gameplay as well, since Laura's left-handed, which reflects both in the way she holds weapons as well as in the game's aiming perspective, which will look over her left shoulder as opposed to her right. I think this is fairly uncommon, actually, so it might take a little bit of time to get used to, but I like the idea of straying from the norm ever so slightly.</p>
|
||||
|
||||
<p>With her mechanical right arm, Laura may also be able to perform actions such as using zip lines. I haven't entirely decided on that yet, though.</p>
|
||||
|
||||
<p>This is what I've created so far:</p>
|
||||
|
||||
<div class="horizontally-centre-aligned">
|
||||
<img src="laura-overview.webp" alt="A featureless blank 3D model of a human body t-posing without feet">
|
||||
<img src="laura-topology.webp" alt="The same human body model with a wiremesh displayed on its right">
|
||||
</div>
|
||||
|
||||
<p>I'll admit, I'm actually quite proud of myself for being able to create this. This is a fairly representative humanoid body, with relatively decent topology and without using a massive amount of polygons – this model currently sits at 2,452 tris.</p>
|
||||
|
||||
<p>The features aren't entirely fleshed out yet, though there are also a few things I want to keep in mind when creating this model:</p>
|
||||
|
||||
<ul>
|
||||
<li>There won't be much character customisation. There'll be some outfits (more on that below) but those are, for the most part, bound to the story progression.</li>
|
||||
<li>I'll do some touchups on the joints to get them to bend better.</li>
|
||||
<li>There's no skeleton yet.</li>
|
||||
<li>The right arm is only in place because I'm using a mirror modifier on the whole body. I'll chop off the right arm once I get to modelling the mechanical arm replacement.</li>
|
||||
</ul>
|
||||
|
||||
<p>The future vision is to give her two outfits: one in which she starts, which looks more like a casual outfit, wearing a hoodie with the right sleeve torn off. It's supposed to look like an outfit that's not really meant for combat, because it's the one she wore before her hibernation. The second outfit is supposed to be a more combat-suited outfit, perhaps a type of armour even.</p>
|
||||
|
||||
<p>For the next progress update, I'll be able to show a largely finished model – I promise!</p>
|
||||
|
||||
<h2 id="story">Story Changes</h2>
|
||||
|
||||
<p>There's reason for these ideas I have for Laura, and it's all in the story I am developing.</p>
|
||||
|
||||
<h3 id="new-story">The New Storyline</h3>
|
||||
|
||||
<p>Laura is a young girl waking up from a hundred-years-long hibernation. Her home – Sol III (Earth) – has been devastated. Before her hibernation, she lost her right arm, which has been replaced with a mechanical arm by a robot at some point during her hibernation. She doesn't get to meet this robot immediately, as they're gone when she wakes up (or perhaps is taken away?).</p>
|
||||
|
||||
<p><i>Project N5</i> is the story of Laura rediscovering what caused the devastation of her home as well as what happened to the robot that saved her life.</p>
|
||||
|
||||
<h3 id="old-story">How to Adapt the Old Storyline</h3>
|
||||
|
||||
<p>Gone is the robot protagonist. Gone is the titular <i>Project N5</i>, for which the protagonist had been built. Gone is the company that the protagonist was built by, and against whom the protagonist swore revenge. I struggled massively with developing this storyline, even just coming up with a general plot that sounded interesting. I think this is good riddance. This wasn't going anywhere.</p>
|
||||
|
||||
<p>This isn't a full rework, however – many aspects remain. The weapons remain, the ideas for planets and space stations remain, etc. The idea of revolving the story around Sol III and basing the story on environmental ruin still very much remains!</p>
|
||||
|
||||
<h3 id="inspiration">Inspiration</h3>
|
||||
|
||||
<p>Believe it or not, most of the inspiration I was able to gather to come up with this new storyline stems from one song: <a href="https://acloudyskye.bandcamp.com/track/spill">acloudyskye – Spill</a>.</p>
|
||||
|
||||
<p>The striking, saturated colours, the feeling of adventure, the sense of loneliness in a large world – all of these aspects combine beautifully in this song and its cover art. It gave me ideas which I want to realise in my game.</p>
|
||||
|
||||
<p>acloudyskye's music has inspired me quite a bit lately, especially their albums <a href="https://acloudyskye.bandcamp.com/album/what-do-you-want">What Do You Want!</a> and <a href="https://acloudyskye.bandcamp.com/album/there-must-be-something-here">There Must Be Something Here</a>. Absolutely recommend listening to them.</p>
|
||||
|
||||
<h2 id="likelies">Likely Future Changes</h2>
|
||||
|
||||
<h3 id="title">Game Title</h3>
|
||||
|
||||
<p>I suppose the title <i>Project N5</i> inherently sounds like a work-in-progress title. A codename of sorts.</p>
|
||||
|
||||
<p>Since the whole idea of the in-game <i>Project N5</i> won't be developed any further, I figure this is the start of a goodbye. A new title will have to come. I haven't decided on one yet, and I think it'll be quite some time until I'll actually settle on a new title, perhaps not until much of the story has already been developed.</p>
|
||||
|
||||
<p>For now, <i>Project N5</i> remains the working title. Don't get too attached to it!</p>
|
||||
|
||||
<h3 id="aesthetics">Aesthetics</h3>
|
||||
|
||||
<p>As I'm moving from working on the game's logic to the aesthetic (which does NOT mean the logic is anywhere near finished!), I'm considering starting to implement shaders. I've decided that I'll likely use a toon-style shader, perhaps a variation of <a href="https://godotshaders.com/shader/flexible-toon-shader/">this one</a>. Looking forward to playing around with the visuals!</p>
|
||||
|
||||
<p>I also have a vision for the 3D models, which I may have already mentioned: I'm planning to use (almost?) exclusively materials for the models' visuals. I'm trying to avoid textures, for multiple reasons:</p>
|
||||
|
||||
<ul>
|
||||
<li>Textures cannot be smoothly scaled up in resolution, whereas models that exclusively use materials and polygons for detail don't depend on an image's pixel resolution.</li>
|
||||
<li>Painting textures is hard!</li>
|
||||
</ul>
|
||||
|
||||
<p>Some low-poly 3D modelling artists use textures for shadows, which I think is cool, although I'm planning to use shaders and generated shadows in my game instead, so painted shadows are likely unnecessary.</p>
|
||||
|
||||
<h2 id="next">Next Steps</h2>
|
||||
|
||||
<p>Next, I'll continue modelling Laura. I most recently worked on her head, where I'm still deciding whether to give her a half-face mask or a full face shield. Doing a half-face mask will enable Laura to emote with her eyes, but that means I'll have to implement eyes, which could be difficult, so using a full face shield that just completely blocks her face would be easier. I could make it work in the story too. I'll model her hair, add some ears (probably), and then I'll get to modelling her mechanical right arm. Afterwards, I'll likely rig it.</p>
|
||||
|
||||
<p>Once I've done that, I'll save this model as a baseline 3D model and then edit a copy of it to add clothes – I want the clothes to be part of the model rather than go on top of the existing mesh, I think.</p>
|
||||
|
||||
<p>After that, I could start animating Laura, though I don't know whether I'll get to that in the next progress update. It could be cool! I'll have to find a way to add and update animations in Godot without re-importing the 3D model. I think a way exists using <a href="https://docs.godotengine.org/en/stable/tutorials/assets_pipeline/escn_exporter/animation.html">NLA tracks</a>, but I'll have to learn how to do this, and whether this works the way I imagine.</p>
|
||||
|
||||
<p>I've already made sketches for how I want to style Laura; this could be fun!</p>
|
||||
</Content>
|
||||
@@ -1,147 +0,0 @@
|
||||
<script>
|
||||
import BannerTitle from "$lib/banner-title.svelte";
|
||||
import Content from "$lib/content.svelte";
|
||||
import TableOfContents from "$lib/table-of-contents.svelte";
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>The Making of a Protagonist, Part II | denizk0461</title>
|
||||
</svelte:head>
|
||||
|
||||
<Content>
|
||||
<BannerTitle
|
||||
title="Project N5 Progress Update: 2024-12-22"
|
||||
subtitle="The Making of a Protagonist, Part II"
|
||||
banner="../../previews/2024/1222.webp"
|
||||
bannerAlt="Laura a-posing and wearing green and brown clothes"
|
||||
/>
|
||||
|
||||
<p>I have lots progress to share!!</p>
|
||||
|
||||
<TableOfContents disableStickyScrolling={true} />
|
||||
|
||||
<p>First things first: Laura is, unlike I promised before, not yet finished. However, I have made <i>so much</i> progress in the past few weeks that I just wanted to get out already. Here's a comparison between my last progress update and the current iteration of Laura:</p>
|
||||
|
||||
<div class="horizontally-centre-aligned">
|
||||
<img src="../1127/laura-overview.webp" alt="A featureless blank 3D model of a human body">
|
||||
<img src="laura.webp" alt="A 3D model of a human girl with brown hair, a full face mask, green sweatshirt, brown trousers, and black boots">
|
||||
</div>
|
||||
|
||||
<p>She's become an actual proper character!! omg omg</p>
|
||||
|
||||
<h2 id="how">How We Got Here</h2>
|
||||
|
||||
<p>So, what happened? How did I create this character?</p>
|
||||
|
||||
<p>I think what's most crucial is that I gathered influence, references, knowledge, and ideas from all kinds of places. Here's some:</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="https://youtu.be/-XYryP_GU8o">Creating Stylized Low Poly Characters in Blender</a> by lacruzo. Shows the entire process of creating a low-poly character from scratch, and was the entire reason why my character got off the ground to begin with.</li>
|
||||
<li id="low-poly-easy"><a href="https://youtu.be/N7GVbdf4H_g">Creating a low-poly character is actually kinda easy</a> by SELS – topology of lower-poly characters. Also, how to create clothes and hair, UV unwrapping and texture painting, as well as rigging with a meta-rig.</li>
|
||||
<li><a href="https://topologyguides.com/loop-reduction">Optimal Edge Loop Reduction Flows</a> on topologyguides.com helps understand how to efficiently transition between spots that require more edge loops for detail (such as hands) and meshes that are less detailed (such as arms).</li>
|
||||
</ul>
|
||||
|
||||
<p>Aside from that, looking at reference images of people, clothes, hairstyles etc. on the internet just helped a lot. I've dragged plenty of images of random people into Blender to use as shape references. It's much easier than trying to imagine how a human is supposed to look, because, to be honest – even though we all look at humans all the time, making one from scratch without reference (and without much practice) is nigh impossible.</p>
|
||||
|
||||
<p>Side note: Laura is <i>not</i> a low-poly character. Her mesh currently consists of about 8,600 tris. However, in trying to understand how topology works to create a humanoid shape, learning from low-poly character creation tutorials helps immensely imo. Low-poly characters rely on as few vertices as possible to display as much detail as needed. Going up in poly count is fairly straightforward – perhaps as simple as applying a subdivision modifier, if your model allows for it. Though for a video game character, I wouldn't necessarily recommend it unless you know what you're doing, because polygon count can quickly skyrocket that way.</p>
|
||||
|
||||
<h2 id="changes">Changes During the Creation Process</h2>
|
||||
|
||||
<h3 id="clothes">Clothes</h3>
|
||||
|
||||
<p>Laura was originally supposed to wear an orange sweatshirt as well as shorts. The orange sweatshirt was thrown out because the character reminded me of Velma from Scooby-Doo, and I changed it to green because I like green. Also, the shorts looked dorky. Here's a picture from 2024-12-01 – Laura oddly looks younger in this picture, I feel. The shorts and hair make a big difference.</p>
|
||||
|
||||
<img src="laura-young.webp" alt="A 3D model of a t-posing human girl with different hair, brown shorts, and no feet">
|
||||
|
||||
<h3 id="hair">Hair</h3>
|
||||
|
||||
<p>Modelling hair has proven... challenging. What style to go with? What modelling technique to use?</p>
|
||||
|
||||
<p>The first try (seen above) was using the technique from <a href="#low-poly-easy">this video</a> – selecting faces from the character's head, duplicating them, separating them into their own mesh, changing the scale, adding a solidify modifier, and then adding faces. This... worked, but I didn't like the results. And I tried quite a few styles.</p>
|
||||
|
||||
<div class="horizontally-centre-aligned">
|
||||
<img src="laura-hair-flat-1.webp" alt="White hair with middle split">
|
||||
<img src="laura-hair-flat-2.webp" alt="White hair with spiky bangs">
|
||||
<img src="laura-hair-flat-3.webp" alt="White hair with spiky ends">
|
||||
</div>
|
||||
|
||||
<div class="horizontally-centre-aligned">
|
||||
<img src="laura-hair-flat-4.webp" alt="Brown hair with middle split, flowing behind the character's ears">
|
||||
<img src="laura-hair-flat-5.webp" alt="Brown hair with middle split and divided at the ears">
|
||||
<img src="laura-hair-flat-6.webp" alt="Brown hair with big bangs">
|
||||
</div>
|
||||
|
||||
<p>It always looked too flat, too shapeless, too boring, wrong cuts. It just didn't work.</p>
|
||||
|
||||
<p>Next up: a technique shown in these two videos: <a href="https://youtu.be/LU0BFThJIco">Blender: How to Make HAIR, Full Workflow</a> by 2AM, and <a href="https://youtu.be/BqWYgrXw7Jk"> Easiest Way To Create Hair in Blender – 5 Minute Tutorial</a> by YanSculpts.</p>
|
||||
|
||||
<p>Essentially, you create a curve and a circle, use the circle's shape as a profile for the curve, then change the circle's shape as well as the position and scale of the curve's vertices to create individual hair strands. Shown well in the two videos linked above, this can look pretty amazing! Only one issue: I'm creating a <b>game</b> character, and this technique is quite expensive, as it creates a lot of polygons for all the individual hair strands and the detail that goes into them. To mitigate this, I lowered the resolution of the profiling and used only a few curves to create an entire head's worth of hair. This looked a little like this:</p>
|
||||
|
||||
<div class="horizontally-centre-aligned">
|
||||
<img src="laura-hair-curves.webp" alt="Toon shaded view at the character with brown hair">
|
||||
<img src="laura-hair-curves-2.webp" alt="Side view at the character without special shading">
|
||||
</div>
|
||||
|
||||
<p>This hair mesh originally (left picture) consisted of three parts: two curves at the front (left/right) and one in the back. This... was okay, but scaling the curves made the hair look weird. Thinner strands, especially when there's only a few of them, made them look more like dreads, and scaling up the vertices to large scales, as seen in the front near the top of the head, makes the hair look as if it's ballooning. Getting the shape right was a mess too: using only a single curve in the back meant that I had exactly one curve to cover quite literally half the head, and making sure that this singular strand of hair covered the head stretching from one ear to another was a pain. I tried using five curves (right picture), so that I have three in the back, but it didn't improve anything.</p>
|
||||
|
||||
<p>I then went <i>back</i> to the first method of scaling up faces from the head, with more knowledge and several tries behind me, and you know what? It actually kind of worked out.</p>
|
||||
|
||||
<div class="horizontally-centre-aligned">
|
||||
<img src="laura-hair-flat-new-2.webp" alt="Front view at the character with a green headband and bangs">
|
||||
<img src="laura-hair-flat-new-3.webp" alt="Front view at the character with a green headband and middle-split hair">
|
||||
</div>
|
||||
|
||||
<p>The right picture is the current iteration of Laura's hair. I added a head band because I thought it looked nice, though that detail is not final.</p>
|
||||
|
||||
<p>Even though I had created a hair style that looks fairly decent in a cel-shaded environment, I wasn't quite happy. So, today in fact, I checked out a tutorial on creating an <a href="https://youtu.be/kxWWBmIUxbc">anisotropic hair shader</a> made in Blender by Lighting Boy Studio. It's really impressive! And quite complicated. Also, it's a Blender tutorial. While this is quite cool, I need shaders for Godot, since I'm creating a game, not a movie. To my surprise, someone already created a similar toon hair shader for Godot – <a href="https://godotshaders.com/shader/simpletoonhair/">SimpleToonHair</a> by D3ZAX. It's <i>exactly</i> what I was looking for, and I really want to use this for Laura! Only one problem: this doesn't really work with her current hair mesh.</p>
|
||||
|
||||
<p>I decided that I want to create a hair mesh more similar to that shown on the shader's images. This mesh consists of several strands of hair, each two quads wide to create individual strands. Making something like that look cohesive is actually fairly easy too, since the cel-shaded style actually hides a lot of overlaps between meshes of the same colour.</p>
|
||||
|
||||
<h3 id="hair-animation">Hair Animation</h3>
|
||||
|
||||
<p>To create flowing long hair, I want to use the <a href="https://godotengine.org/asset-library/asset/1595">JiggleBones</a> add-on. Using this add-on, I can add bones to the hair mesh in Blender, which will then be moved by the add-on whenever the character moves. It's essentially an inertia effect. I haven't tried this out yet, however.</p>
|
||||
|
||||
<h3 id="mask">Her Mask / Face Shield</h3>
|
||||
|
||||
<p>Canonically, Laura is supposed to wear some type of respiratory device, because the hazardous conditions on her home planet do not allow her to sustain life without it anymore. I'm not quite sure yet whether this respiratory device will come in the shape of a full face shield or a partial face mask, covering her nose and mouth.</p>
|
||||
|
||||
<p>Part of why I want to integrate this is because... modelling is hard, and I imagine animating a face will be even more difficult. Realistically, I'm a single dev trying to make a game that's fairly large in scope, so I should try to reduce complexity if possible. However, I have not yet decided whether I want to give Laura eyes. Eyes would make her feel more alive, I think, but again, it adds additional complexity. Also, I'd have to create eyes without using any textures, since I set out to create a game with as few image textures as possible (hopefully 0) to, again, avoid some complexity that comes with creating textures. I think it would be doable.</p>
|
||||
|
||||
<h3 id="arm">Her Right Arm</h3>
|
||||
|
||||
<p>Laura's supposed to have a mechanical right arm – on the current model, however, I have applied a mirror modifier, which means her left and right arms are identical. The grey mesh in front of her right arm, however, is the work-in-progress mechanical arm.</p>
|
||||
|
||||
<img src="arm.webp" alt="Grey mechanical arm">
|
||||
|
||||
<p>I'm not entirely happy with this yet. The general shape of the arm is relatively decent, the hinge looks ok, but I feel it's missing something. I think I want to add LEDs to the arm, which in-game can serve to display Laura's health status (alongside a more clearly legible health UI element).</p>
|
||||
|
||||
<h3 id="pose">Modelling Pose</h3>
|
||||
|
||||
<p>Influenced while I was researching a tangential topic on a Blender forum, I read up on A-pose versus T-pose when modelling 3D characters. From what I could gather reading the forum, the T-pose is mostly used because it's convenient for modelling orthogonally. However, the A-pose is preferable, as it better preserves the shoulder mesh. When modelling in a T-pose, the character's shoulders are stretched fairly unnaturally, whereas the A-pose puts the arms further towards a more natural, relaxed pose, which means that the shoulder mesh is not stretched quite as significantly when the character has their arms hanging down.</p>
|
||||
|
||||
<p>To illustrate my point (get it?), here are some pictures. Left is in T-pose, right is in A-pose:</p>
|
||||
|
||||
<div class="horizontally-centre-aligned">
|
||||
<img src="deform-1.webp" alt="Diagram showing a t-posing character, with the text 'large angle, thus more deformation'">
|
||||
<img src="deform-2.webp" alt="Diagram showing an a-posing character, with the text 'smaller angle, thus less deformation'">
|
||||
</div>
|
||||
|
||||
<p>However, after watching <a href="https://youtu.be/FXfc4Gyw6I0">this video on bind poses</a> by Doodley, it seems that... it doesn't really matter. Whether you use the T-pose, the A-pose, the lovingly-called hug-pose, or anything else really depends on what you plan to do with your character. Since Laura will mostly wield guns and keep her arms fairly low for most of the game, I decided to change Laura's modelling pose to an A-pose, with her arms pointed 30 degrees downward.</p>
|
||||
|
||||
<h2 id="next">What's Next</h2>
|
||||
|
||||
<ul>
|
||||
<li>Create a new hair mesh that looks and flows nicer and works better with the anisotropic toon hair shader.</li>
|
||||
<li>Adjust the hands (they look decent but I want them to look just a slight bit better).</li>
|
||||
<li>Finish the mechanical arm and attach it to Laura.</li>
|
||||
<li>Learn how to assign multiple meshes to a single skeleton – this will serve to swap between this more casual outfit and the eventual armour-type outfit.</li>
|
||||
</ul>
|
||||
|
||||
<p>I suppose that's mostly what I've been up to. There's not been much going on in the Godot project, though I'm preparing for bigger changes. I want to refactor the weapon scripts, for instance – I tried to make them more modular at one point, having different scripts for Throwers, Semiautos, Automatics, but it made things pretty convoluted. I'll see if I can fix this up to make adding weapons into the game more streamlined.</p>
|
||||
|
||||
<p>Also, I'm changing the way weapon stats are put into the game. Currently, data for the individual weapons such as damage, fire rate, vendor price, max ammo, etc. is stored in <b>three different places</b> – two different nodes attached to the weapon itself, as well as a singleton instance holding some additional data. My current idea was to transfer all of this data into a single CSV file, where I can neatly and easily add and change values as I see fit. This CSV data can then easily be imported into the game and used wherever needed I think that'll be a huge quality of life improvement during development.</p>
|
||||
|
||||
<p>For the time being, here's a picture of the soon-to-be-retired current protagonist character. Smoothly shaded for your viewing pleasure.</p>
|
||||
|
||||
<img src="retiree.webp" alt="The previous purple protagonist with a shiny body in a seductive pose">
|
||||
</Content>
|
||||
66
src/routes/projects/projectn5/devlog/20240210.md
Normal file
@@ -0,0 +1,66 @@
|
||||
---
|
||||
title: 'Progress Update #5'
|
||||
date: '2024-02-10'
|
||||
tag: '20240210'
|
||||
bannerAlt: Panorama of the environment
|
||||
---
|
||||
<script lang="ts">
|
||||
import Video from "$lib/video.svelte";
|
||||
</script>
|
||||
|
||||
My apologies for the lack of updates lately! Between being hard at work on the game's progress, lacking motivation, and university exams, I really didn't have the time to write a proper update. Instead, I figured it would now be a great time to do a bundled progress update, since I really did get a lot done that takes the game quite a few steps further!
|
||||
|
||||
The most apparent change may be the new character! It's a temporary character once again – character number 3, to be exact – but this time it's rigged properly. There are no bends in the character, which sounds PS1-esque but is actually on purpose because the final character is supposed to be a robot.
|
||||
|
||||
There are also new animations! Nothing finished, of course, but I created them to play around with Godot's `AnimationTree` and `Blend2D`, which worked very well to lay out and play even multiple animations at once. There are now animations for walking, standing still, pointing a gun, single jumping, and double jumping! What's missing is a falling animations, but that will be implemented once I figure out how to import NLA tracks instead of needing to re-import the entire character for every animation change.
|
||||
|
||||
<Video src="animations.mp4" />
|
||||
|
||||
The game also now has a proper sky! I used this <a href="https://godotshaders.com/shader/stylized-sky-with-procedural-sun-and-moon/">Procedural Sky with Procedural Sun and Moon shader</a>
|
||||
by krzmig and tweaked the colours and light to get the current look. I don't expect this to be final necessarily, but I'll definitely at the very least use this as a base. I do like the look though, so it might remain final after all!
|
||||
|
||||
<img src="sky.webp" alt="Panorama shot of the scene and the orange-to-pink sky with the character in front">
|
||||
|
||||
I fixed the glowing issues in the game at one point, but then screwed up again because glow wasn't working *at all* anymore. Only after over an hour of troubleshooting did I realise that I disabled glow in the `WorldEnvironment` node...
|
||||
|
||||
In tweaking the `WorldEnvironment`, I even got shadows to work!
|
||||
|
||||
<img src="shadows.webp" alt="The character standing next to a new enemy">
|
||||
|
||||
That red thing in the top right is an enemy. It doesn't move yet, and it can't take damage either (thus making it invulnerable), but it can be targetted, and it can damage the player too!
|
||||
|
||||
It can be *targetted?* Yes! There's now an `AutoAimAgent` component available for all weapons that targets the nearest enemy that's inside a collision cone attached to the weapon. Once an enemy is inside this collision zone, a target is shown to let the player know which enemy is targetted, and the weapon fires in the precise direction of the enemy.
|
||||
|
||||
<img src="target.webp" alt="The character aiming the N5 Blaster at an enemy. A crosshair is displayed on top of the enemy">
|
||||
|
||||
The weapons received more updates! There's now a quick change function that allows for quickly switching between the 3 most recently used weapons by pressing the Quick Select button quickly.
|
||||
|
||||
<img src="quickchange.webp" alt="The weapons UI displaying the equipped weapon and two extra weapons accessible via quick change">
|
||||
|
||||
That sperm rocket you're seeing in the picture above is the new rocket launcher. I wanted to implement the rocket launcher as a weapon type already, so I quickly whipped by a temporary model for launcher and rockets, and implemented the functionality. And it works! It even has particle effects for the rockets!
|
||||
|
||||
overcompensation be like
|
||||
|
||||
<img src="rocketlauncher.webp" alt="The character holding a massive rocket launcher">
|
||||
|
||||
<Video src="rockets.mp4" />
|
||||
|
||||
I really feared GPU particles because I figured they would be insanely difficult to implement, but Godot really made this a breeze. Now, making them look *good* is a different story, but that's more so due to my lacking creativity and skill.
|
||||
|
||||
What you don't possess, you can buy. And what do you need to buy those things? Money.
|
||||
|
||||
<img src="money.webp" alt="Golden bolts arranged in a line on the floor">
|
||||
|
||||
Aside from increasing a counter upon being collected, these totally-not-bolts don't do anything at the moment. But it's a start! In the future, the money can be used to buy things at the vendor that also already exists! But interacting with it only yields a blank menu at the moment.
|
||||
|
||||
<img src="vendor.webp" alt="The character standing next to the vendor object">
|
||||
|
||||
There's more that I can't really show visually though. I made huge progress with the character, for instance. Or rather, *I fixed some of the issues my own script caused.* I used to use a custom solution based on someone else's code to handle movement speed and sliding on slopes, but this introduced two massive issues. For one, stepping onto a steep slope while still half-standing on a surface that can be walked on caused the character to lose the ability to move until jumping, thus getting stuck. The other issue was that some abrupt slope angle changes caused the entire game to crash, probably caused by a faulty `RayCast` check.
|
||||
|
||||
Now, how did I fix these issues? Well, I found out that Godot already offers these functions in the default `CharacterController3D`. Hence, I ripped out all the custom code, I essentially checked two boolean flags, and I had the same behaviour, minus the game-breaking bugs. Despite my stupidity, I felt very happy to have discovered that. My player script is now a lot cleaner!
|
||||
|
||||
And so are other scripts! I cleaned up a few scripts, most recently the Inventory script. There used to be a lot of redundant function calls that essentially did the same thing except with one check that could be performed more centrally. I also double-checked item IDs unnecessarily. All gone now! Inventory is much more streamlined now.
|
||||
|
||||
My next goals are to implement enemy health as well as a level travelling mechanic. To be able to test weapons, enemy movement, and balancing, I want to add an arena world with test challenges. Adding an arena is convenient anyways, since I aim to have an arena in the final game anyway, so I can feel free to dedicate more resources into the arena than if it only were for testing.
|
||||
|
||||
Let's see how long it'll take me to get these things done! I really do love working on my game, but I often lack the motivation to *start* working on it. Once I'm in the flow, I can get a lot done, but getting into that flow, just getting out of bed to start something that can be considered "work" – that's the difficult part.
|
||||
76
src/routes/projects/projectn5/devlog/20240312.md
Normal file
@@ -0,0 +1,76 @@
|
||||
---
|
||||
title: 'Progress Update #6'
|
||||
date: '2024-03-12'
|
||||
tag: '20240312'
|
||||
bannerAlt: Protagonist pointing the N5 Blaster into the sky
|
||||
---
|
||||
<script lang="ts">
|
||||
import Video from "$lib/video.svelte";
|
||||
</script>
|
||||
|
||||
I've unfortunately not gotten a lot done lately. Both an internship and many university courseworks had robbed me of much time, while the remainder of my free time had been taken up by a lack of motivation for working on my game. Despite this, I've still made a little bit of progress that I'm quite happy to share here!
|
||||
|
||||
## Back to Title Screen
|
||||
|
||||
I needed a means to launch different levels quickly, so I created a basic title screen for the game! Behind this is a basic custom level manager that allows for launching and switching between different levels. Currently, there exist two of them – Unity and Arena. Unity is the original level that's been in the game since day 1, using Unity's (old) logo as a floor plane, mostly as a joke because I switched from Unity to Godot.
|
||||
|
||||
<img src="titlescreen.webp" alt="The title screen displaying two levels: Unity and Arena">
|
||||
|
||||
## Level 2: Arena
|
||||
|
||||
The arena level is a new addition, everyone welcome the arena! While I do intend to design a proper arena for the final game, this arena is intended to test enemies and the arena menu.
|
||||
|
||||
<img src="arena.webp" alt="A panorama of the arena with a blue sky, white clouds, and an arena terminal">
|
||||
|
||||
<span class="image-subtitle">the blue sky gives the level such a different feel. the clouds move really quickly here compared to Unity's clouds, suggesting a stormy atmosphere on this planet.</span>
|
||||
|
||||
The computer over there is the arena terminal. By interacting with it, you can select an arena challenge. Currently, it doesn't work. The menu does work! But the buttons don't do anything so far.
|
||||
|
||||
<img src="arena-terminal.webp" alt="Three arena challenges displayed in the arena terminal UI">
|
||||
|
||||
## Talking about yourself in the 3rd person
|
||||
|
||||
I discovered this great plugin for Godot called [Phantom Camera](https://phantom-camera.dev/). It's a plugin that allows you to use agents to control the game camera smoothly, efficiently, and hassle-free. In order to implement it in my game, I only had to do the totally easy task of ripping out my entire camera system. It totally didn't almost make me restart the project from scratch. But it works flawlessly now!
|
||||
|
||||
<img src="shoulder.webp" alt="An over-the-shoulder view of the protagonist aiming the N5 Blaster">
|
||||
|
||||
It wasn't quite flawless from the start though. I had issues with the camera facing my character's front instead of their back. Turns out though, that's not the camera's fault; Phantom Camera's agent was specifically designed to look at the character's back – only problem was that my character model was facing the wrong way! Fixing that took a little bit of time, but I got it done, and now the camera works pretty decently. I even added two more fancy camera gizmos: the first one is a level overview camera, like in Ratchet & Clank! It shows an overview of the level when you enter it. It smootly transitions to the player once any input is made.
|
||||
|
||||
<img src="overview.webp" alt="A panorama shot of the Unity level with the brick wall filling the entire left half">
|
||||
|
||||
The other is an over-the-shoulder camera! This one allows for (allegedly) more precise aiming. Come to think of it, I should actually turn down the camera sensitivity when the player is in this mode...
|
||||
|
||||
<Video src="shoulder.mp4" />
|
||||
|
||||
Funnily, due to initial collision issues, I first accidentally turned my game into a first person shooter. Actually looks kind of cool, I have to say. Maybe I'll implement a first person view as an alternative option to the over-the-shoulder view.
|
||||
|
||||
<Video src="firstperson.mp4" />
|
||||
|
||||
## Can I offer you a nice sketch in this trying time?
|
||||
|
||||
When I'm not developing, I'm often doing something else related to my game. Sometimes, I sketch!
|
||||
|
||||
I am by NO MEANS a skilled sketch artist, but it really helps to note down ideas to remember them, visualise them, and expand on them.
|
||||
|
||||
<img src="sketches.webp" alt="Sketches of the protagonist as well as their armour and weapons">
|
||||
<span class="image-subtitle">don't judge</span>
|
||||
|
||||
## Kanban for my TODOs
|
||||
|
||||
Perhaps as a small insight into my project management process: I'm using [Obsidian](https://obsidian.md/), a markdown editor, as my means of collecting and managing my projects' notes and ideas. Recently, I've also tried using the Kanban plugin to organise my TODOs (I have <i>a lot</i> of them), which is working quite well! I often create small notes on this board, saving sparks of ideas that I occasionally have, and I like adding extra information that will help me remember in the long term what those ideas were about.
|
||||
|
||||
<img src="kanban.webp" alt="The kanban board housing all TODOs for the game">
|
||||
|
||||
I can only recommend it – both Kanban as a means of project management as well as Obsidian as a note vault!
|
||||
|
||||
## in hopes of more to come
|
||||
|
||||
Progress has been slow lately, but I have not stopped thinking about my game. I have big ambitions for this title – of course bearing in mind that I am only one person, and that this is also my first proper attempt at making a video game. Still, I think that, with enough time and dedication, I can pull off developing something that I will be quite proud of. Even right now, I am already proud of what I've accomplished. I have a large chunk of the basic game mechanics down already, and I did it all on my own (with the help of online documentation and a few tutorials, of course)!
|
||||
|
||||
After every day of working on my game, I ask myself: "did I really accomplish much today?" Often, my immediate response is "no", but my second response is "of course I did!" Because while a lot of things that take me quite a bit of time are children's play for another person most likely, the fact that I worked through it and managed to successfully create or implement something is huge. I'm always quite happy once I realise this.
|
||||
|
||||
And so, while my day-to-day motivation for working on my game directly is rather low, this is only a symptom of a general lack of motivation for anything. In the long term, I think I am quite dedicated to this game. When I'm not coding something, I'm coming up with ideas. I'm managing my notes. I'm designing something. Maybe I'm talking to someone about my ideas. That last point is actually something I would love to do more, but I don't really know any person that would enjoy listening to my ramblings.
|
||||
Let's see how far we get.
|
||||
|
||||
<img src="alone.webp" alt="Protagonist staring longingly into the distance, pointing the N5 Blaster thereto">
|
||||
<span class="image-subtitle">staring longingly into the sunset</span>
|
||||
134
src/routes/projects/projectn5/devlog/20240323.md
Normal file
@@ -0,0 +1,134 @@
|
||||
---
|
||||
title: 'Progress Update #7'
|
||||
date: '2024-03-23'
|
||||
tag: '20240323'
|
||||
bannerAlt: A red enemy being blown up by an incoming rocket
|
||||
---
|
||||
<script lang="ts">
|
||||
import Video from "$lib/video.svelte";
|
||||
</script>
|
||||
|
||||
I have quite a bit of free time on my hands until the next semester starts (in a few days...), and this leisure time has allowed me to continue working on my game a lot more than usual! I made quite a bit of progress that makes this game prototype feel slightly more polished and I'm really happy to share it here and now.
|
||||
|
||||
## Attraction <3
|
||||
|
||||
Collectibles are now attracted by the player once they're within a certain range (specified by a spherical `CollisionShape3D`) and are collected once they get close enough to the player – which is to say, once they collide with another, smaller spherical `CollisionShape3D`. The first try didn't work out amazingly, as the collectibles didn't want my character to intrude on their personal space though...
|
||||
|
||||
<Video src="personalspace.mp4" />
|
||||
|
||||
I fixed that issue, and lowered the attraction velocity to test, but that resulted in a spooky haunting effect.
|
||||
|
||||
<Video src="haunting.mp4" />
|
||||
|
||||
Here's another demonstration of that! I played around with PhantomCamera's dampening, which makes the haunting effect more evident. Also something I only came to notice then: my player jumps INSANELY high. Like 8x their height. This will be fixed later.
|
||||
|
||||
<Video src="high.mp4" />
|
||||
|
||||
After tweaking the speed, I got some nice attracted collectibles.
|
||||
|
||||
<Video src="attraction_stuck.mp4" />
|
||||
|
||||
One issue still remains though: when moving, the collectibles don't attract all the way into the player, therefore they don't get collected and fly next to the player until they stop moving.
|
||||
I learned that `lerp()` was at fault (no offense!) – `lerp()` would work perfectly fine if the player were standing still, but since the player – and therefore, the target position – is moving, `lerp()` calculates a speed that cannot overcome the difference between the collectible position and the player.
|
||||
I overcame this issue by increasing the weight of `lerp()` on every frame, thus increasing the speed linearly. This resulted in a very smooth attraction transition.
|
||||
|
||||
<Video src="attraction_smooth.mp4" />
|
||||
|
||||
## rocket go boom
|
||||
I finally implemented enemy health – they can now take damage from weapons and die. But it felt so hollow without any impact. I wanted my rockets to explode. So I started working on that.
|
||||
|
||||
### Stage 1: Experimentation
|
||||
|
||||
I first implemented a fairly basic particle effect using cube meshes. Not exactly photorealistic, but it gets the message across.
|
||||
|
||||
<Video src="explosion_0.mp4" />
|
||||
<span class="image-subtitle">boom</span>
|
||||
|
||||
### Stage 2: Struggle Colliding
|
||||
|
||||
I struggled EXTREMELY with getting the rockets to collide with the floor and walls. Oddly enough, they collided perfectly fine with the enemies! I was particularly confused because both the walls/floors and the enemies were types of `body` nodes, thus using the same piece of code to register a collision.
|
||||
|
||||
I looked up the issue online, to no avail, really, until I stumbled upon a thread about a completely different problem where someone advised to change the physics engine. I am, in fact, using a different physics engine – Jolt. So I figured, I'll go into the settings, and I'll change it, just to see what happens.
|
||||
|
||||
I briefly checked out Jolt's settings page... and then I saw something.
|
||||
|
||||
<img src="joltsettings.webp" alt="Screenshot of the game's Jolt configuration, the option 'Areas Detect Static Bodies' is enabled and highlighted">
|
||||
|
||||
"Areas Detect Static Bodies." This setting was OFF by default. This could actually apply, I figured, because my rockets are `Area3D`s and the walls/floors are `StaticBody3D` nodes. I turned it on, and... my issue was solved. Slightly frustrated, but more so amused and relieved, I continued work, happy that my code was fine and my solution worked.
|
||||
|
||||
I introduced an exported property that allows for setting the amount of collisions a projectile may experience before it despawns, thus allowing, for example, for the rocket to explode through a wall! I might use this in the future for the v3 rocket laucher.
|
||||
|
||||
<Video src="explosion_wall.mp4" />
|
||||
|
||||
### Stage 3: Style
|
||||
|
||||
One day after that, I was motivated to create a more convincing explosion. I watched a YouTube tutorial, and ultimately got something that looks quite nice:
|
||||
|
||||
<Video src="explosion_test.mp4" />
|
||||
|
||||
<Video src="explosion_1.mp4" />
|
||||
|
||||
Interesting observation: in Godot, you can use the "RAW" tab when picking a colour to set values above 100%. The explosions, for example, use red values between 300% and 500%, which, with my `WorldEnvironment` light setup, produces a glowing effect that's just perfect for explosions!
|
||||
|
||||
I also messed up my lighting setup in configuring this, which results in my character being extra shiny and the N5 Blaster to glow excessively, but that's ok, we can fix that later.
|
||||
|
||||
In a strange coincidence, [Masahiro Sakurai](https://youtu.be/rXwo0qcKJDk) released a video about particle effects and the "right level of detail" just one day after I had started working on my explosion particle effects. Interesting video, by the way – I was not aware of how important scale is when designing VFX.
|
||||
|
||||
## Camera Shake
|
||||
|
||||
Anyway, I got to work on camera shake! Through a tiny bug that has already been fixed, I briefly got to experience something resembling a camera shake in my game while I was firing a rocket. I thought that was super cool, so I looked up camera shake and implemented it.
|
||||
|
||||
The tutorial I followed (a 2D tutorial, btw) used a strength value of 30. I figured that'd be too much, so I set it to 20, just in case.
|
||||
|
||||
<Video src="shake_0.mp4" />
|
||||
|
||||
...I later set down the strength value to about 0.35.
|
||||
|
||||
I also implemented distance fade for the camera shake strength! The strength now depends on how close the player is to the explosion origin. An explosion far away won't shake the camera, but one close up has much more impact!
|
||||
|
||||
<Video src="shake_impact.mp4" />
|
||||
|
||||
## A new weapon is in the works!
|
||||
|
||||
I had a random burst inspiration recently while I was on the bus, and once I got home, I started modelling it. Introducing: a weapon that is unfinished and has no (finalised) name yet, but I'm still fairly proud of:
|
||||
|
||||
<img src="venom_front.webp" alt="Front view at a new weapon with two barrels, a golden lead-up to the top barrel, and a bolt in the back">
|
||||
|
||||
<img src="venom_back.webp" alt="Back view of the previously-described weapon">
|
||||
|
||||
I'm thinking this could be a blaster of types, maybe similar to an N5 Blaster upgrade – two-handed. Though I think it should be separate from the N5 Blaster. It could also be a flamethrower, though I want the flamethrower to look a bit different, especially at the gun barrel.
|
||||
|
||||
I quite like the bolt at the back as well as the yellow gunmetal-ish colour of the bolt and the gun barrel. The body is far from finalised – I still have to figure out a fitting one. I do like the cutouts in the shape, however, so I'll probably keep them for the final body shape.
|
||||
|
||||
## Camera Adjustments
|
||||
|
||||
I also worked quite a bit on the camera, specifically how it moves! This is the main thing that, in my opinion, makes the current build feel just a bit more polished than the previous ones – relatively speaking, of course.
|
||||
|
||||
The camera now moves quicker and more smoothly in and out of the precision aiming mode, for example:
|
||||
|
||||
<Video src="camera_precision.mp4" />
|
||||
|
||||
The level overview camera also moves in a much cooler way, using a quint transition type instead of the previous linear transition. I think using quint improves the look significantly.
|
||||
|
||||
<Video src="camera_overview.mp4" />
|
||||
|
||||
Look at how smoothly the camera follows the player, even when the player jumps up a platform or falls down from one!
|
||||
|
||||
<Video src="camera_smooth.mp4" />
|
||||
|
||||
The camera now sticks to the ground briefly when the player jumps, but it returns to the player once the player exceeds a certain height above the jump origin or falls lower than the starting point.
|
||||
|
||||
Also notice how, at the end of the video, I struggle to jump up the (admittedly massive) wall, but ultimately make it. Why is that? It's because I:
|
||||
|
||||
1. Adjusted the jump height to much more sensible values
|
||||
2. Implemented variable jump height, letting the player jump heigher the longer the jump button is pressed
|
||||
|
||||
Of course, obligatory *I accidentally turned my game into a first-person shooter*, again. This view of the N5 Blaster actually reminds me of Metroid.
|
||||
|
||||
<img src="firstperson.webp" alt="Erroneous first-person view">
|
||||
|
||||
## Looking down upon the mess I've created
|
||||
|
||||
I'm really happy with my progress. As a bonus, here's an overview of my current testing level Unity.
|
||||
|
||||
<img src="unity_overview.webp" alt="Bird's eye perspective overview at the Unity level">
|
||||
93
src/routes/projects/projectn5/devlog/20240324.md
Normal file
@@ -0,0 +1,93 @@
|
||||
---
|
||||
title: The Arena Update
|
||||
date: '2024-03-24'
|
||||
tag: '20240324'
|
||||
bannerAlt: Protagonist being swamped by many monkey enemies
|
||||
---
|
||||
<script lang="ts">
|
||||
import Video from "$lib/video.svelte";
|
||||
</script>
|
||||
|
||||
A new update *so* soon‽ Yes! I have things to share that I'm really excited about!
|
||||
|
||||
## What did I actually do?
|
||||
|
||||
Today, while I was standing in the shower, I set out a goal for myself: implement the arena mechanic. This was actually a goal that I had set out for myself to complete months ago, and my ultimate goal was to have it done by April. A few weeks ago, I thought to myself that I had postponed it too much, and that I wouldn't be able to get it done by April anymore – especially concerning the lacking motivation I had back then.
|
||||
|
||||
So, did I actually get done what I had set out to do? Also yes! I worked on my game (with breaks in-between, even one I used to bake a small cake) for a whole 10 hours today, and I actually worked out a decent, modular arena challenge system.
|
||||
|
||||
## The Finished Product
|
||||
|
||||
<Video src="demonstration.mp4" />
|
||||
|
||||
## The Good
|
||||
|
||||
- Arenas are fully functional; challenges can be selected, enemies fought, and rounds finished
|
||||
- The arena terminal automatically receives all arena challenges and creates an interactable menu with clickable buttons that can be used to start challenges
|
||||
- Lots of components are easily reusable and meshes are able to be replaced with finished products with ease once the time comes
|
||||
- Finishing a challenge successfully yields a monetary reward
|
||||
- A new test enemy type has been added that can more appropriately attack the player and even move towards them, thus laying the groundwork for a general-purpose enemy behaviour script
|
||||
- Adding new challenges to the arena terminal is insanely easy and intuitive
|
||||
|
||||
### The New Enemy, Suzanne Cylinder
|
||||
|
||||
<img src="suzannecylinder.webp" alt="Suzanne cylinder; an enemy made from a few cylinders and Blender's default 'Suzanne' monkey head">
|
||||
|
||||
Suzanne cylinder (called "test_monkey" in the game) is the first enemy that has movement code implemented, able to follow the player once close enough and attack once the player gets too close. Without gravity holding Suzanne cylinder to the ground, though, the situation gets spooky quickly.
|
||||
|
||||
<Video src="haunted.mp4" />
|
||||
|
||||
Initial movement tests were quite funny, because `look_at()` adjusts rotation on both the y axis (left-right rotation) as well as the x-axis (up-down rotation), which meant that the enemy kept looking up when the player was at a higher elevation than it.
|
||||
|
||||
<img src="lookingup.webp" alt="Suzanne cylinder staring up at the protagonist from beneath a ramp">
|
||||
<span class="image-subtitle">send help</span>
|
||||
|
||||
### Developing Arena Challenges
|
||||
|
||||
To expand on the last point: I'm actually quite proud of the solution I implemented for creating arena challenges. The way this works right now is that the arena terminal contains a dictionary which stores all arena challenges, including any information that needs to be associated with them: round and enemy count and types, rewards, etc.
|
||||
|
||||
All that information looks a little like this:
|
||||
|
||||
<pre class="code-block">
|
||||
const arena_challenges = {
|
||||
1099: {
|
||||
"reward": 7382,
|
||||
"rounds": [
|
||||
{
|
||||
"type": "regular",
|
||||
"spawner_count": 3,
|
||||
"enemies": [
|
||||
ENEMY_MONKEY,
|
||||
ENEMY_MONKEY,
|
||||
ENEMY_MONKEY,
|
||||
...
|
||||
],
|
||||
},
|
||||
...
|
||||
],
|
||||
},
|
||||
}</pre>
|
||||
|
||||
`1099` is the unique ID by which the challenge is identified; this can later be used to save which challenges the player has already successfully completed. The ID is also used to fetch strings, such as the title of the challenge, and later the description and perhaps other useful information that could be displayed to the player in the arena terminal GUI.
|
||||
|
||||
`reward` is the money count that is rewarded after completing a challenge; the option to receive items could be implemented later. A reward for completions after the first one should also be added later, so that the player doesn't receive an insane amount of money for completing the same challenge over and over again!
|
||||
|
||||
`rounds` is an array that contains `round` objects which store the `type` of round – which is currently unused, but could be used later for boss rounds –, the `spawner_count`, defining how many of the current total of 8 spawners should be used for spawning enemies, and of course, `enemies`, which defines what types of enemies and how many should be spawned in the given round. `enemies` are defined simply by entering the string paths to their scene file (here, `ENEMY_MONKEY` is a constant string pointing to the enemy's `enemy.tscn` file).
|
||||
|
||||
This system is actually super easy to use; by defining a `spawner_count` and `enemies`, the arena script can figure out how many enemies should be spawned per spawner in order to balance out the spread of enemies. Spawners are picked at random, and enemies are shuffled before being spawned, so that the order entered in the challenge definition doesn't produce same results every time.
|
||||
|
||||
A challenge ends once all rounds have been cleared; a round ends once all enemies in a given round have been defeated.
|
||||
|
||||
## The Bad
|
||||
|
||||
- I have yet to implement handling for when the player dies during the challenge
|
||||
- It all still looks a little janky – although that's to be expected, since I implemented this entire system just a few hours ago, as of writing this webpage
|
||||
- It's a bit annoying to fight the enemies with the current, primitive roster of weapons
|
||||
|
||||
## Verdict
|
||||
|
||||
Very happy with my progress today – I got so much done. This was my most productive day in a *very* long time.
|
||||
|
||||
The great thing is that, now that there's an arena challenge, and with it, a constantly spawning stream of enemies attacking the player, the game actually has a proper gameplay loop, in some way! In other words – there's actually something to do now!!
|
||||
|
||||
I think that's pretty [neat](https://youtu.be/DrQqajtiRt4).
|
||||
88
src/routes/projects/projectn5/devlog/20240401.md
Normal file
@@ -0,0 +1,88 @@
|
||||
---
|
||||
title: The Behind-the-Scenes Update
|
||||
date: '2024-04-01'
|
||||
tag: '20240401'
|
||||
bannerAlt: N5 Blaster with its lights turned off
|
||||
---
|
||||
<script lang="ts">
|
||||
import Video from "$lib/video.svelte";
|
||||
</script>
|
||||
|
||||
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.
|
||||
|
||||
## 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](https://youtu.be/74y6zWZfQKk) 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:
|
||||
|
||||
<pre class="code-block">
|
||||
var enemies = [
|
||||
"path-to-enemy-0",
|
||||
"path-to-enemy-1",
|
||||
...,
|
||||
]
|
||||
|
||||
...
|
||||
|
||||
for enemy_path in enemies {
|
||||
enemy = load(enemy_path).instantiate()
|
||||
}</pre>
|
||||
|
||||
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:
|
||||
|
||||
<pre class="code-block">
|
||||
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()
|
||||
}</pre>
|
||||
|
||||
This yielded a great performance boost, as the `preload`s 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:
|
||||
|
||||
<img alt="An untextured work-in-progress 3D model of a blaster" src="venom.webp">
|
||||
|
||||
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:
|
||||
|
||||
<div class="horizontally-centre-aligned">
|
||||
<img alt="A REALLY crude sketch of a blaster." src="dual_venom_sketch.webp">
|
||||
<img alt="A crude sketch of a blaster resembling the 3D model shown above." src="venom_sketch.webp">
|
||||
</div>
|
||||
|
||||
The bolt visible in the first sketch actually makes me consider using [the model I showed off recently](/projects/projectn5/devlog/20240323) as the v2 for the Venom (which I would call Antidote by the way, in reference to [this song](https://youtu.be/fbafd6UV3w4)).
|
||||
|
||||
## 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.
|
||||
|
||||
<Video src="n5-glow.mp4" />
|
||||
<img alt="The N5 Blaster. Its lights are turned off, and the icosphere in the middle is dimly glowing." src="n5-dim.webp">
|
||||
|
||||
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)!
|
||||
33
src/routes/projects/projectn5/devlog/20240713.md
Normal file
@@ -0,0 +1,33 @@
|
||||
---
|
||||
title: The WHERE HAVE I BEEN?? Update
|
||||
date: '2024-07-13'
|
||||
tag: '20240713'
|
||||
bannerAlt: Protagonist staring longingly into the distance, pointing the N5 Blaster thereto
|
||||
---
|
||||
<script lang="ts">
|
||||
import Video from "$lib/video.svelte";
|
||||
</script>
|
||||
|
||||
University.
|
||||
|
||||
Things have been busy. I had more responsibilities than I assumed this semester. More importantly perhaps, I had more exams *during* the semester than I assumed. It robbed me of a lot of time and I have virtually not progressed with Project N5 or any other project of mine in the past 3 months.
|
||||
|
||||
I can't express how much I loathe it – I'd much rather work on meaningful, creative tasks than these worthless university submissions and exams, especially considering that I don't feel my university courses contribute anything of value to my education, at least in regards to my future job. In fact, I believe that my lack of time to work on creative projects might have made me forget how rewarding those can be, which in turn has robbed me of motivation to do just that.
|
||||
|
||||
The semester has wrapped up, and all that's left is an exam next week (for which I am supposed to study right now – I am currently procrastinating), an oral exam in 3½ weeks, and two submissions due at the start of August and mid-September, respectively. Not exactly fulfilling tasks, I have to admit, but I'll have to push through.
|
||||
|
||||
If there's one positive thing I can report back with, it's that I've been doing pretty well in my exams. I've yet to receive a grade lower than 2.0 this semester (which likely will change once I receive my geography didactics exam grade, but still), and that's despite the fact that I've really not put in the appropriate amount of work for it. Just as my motivation for my creative projects has been dwindling, I've been procrastinating on all my university tasks hardcore.
|
||||
|
||||
<Video src="procrastination.mp4" />
|
||||
|
||||
Project N5 is not cancelled, though! I'm still confident that work will commence soon! I just have to gather the motivation to actually start working on it again (which is much easier said than done).
|
||||
|
||||
Part of my problem, I think, is that I want to start with story and artistic content. For instance, I want to actually create my protagonist! I want to create the character so I can create animations, set up the proper node hierarchy, and just to take cool presentable screenshots of my work. Would it not be a lot cooler if all my devlog screenshots had a fully fleshed-out, poseable character instead of the T-posing temporary character?
|
||||
|
||||
For what it's worth, here's a picture of something I printed a few weeks ago. It's an N5 Blaster magnet that's hanging on my PC! I printed it myself, using my new [Bambu A1 mini 3D printer](https://eu.store.bambulab.com/products/a1-mini?variant=49003631083868), and the filament I used is [PLA Galaxy green](https://eu.store.bambulab.com/products/pla-galaxy?variant=47730388107612).
|
||||
|
||||
<img alt="A 3D-printed half of an N5 Blaster that's hanging on the side wall of a PC" src="3dprint.webp">
|
||||
|
||||
I'd love to 3D print more Project N5 weapons – though for that I'll have to design the weapons first!! And in order to do *that*, I'll have to come up with the ideas for the weapons, which is also proving difficult. A friend suggested to me a while back that I should consider which types of weapons *I* like in games, and which types I find fun to use.
|
||||
|
||||
As for now, I should get started with my studies – I'll write my next update once I have more things to present from Project N5, which will (hopefully) be in less than 3 months! Until then~
|
||||
80
src/routes/projects/projectn5/devlog/20241012.md
Normal file
@@ -0,0 +1,80 @@
|
||||
---
|
||||
title: The Returnal Update
|
||||
date: '2024-10-12'
|
||||
tag: '20241012'
|
||||
bannerAlt: Protagonist aiming at two monkeys
|
||||
---
|
||||
I'M BACK!!!!
|
||||
|
||||
For real this time!! I've been busy with university, then I started working on other projects including 3D prints, electronics, a different game, then got busy with university again, and now I FINALLY started work on Project N5 again. And, as I promised in [my last update](/projects/projectn5/devlog/20240713), it would not take me another 3 months to get back to development – in fact, I undercut that deadline by a whole 24 hours!
|
||||
|
||||
Since even though Project N5 was stalled, I gained some more knowledge about and mostly confidence with Godot through another game project I'm working on in parallel with friends, I've kicked off Project N5 development by restructuring a few things. This means there's not that much visual stuff to show so far, but there are some sorely needed mechanical and programmatical under-the-hood improvements.
|
||||
|
||||
## New 2D-Based Aim Helper
|
||||
|
||||
I overhauled the auto aim mechanism (which is now called aim helper). Previously, the aim helper worked by putting a 3D collision shape in front of the gun, registering all collisions within this cone, and determining a target by calculating the shortest distance between the player and the enemies. Here's a visual of the old cone at the tip of the N5 Blaster:
|
||||
|
||||
<img src="cone.webp" alt="The protagonist pointing the N5 Blaster, which is emitting a wiremeshed cone shape">
|
||||
|
||||
This was a good solution, because it allowed for targetting enemies without much effort – add an enemy to the 'targetable' group and let the aim helper script take care of it. However, customisation proved difficult. Since the collider was a 3D shape, a new 3D shape would have to be created for every weapon and every upgrade that demanded a unique shape. While this offered flexibility, it proved cumbersome in execution. Cones could only be changed in scale uniformally, which means that, while they can be changed in size, no single dimension could be changed without causing bugs. Keeping X and Y while increasing the Z distance would mandate a whole new shape. Furthermore, the cone would have to be manually rotated and positioned in front of the gun every frame, which wasn't particularly elegant.
|
||||
|
||||
Thus, a new solution was born: a 2D approach to the aim helper!
|
||||
|
||||
<img src="aim_helper.webp" alt="A 2D circle on the screen aiming at an enemy, which is displayed as a target via crosshair">
|
||||
|
||||
The way the new aim helper works is by putting a 2D collision shape on the screen of the player. All enemies contain a 2D shape as well, which is unprojected onto the screen by the player camera. This means that the 2D shapes are positioned on top of the 3D characters. As soon as the player's collision shape collides with one of the enemies', it's added to the list of collisions and the shortest distance is calculated. This procedure hasn't changed between the 3D and 2D approaches.
|
||||
|
||||
Using this 2D shape is a lot simpler, however, because it allows for much easier changes of the collision shape. Using just a circle, the diameter can be changed by just changing one variable, and the max distance can be changed with another variable – much more easily configurable than modelling new cones! And new shapes can easily be created using 1-bit (black and white) bitmaps instead of 3D shapes.
|
||||
|
||||
There's also a blue line shooting out of the gun in the picture above. That's a raycast spanning from the player to the targetted enemy, checking whether a wall is obstructing line of sight. Enemies can no longer be targetted if they're behind a wall or similar.
|
||||
|
||||
## Overhauled N5 Weapon Icons
|
||||
|
||||
The N5 Blaster received an overhauled icon. The soon-to-be-implemented N5 Bomb Launcher also received its own icon!
|
||||
|
||||
<div class="horizontally-centre-aligned">
|
||||
<img src="n5-blaster-icon.webp" alt="N5 Blaster logo made from an icosphere and two handles">
|
||||
<img src="n5-bomb-launcher-icon.webp" alt="N5 Bomb Launcher logo made from an icosphere and waves">
|
||||
</div>
|
||||
|
||||
I changed the icosphere by tracing its 3D counterpart (the ball inside the N5 Blaster's glass tube) from a different point of view. It wasn't symmetrical before – it is now.
|
||||
|
||||
Admittedly, seeing the two icons side-by-side... they look damn similar. I think they might be difficult to tell apart in-game. One of these icons will be changed most likely. I'm also considering using the right icon for the N5 Blaster instead, maybe.
|
||||
|
||||
The idea with these weapons is that they're both N5 series weapons – they are supposed to be similar in style to the protagonist and be default gear. Perhaps both of them will be available from the start of the game. They're basic weapons like the Lancer and Gravity Bomb in Ratchet & Clank 2, for instance.
|
||||
|
||||
## Minor Changes
|
||||
|
||||
### Hopping on the Signal Bus
|
||||
|
||||
Minor change, but I overhauled the inventory by removing complicated signal lines and simplifying them through a `SignalBus` singleton.
|
||||
|
||||
Previously, in order to change weapons, the quick select menu would directly interact with the inventory; the weapons menu would signal to the pause menu, and the pause menu would thus interact with the inventory. This was unnecessarily complicated.
|
||||
|
||||
Instead, I'm now using a `SignalBus` containing a signal `on_player_equip()` that can easily be triggered by the quick select and weapons menus without a direct connection to the inventory. In order to receive these signals, the inventory connects one of its functions to the signal in `SignalBus`, consolidating functions such as `on_quick_select_item_equipped()`, `on_weapons_menu_item_equipped()`, etc.
|
||||
|
||||
This `SignalBus` isn't even new in my game; I've previously already used it for the aim helper described above! Using such a bus is genuinely useful for any kind of Godot game that needs to allow communication between nodes that have no direct connection to one another. It's much more convenient – and safe! – than fetching nodes directly by their path, like `get_node("/root/Main/Level/Player/CharacterBody3D/Inventory")`. Imagine you change just one of these nodes' names a few weeks down the line. Nightmare to debug.
|
||||
|
||||
### Strafing Like a Gladiator
|
||||
|
||||
Another minor change that affects gameplay more so than code: the player now strafes automatically when having a weapon equipped. This emulates the strafing behaviour in Ratchet: Gladiator, which may have been influenced by the fact that I've been playing this game a bunch these past few days... on Exterminator difficulty, no less. Not easy, but really fun.
|
||||
|
||||
Conveniently, forcing strafing when holding a weapon elminiates the need to fix bugs related to strafing – for example, if the player doesn't strafe, or doesn't stop strafing. Though I may need to change this behaviour again if I decide to introduce gadgets.
|
||||
|
||||
## What's Next?
|
||||
|
||||
It's not quite certain, but I have ideas. Next on my agenda is, for example, continuing to clean up the project. I think there's a lot of streamlining I can do using signals, the `SignalBus`, and overall just writing more cohesive code. I've come a long way since I started this game project 13 or so months ago, after all.
|
||||
|
||||
I also want to implement more visual things. I've been meaning to 3D model again, creating crates, a new ammo pickup, and even some weapons. Of course, I'd also love to create a new, more final protagonist, but ideas are slow to come. Still, there are some I've newly come up with or written down. The N5 Bomb Launcher especially is something I want to implement soon. Since it's a thrower-type weapon, meaning it fires its shots in an arch and targetting the floor, there's a little bit of work involved to make that happen. I've been thinking about possible approaches to this lately, and I think I might settle on a pre-baked curve/collision mesh, because I think the PS2 Ratchet & Clank games may be using a similar approach.
|
||||
|
||||
Here's a sneak peek at an ammo pickup I started working on recently:
|
||||
|
||||
<img src="ammo.webp" alt="An ammo canister with a question mark at its front">
|
||||
|
||||
And of course, there's always the struggle of motivation. With my new game project, I have the fortune of working with two other people who also do work. We can motivate one another, since we're all interested in developing the game further. I don't have this with Project N5. At least as far as I know, I'm the only one who's really interested in seeing this game flourish, so there's no real option for me to gain motivation through other people. It's difficult, and I don't quite know how to deal with it. I've also considered uploading snippets onto my Instagram, but even disregarding my dislike for the platform, I don't think anyone would really care – I've uploaded snippets in the past already, to little resonance. I don't blame other people, but it just illustrates that I need to have intrinsic motivation to continue work on Project N5.
|
||||
|
||||
That's where my idea of adding visual things came from, by the way. By making visually (or sonically, for that matter) distinct changes, such as through introducing new meshes and models, I could *see* my progress much more clearly than I can now. Perhaps by gauging my progress through visuals, I could lift my motivation?
|
||||
|
||||
Then again, in order to create visual things, I'll have to have motivation from the start, so we're in a bit of a pickle here.
|
||||
|
||||
I can do this.
|
||||
140
src/routes/projects/projectn5/devlog/20241103.md
Normal file
@@ -0,0 +1,140 @@
|
||||
---
|
||||
title: The Visual Update
|
||||
date: '2024-11-03'
|
||||
tag: '20241103'
|
||||
bannerAlt: Two N5 Blaster side-to-side
|
||||
---
|
||||
<script lang="ts">
|
||||
import Video from "$lib/video.svelte";
|
||||
</script>
|
||||
|
||||
As promised, I've been working on a few visual things! There's not *that* much to show yet, but I have a model or two to show, plus a lot more to talk about in terms of where I want to take the game.
|
||||
|
||||
Before this, though, here's some progress in the coding department (that's where I'm best at):
|
||||
|
||||
## Simplifying Node Chains
|
||||
|
||||
Behind-the-scenes, I've been steadily working at overhauling and refactoring some of my code. I wrote the majority of my game's scripts 6 to 12 months ago, and some of it hasn't aged that well. Complicated code structures and wonky node paths such as `get_node("/root/Main/LevelParent/Level/Camera/AimRayCastContainer/AimRayCast3D")` aren't things I want to maintain, so I'm trying my best to implement more best-practices – or at least better-practices.
|
||||
|
||||
One challenge I faced was referencing a node that has no clear direct relationship to the one I'm calling it from. Picture this node chain:
|
||||
|
||||
<img src="node_chain.webp" alt="A very long node chain displayed using Obsidian's canvas feature">
|
||||
|
||||
Say, for example, that I'm writing a script in `Automatic` – that's the node that handles projectile spawning and their direction in automatic weapons, among other things – and I need to reference `AimRayCast3D` to determine in which direction the projectile needs to be fired. Reasonable use case, seen as the `RayCast3D` is attached to the `Camera3D` to point exactly where the player is facing – except there's no real path I can follow to get to that node. Their closest relative is `Level`, which is the root node of the level, and no less than **eight nodes away** from `Automatic`! It's possible to retrieve the node in this way, starting from `Automatic`, but it's not pretty...
|
||||
|
||||
`var _ray_cast = get_node("../../../../../../../../Camera/AimRayCastContainer/AimRayCast3D")`
|
||||
|
||||
Imagine if any of these nodes has their name changed – or worse, if the order of nodes is changed. It *could* spell disaster. This method grabs the node relative to `Automatic`, which means it relies on this specific count of nodes as well as the names of the nodes, starting at `Camera`. We could switch this around:
|
||||
|
||||
`var _ray_cast = get_node("/root/Main/LevelParent/Level/Camera/AimRayCastContainer/AimRayCast3D")`
|
||||
|
||||
...but now we're reliant on the order starting from the root node (from the top), plus we now have to be wary of even more node names, so this is no good either. For quick testing, sure, but not to be implemented in a production release – hopefully. How do we fix this? I thought of using a singleton script that holds references to the most important nodes (level parent, player, camera) to retrieve nodes relative to them:
|
||||
|
||||
`var _ray_cast = GlobalReferences.camera.get_node("AimRayCastContainer/AimRayCast3D")`
|
||||
|
||||
This *is* a lot more streamlined, but... it doesn't work. You need to initialise the `camera` variable at some point after the level has loaded, but before the variable is used. If you use the variable in any `_ready()` call, then you're hosed, because you must initialise the variables in the level's `_ready()` and you cannot be certain that the level has its `_ready()` function called in time for the other node to retrieve a proper reference in `camera` instead of `null`.
|
||||
|
||||
Instead, we can use the function `get_first_node_in_group()` on the `SceneTree` to retrieve *any* node! We just have to make sure that the node has a group name that is unique to it within the `SceneTree` – in the case of a level camera, that's a given. Having multiple nodes with this group name is also possible by using `get_nodes_in_group()` and then filtering the returned array by, for example, checking its class name.
|
||||
|
||||
`var _ray_cast = get_tree().get_first_node_in_group("level_camera").get_node("AimRayCastContainer/AimRayCast3D")`
|
||||
|
||||
Almost there! We can pretty this up by adding two more things:
|
||||
|
||||
Turn `"level_camera"` into a constant. I did this by creating a global class called `Groups` and adding: `const LEVEL_CAMERA: String = "level_camera"` This simplifies changing group names, though keep in mind that this constant cannot be used inside the node's group assignment, meaning that, if you do change the name, you will have to change it in at least two places (the node and the constant).
|
||||
|
||||
Remove the `get_node("AimRayCastContainer/AimRayCast3D")` call and replace it with a variable call. Inside the camera's script, we can add a variable referencing `AimRayCast3D` quite easily because it's a child of the camera. Add to the camera script: `@onready var aim_ray_cast: RayCast3D = $AimRayCastContainer/AimRayCast3D` And then use `camera.aim_ray_cast` to retrieve it. Remember to add `@onready` because the node cannot be retrieved before `_ready()` is called.
|
||||
|
||||
In the end, we have the following statement:
|
||||
|
||||
`var _ray_cast = get_tree().get_first_node_in_group(Groups.LEVEL_CAMERA).aim_ray_cast`
|
||||
|
||||
We can use this *anywhere* in our game to retrieve the node, as long as it exists within the scene tree!
|
||||
|
||||
## ByteMuncher7's Approach to Projectiles
|
||||
|
||||
A while back, ByteMuncher7 on YouTube uploaded a video on [projectiles in video games](https://youtu.be/0rTI_UUfB-E?t=89). They use the Godot engine as well, so anything they implement, I can implement as well. The issue they faced was that projectiles often fly through walls a bit before colliding, since they may move past an object's surface between frames. I finally got around to implementing their solution, which worked quite well: you add a raycast to the projectile pointing from its current location to its last location, see if collides with anything, and if it does, you move the projectile to that position. It's quite a neat solution!
|
||||
|
||||
## Lighten the Mood
|
||||
|
||||
<img src="sky.webp" alt="A bright blue sky and procedually generated white clouds">
|
||||
|
||||
I changed the sky to be brighter and more friendly in the Unity test level. This doesn't serve the game in its final form in any way, it's just a measure I took to <a href="/projects/projectn5/devlog/2024/1012/#whats-next">give myself the impression that a lot has changed</a>, since the game has visually changed.
|
||||
|
||||
Interestingly though, this did give me ideas. This sky shader has a setting for cloud fuzziness, which, when turned down, gives the clouds a more toon-like aesthetic (pictured here). This is great, because this is actually an aesthetic direction I had recently decided to pursue with Project N5.
|
||||
|
||||
## Create New World
|
||||
|
||||
I discovered this <a href="https://deep-fold.itch.io/pixel-planet-generator">insanely cool planet generator</a> by Deep-Fold on itch.io. It's a *pixel* planet generator, strictly speaking, but since its output is just determined by generated noise (I think), the resolution can be increased much further to create sharp toon-like planets. Here's one I generated that I quite liked:
|
||||
|
||||
<Video src="planet.mp4" />
|
||||
|
||||
This shader made me think that I really do want planets to be present in my game similar to how Ratchet & Clank does it – on the starmap as well as when flying towards the planets. Maybe you could even see a planet if you look into the sky from another planet's surface?
|
||||
|
||||
I'm unsure how I feel about using someone else's generator in my own game, though, so I followed a <a href="https://docs.godotengine.org/en/stable/tutorials/shaders/using_viewport_as_texture.html">tutorial</a> I found in the Godot documentation by coincidence – I wanted to look up something for an entirely different game. The result:
|
||||
|
||||
<img src="planet-mine.webp" alt="A sphere with green and purple noise artifacts representing land and potentially poisonous liquid">
|
||||
|
||||
...it's a work-in-progress. A relatively decent start though! I think there's potential.
|
||||
|
||||
The debate of "should I use someone else's work in my own?" is one I find myself debating frequently, actually. It's always been a problem with me, and I think it started with using other people's samples and synth patches in my music, which I did do, but tried to avoid rather frequently. This sentiment still holds true to this day, whether it's in music, 3D modelling, or... literally any of the rubbish generated by AI these days. I think a healthy dose of attempting to create things on your own is good though, because it allows you to both expand your own skillset and adapt the work to your own vision much more easily than if you had to modify an existing work you didn't create.
|
||||
|
||||
No harm in studying other people's work though – in fact, I'd say that's super beneficial! Don't fall into the trap of "good artists copy, great artists steal"; go for "great artists are inspired by other people's works and incorporate this into their own works" instead. Doesn't roll off the tongue quite as nicely though.
|
||||
|
||||
## Remeshing
|
||||
|
||||
Continuing the streak of visual elements, I worked on the N5 Blaster... again. This time I didn't tweak its visuals much, however; I modelled it from scratch to fix its terrible meshes.
|
||||
|
||||
Back when I modelled the N5 Blaster around a year ago, I didn't have much experience in using Blender. Thus, it wasn't modelled very well. The model consisted of 8 parts for the body, 3 or 4 parts for the grip, and the icosphere spinning in the middle of the gun. My goal today was to recreate the N5 Blaster with a more streamlined mesh, and I must say, I achieved my goal quite well: the gun now consists of one mesh for the body, one for the grip, and another for the icosphere.
|
||||
|
||||
<img src="101-comparison.webp" alt="The remeshed N5 Blaster on the left compared to the old N5 Blaster on the right">
|
||||
<span class="image-subtitle">left: new, right: old</span>
|
||||
|
||||
With this change, I also adjusted the material slightly. The gun has a more matte look and the grip is more rounded. I should say that the blue glass is only a temporary material I assigned within Blender; it's transparent in-engine to display the icosphere hiding within.
|
||||
|
||||
Also of note is the reduced tri count I achieved by optimising the model: I managed to push the tris down from 2,520 to... 2,510. Of course, reducing tri count wasn't the primary objective, I just thought this minuscule reduction was somewhat amusing.
|
||||
|
||||
Oh and, with this change, I think I decided on the upgraded version of the N5 Blaster: instead of changing into a bigger weapon, I think it'd be neat if the character would use two of the blasters when upgraded. I like the look of the two blasters side-by-side in the picture above.
|
||||
|
||||
<img src="101-profile.webp" alt="The N5 Blaster from an orthogonal side view">
|
||||
|
||||
## Need Some Ammo?
|
||||
|
||||
After I introduced a [new ammo crate in the last devlog](/projects/projectn5/devlog/20241012), I completely overhauled its look. It's now quite different, more simplistic in its mesh, and it's so round, I stopped calling it crate and started naming it canister.
|
||||
|
||||
<img src="canister.webp" alt="A new 8-sided ammo canister with the N5 Bomb Launcher logo on its sides">
|
||||
|
||||
It's simple! But I kinda like it that way. Plus, neat feature: the canister displays the icon of the weapon for which it holds ammo! So far, only the N5 Bomb Launcher's icon is implemented, but others are easy to put in once I create icons for more weapons.
|
||||
|
||||
## A New Weapon
|
||||
|
||||
Introducing: the N5 Bomb Launcher.
|
||||
|
||||
<img src="102-profile.webp" alt="A side view of the N5 Bomb Launcher, depicted using two cuboids and an icosphere in the front">
|
||||
|
||||
Okay, it's not exactly a looker at this stage, but it's functionally largely implemented. This is an, as the name implies, bomb-launching device with ground targetting. This sets it apart from other weapons, and is the reason for why I was so hesitant to imlpement it: it meant I had to change my existing code to accommodate for this.
|
||||
|
||||
It also meant that I had to figure out how the projectile will fly. The problem: I wanted a projectile that follows a predictable curve and has ground targetting so that you can see where the bomb will land. I achieved the former through using a [`Path3D`](https://docs.godotengine.org/en/stable/classes/class_path3d.html) node and modelling a curve into it. The latter still proves a challenge, however; how do I retrieve a collision where the projectile is projected to land? I have not implemented anything of the sort yet. An idea solution would be a curved raycast, but that doesn't exist. Maybe a `ShapeCast3D` and retrieving the collision closest to the player? We'll see.
|
||||
|
||||
I've been playing around with the explosion as well:
|
||||
|
||||
<img src="102-explosion.webp" alt="An icosphere-based explosion effect with white streaks in the middle of it">
|
||||
|
||||
I like the idea of the explosion looking 'technical', if that makes sense. A quick explosion with a large wireframe icosphere. The colour definitely needs changing; I'm even considering changing it to blue, even if that doesn't match the N5 colours. Maybe for the V2 upgrade of the weapon.
|
||||
|
||||
The white stripes are strongly inspired by the art to Jaron's track [ONCE](https://youtu.be/M7Ng0hIzsIg). Looking at the art again, I actually quite like the colourshift effect, I *might* try to incorporate that as well. Then again, maybe the two effects (stripes and icosphere) don't match quite so well. I'll figure something out.
|
||||
|
||||
## Character Inspiration
|
||||
|
||||
In an effort to gain more inspiration for my project's visual direction, I've turned to a place I never thought I would voluntarily step foot in: Pinterest. Turns out, Pinterest is not only good for fashion and home furnishing inspo (though I also like it for that), but it has a slew of game art as well. I only created my account 10 hours ago, and I've already collected quite a lot of cool art [here](https://de.pinterest.com/denizk0461/character-design/)!
|
||||
|
||||
Using Pinterest for this purpose allows me to visually see lots of different options I could go for with my character, which is a huge improvement over just... trying to come up with something exclusively on my own.
|
||||
|
||||
Seeing all of this art gives me ideas for how I could design a robot character, for instance. It allows me to decide on a shading style – there's a pin of a [toon-shaded character](https://de.pinterest.com/pin/999165867324583246/) in there that I quite like. It also makes me contemplate the direction of the character's identity. With designing a robot character, I find that falling into the stereotype of 'cool and strong male robot' is too easy. I've done it myself. Why does it have to be a *male*-looking robot, anyway? The idea from the start was to create relatively non-binary robots anyway; after all, they're robots living 600 years in the future, why should they confine to humanity's societal standards?
|
||||
|
||||
## Retrospective
|
||||
|
||||
It's been almost 14 months of working on Project N5 – sometimes actively, with occasional breaks in-between. Can you believe that this game started from *this?* (video from [2023-09-16](/projects/projectn5/devlog/202309))
|
||||
|
||||
<Video src="../../202309/2023-09-16_00.mp4" />
|
||||
|
||||
Logically speaking, of course, that makes complete sense. I had to start from somewhere. But it's the fact that I managed to get so far already, working on my own, that I find crazy. I've already managed to implement many basics of this game, slowly but surely realising my vision. I think this really has potential. I should keep up the work.
|
||||
87
src/routes/projects/projectn5/devlog/20241127.md
Normal file
@@ -0,0 +1,87 @@
|
||||
---
|
||||
title: The Making of a Protagonist, Part I
|
||||
date: '2024-11-27'
|
||||
tag: '20241127'
|
||||
bannerAlt: Multiple iterations of untextured hand 3D models
|
||||
---
|
||||
I've been busy at work on this game! I've not done any programming work lately – which I feel a bit guilty about – *however!* I've been improving in the 3D modelling department. I started modelling a humanoid character, based on references and my personal ideas, to become my new protagonist for Project N5. Here's what I've been able to do so far, and how I managed to get to this point.
|
||||
|
||||
## Laura
|
||||
|
||||
My new protagonist is called Laura. This is a change from my original idea, where I would have a robot protagonist, but more on that further down.
|
||||
|
||||
Laura is a 20-something year old human girl fitted with a mechanical right arm. This is supposed to affect gameplay as well, since Laura's left-handed, which reflects both in the way she holds weapons as well as in the game's aiming perspective, which will look over her left shoulder as opposed to her right. I think this is fairly uncommon, actually, so it might take a little bit of time to get used to, but I like the idea of straying from the norm ever so slightly.
|
||||
|
||||
With her mechanical right arm, Laura may also be able to perform actions such as using zip lines. I haven't entirely decided on that yet, though.
|
||||
|
||||
This is what I've created so far:
|
||||
|
||||

|
||||
|
||||
I'll admit, I'm actually quite proud of myself for being able to create this. This is a fairly representative humanoid body, with relatively decent topology and without using a massive amount of polygons – this model currently sits at 2,452 tris.
|
||||
|
||||
The features aren't entirely fleshed out yet, though there are also a few things I want to keep in mind when creating this model:
|
||||
|
||||
- There won't be much character customisation. There'll be some outfits (more on that below) but those are, for the most part, bound to the story progression.
|
||||
- I'll do some touchups on the joints to get them to bend better.
|
||||
- There's no skeleton yet.
|
||||
- The right arm is only in place because I'm using a mirror modifier on the whole body. I'll chop off the right arm once I get to modelling the mechanical arm replacement.
|
||||
|
||||
The future vision is to give her two outfits: one in which she starts, which looks more like a casual outfit, wearing a hoodie with the right sleeve torn off. It's supposed to look like an outfit that's not really meant for combat, because it's the one she wore before her hibernation. The second outfit is supposed to be a more combat-suited outfit, perhaps a type of armour even.
|
||||
|
||||
For the next progress update, I'll be able to show a largely finished model – I promise!
|
||||
|
||||
### Story Changes
|
||||
|
||||
There's reason for these ideas I have for Laura, and it's all in the story I am developing.
|
||||
|
||||
### The New Storyline
|
||||
|
||||
Laura is a young girl waking up from a hundred-years-long hibernation. Her home – Sol III (Earth) – has been devastated. Before her hibernation, she lost her right arm, which has been replaced with a mechanical arm by a robot at some point during her hibernation. She doesn't get to meet this robot immediately, as they're gone when she wakes up (or perhaps is taken away?).
|
||||
|
||||
*Project N5* is the story of Laura rediscovering what caused the devastation of her home as well as what happened to the robot that saved her life.
|
||||
|
||||
### How to Adapt the Old Storyline
|
||||
|
||||
Gone is the robot protagonist. Gone is the titular *Project N5*, for which the protagonist had been built. Gone is the company that the protagonist was built by, and against whom the protagonist swore revenge. I struggled massively with developing this storyline, even just coming up with a general plot that sounded interesting. I think this is good riddance. This wasn't going anywhere.
|
||||
|
||||
This isn't a full rework, however – many aspects remain. The weapons remain, the ideas for planets and space stations remain, etc. The idea of revolving the story around Sol III and basing the story on environmental ruin still very much remains!
|
||||
|
||||
### Inspiration
|
||||
|
||||
Believe it or not, most of the inspiration I was able to gather to come up with this new storyline stems from one song: [acloudyskye – Spill](https://acloudyskye.bandcamp.com/track/spill).
|
||||
|
||||
The striking, saturated colours, the feeling of adventure, the sense of loneliness in a large world – all of these aspects combine beautifully in this song and its cover art. It gave me ideas which I want to realise in my game.
|
||||
|
||||
acloudyskye's music has inspired me quite a bit lately, especially their albums [What Do You Want!](https://acloudyskye.bandcamp.com/album/what-do-you-want) and [There Must Be Something Here](https://acloudyskye.bandcamp.com/album/there-must-be-something-here). Absolutely recommend listening to them.
|
||||
|
||||
## Likely Future Changes
|
||||
|
||||
### Game Title
|
||||
|
||||
I suppose the title *Project N5* inherently sounds like a work-in-progress title. A codename of sorts.
|
||||
|
||||
Since the whole idea of the in-game *Project N5* won't be developed any further, I figure this is the start of a goodbye. A new title will have to come. I haven't decided on one yet, and I think it'll be quite some time until I'll actually settle on a new title, perhaps not until much of the story has already been developed.
|
||||
|
||||
For now, *Project N5* remains the working title. Don't get too attached to it!
|
||||
|
||||
### Aesthetics
|
||||
|
||||
As I'm moving from working on the game's logic to the aesthetic (which does NOT mean the logic is anywhere near finished!), I'm considering starting to implement shaders. I've decided that I'll likely use a toon-style shader, perhaps a variation of [this one](https://godotshaders.com/shader/flexible-toon-shader/). Looking forward to playing around with the visuals!
|
||||
|
||||
I also have a vision for the 3D models, which I may have already mentioned: I'm planning to use (almost?) exclusively materials for the models' visuals. I'm trying to avoid textures, for multiple reasons:
|
||||
|
||||
- Textures cannot be smoothly scaled up in resolution, whereas models that exclusively use materials and polygons for detail don't depend on an image's pixel resolution.
|
||||
- Painting textures is hard!
|
||||
|
||||
Some low-poly 3D modelling artists use textures for shadows, which I think is cool, although I'm planning to use shaders and generated shadows in my game instead, so painted shadows are likely unnecessary.
|
||||
|
||||
## Next Steps
|
||||
|
||||
Next, I'll continue modelling Laura. I most recently worked on her head, where I'm still deciding whether to give her a half-face mask or a full face shield. Doing a half-face mask will enable Laura to emote with her eyes, but that means I'll have to implement eyes, which could be difficult, so using a full face shield that just completely blocks her face would be easier. I could make it work in the story too. I'll model her hair, add some ears (probably), and then I'll get to modelling her mechanical right arm. Afterwards, I'll likely rig it.
|
||||
|
||||
Once I've done that, I'll save this model as a baseline 3D model and then edit a copy of it to add clothes – I want the clothes to be part of the model rather than go on top of the existing mesh, I think.
|
||||
|
||||
After that, I could start animating Laura, though I don't know whether I'll get to that in the next progress update. It could be cool! I'll have to find a way to add and update animations in Godot without re-importing the 3D model. I think a way exists using [NLA tracks](https://docs.godotengine.org/en/stable/tutorials/assets_pipeline/escn_exporter/animation.html), but I'll have to learn how to do this, and whether this works the way I imagine.
|
||||
|
||||
I've already made sketches for how I want to style Laura; this could be fun!
|
||||
127
src/routes/projects/projectn5/devlog/20241222.md
Normal file
@@ -0,0 +1,127 @@
|
||||
---
|
||||
title: The Making of a Protagonist, Part II
|
||||
date: '2024-12-22'
|
||||
tag: '20241222'
|
||||
bannerAlt: Laura a-posing and wearing green and brown clothes
|
||||
---
|
||||
I have lots progress to share!!
|
||||
|
||||
First things first: Laura is, unlike I promised before, not yet finished. However, I have made *so much* progress in the past few weeks that I just wanted to get out already. Here's the current iteration of Laura:
|
||||
|
||||
<img src="laura.webp" alt="A 3D model of a human girl with brown hair, a full face mask, green sweatshirt, brown trousers, and black boots">
|
||||
|
||||
She's become an actual proper character!! omg omg
|
||||
|
||||
## How We Got Here
|
||||
|
||||
So, what happened? How did I create this character?
|
||||
|
||||
I think what's most crucial is that I gathered influence, references, knowledge, and ideas from all kinds of places. Here's some:
|
||||
|
||||
[Creating Stylized Low Poly Characters in Blender](https://youtu.be/-XYryP_GU8o) by lacruzo. Shows the entire process of creating a low-poly character from scratch, and was the entire reason why my character got off the ground to begin with.
|
||||
|
||||
[Creating a low-poly character is actually kinda easy](https://youtu.be/N7GVbdf4H_g) by SELS – topology of lower-poly characters. Also, how to create clothes and hair, UV unwrapping and texture painting, as well as rigging with a meta-rig.
|
||||
|
||||
[Optimal Edge Loop Reduction Flows](https://topologyguides.com/loop-reduction) on topologyguides.com helps understand how to efficiently transition between spots that require more edge loops for detail (such as hands) and meshes that are less detailed (such as arms).
|
||||
|
||||
Aside from that, looking at reference images of people, clothes, hairstyles etc. on the internet just helped a lot. I've dragged plenty of images of random people into Blender to use as shape references. It's much easier than trying to imagine how a human is supposed to look, because, to be honest – even though we all look at humans all the time, making one from scratch without reference (and without much practice) is nigh impossible.
|
||||
|
||||
Side note: Laura is *not* a low-poly character. Her mesh currently consists of about 8,600 tris. However, in trying to understand how topology works to create a humanoid shape, learning from low-poly character creation tutorials helps immensely imo. Low-poly characters rely on as few vertices as possible to display as much detail as needed. Going up in poly count is fairly straightforward – perhaps as simple as applying a subdivision modifier, if your model allows for it. Though for a video game character, I wouldn't necessarily recommend it unless you know what you're doing, because polygon count can quickly skyrocket that way.
|
||||
|
||||
## Changes During the Creation Process
|
||||
|
||||
### Clothes
|
||||
|
||||
Laura was originally supposed to wear an orange sweatshirt as well as shorts. The orange sweatshirt was thrown out because the character reminded me of Velma from Scooby-Doo, and I changed it to green because I like green. Also, the shorts looked dorky. Here's a picture from 2024-12-01 – Laura oddly looks younger in this picture, I feel. The shorts and hair make a big difference.
|
||||
|
||||
<img src="laura-young.webp" alt="A 3D model of a t-posing human girl with different hair, brown shorts, and no feet">
|
||||
|
||||
### Hair
|
||||
|
||||
Modelling hair has proven... challenging. What style to go with? What modelling technique to use?
|
||||
|
||||
The first try (seen above) was using the technique from the SELS video – selecting faces from the character's head, duplicating them, separating them into their own mesh, changing the scale, adding a solidify modifier, and then adding faces. This... worked, but I didn't like the results. And I tried quite a few styles.
|
||||
|
||||
<div class="horizontally-centre-aligned">
|
||||
<img src="laura-hair-flat-1.webp" alt="White hair with middle split">
|
||||
<img src="laura-hair-flat-2.webp" alt="White hair with spiky bangs">
|
||||
<img src="laura-hair-flat-3.webp" alt="White hair with spiky ends">
|
||||
</div>
|
||||
|
||||
<div class="horizontally-centre-aligned">
|
||||
<img src="laura-hair-flat-4.webp" alt="Brown hair with middle split, flowing behind the character's ears">
|
||||
<img src="laura-hair-flat-5.webp" alt="Brown hair with middle split and divided at the ears">
|
||||
<img src="laura-hair-flat-6.webp" alt="Brown hair with big bangs">
|
||||
</div>
|
||||
|
||||
It always looked too flat, too shapeless, too boring, wrong cuts. It just didn't work.
|
||||
|
||||
Next up: a technique shown in these two videos: [Blender: How to Make HAIR, Full Workflow](https://youtu.be/LU0BFThJIco) by 2AM, and [Easiest Way To Create Hair in Blender – 5 Minute Tutorial](https://youtu.be/BqWYgrXw7Jk) by YanSculpts.
|
||||
|
||||
Essentially, you create a curve and a circle, use the circle's shape as a profile for the curve, then change the circle's shape as well as the position and scale of the curve's vertices to create individual hair strands. Shown well in the two videos linked above, this can look pretty amazing! Only one issue: I'm creating a **game** character, and this technique is quite expensive, as it creates a lot of polygons for all the individual hair strands and the detail that goes into them. To mitigate this, I lowered the resolution of the profiling and used only a few curves to create an entire head's worth of hair. This looked a little like this:
|
||||
|
||||
<div class="horizontally-centre-aligned">
|
||||
<img src="laura-hair-curves.webp" alt="Toon shaded view at the character with brown hair">
|
||||
<img src="laura-hair-curves-2.webp" alt="Side view at the character without special shading">
|
||||
</div>
|
||||
|
||||
This hair mesh originally (left picture) consisted of three parts: two curves at the front (left/right) and one in the back. This... was okay, but scaling the curves made the hair look weird. Thinner strands, especially when there's only a few of them, made them look more like dreads, and scaling up the vertices to large scales, as seen in the front near the top of the head, makes the hair look as if it's ballooning. Getting the shape right was a mess too: using only a single curve in the back meant that I had exactly one curve to cover quite literally half the head, and making sure that this singular strand of hair covered the head stretching from one ear to another was a pain. I tried using five curves (right picture), so that I have three in the back, but it didn't improve anything.
|
||||
|
||||
I then went *back* to the first method of scaling up faces from the head, with more knowledge and several tries behind me, and you know what? It actually kind of worked out.
|
||||
|
||||
<div class="horizontally-centre-aligned">
|
||||
<img src="laura-hair-flat-new-2.webp" alt="Front view at the character with a green headband and bangs">
|
||||
<img src="laura-hair-flat-new-3.webp" alt="Front view at the character with a green headband and middle-split hair">
|
||||
</div>
|
||||
|
||||
The right picture is the current iteration of Laura's hair. I added a head band because I thought it looked nice, though that detail is not final.
|
||||
|
||||
Even though I had created a hair style that looks fairly decent in a cel-shaded environment, I wasn't quite happy. So, today in fact, I checked out a tutorial on creating an [anisotropic hair shader](https://youtu.be/kxWWBmIUxbc) made in Blender by Lighting Boy Studio. It's really impressive! And quite complicated. Also, it's a Blender tutorial. While this is quite cool, I need shaders for Godot, since I'm creating a game, not a movie. To my surprise, someone already created a similar toon hair shader for Godot – [SimpleToonHair](https://godotshaders.com/shader/simpletoonhair/) by D3ZAX. It's *exactly* what I was looking for, and I really want to use this for Laura! Only one problem: this doesn't really work with her current hair mesh.
|
||||
|
||||
I decided that I want to create a hair mesh more similar to that shown on the shader's images. This mesh consists of several strands of hair, each two quads wide to create individual strands. Making something like that look cohesive is actually fairly easy too, since the cel-shaded style actually hides a lot of overlaps between meshes of the same colour.
|
||||
|
||||
### Hair Animation
|
||||
|
||||
To create flowing long hair, I want to use the [JiggleBones](https://godotengine.org/asset-library/asset/1595) add-on. Using this add-on, I can add bones to the hair mesh in Blender, which will then be moved by the add-on whenever the character moves. It's essentially an inertia effect. I haven't tried this out yet, however.
|
||||
|
||||
### Her Mask / Face Shield
|
||||
|
||||
Canonically, Laura is supposed to wear some type of respiratory device, because the hazardous conditions on her home planet do not allow her to sustain life without it anymore. I'm not quite sure yet whether this respiratory device will come in the shape of a full face shield or a partial face mask, covering her nose and mouth.
|
||||
|
||||
Part of why I want to integrate this is because... modelling is hard, and I imagine animating a face will be even more difficult. Realistically, I'm a single dev trying to make a game that's fairly large in scope, so I should try to reduce complexity if possible. However, I have not yet decided whether I want to give Laura eyes. Eyes would make her feel more alive, I think, but again, it adds additional complexity. Also, I'd have to create eyes without using any textures, since I set out to create a game with as few image textures as possible (hopefully 0) to, again, avoid some complexity that comes with creating textures. I think it would be doable.
|
||||
|
||||
### Her Right Arm
|
||||
|
||||
Laura's supposed to have a mechanical right arm – on the current model, however, I have applied a mirror modifier, which means her left and right arms are identical. The grey mesh in front of her right arm, however, is the work-in-progress mechanical arm.
|
||||
|
||||
<img src="arm.webp" alt="Grey mechanical arm">
|
||||
|
||||
I'm not entirely happy with this yet. The general shape of the arm is relatively decent, the hinge looks ok, but I feel it's missing something. I think I want to add LEDs to the arm, which in-game can serve to display Laura's health status (alongside a more clearly legible health UI element).
|
||||
|
||||
### Modelling Pose
|
||||
|
||||
Influenced while I was researching a tangential topic on a Blender forum, I read up on A-pose versus T-pose when modelling 3D characters. From what I could gather reading the forum, the T-pose is mostly used because it's convenient for modelling orthogonally. However, the A-pose is preferable, as it better preserves the shoulder mesh. When modelling in a T-pose, the character's shoulders are stretched fairly unnaturally, whereas the A-pose puts the arms further towards a more natural, relaxed pose, which means that the shoulder mesh is not stretched quite as significantly when the character has their arms hanging down.
|
||||
|
||||
To illustrate my point (get it?), here are some pictures. Left is in T-pose, right is in A-pose:
|
||||
|
||||
<div class="horizontally-centre-aligned">
|
||||
<img src="deform-1.webp" alt="Diagram showing a t-posing character, with the text 'large angle, thus more deformation'">
|
||||
<img src="deform-2.webp" alt="Diagram showing an a-posing character, with the text 'smaller angle, thus less deformation'">
|
||||
</div>
|
||||
|
||||
However, after watching [this video on bind poses](https://youtu.be/FXfc4Gyw6I0) by Doodley, it seems that... it doesn't really matter. Whether you use the T-pose, the A-pose, the lovingly-called hug-pose, or anything else really depends on what you plan to do with your character. Since Laura will mostly wield guns and keep her arms fairly low for most of the game, I decided to change Laura's modelling pose to an A-pose, with her arms pointed 30 degrees downward.
|
||||
|
||||
## What's Next
|
||||
|
||||
- Create a new hair mesh that looks and flows nicer and works better with the anisotropic toon hair shader.
|
||||
- Adjust the hands (they look decent but I want them to look just a slight bit better).
|
||||
- Finish the mechanical arm and attach it to Laura.
|
||||
- Learn how to assign multiple meshes to a single skeleton – this will serve to swap between this more casual outfit and the eventual armour-type outfit.
|
||||
|
||||
I suppose that's mostly what I've been up to. There's not been much going on in the Godot project, though I'm preparing for bigger changes. I want to refactor the weapon scripts, for instance – I tried to make them more modular at one point, having different scripts for Throwers, Semiautos, Automatics, but it made things pretty convoluted. I'll see if I can fix this up to make adding weapons into the game more streamlined.
|
||||
|
||||
Also, I'm changing the way weapon stats are put into the game. Currently, data for the individual weapons such as damage, fire rate, vendor price, max ammo, etc. is stored in **three different places** – two different nodes attached to the weapon itself, as well as a singleton instance holding some additional data. My current idea was to transfer all of this data into a single CSV file, where I can neatly and easily add and change values as I see fit. This CSV data can then easily be imported into the game and used wherever needed I think that'll be a huge quality of life improvement during development.
|
||||
|
||||
For the time being, here's a picture of the soon-to-be-retired current protagonist character. Smoothly shaded for your viewing pleasure.
|
||||
|
||||
<img src="retiree.webp" alt="The previous purple protagonist with a shiny body in a seductive pose">
|
||||
@@ -1,109 +0,0 @@
|
||||
<script>
|
||||
import BannerTitle from "$lib/banner-title.svelte";
|
||||
import Content from "$lib/content.svelte";
|
||||
import TableOfContents from "$lib/table-of-contents.svelte";
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>The Making of a Protagonist, Part III | denizk0461</title>
|
||||
</svelte:head>
|
||||
|
||||
<Content>
|
||||
<BannerTitle
|
||||
title="Project N5 Progress Update: 2025-02-03"
|
||||
subtitle="The Making of a Protagonist, Part III"
|
||||
banner="../../previews/2025/0203.webp"
|
||||
bannerAlt="Three t-posing untextured Lauras"
|
||||
/>
|
||||
|
||||
<TableOfContents disableStickyScrolling={true} />
|
||||
|
||||
<p>While I've been busy working on another game with friends lately, I've managed to almost completely finish Laura. Here's what I've achieved!</p>
|
||||
|
||||
<h2 id="eyes-hair">Visual Personality Adjustment</h2>
|
||||
|
||||
<p>As promised before, I've worked on Laura's head a bit more. Her full face shield has been replaced with a face mask / respirator covering only the bottom half of her face. Also, I finally got the hair into a state I'm actually happy with. Here's a comparison:</p>
|
||||
|
||||
<div class="horizontally-centre-aligned">
|
||||
<img src="../../2024/1222/laura-hair-flat-new-3.webp" alt="The old protagonist's head with green clothing and full-face mask">
|
||||
<img src="laura-head-new.webp" alt="The new protagonist Laura's head with red clothing, a half-face mask. The character now has a brown left eye, a mechanical right eye, and eyebrows, as well as bangs">
|
||||
</div>
|
||||
|
||||
<p>The eyes took some work to get right, but I'm pretty happy with the current result. They're not proper eyeballs, but instead they're embedded into the head, which visually isn't significant because the flat shading would hide these details anyway. She has a brown left eye with a small sparkle, as well as a right eye replacement. This implies that Laura sustained further damage to the right side of her body, which necessitated replacement of her eye in addition to her right arm.</p>
|
||||
|
||||
<p>It's actually the result of UV unwrapping her model. Previously, every colour was its own material, which I wanted to change by switching to a texture atlas. Initially, of course, the UVs were a bit messed up, which resulted in this look:</p>
|
||||
|
||||
<img src="laura-uv.webp" alt="A close-up of Laura with her UV textures wrongly mapped; the hair is brown and grey, the right eye white, and the left eye red">
|
||||
|
||||
<p>I still think this looks kind of cool.</p>
|
||||
|
||||
<h3 id="hair">New Hair 💇♀️</h3>
|
||||
|
||||
<p>Her hair is now not a cohesive mesh anymore, but rather made up of something between 15 and 20 individual strands using custom normals to get a flat look. It also has a faint gradient, changing from a brighter colour at the top to a darker shade at the bottom.</p>
|
||||
|
||||
<p>I added earrings too:</p>
|
||||
|
||||
<img src="earrings.webp" alt="Side view of Laura. Her brown hair is straight and her ear has a round black earring">
|
||||
|
||||
<p>Just some small metallic rings that I thought looked cool. For positioning these correctly, I hid Laura's back hair at one point, which gave me the idea to model a ponytail / tied-up alternative hair look for Laura. I think it'd look really cool. I haven't created this yet, but I've laid some groundwork to make it work:</p>
|
||||
|
||||
<p>Laura's hair is now separate from her main mesh. The main mesh is rigged using a metarig generated through Rigify, whereas the hair has a manually-created armature. Also, the hair is split into the front part and the back part, separated by the hair band (which is part of the main mesh). This allows me to replace the flowing back hair with a ponytail easily in-engine without swapping out the entire character.</p>
|
||||
|
||||
<p>This is pretty cool, because I can now create scenes for each hairstyle, set them up with <a href="/projects/projectn5/devlog/2024/1222/#hair-animation">jiggle bones</a> to create flowing hair, and essentially add a toggle to switch between them in-game!</p>
|
||||
|
||||
<h2 id="rigify">Rigging and Using Blender's Rigify</h2>
|
||||
|
||||
<p>Rigify is really cool for rigging characters easily. However, you need to know some things that I didn't before you start using it:</p>
|
||||
|
||||
<ul>
|
||||
<li>When adding a Rigify armature to the scene, <i>do not parent the rig to the model</i>. You need to place the rig as intended, then click on "Generate rig", and then parent the <i>new</i> armature with the mesh and weight paint that way. I made the mistake of weight painting before generating the rig, which isn't transferrable because the metarig adds extra bones which require individual weight painting (e.g. the thighs being made up of two bones instead of just one).</li>
|
||||
<li>Know how to switch between forward kinematics (FK) and inverse kinematics (IK). At the top right of the editor, there'll be a window with a slider to switch between FK and IK, as well as buttons to transfer an FK pose to IK and vice-versa. Don't be confused if posing a specific control doesn't work – you might need to switch to FK or IK, respectively.</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="face">Facial Animations and Shape Keys</h2>
|
||||
|
||||
<h2 id="animation">Animation and Framerate</h2>
|
||||
|
||||
<p>I've been playing around with the idea of using a lower framerate for the animations. I got the idea from <a href="https://www.youtube.com/watch?v=_KRb_qV9P4g">Noodle's video on animation</a>. Not sure whether I'll go through with this, but if I do, I think I'll go with 15fps or 20fps animation, since that's easily implementable a 60fps environment.</p>
|
||||
|
||||
<p>I already adjusted the jiggle bone script, which was easy to do since it runs in Godot's <code>_physics_process(delta)</code> function. This runs 60 times per second, so having code run only 15 times per second, for example, is as easy as wrapping the code in question in <code>if Engine.get_physics_frames() % 4 == 0:</code>, which makes a code block run only once every 4 frames – 60fps/4 == 15fps.</p>
|
||||
|
||||
<h2 id="in-engine">Laura In-Engine</h2>
|
||||
|
||||
<p>Since the shader I'm using in Blender is quite different from the one I am planning to use in Godot, here's a shot of Laura with the Godot shader:</p>
|
||||
|
||||
<img src="laura-shader-inengine.webp" alt="Full model of Laura imported into Godot with a toon shader applied">
|
||||
|
||||
<p>I've been thinking of adding an option (perhaps as a cheat code) to change her outfit's colour – hair band, sweatshirt, and the rings on her right prosthetic fingers. I first didn't know how to implement this, but now that I've learnt a bit on how to use shaders, I think this could be achieved with a custom UV mask and a parameter that determines at which position the UV is sampled from – the UV would then contain several colour options.</p>
|
||||
|
||||
<h2 id="pics">Some Funny Pictures</h2>
|
||||
|
||||
<div class="horizontally-centre-aligned">
|
||||
<img src="ok.webp" alt="An OK hand">
|
||||
<img src="dance.webp" alt="Laura flailing her arms">
|
||||
<img src="naruto.webp" alt="Laura naturo-running">
|
||||
</div>
|
||||
<div class="horizontally-centre-aligned">
|
||||
<img src="shock.webp" alt="Laura's face looking shocked">
|
||||
<img src="reprehension.webp" alt="Laura's face looking astonished">
|
||||
<img src="disgust.webp" alt="Laura's face looking disgusted">
|
||||
</div>
|
||||
|
||||
<h2 id="future">The Future of this Devlog</h2>
|
||||
|
||||
<p>I feel that this blog-like format makes me think that the content here should be educational; that someone may read this and learn from it. It's likely not the case, but either way, perhaps it would make sense to limit the progress updates to a mere "here's what I made!" and only a little bit of background, if it's interesting.</p>
|
||||
|
||||
<p>Most times, I find myself struggling to explain my progress anyway, mostly since I'm learning as I go and because I publish progress updates pretty rarely. For example, I added eyes to Laura's model on 2025-01-01, there's no way I'll remember everything I did and thought of over a month ago.</p>
|
||||
|
||||
<p>Switching to a more short-form content format might help in publishing updates more regularly, and being more in the style of: "hey look at this cool thing I made!" It would also focus on visual changes, possibly helping me to keep a better schedule, merely because I can see my progress more steadily and be motivated more frequently.</p>
|
||||
|
||||
<p>I've been thinking of creating an Instagram account for that – though I despise Meta (and Instagram by extension). It feels like a decent platform for my idea, though: presenting progress mostly through visuals. I also know more people who are on Instagram who may follow my progress... maybe. Bluesky <i>may</i> be an option, though it's more text-focussed and more short-form than Instagram.</p>
|
||||
|
||||
<p>Either way, I'd lose out on the progress I've already shared here.</p>
|
||||
|
||||
<p>Or maybe I just don't share my stuff at all and don't stress out about it lol, no one's seeing this anyway and I'm not a social media person anyway.</p>
|
||||
|
||||
<p>idk</p>
|
||||
|
||||
<p>Maybe it's time to change the format of the devlog on this website?</p>
|
||||
</Content>
|
||||
@@ -1,183 +0,0 @@
|
||||
<script>
|
||||
import BannerTitle from "$lib/banner-title.svelte";
|
||||
import Content from "$lib/content.svelte";
|
||||
import TableOfContents from "$lib/table-of-contents.svelte";
|
||||
import Video from "$lib/video.svelte";
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Refactoring | denizk0461</title>
|
||||
</svelte:head>
|
||||
|
||||
<Content>
|
||||
<BannerTitle
|
||||
title="Project N5 Progress Update: 2025-03-16"
|
||||
subtitle="Refactoring"
|
||||
banner="../../previews/2025/0316.webp"
|
||||
bannerAlt="Laura t-posing in front of a smiling water tower"
|
||||
/>
|
||||
|
||||
<TableOfContents disableStickyScrolling={true} />
|
||||
|
||||
<p>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!</p>
|
||||
|
||||
<h2 id="laura">Introducing: Laura</h2>
|
||||
|
||||
<img src="laura.webp" alt="Full-body shot of Laura imported into Godot">
|
||||
|
||||
<p>Laura is finally, <i>FINALLY</i> 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.</p>
|
||||
|
||||
<p>As you can see in the screenshot above, Laura has a toon shader applied – it's <a href="https://godotengine.org/asset-library/asset/1900">this one again</a>.</p>
|
||||
|
||||
<p>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.</p>
|
||||
|
||||
<img src="laura-spinning.gif" style="max-width: 400px; object-fit: cover;" alt="Laura moving in a circle on top of a box">
|
||||
|
||||
<p>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.</p>
|
||||
|
||||
<Video src="hair-swoosh.mp4" />
|
||||
|
||||
<p>I was also able to implement <code>LookAtModifier3D</code> 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.</p>
|
||||
|
||||
<Video src="look-at.mp4" />
|
||||
|
||||
<h3 id="not-happy">...and I'm not happy about it?</h3>
|
||||
|
||||
<p>I want to change Laura.</p>
|
||||
|
||||
<p>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 <i>is</i> 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 <i>nothing</i> 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.</p>
|
||||
|
||||
<p>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 <i>do</i> have an idea for how to fix that – by modelling it straight and then placing a capsule as collision shape for the <code>SpringBoneSimulator3D</code> – but this didn't even exist when I modelled Laura.</p>
|
||||
|
||||
<p>Also, I think I want to go with <a href="/projects/projectn5/devlog/2025/0203/#hair">tied-up hair</a> instead. Not only does it animate much easier without clipping, but it'll give Laura a more unique silhouette, I believe!</p>
|
||||
|
||||
<p>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.</p>
|
||||
|
||||
<p>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 <b><i>ideas!</i></b> I was struggling <i>so hard</i> to come up with ideas for Laura before, <i>especially</i> concerning her clothes!</p>
|
||||
|
||||
<p>I am confident that Laura 2.0 will be awesome.</p>
|
||||
|
||||
<h2 id="weapons">New Firepower</h2>
|
||||
|
||||
<p>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.</p>
|
||||
|
||||
<h3 id="igniter">Igniter / Flamethrower</h3>
|
||||
|
||||
<p>The Igniter is a flamethrower with a rapid firing rate. Here is it in action:</p>
|
||||
|
||||
<Video src="106.mp4" />
|
||||
|
||||
<p>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 <code>StandardMaterial3D</code> and kind of liked the effect, so I kept it. The fire effect is BY NO MEANS finished though.</p>
|
||||
|
||||
<p>I was initially writing custom logic for the Igniter, which, <a href="#weapon-code">as you will see</a>, 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.</p>
|
||||
|
||||
<p>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 <a href="#story">the game's story</a>, 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.</p>
|
||||
|
||||
<p>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.</p>
|
||||
|
||||
<p>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.</p>
|
||||
|
||||
<h3 id="rifle">Unnamed Rifle</h3>
|
||||
|
||||
<p>The second weapon I've added is a rifle-type weapon! Whether it'll just be a rifle or a <i>sniper</i> rifle, I haven't decided yet.</p>
|
||||
|
||||
<Video src="107.mp4" />
|
||||
|
||||
<p>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.</p>
|
||||
|
||||
<p>The projectile ray takes a while to spawn after pressing the fire button. This happens because the projectile uses a <code>RayCast3D</code> 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 <code>RayCast3D</code>, 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 <code>RayCast3D</code> idea.</p>
|
||||
|
||||
<p>The projectile also... doesn't exactly hit where the crosshair is pointing. I'm pretty sure this has to do with the <code>RayCast3D</code> 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.</p>
|
||||
|
||||
<p>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.</p>
|
||||
|
||||
<h3 id="preview">Item Preview Window</h3>
|
||||
|
||||
<p>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:</p>
|
||||
|
||||
<Video src="item-preview.mp4" />
|
||||
|
||||
<p>I also fixed a long-running bug where the <code>DirectionalLight3D</code> 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.</p>
|
||||
|
||||
<h3 id="weapon-icons">Please Appreciate These Wonderful Temporary Weapon Icons</h3>
|
||||
|
||||
<div class="horizontally-centre-aligned">
|
||||
<img src="104-icon.webp" alt="An icon for a rocket launcher that looks like a sperm">
|
||||
<img src="106-icon.webp" alt="A primitive flame as an icon for a flame thrower">
|
||||
<img src="107-icon.webp" alt="A hand-drawn crosshair serving as an icon for a rifle">
|
||||
<img src="108-icon.webp" alt="The words 'VENOM' as an icon for the weapon of that name">
|
||||
</div>
|
||||
|
||||
<h2 id="code">Grand Code Overhaul</h2>
|
||||
|
||||
<p>In (re)starting work on my game, I've been confronted with a lot of... <i>legacy code?</i> Lots of code that I was unhappy with, at the very least.</p>
|
||||
|
||||
<p>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.</p>
|
||||
|
||||
<p>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 <i>this morning</i> 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.</p>
|
||||
|
||||
<h3 id="godot-4-4">Godot 4.4 Changes</h3>
|
||||
|
||||
<p>If you haven't heard, Godot 4.4 is out! And that meant quite a few changes for my game:</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="https://github.com/godotengine/godot/pull/99895">Jolt is now integrated into the engine!</a> Since my use of the physics engine is relatively basic and does not rely on Jolt features that haven't been implemented in the engine yet, I switched immediately and was able to remove a dependency. The work that went into this is insane, I recommend checking out the pull request.</li>
|
||||
<li>Godot 4.4 added a new node called <a href="https://docs.godotengine.org/en/stable/classes/class_springbonesimulator3d.html"><code>SpringBoneSimulator3D</code></a>, which can be used for jiggle physics in a similar manner to <a href="https://godotengine.org/asset-library/asset/1595">JiggleBones</a>. I replaced my JiggleBones implementation with <code>SpringBoneSimulator3D</code> and was thus able to remove another dependency. I like the <code>SpringBoneSimulator3D</code> setup better, though I'm not as happy with the current result. I'll have to spend more time tweaking it and learning how to use it properly; it involves a bit more setup than JiggleBones, but it's more reliable, especially since it has better support for collision shapes (JiggleBones only supports spheres, but it's very rudimentary support, and they have to be sized way larger than expected to work at all. It's very unreliable. <a href="https://docs.godotengine.org/en/stable/classes/class_springbonecollision3d.html#class-springbonecollision3d"><code>SpringBoneCollision3D</code></a> works <i>so much better</i> and supports capsules and planes as well).</li>
|
||||
<li>Physics interpolation is now available for 3D, which fixed <a href="https://phantom-camera.dev/support/faq#i-m-seeing-jitter-what-can-i-do">an issue that caused nodes tracked with a Phantom Camera to jitter</a>.</li>
|
||||
<li>Godot has typed <code>Dictionary</code> support in <code>@export</code> properties now, which in <i>my world</i> is a <b>huge</b> deal. It means you can do <code>@export var dict: Dictionary[int, String]</code> and dynamically add to the Dictionary in the inspector. This, of course, allows for custom <code>Resource</code>s as well. I use this, for example, in the item statistics, where I have a <code>Dictionary</code> holding item statistics as a custom <code>Resource</code> associated with the item's ID. This <code>Resource</code> has nested <code>Resource</code>s for individual weapon levels. It's <i>so</i> cool! I'm disproportionately happy about this change.</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="node-refs">$</h3>
|
||||
|
||||
<p>Yesterday, I replaced a lot of $ node references with <code>@export</code> properties for performance reasons. I watched <a href="https://www.youtube.com/watch?v=fb68YXIBinc">this video on node retrieval</a>, where I found out that $ references are inefficient. I then thought about this, and... yeah, that makes sense. $ is just a short-hand for <code>get_node()</code>, which means that, in a <code>_process()</code> context, I'm calling <code>get_node()</code> potentially 60 times a second – every time I use it. Considering this <i>massive</i> performance implication, I refactored a lot of code and created loads more <code>@export</code> references. They're easier to manage in case of moving or renaming nodes, anyway.</p>
|
||||
|
||||
<h3 id="weapon-code">Weapon Code</h3>
|
||||
|
||||
<p>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.</p>
|
||||
|
||||
<p>It was a mess. It's all overhauled now.</p>
|
||||
|
||||
<p>There's <code>weapon3.gd</code>, which is the base weapon class for all weapons, inheriting from <code>item.gd</code>. Then, there are <code>semiauto3.gd</code> and <code>automatic3.gd</code>, 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.</p>
|
||||
|
||||
<p>Notice there's no <code>thrower3.gd</code>? 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: <code>start_moving(direction: Vector3, ramp_up_speed: float, damage: float, explosion_resource: PackedScene) -> void</code></p>
|
||||
|
||||
<h2 id="enemies">My Enemies Follow Me Wherever I Go</h2>
|
||||
|
||||
<p>The enemies have pathfinding now implemented! I used Godot's <code>NavigationRegion</code> to create a mesh the enemies can traverse. Since they all inherit from <code>StairsCharacter</code> – a class I once downloaded to deal with stair stepping for <code>CharacterController3D</code>s – 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.</p>
|
||||
|
||||
<Video src="enemy-stairs.mp4" />
|
||||
|
||||
<h2 id="story">Story Changes</h2>
|
||||
|
||||
<p>I have some minor ideas for where I want the story to head in.</p>
|
||||
|
||||
<h3 id="genre">Where the Game is Headed Gameplay-Wise</h3>
|
||||
|
||||
<p>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.</p>
|
||||
|
||||
<p>That's the general idea.</p>
|
||||
|
||||
<h3 id="story-weapons">How (Many) Weapons Will Play Into It</h3>
|
||||
|
||||
<p>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.</p>
|
||||
|
||||
<p>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.</p>
|
||||
|
||||
<h2 id="notebook">A Notebook for My Thoughts</h2>
|
||||
|
||||
<p>I bought a new notebook recently! While I had a notebook before – a <a href="https://www.thalia.de/shop/home/artikeldetails/A1071363499">green A5 notebook with dotted pages by Share</a> – it was filling up with notes from university, internships, and other miscellaneous things I didn't want to clutter my project notebook with.</p>
|
||||
|
||||
<p>I switched to a <a href="https://www.thalia.de/shop/home/artikeldetails/A1071895735">black B5 notebook, also with dotted pages, by Plan A</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.</p>
|
||||
|
||||
<h2 id="bsky">Bluesky</h2>
|
||||
|
||||
<p>I have a <a href="https://bsky.app/profile/denizk0461.bsky.social">Bluesky account</a> now!</p>
|
||||
|
||||
<p>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.</p>
|
||||
|
||||
<p>Maybe this'll be different though, seen as I have a relatively specific goal here. We'll see!</p>
|
||||
|
||||
<h2 id="addendum">Addendum</h2>
|
||||
|
||||
<p>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 <i>absolutely</i> 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!!</p>
|
||||
</Content>
|
||||
@@ -1,113 +0,0 @@
|
||||
<script>
|
||||
import BannerTitleAlt from "$lib/banner-title-alt.svelte";
|
||||
import ContentSidebar from "$lib/content-sidebar.svelte";
|
||||
import TableOfContents from "$lib/table-of-contents.svelte";
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>The Making of a Protagonist IV | denizk0461</title>
|
||||
</svelte:head>
|
||||
|
||||
<BannerTitleAlt
|
||||
title="The Making of a Protagonist, Part IV"
|
||||
subtitle="Project N5 Devlog"
|
||||
date="2025-04-27"
|
||||
banner="../../previews/2025/0427.webp"
|
||||
bannerAlt="Sketches of Laura's new clothes"
|
||||
/>
|
||||
|
||||
<ContentSidebar>
|
||||
|
||||
<TableOfContents slot="side-left" />
|
||||
|
||||
<div slot="main">
|
||||
|
||||
<p></p>
|
||||
|
||||
<h2>Current Progress</h2>
|
||||
|
||||
<p>As promised, I've been working on Laura v2 – which has now become v4. On the right is the current/soon-to-be previous model of Laura, on the left is my current progress on her new model!</p>
|
||||
|
||||
<img src="laura-comparison.webp" alt="Laura's old model on the right, Laura's new model on the left">
|
||||
|
||||
<p>(By the way, the left picture is the most recent version of the model. Other pictures on this page will be older and may have some slightly different details!)</p>
|
||||
|
||||
<h3>New and Improved</h3>
|
||||
|
||||
<p>Notable differences are:</p>
|
||||
<ul class="styled-list">
|
||||
<li>Laura wears a cropped zip-up hoodie with a more saturated colour than before, and a black shirt underneath. Her clothes are generally fairly similar between versions, though her dimensions and especially the topology are quite different and optimised.</li>
|
||||
<li>Her shoulder area was a previous pain point of mine – notice the completely smooth transition from neck to arms in the right model. In the new version, her shoulders have been given much more shape.</li>
|
||||
<li>Her hoodie's colour is more saturated than before. The comparison here is not quite fair, since the left is an image from Blender and the second is from Godot, thus impacting how the colours look since there are different shaders used, but the idea still stands.</li>
|
||||
<li>Her hair is tied-up in a ponytail, which not only looks cooler, but is also way easier to animate, imo.</li>
|
||||
<li>Her eyes have been refined in shape and her lashes/eyeliner have been extended to wrap around her eyes more, which, in my opinion, looks quite a lot sharper than before.</li>
|
||||
<li>Her eyes have been socketed in a different way. Previously, they were flat faces directly behind her irises, but now they're much more recessed, which likely/hopefully won't be visible using flat shading. I also edited the normals to look less like the sclera is recessed. I'm hoping this'll make animating easier, since the irises can now move more freely without clipping into the sclera.</li>
|
||||
</ul>
|
||||
|
||||
<img src="laura-comparison-eyes.webp" alt="Close-up of Laura's eyes compared between versions. The new version has sharper and more defined eyes as well as eyelashes that extend further around the eyes">
|
||||
|
||||
<h3>Things to Work On</h3>
|
||||
|
||||
<p>Parts that have not yet received much attention are:</p>
|
||||
<ul class="styled-list">
|
||||
<li>Her trousers, which have received a general shape, but no details.</li>
|
||||
<li>Her belt, oxygen mask, and left hand, which are mostly copied over and adjusted to not look completely out of place.</li>
|
||||
<li>The shoes, which are placeholders.</li>
|
||||
<li>The right arm, which is notably present in the picture, but nowhere near finalised and to be attached.</li>
|
||||
<li>Her hair, which is present only in a basic shape to serve as a placeholder for what I have planned.</li>
|
||||
<li>I might add her hair band back.</li>
|
||||
</ul>
|
||||
|
||||
<h3>Further Thoughts on Modelling</h3>
|
||||
|
||||
<p>This model is supposed to look more dynamic and lively than the previous one. I want to more granularly animate the hair by adding more bones to individual strands. I'll also add bones for the hood so that it can bounce up and down when running. I'm also considering adding bones to allow the sleeves and trouser legs to move slightly, though I'm not sure if I'd be able to make that look good, so I'm keeping this idea in the 'optional' pile for now.</p>
|
||||
|
||||
<p>I think what helped with modelling this time around was that I let go of the notion that Laura should be a low-poly character. I started out that way when I was modelling v1 but then I changed my mind, which created some problems, I find. This time, I still don't want to go crazy with tris, but it's not as much of an issue to me. At one point I even intended to subdivide her entire model by 1 level to smoothen some rough edges and overall make the model a bit more polished, but I discarded that idea yesterday.</p>
|
||||
|
||||
<h3>The Eternal Hair Struggle</h3>
|
||||
|
||||
<p>I've <a href="/projects/projectn5/devlog/2024/1222/#hair">struggled with hair before</a>, and it's not gotten <i>much</i> better. Check out Laura's current ponytail:</p>
|
||||
|
||||
<img src="ponytail.webp" alt="Back perspective at Laura showing her ponytail">
|
||||
|
||||
<p>Looks like a banana!</p>
|
||||
|
||||
<p>I think my next try will be to polymodel strands of hair out of subdivided planes. It'll increase the poly count quite significantly, but it's a trade-off I'm willing to make for hair that'll look better and flow (animate) much more nicely!</p>
|
||||
|
||||
<h3>wdym v4?</h3>
|
||||
|
||||
<p>The current version of Laura is based on the following sketches:</p>
|
||||
|
||||
<img src="body-sketches.webp" alt="Sketches showing ideas for Laura's clothes">
|
||||
|
||||
<img class="inline-img-left" src="laura-v2.webp" alt="Laura v2 wearing a top with puffed-up sleeves">
|
||||
|
||||
<p>I worked with these sketches to create the first remodel of Laura. Originally, I was decently happy with the result, though her sleeves seemed boring – just ballooning and lacking an interesting shape.</p>
|
||||
|
||||
<img class="inline-img-right" src="laura-v3.webp" alt="Laura v3 wearing a black dress and a red longsleeve underneath">
|
||||
|
||||
<p>I had quite a few ideas to improve the current and rather boring Laura model. At the centre of the remodelling was keeping Laura's character but giving it more edge through a more unique silhouette. I wanted to accomplish this by adding textures and detail, layering clothes, and giving more shape to her.</p>
|
||||
|
||||
<p>Eventually, I had a different vision for Laura, though. This time, she would wear a dress with a long-sleeve shirt beneath. I liked this idea because it showed off the shape of her legs more, whereas the previous idea would hide them inside of straight-cut trousers. It would just look more interesting, I felt. I was also inspired by some 3D models I saw on Pinterest.</p>
|
||||
|
||||
<p>While I generally liked the idea, there were two major problems: firstly, I felt I wasn't really able to execute the idea in a way that I found fitting. Secondly – and this plays into the first aspect – the model didn't look as mature as I liked. Partially in its style, but also in its execution.</p>
|
||||
|
||||
<p>This v3 of Laura was then superseded by another Laura, which essentially went back to the previously style, though I used v3 as a base due to some improvements I made on the model. Thus the new version is now called v4.</p>
|
||||
|
||||
<p>Notice how specifically her head and the prosthetic aren't present in the v2 screenshot – those were v3 additions.</p>
|
||||
|
||||
<h2 id="laura">Prosthetic Implications</h2>
|
||||
|
||||
<p>I'm changing Laura's amputation from its previous below-the-elbow cutoff to above-the-elbow. This is mostly a stylistic change, because it means her elbow will be a mechanical replacement as well, and that might look cool, I think.</p>
|
||||
|
||||
<p>I've also been thinking about how her prosthetic could play into the story. A while back, I watched <a href="https://www.youtube.com/watch?v=jZfgQTC9CEA">this video by champutee</a> on arm amputee representation in video games. Admittedly, I feel I'll likely fall into quite the same categories in some ways, making Laura's prosthetic so advanced that it'll more or less serve as a perfect replacement for her organic arm. I had a potentially neat idea that would impact gameplay, though.</p>
|
||||
|
||||
<h3>Difficulty Scaling</h3>
|
||||
|
||||
<p>At one point in the game, Laura could lose function of her prosthetic entirely and be forced to continue without being able to use it. This would reflect in gameplay especially because Laura would then be unable to use any two-handed items, which will include a majority of her weapons as well.</p>
|
||||
|
||||
<p>Laura will likely have something between 4 and 8 weapons available to her. I'm thinking that some will be two-handed from the start (including her main rifle), and some will level-up from one-handed to two-handed or dual-handed (for example, a blaster in each hand). This would mean that more advanced players who progress quicker and manage to level up their weapons early (through XP, collectibles, or purchases, I've not decided) will face a greater challenge, since more of their weapons will be levelled up to their two-handed versions, thus making a larger part of their arsenal unavailable for this part of the game.</p>
|
||||
|
||||
<p>In my teacher training, we call this type of catering to different skill sets <i>differentiation (Differenzierung)</i>!</p>
|
||||
</div>
|
||||
</ContentSidebar>
|
||||
@@ -1,81 +0,0 @@
|
||||
<script>
|
||||
import BannerTitleAlt from "$lib/banner-title-alt.svelte";
|
||||
import ContentSidebar from "$lib/content-sidebar.svelte";
|
||||
import TableOfContents from "$lib/table-of-contents.svelte";
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Reboot | denizk0461</title>
|
||||
</svelte:head>
|
||||
|
||||
<BannerTitleAlt
|
||||
title="Rebooting the Project"
|
||||
subtitle="Project N5 Devlog"
|
||||
date="2025-05-23"
|
||||
banner="../../previews/2025/0523.webp"
|
||||
bannerAlt="Untextured Laura in a new purple level looking at two cubes"
|
||||
/>
|
||||
|
||||
<ContentSidebar>
|
||||
|
||||
<TableOfContents slot="side-left" />
|
||||
|
||||
<div slot="main">
|
||||
|
||||
<p>20 months after starting <i>Project N5</i>, I decided to restart the project. In fact, a friend of mine assumed I'd do it all the way back in December 2023! Initially, I resisted, though I toyed with the idea for quite a while, before finally deciding that this is best for the project last Friday (<b>2025-05-16</b>).</p>
|
||||
|
||||
<h2 id="why">Why?</h2>
|
||||
|
||||
<p>There are two main reasons for starting the project from scratch again.</p>
|
||||
|
||||
<h3 id="improvement">I Improved</h3>
|
||||
|
||||
<p>The first reason is simple: I improved as a programmer.</p>
|
||||
|
||||
<p>Back when I started <i>Project N5</i>, I had never actually used Godot before. This project was my first experience developing in Godot, and to a greater extent, my first attempt at making a full-scale game! I set out a huge goal for myself, though I welcomed the challenge.</p>
|
||||
|
||||
<p>With stagnation in my progress especially in the summer of 2024, I felt I outgrew the project's codebase in some way. Also adding to that is the fact that I was working on <a href="/projects/#projektike">another game</a> with two friends, where I had to write clean solutions and well-structured code to keep the project modular (especially during the stage where we hadn't quite figured out where to take the project) and understandable for the others. This resulted in me learning the ropes of Godot and GDScript much more than I had before.</p>
|
||||
|
||||
<p>I initially tried to tackle the issue by refactoring the codebase of <i>Project N5</i>. Even though I made significant progress, I later felt that the codebase was flawed from the core. I felt this way especially while I was recently trying to implement a new weapon – what a hassle that was!</p>
|
||||
|
||||
<p>Which leads nicely into my second reason...</p>
|
||||
|
||||
<h3 id="changes">The Project Changed</h3>
|
||||
|
||||
<p>For quite a while after I started <i>Project N5</i>, I didn't know where to take the project. In fact, I was stuck at the idea of a robot protagonist for <i>such a long time!</i> Laura only came to mind <a href="/projects/projectn5/devlog/2024/1127/">much later</a>. With her, however, my ideas for the project started to change slightly.</p>
|
||||
|
||||
<p>Don't get me wrong – the essence of the game is probably still pretty much intact. However, I want to make the game a little less combat-focussed, which meant that especially the weapon structure I had built up made no sense anymore. I built the system specifically so I could implement as many different weapons as I liked. Recently, though, I decided that 4 is enough, which made the grand system redundant.</p>
|
||||
|
||||
<p>Add to this the fact that, with a lesser focus on combat, an <a href="/projects/projectn5/devlog/2024/0324/">arena</a> made <i>no sense at all!</i></p>
|
||||
|
||||
<p>Trying to bodge my old codebase – "Altlasten mit sich tragen", as one would say in German – felt wasteful.</p>
|
||||
|
||||
<h2 id="currently">The Current State of the New Project</h2>
|
||||
|
||||
<p>Considering I started one week ago, I'm doing decently well:</p>
|
||||
|
||||
<img src="over_the_shoulder.webp" alt="An over-the-shoulder view of Laura's new model looking at two cubes. Above the cubes, the text 'Pure Evil' is hovering">
|
||||
|
||||
<p>What you can see here is my new Laura model (not yet finished!), with a partially-applied toon shader and an outline shader on top. The UI elements include a health counter (on top), a money counter (bottom right), a placeholder for the popup menu(s), a crosshair in the middle of the screen (the dot), and an aim helper texture also in the middle of the screen (the cross). The two boxes represent enemies, not in function, but in their physics layers and in targetability.</p>
|
||||
|
||||
<p>There are a lot of improvements: targets, for example, are now not defined by a special node setup, but rather by a <code>Target</code> prefab, which can easily be positioned anywhere (enemy or environment) and be used to guide player projectiles.</p>
|
||||
|
||||
<p>The code is also <i>so much more streamlined...</i> I put many elements into their own components to avoid cluttering the <code>player.gd</code> script with an overwhelming amount of responsibilities. That way, what was previously a 300+ line script handling player movement, aim direction, messages, equipping items, interacting with objects etc. is now a lean 50+ line script (although ofc not everything from the previous project is implemented here yet, such as the vendor interactions). Anything that's not directly related to the player has its own component script to keep things separated as much as possible. Currently, there is also no singleton <code>SignalBus</code> routing wildly between any and all nodes. Instead, signals are just defined in their components and connected directly to only the components needing them. This also means that components only take care of tasks that are explicitly meant for them; the guns, for example, no longer calculate the position which the projectile is flying towards. Instead, they can now simply retrieve an aim direction from the <code>AimManager</code>, requiring much less code in each weapon. Everything's so clean and I love it.</p>
|
||||
|
||||
<h3 id="weapons">The New Weapon Arsenal</h3>
|
||||
|
||||
<p>Check out the new weapons:</p>
|
||||
|
||||
<img src="new_weapons.webp" alt="The placeholder weapons, untextured and made from primitive shapes">
|
||||
|
||||
<p>With these, and with the UI in the previous screenshot, you may have noticed a theme: I'm putting less time into temporary assets. While nice to play around with, it's unnecessary to spend an hour designing a UI element when I already know I'll 100% replace it down the line. Thus, most elements are either entirely simplistic (text, primitive MeshInstance3D, etc.), or just very simple textures.</p>
|
||||
|
||||
<h2 id="continuing">Continuing</h2>
|
||||
|
||||
<p>Progress has been quick, which I really liked. It felt as if project development picked up again. Of course, a lot of this has to do with the fact that I'm just programming things I've already once programmed, so I have to put less time into coming up with ideas and can instead solely focus on the implementation. However, I feel that this cleaner codebase will allow me to expand much more easily and develop a less bug-ridden game than if I had simply continued with the old codebase.</p>
|
||||
|
||||
<p>I'm happy I took this step!</p>
|
||||
|
||||
<img src="taking_aim.webp" alt="A blue raycast emitting from Laura to the camera">
|
||||
</div>
|
||||
</ContentSidebar>
|
||||
@@ -1,133 +0,0 @@
|
||||
<script>
|
||||
import BannerTitleAlt from "$lib/banner-title-alt.svelte";
|
||||
import ContentSidebar from "$lib/content-sidebar.svelte";
|
||||
import TableOfContents from "$lib/table-of-contents.svelte";
|
||||
import Video from "$lib/video.svelte";
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Remeshing and Recolouring | denizk0461</title>
|
||||
</svelte:head>
|
||||
|
||||
<BannerTitleAlt
|
||||
title="Remeshing and Recolouring"
|
||||
subtitle="Project N5 Devlog"
|
||||
date="2025-07-13"
|
||||
banner="../../previews/2025/0713.webp"
|
||||
bannerAlt="Close-up of Laura at face height"
|
||||
/>
|
||||
|
||||
<ContentSidebar>
|
||||
|
||||
<TableOfContents slot="side-left" />
|
||||
|
||||
<div slot="main">
|
||||
|
||||
<p><i>Why are we still here? Just to suffer?</i></p>
|
||||
|
||||
<p>Note: the screenshots here are covering almost 3 months of work, and they're not in chronological order either. Some details from older versions that are intended to be kept will be missing in newer versions.</p>
|
||||
|
||||
<h2 id="mesh">Mesh Improvements</h2>
|
||||
<h3 id="head">Skull Remeshing</h3>
|
||||
|
||||
<p>When I was at uni recently, I decided to recreate Laura's head from scratch. The intention was to clean up the messy topology and just make it look a bit better. This time around, I didn't use a sphere as the base, but rather started from a single vertex and extruded out vertices manually to tailor it exactly to what I wanted. Here's the result, which I'm actually quite proud of:</p>
|
||||
|
||||
<Video src="headmesh.mp4" />
|
||||
|
||||
<p>Compare this to the old head mesh:</p>
|
||||
|
||||
<img src="head_old.webp" alt="A bust in Blender, displayed in edit mode. The topology is messy because the vertices are not evenly distributed">
|
||||
|
||||
<p>The old head was quite messy in topology; it's an artifact from Laura v1. There, I initially designed the head to not have any kind of face, but later I added eyes, a nose, refined the eye shape, and most recently, I added some shape around the eyes (the eyes are inset a bit and the eyebrows are comparatively further forward to follow the shape of an actual skull). All these edits required more edge loops and vertices than I had originally planned, which is the root cause for this mess of vertices.</p>
|
||||
|
||||
<p>The new head was designed from the ground up for exactly what I need. The entire head is made of easily-editable edge loops based on quads, except for one further cut along the nose to give it a bit more shape. I deemed this addition acceptable and even preferrable over slicing an entire new edge loop into the head.</p>
|
||||
|
||||
<p>With the head remeshing came more changes: I edited the shape of Laura's head. I made it rounder for one, but I also edited her jawline and made the head shorter in general.</p>
|
||||
|
||||
<p>I found I struggled with hairstyles because her forehead was quite massive compared to the rest of her head. It didn't lend itself to the style I wanted to achieve. Thus, I edited the dimensions, and now it looks a lot better, I find.</p>
|
||||
|
||||
<h3 id="hair-shading">Sharper (get it?) Hair Shading</h3>
|
||||
|
||||
<p> I figured out yesterday how to improve the shading of Laura's hair significantly!</p>
|
||||
|
||||
<p>Here's something that bothered me: her hair consisted of essentially rectangular tubes (in Blender: a path with a circle consisting of 4 vertices wrapped around it, vertices set to 'vector' to turn them into corners). Because it was smoothly-shaded, any shader would try to wrap around the light as if the strands were circular/tubular. This meant that the sides were far darker than I would have liked.</p>
|
||||
|
||||
<p>I managed to 'fix' this (depending on your perspective on the issue) by marking the sides of all strands as sharp edges. This now means that the strands are shaded separately at the front and the back, respective, with a sharp edge where they previously transitioned smoothly.</p>
|
||||
|
||||
<img src="hair_shading.webp" alt="An in-engine comparison of the shading between the old hair with smooth edges (left) and the new hair with sharp edges (right)">
|
||||
|
||||
<p>The left hair is the old style, the right is the new one. Notice how the strands are much more distinct on the left because of their darker outlines (shadows).</p>
|
||||
|
||||
<p>The idea came to me while I was experimenting with new hair styles and enabled flat shading on the strands to see their flow better.</p>
|
||||
|
||||
<h2 id="makeover">Continuing the Makeover</h2>
|
||||
<h3 id="hair-style">Hairdressing</h3>
|
||||
|
||||
<p>I played around with Laura's hair a little bit recently.</p>
|
||||
|
||||
<p>More importantly, I figured out her ponytail! Previously, I created a sort of 'banana' and extruded individual strands from it to create a more hair-like appearance.</p>
|
||||
|
||||
<img src="ponytail_old.webp" alt="The old ponytail style">
|
||||
|
||||
<p>However, I didn't like this very much, because it... well, I just think it looked bad. What I did instead is something that was actually inspired by a girl's hairstyle I saw on a bus:</p>
|
||||
|
||||
<img src="ponytail_new.webp" alt="The new ponytail style. Left view is unshaded, right view displays a cel shader">
|
||||
|
||||
<p>The shadow effects are – once again – created by sharp edges! It actually works very similarly to the tied-up hair on the back of her head.</p>
|
||||
|
||||
<img src="hair_back.webp" alt="An unshaded view of the back of Laura's head, with her tied-up hair at the centre">
|
||||
|
||||
<p>This effect I made by creating a sphere, selecting every second edge loop, scaling it down to create a spiky effect (that is mitigated by smooth shading) and then marking the scaled-down edges as sharp.</p>
|
||||
|
||||
<h3 id="eyes">Those Damn Eyes</h3>
|
||||
|
||||
<p>I decided to recolour Laura's right eye. Previously, it was a shade of red to match the rest of her outfit. Instead, though, I decided to go the complete opposite: it now looks borderline out of place against her colour palette, and for good reason.</p>
|
||||
|
||||
<img src="eyes.webp" alt="A comparison of Laura's eyes. Left is the old style with a red eye, right is the new style with a blue eye">
|
||||
|
||||
<p>It's blue and cold grey to display a discrepancy in her new body parts. That colour scheme will be used for her right arm, too, as well as some robots and environmental pieces. It shows how, even though Laura will find herself in her home world, the world around her has changed beyong recognition. This change, this unfamiliarity reflects back on her.</p>
|
||||
|
||||
<p>I'll also texture them once I finish modelling to make them look more interesting.</p>
|
||||
|
||||
<p>Due to a non-applied mirror modifier, Laura's eyes look identical (which is to say, the right eye is organic) on some pictures here. This will change, though.</p>
|
||||
|
||||
<h3 id="shoes">Shoe Shopping</h3>
|
||||
|
||||
<p>Laura finally has (almost) permanent shoes!!</p>
|
||||
|
||||
<img src="shoes_0.webp" alt="A comparison of Laura's old, temporary boots (left) and her new sneakers (right)">
|
||||
|
||||
<p>In v1, I intended to give Laura boots. However, I wasn't happy with how they looked. Furthermore, boots just didn't quite fit the style I wanted to go for. So instead, I modelled some sneakers, of course gathering reference from a shopping website.</p>
|
||||
|
||||
<img src="shoes_1.webp" alt="A close-up of Laura's new sneakers, with orange colour added to the bottoms">
|
||||
|
||||
<h3 id="misc-style">Minor Adjustments</h3>
|
||||
|
||||
<p>Further things I changed:</p>
|
||||
<ul class="styled-list">
|
||||
<li>Laura's hoodie has a more vibrant red colour now.</li>
|
||||
<li>Her trousers are wider now. She has a much more unique silhouette now than she did in v1!</li>
|
||||
<li>The trousers also have cargo pockets now.</li>
|
||||
<li>The shape of her eyelashes has been refined.</li>
|
||||
</ul>
|
||||
|
||||
<p>Her right (mechanical) arm is still not in place, however. I've been struggling with ideas for it.</p>
|
||||
|
||||
<p>Actually, I've not thought about it enough recently. I should change that.</p>
|
||||
|
||||
<h2 id="zipline">Sway to and fro like little insects!</h2>
|
||||
|
||||
<p>Gameplay-wise, I also made some progress: there's now ziplining in the game! The idea is that Laura will be able to use her right arm (which doesn't feel rope burn like her organic left arm would) to hook onto ropes and zip across (intended) parts of the levels.</p>
|
||||
|
||||
<Video src="ziplining.mp4" />
|
||||
|
||||
<p>In the video, Laura ziplines <i>up</i> and even does a flip, which won't be in the game. It's intended to go downhill only instead, to travel between two platforms in a non-reversible way. This loop was just a test.</p>
|
||||
|
||||
<h2 id="laura">Laura as of Today</h2>
|
||||
|
||||
<p>and to end this devlog, here's how Laura currently looks in her entirety:</p>
|
||||
|
||||
<img src="laura.webp" alt="A full-body screenshot of Laura">
|
||||
|
||||
</div>
|
||||
</ContentSidebar>
|
||||
93
src/routes/projects/projectn5/devlog/20250203.md
Normal file
@@ -0,0 +1,93 @@
|
||||
---
|
||||
title: The Making of a Protagonist, Part III
|
||||
date: '2025-02-03'
|
||||
tag: '20250203'
|
||||
bannerAlt: Three t-posing untextured Lauras
|
||||
---
|
||||
While I've been busy working on another game with friends lately, I've managed to almost completely finish Laura. Here's what I've achieved!
|
||||
|
||||
## Visual Personality Adjustment
|
||||
|
||||
As promised before, I've worked on Laura's head a bit more. Her full face shield has been replaced with a face mask / respirator covering only the bottom half of her face. Also, I finally got the hair into a state I'm actually happy with. Here's a comparison:
|
||||
|
||||
<div class="horizontally-centre-aligned">
|
||||
<img src="../20241222/laura-hair-flat-new-3.webp" alt="The old protagonist's head with green clothing and full-face mask">
|
||||
<img src="laura-head-new.webp" alt="The new protagonist Laura's head with red clothing, a half-face mask. The character now has a brown left eye, a mechanical right eye, and eyebrows, as well as bangs">
|
||||
</div>
|
||||
|
||||
The eyes took some work to get right, but I'm pretty happy with the current result. They're not proper eyeballs, but instead they're embedded into the head, which visually isn't significant because the flat shading would hide these details anyway. She has a brown left eye with a small sparkle, as well as a right eye replacement. This implies that Laura sustained further damage to the right side of her body, which necessitated replacement of her eye in addition to her right arm.
|
||||
|
||||
It's actually the result of UV unwrapping her model. Previously, every colour was its own material, which I wanted to change by switching to a texture atlas. Initially, of course, the UVs were a bit messed up, which resulted in this look:
|
||||
|
||||

|
||||
|
||||
I still think this looks kind of cool.
|
||||
|
||||
### New Hair 💇♀️
|
||||
|
||||
Her hair is now not a cohesive mesh anymore, but rather made up of something between 15 and 20 individual strands using custom normals to get a flat look. It also has a faint gradient, changing from a brighter colour at the top to a darker shade at the bottom.
|
||||
|
||||
I added earrings too:
|
||||
|
||||

|
||||
|
||||
Just some small metallic rings that I thought looked cool. For positioning these correctly, I hid Laura's back hair at one point, which gave me the idea to model a ponytail / tied-up alternative hair look for Laura. I think it'd look really cool. I haven't created this yet, but I've laid some groundwork to make it work:
|
||||
|
||||
Laura's hair is now separate from her main mesh. The main mesh is rigged using a metarig generated through Rigify, whereas the hair has a manually-created armature. Also, the hair is split into the front part and the back part, separated by the hair band (which is part of the main mesh). This allows me to replace the flowing back hair with a ponytail easily in-engine without swapping out the entire character.
|
||||
|
||||
This is pretty cool, because I can now create scenes for each hairstyle, set them up with [jiggle bones](/projects/projectn5/devlog/2024/1222/) to create flowing hair, and essentially add a toggle to switch between them in-game!
|
||||
|
||||
## Rigging and Using Blender's Rigify
|
||||
|
||||
Rigify is really cool for rigging characters easily. However, you need to know some things that I didn't before you start using it:
|
||||
|
||||
- When adding a Rigify armature to the scene, do not parent the rig to the model. You need to place the rig as intended, then click on "Generate rig", and then parent the new armature with the mesh and weight paint that way. I made the mistake of weight painting before generating the rig, which isn't transferrable because the metarig adds extra bones which require individual weight painting (e.g. the thighs being made up of two bones instead of just one).
|
||||
- Know how to switch between forward kinematics (FK) and inverse kinematics (IK). At the top right of the editor, there'll be a window with a slider to switch between FK and IK, as well as buttons to transfer an FK pose to IK and vice-versa. Don't be confused if posing a specific control doesn't work – you might need to switch to FK or IK, respectively.
|
||||
|
||||
## Facial Animations and Shape Keys
|
||||
|
||||
## Animation and Framerate
|
||||
|
||||
I've been playing around with the idea of using a lower framerate for the animations. I got the idea from [Noodle's video on animation](https://www.youtube.com/watch?v=_KRb_qV9P4g). Not sure whether I'll go through with this, but if I do, I think I'll go with 15fps or 20fps animation, since that's easily implementable a 60fps environment.
|
||||
|
||||
I already adjusted the jiggle bone script, which was easy to do since it runs in Godot's `_physics_process(delta)` function. This runs 60 times per second, so having code run only 15 times per second, for example, is as easy as wrapping the code in question in `if Engine.get_physics_frames() % 4 == 0:`, which makes a code block run only once every 4 frames – 60fps/4 == 15fps.
|
||||
|
||||
## Laura In-Engine
|
||||
|
||||
Since the shader I'm using in Blender is quite different from the one I am planning to use in Godot, here's a shot of Laura with the Godot shader:
|
||||
|
||||

|
||||
|
||||
I've been thinking of adding an option (perhaps as a cheat code) to change her outfit's colour – hair band, sweatshirt, and the rings on her right prosthetic fingers. I first didn't know how to implement this, but now that I've learnt a bit on how to use shaders, I think this could be achieved with a custom UV mask and a parameter that determines at which position the UV is sampled from – the UV would then contain several colour options.
|
||||
|
||||
## Some Funny Pictures
|
||||
|
||||
<div class="horizontally-centre-aligned">
|
||||
<img src="ok.webp" alt="An OK hand">
|
||||
<img src="dance.webp" alt="Laura flailing her arms">
|
||||
<img src="naruto.webp" alt="Laura naturo-running">
|
||||
</div>
|
||||
|
||||
<div class="horizontally-centre-aligned">
|
||||
<img src="shock.webp" alt="Laura's face looking shocked">
|
||||
<img src="reprehension.webp" alt="Laura's face looking astonished">
|
||||
<img src="disgust.webp" alt="Laura's face looking disgusted">
|
||||
</div>
|
||||
|
||||
## The Future of this Devlog
|
||||
|
||||
I feel that this blog-like format makes me think that the content here should be educational; that someone may read this and learn from it. It's likely not the case, but either way, perhaps it would make sense to limit the progress updates to a mere "here's what I made!" and only a little bit of background, if it's interesting.
|
||||
|
||||
Most times, I find myself struggling to explain my progress anyway, mostly since I'm learning as I go and because I publish progress updates pretty rarely. For example, I added eyes to Laura's model on 2025-01-01, there's no way I'll remember everything I did and thought of over a month ago.
|
||||
|
||||
Switching to a more short-form content format might help in publishing updates more regularly, and being more in the style of: "hey look at this cool thing I made!" It would also focus on visual changes, possibly helping me to keep a better schedule, merely because I can see my progress more steadily and be motivated more frequently.
|
||||
|
||||
I've been thinking of creating an Instagram account for that – though I despise Meta (and Instagram by extension). It feels like a decent platform for my idea, though: presenting progress mostly through visuals. I also know more people who are on Instagram who may follow my progress... maybe. Bluesky *may* be an option, though it's more text-focussed and more short-form than Instagram.
|
||||
|
||||
Either way, I'd lose out on the progress I've already shared here.
|
||||
|
||||
Or maybe I just don't share my stuff at all and don't stress out about it lol, no one's seeing this anyway and I'm not a social media person anyway.
|
||||
|
||||
idk
|
||||
|
||||
Maybe it's time to change the format of the devlog on this website?
|
||||
172
src/routes/projects/projectn5/devlog/20250316.md
Normal file
@@ -0,0 +1,172 @@
|
||||
---
|
||||
title: Refactoring
|
||||
date: '2025-03-16'
|
||||
tag: '20250316'
|
||||
bannerAlt: Laura t-posing in front of a smiling water tower
|
||||
---
|
||||
<script lang="ts">
|
||||
import Video from "$lib/video.svelte";
|
||||
</script>
|
||||
|
||||
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](https://godotengine.org/asset-library/asset/1900).
|
||||
|
||||
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.
|
||||
|
||||
<img src="laura-spinning.gif" style="max-width: 400px; object-fit: cover;" alt="Laura moving in a circle on top of a box">
|
||||
|
||||
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.
|
||||
|
||||
<Video src="hair-swoosh.mp4" />
|
||||
|
||||
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.
|
||||
|
||||
<Video src="look-at.mp4" />
|
||||
|
||||
### ...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](/projects/projectn5/devlog/2025/0203) 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:
|
||||
|
||||
<Video src="106.mp4" />
|
||||
|
||||
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.
|
||||
|
||||
<Video src="107.mp4" />
|
||||
|
||||
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:
|
||||
|
||||
<Video src="item-preview.mp4" />
|
||||
|
||||
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
|
||||
|
||||
<div class="horizontally-centre-aligned">
|
||||
<img src="104-icon.webp" alt="An icon for a rocket launcher that looks like a sperm">
|
||||
<img src="106-icon.webp" alt="A primitive flame as an icon for a flame thrower">
|
||||
<img src="107-icon.webp" alt="A hand-drawn crosshair serving as an icon for a rifle">
|
||||
<img src="108-icon.webp" alt="The words 'VENOM' as an icon for the weapon of that name">
|
||||
</div>
|
||||
|
||||
## 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:
|
||||
|
||||
[Jolt is now integrated into the engine!](https://github.com/godotengine/godot/pull/99895) Since my use of the physics engine is relatively basic and does not rely on Jolt features that haven't been implemented in the engine yet, I switched immediately and was able to remove a dependency. The work that went into this is insane, I recommend checking out the pull request.
|
||||
|
||||
Godot 4.4 added a new node called [`SpringBoneSimulator3D`](https://docs.godotengine.org/en/stable/classes/class_springbonesimulator3d.html), which can be used for jiggle physics in a similar manner to [JiggleBones](https://godotengine.org/asset-library/asset/1595). I replaced my JiggleBones implementation with `SpringBoneSimulator3D` and was thus able to remove another dependency. I like the `SpringBoneSimulator3D` setup better, though I'm not as happy with the current result. I'll have to spend more time tweaking it and learning how to use it properly; it involves a bit more setup than JiggleBones, but it's more reliable, especially since it has better support for collision shapes (JiggleBones only supports spheres, but it's very rudimentary support, and they have to be sized way larger than expected to work at all. It's very unreliable. [`SpringBoneCollision3D`](https://docs.godotengine.org/en/stable/classes/class_springbonecollision3d.html#class-springbonecollision3d) works *so much better* and supports capsules and planes as well).
|
||||
|
||||
Physics interpolation is now available for 3D, which fixed [an issue that caused nodes tracked with a Phantom Camera to jitter](https://phantom-camera.dev/support/faq#i-m-seeing-jitter-what-can-i-do).
|
||||
|
||||
Godot has typed `Dictionary` support in `@export` properties now, which in *my world* is a **huge** deal. It means you can do `@export var dict: Dictionary[int, String]` and dynamically add to the Dictionary in the inspector. This, of course, allows for custom `Resource`s as well. I use this, for example, in the item statistics, where I have a `Dictionary` holding item statistics as a custom `Resource` associated with the item's ID. This `Resource` has nested `Resource`s for individual weapon levels. It's *so* cool! I'm disproportionately happy about this change.
|
||||
|
||||
### $
|
||||
|
||||
Yesterday, I replaced a lot of $ node references with `@export` properties for performance reasons. I watched [this video](https://www.youtube.com/watch?v=fb68YXIBinc) 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 `CharacterController3D`s – 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.
|
||||
|
||||
<Video src="enemy-stairs.mp4" />
|
||||
|
||||
## 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](https://www.thalia.de/shop/home/artikeldetails/A1071363499) 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](https://www.thalia.de/shop/home/artikeldetails/A1071895735), 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](https://bsky.app/profile/denizk0461.bsky.social) 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!!
|
||||
90
src/routes/projects/projectn5/devlog/20250427.md
Normal file
@@ -0,0 +1,90 @@
|
||||
---
|
||||
title: The Making of a Protagonist, Part IV
|
||||
date: '2025-04-27'
|
||||
tag: '20250427'
|
||||
bannerAlt: Sketches of Laura's new clothes
|
||||
---
|
||||
## Current Progress
|
||||
|
||||
As promised, I've been working on Laura v2 – which has now become v4. On the right is the current/soon-to-be previous model of Laura, on the left is my current progress on her new model!
|
||||
|
||||
<img src="laura-comparison.webp" alt="Laura's old model on the right, Laura's new model on the left">
|
||||
|
||||
(By the way, the left picture is the most recent version of the model. Other pictures on this page will be older and may have some slightly different details!)
|
||||
|
||||
### New and Improved
|
||||
|
||||
Notable differences are:
|
||||
|
||||
- Laura wears a cropped zip-up hoodie with a more saturated colour than before, and a black shirt underneath. Her clothes are generally fairly similar between versions, though her dimensions and especially the topology are quite different and optimised.
|
||||
- Her shoulder area was a previous pain point of mine – notice the completely smooth transition from neck to arms in the right model. In the new version, her shoulders have been given much more shape.
|
||||
- Her hoodie's colour is more saturated than before. The comparison here is not quite fair, since the left is an image from Blender and the second is from Godot, thus impacting how the colours look since there are different shaders used, but the idea still stands.
|
||||
- Her hair is tied-up in a ponytail, which not only looks cooler, but is also way easier to animate, imo.
|
||||
- Her eyes have been refined in shape and her lashes/eyeliner have been extended to wrap around her eyes more, which, in my opinion, looks quite a lot sharper than before.
|
||||
- Her eyes have been socketed in a different way. Previously, they were flat faces directly behind her irises, but now they're much more recessed, which likely/hopefully won't be visible using flat shading. I also edited the normals to look less like the sclera is recessed. I'm hoping this'll make animating easier, since the irises can now move more freely without clipping into the sclera.
|
||||
|
||||

|
||||
|
||||
### Things to Work On
|
||||
|
||||
Parts that have not yet received much attention are:
|
||||
|
||||
- Her trousers, which have received a general shape, but no details.
|
||||
- Her belt, oxygen mask, and left hand, which are mostly copied over and adjusted to not look completely out of place.
|
||||
- The shoes, which are placeholders.
|
||||
- The right arm, which is notably present in the picture, but nowhere near finalised and to be attached.
|
||||
- Her hair, which is present only in a basic shape to serve as a placeholder for what I have planned.
|
||||
- I might add her hair band back.
|
||||
|
||||
|
||||
### Further Thoughts on Modelling
|
||||
|
||||
This model is supposed to look more dynamic and lively than the previous one. I want to more granularly animate the hair by adding more bones to individual strands. I'll also add bones for the hood so that it can bounce up and down when running. I'm also considering adding bones to allow the sleeves and trouser legs to move slightly, though I'm not sure if I'd be able to make that look good, so I'm keeping this idea in the 'optional' pile for now.
|
||||
|
||||
I think what helped with modelling this time around was that I let go of the notion that Laura should be a low-poly character. I started out that way when I was modelling v1 but then I changed my mind, which created some problems, I find. This time, I still don't want to go crazy with tris, but it's not as much of an issue to me. At one point I even intended to subdivide her entire model by 1 level to smoothen some rough edges and overall make the model a bit more polished, but I discarded that idea yesterday.
|
||||
|
||||
### The Eternal Hair Struggle
|
||||
|
||||
I've [struggled with hair before](/projects/projectn5/devlog/20241222/), and it's not gotten *much* better. Check out Laura's current ponytail:
|
||||
|
||||

|
||||
|
||||
Looks like a banana!
|
||||
|
||||
I think my next try will be to polymodel strands of hair out of subdivided planes. It'll increase the poly count quite significantly, but it's a trade-off I'm willing to make for hair that'll look better and flow (animate) much more nicely!
|
||||
|
||||
### wdym v4?
|
||||
|
||||
The current version of Laura is based on the following sketches:
|
||||
|
||||

|
||||
|
||||
<img class="inline-img-left" src="laura-v2.webp" alt="Laura v2 wearing a top with puffed-up sleeves">
|
||||
|
||||
I worked with these sketches to create the first remodel of Laura. Originally, I was decently happy with the result, though her sleeves seemed boring – just ballooning and lacking an interesting shape.
|
||||
|
||||
<img class="inline-img-right" src="laura-v3.webp" alt="Laura v3 wearing a black dress and a red longsleeve underneath">
|
||||
|
||||
I had quite a few ideas to improve the current and rather boring Laura model. At the centre of the remodelling was keeping Laura's character but giving it more edge through a more unique silhouette. I wanted to accomplish this by adding textures and detail, layering clothes, and giving more shape to her.
|
||||
|
||||
Eventually, I had a different vision for Laura, though. This time, she would wear a dress with a long-sleeve shirt beneath. I liked this idea because it showed off the shape of her legs more, whereas the previous idea would hide them inside of straight-cut trousers. It would just look more interesting, I felt. I was also inspired by some 3D models I saw on Pinterest.
|
||||
|
||||
While I generally liked the idea, there were two major problems: firstly, I felt I wasn't really able to execute the idea in a way that I found fitting. Secondly – and this plays into the first aspect – the model didn't look as mature as I liked. Partially in its style, but also in its execution.
|
||||
|
||||
This v3 of Laura was then superseded by another Laura, which essentially went back to the previously style, though I used v3 as a base due to some improvements I made on the model. Thus the new version is now called v4.
|
||||
|
||||
Notice how specifically her head and the prosthetic aren't present in the v2 screenshot – those were v3 additions.
|
||||
|
||||
## Prosthetic Implications
|
||||
|
||||
I'm changing Laura's amputation from its previous below-the-elbow cutoff to above-the-elbow. This is mostly a stylistic change, because it means her elbow will be a mechanical replacement as well, and that might look cool, I think.
|
||||
|
||||
I've also been thinking about how her prosthetic could play into the story. A while back, I watched [this video](https://www.youtube.com/watch?v=jZfgQTC9CEA) by champutee on arm amputee representation in video games. Admittedly, I feel I'll likely fall into quite the same categories in some ways, making Laura's prosthetic so advanced that it'll more or less serve as a perfect replacement for her organic arm. I had a potentially neat idea that would impact gameplay, though.
|
||||
|
||||
### Difficulty Scaling
|
||||
|
||||
At one point in the game, Laura could lose function of her prosthetic entirely and be forced to continue without being able to use it. This would reflect in gameplay especially because Laura would then be unable to use any two-handed items, which will include a majority of her weapons as well.
|
||||
|
||||
Laura will likely have something between 4 and 8 weapons available to her. I'm thinking that some will be two-handed from the start (including her main rifle), and some will level-up from one-handed to two-handed or dual-handed (for example, a blaster in each hand). This would mean that more advanced players who progress quicker and manage to level up their weapons early (through XP, collectibles, or purchases, I've not decided) will face a greater challenge, since more of their weapons will be levelled up to their two-handed versions, thus making a larger part of their arsenal unavailable for this part of the game.
|
||||
|
||||
In my teacher training, we call this type of catering to different skill sets *differentiation (Differenzierung)*!
|
||||
61
src/routes/projects/projectn5/devlog/20250523.md
Normal file
@@ -0,0 +1,61 @@
|
||||
---
|
||||
title: Reboot
|
||||
date: '2025-05-23'
|
||||
tag: '20250523'
|
||||
bannerAlt: Untextured Laura in a new purple level looking at two cubes
|
||||
---
|
||||
20 months after starting *Project N5*, I decided to restart the project. In fact, a friend of mine assumed I'd do it all the way back in December 2023! Initially, I resisted, though I toyed with the idea for quite a while, before finally deciding that this is best for the project last Friday (**2025-05-16**).
|
||||
|
||||
## Why?
|
||||
|
||||
There are two main reasons for starting the project from scratch again.
|
||||
|
||||
### I Improved
|
||||
|
||||
The first reason is simple: I improved as a programmer.
|
||||
|
||||
Back when I started *Project N5*, I had never actually used Godot before. This project was my first experience developing in Godot, and to a greater extent, my first attempt at making a full-scale game! I set out a huge goal for myself, though I welcomed the challenge.
|
||||
|
||||
With stagnation in my progress especially in the summer of 2024, I felt I outgrew the project's codebase in some way. Also adding to that is the fact that I was working on [another game](/projects/#projektike) with two friends, where I had to write clean solutions and well-structured code to keep the project modular (especially during the stage where we hadn't quite figured out where to take the project) and understandable for the others. This resulted in me learning the ropes of Godot and GDScript much more than I had before.
|
||||
|
||||
I initially tried to tackle the issue by refactoring the codebase of *Project N5*. Even though I made significant progress, I later felt that the codebase was flawed from the core. I felt this way especially while I was recently trying to implement a new weapon – what a hassle that was!
|
||||
|
||||
Which leads nicely into my second reason...
|
||||
|
||||
### The Project Changed
|
||||
|
||||
For quite a while after I started *Project N5*, I didn't know where to take the project. In fact, I was stuck at the idea of a robot protagonist for *such a long time!* Laura only came to mind [much later](/projects/projectn5/devlog/20241127/). With her, however, my ideas for the project started to change slightly.
|
||||
|
||||
Don't get me wrong – the essence of the game is probably still pretty much intact. However, I want to make the game a little less combat-focussed, which meant that especially the weapon structure I had built up made no sense anymore. I built the system specifically so I could implement as many different weapons as I liked. Recently, though, I decided that 4 is enough, which made the grand system redundant.
|
||||
|
||||
Add to this the fact that, with a lesser focus on combat, an [arena](/projects/projectn5/devlog/20240324/) made *no sense at all!*
|
||||
|
||||
Trying to bodge my old codebase – "Altlasten mit sich tragen", as one would say in German – felt wasteful.
|
||||
|
||||
## The Current State of the New Project
|
||||
|
||||
Considering I started one week ago, I'm doing decently well:
|
||||
|
||||

|
||||
|
||||
What you can see here is my new Laura model (not yet finished!), with a partially-applied toon shader and an outline shader on top. The UI elements include a health counter (on top), a money counter (bottom right), a placeholder for the popup menu(s), a crosshair in the middle of the screen (the dot), and an aim helper texture also in the middle of the screen (the cross). The two boxes represent enemies, not in function, but in their physics layers and in targetability.
|
||||
|
||||
There are a lot of improvements: targets, for example, are now not defined by a special node setup, but rather by aTarget prefab, which can easily be positioned anywhere (enemy or environment) and be used to guide player projectiles.
|
||||
|
||||
The code is also *so much more streamlined...* I put many elements into their own components to avoid cluttering theplayer.gd script with an overwhelming amount of responsibilities. That way, what was previously a 300+ line script handling player movement, aim direction, messages, equipping items, interacting with objects etc. is now a lean 50+ line script (although ofc not everything from the previous project is implemented here yet, such as the vendor interactions). Anything that's not directly related to the player has its own component script to keep things separated as much as possible. Currently, there is also no singletonSignalBus routing wildly between any and all nodes. Instead, signals are just defined in their components and connected directly to only the components needing them. This also means that components only take care of tasks that are explicitly meant for them; the guns, for example, no longer calculate the position which the projectile is flying towards. Instead, they can now simply retrieve an aim direction from theAimManager, requiring much less code in each weapon. Everything's so clean and I love it.
|
||||
|
||||
### The New Weapon Arsenal
|
||||
|
||||
Check out the new weapons:
|
||||
|
||||

|
||||
|
||||
With these, and with the UI in the previous screenshot, you may have noticed a theme: I'm putting less time into temporary assets. While nice to play around with, it's unnecessary to spend an hour designing a UI element when I already know I'll 100% replace it down the line. Thus, most elements are either entirely simplistic (text, primitive MeshInstance3D, etc.), or just very simple textures.
|
||||
|
||||
## Continuing
|
||||
|
||||
Progress has been quick, which I really liked. It felt as if project development picked up again. Of course, a lot of this has to do with the fact that I'm just programming things I've already once programmed, so I have to put less time into coming up with ideas and can instead solely focus on the implementation. However, I feel that this cleaner codebase will allow me to expand much more easily and develop a less bug-ridden game than if I had simply continued with the old codebase.
|
||||
|
||||
I'm happy I took this step!
|
||||
|
||||

|
||||
115
src/routes/projects/projectn5/devlog/20250713.md
Normal file
@@ -0,0 +1,115 @@
|
||||
---
|
||||
title: Remeshing and Recolouring
|
||||
date: '2025-07-13'
|
||||
tag: '20250713'
|
||||
bannerAlt: Close-up of Laura at face height
|
||||
---
|
||||
<script lang="ts">
|
||||
import Video from "$lib/video.svelte";
|
||||
</script>
|
||||
|
||||
*Why are we still here? Just to suffer?*
|
||||
|
||||
Note: the screenshots here are covering almost 3 months of work, and they're not in chronological order either. Some details from older versions that are intended to be kept will be missing in newer versions.
|
||||
|
||||
## Mesh Improvements
|
||||
### Skull Remeshing
|
||||
|
||||
When I was at uni recently, I decided to recreate Laura's head from scratch. The intention was to clean up the messy topology and just make it look a bit better. This time around, I didn't use a sphere as the base, but rather started from a single vertex and extruded out vertices manually to tailor it exactly to what I wanted. Here's the result, which I'm actually quite proud of:
|
||||
|
||||
<Video src="headmesh.mp4" />
|
||||
|
||||
Compare this to the old head mesh:
|
||||
|
||||

|
||||
|
||||
The old head was quite messy in topology; it's an artifact from Laura v1. There, I initially designed the head to not have any kind of face, but later I added eyes, a nose, refined the eye shape, and most recently, I added some shape around the eyes (the eyes are inset a bit and the eyebrows are comparatively further forward to follow the shape of an actual skull). All these edits required more edge loops and vertices than I had originally planned, which is the root cause for this mess of vertices.
|
||||
|
||||
The new head was designed from the ground up for exactly what I need. The entire head is made of easily-editable edge loops based on quads, except for one further cut along the nose to give it a bit more shape. I deemed this addition acceptable and even preferrable over slicing an entire new edge loop into the head.
|
||||
|
||||
With the head remeshing came more changes: I edited the shape of Laura's head. I made it rounder for one, but I also edited her jawline and made the head shorter in general.
|
||||
|
||||
I found I struggled with hairstyles because her forehead was quite massive compared to the rest of her head. It didn't lend itself to the style I wanted to achieve. Thus, I edited the dimensions, and now it looks a lot better, I find.
|
||||
|
||||
### Sharper (get it?) Hair Shading
|
||||
|
||||
I figured out yesterday how to improve the shading of Laura's hair significantly!
|
||||
|
||||
Here's something that bothered me: her hair consisted of essentially rectangular tubes (in Blender: a path with a circle consisting of 4 vertices wrapped around it, vertices set to 'vector' to turn them into corners). Because it was smoothly-shaded, any shader would try to wrap around the light as if the strands were circular/tubular. This meant that the sides were far darker than I would have liked.
|
||||
|
||||
I managed to 'fix' this (depending on your perspective on the issue) by marking the sides of all strands as sharp edges. This now means that the strands are shaded separately at the front and the back, respective, with a sharp edge where they previously transitioned smoothly.
|
||||
|
||||

|
||||
|
||||
The left hair is the old style, the right is the new one. Notice how the strands are much more distinct on the left because of their darker outlines (shadows).
|
||||
|
||||
The idea came to me while I was experimenting with new hair styles and enabled flat shading on the strands to see their flow better.
|
||||
|
||||
## Continuing the Makeover
|
||||
### Hairdressing
|
||||
|
||||
I played around with Laura's hair a little bit recently.
|
||||
|
||||
More importantly, I figured out her ponytail! Previously, I created a sort of 'banana' and extruded individual strands from it to create a more hair-like appearance.
|
||||
|
||||

|
||||
|
||||
However, I didn't like this very much, because it... well, I just think it looked bad. What I did instead is something that was actually inspired by a girl's hairstyle I saw on a bus:
|
||||
|
||||

|
||||
|
||||
The shadow effects are – once again – created by sharp edges! It actually works very similarly to the tied-up hair on the back of her head.
|
||||
|
||||

|
||||
|
||||
This effect I made by creating a sphere, selecting every second edge loop, scaling it down to create a spiky effect (that is mitigated by smooth shading) and then marking the scaled-down edges as sharp.
|
||||
|
||||
### Those Damn Eyes
|
||||
|
||||
I decided to recolour Laura's right eye. Previously, it was a shade of red to match the rest of her outfit. Instead, though, I decided to go the complete opposite: it now looks borderline out of place against her colour palette, and for good reason.
|
||||
|
||||

|
||||
|
||||
It's blue and cold grey to display a discrepancy in her new body parts. That colour scheme will be used for her right arm, too, as well as some robots and environmental pieces. It shows how, even though Laura will find herself in her home world, the world around her has changed beyong recognition. This change, this unfamiliarity reflects back on her.
|
||||
|
||||
I'll also texture them once I finish modelling to make them look more interesting.
|
||||
|
||||
Due to a non-applied mirror modifier, Laura's eyes look identical (which is to say, the right eye is organic) on some pictures here. This will change, though.
|
||||
|
||||
### Shoe Shopping
|
||||
|
||||
Laura finally has (almost) permanent shoes!!
|
||||
|
||||

|
||||
|
||||
In v1, I intended to give Laura boots. However, I wasn't happy with how they looked. Furthermore, boots just didn't quite fit the style I wanted to go for. So instead, I modelled some sneakers, of course gathering reference from a shopping website.
|
||||
|
||||

|
||||
|
||||
### Minor Adjustments
|
||||
|
||||
Further things I changed:
|
||||
|
||||
- Laura's hoodie has a more vibrant red colour now.
|
||||
- Her trousers are wider now. She has a much more unique silhouette now than she did in v1!
|
||||
- The trousers also have cargo pockets now.
|
||||
- The shape of her eyelashes has been refined.
|
||||
|
||||
|
||||
Her right (mechanical) arm is still not in place, however. I've been struggling with ideas for it.
|
||||
|
||||
Actually, I've not thought about it enough recently. I should change that.
|
||||
|
||||
## Sway to and fro like little insects!
|
||||
|
||||
Gameplay-wise, I also made some progress: there's now ziplining in the game! The idea is that Laura will be able to use her right arm (which doesn't feel rope burn like her organic left arm would) to hook onto ropes and zip across (intended) parts of the levels.
|
||||
|
||||
<Video src="ziplining.mp4" />
|
||||
|
||||
In the video, Laura ziplines *up* and even does a flip, which won't be in the game. It's intended to go downhill only instead, to travel between two platforms in a non-reversible way. This loop was just a test.
|
||||
|
||||
## Laura as of Today
|
||||
|
||||
and to end this devlog, here's how Laura currently looks in her entirety:
|
||||
|
||||

|
||||
@@ -2,6 +2,7 @@
|
||||
title: Freeing the Past
|
||||
date: '2025-08-16'
|
||||
tag: '20250816'
|
||||
bannerAlt: Bottom-up view at Laura v1 in front of a blue sky
|
||||
---
|
||||
<script lang="ts">
|
||||
import LinkList, { type LinkEntry } from "$lib/link-list.svelte";
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
title: She's Here
|
||||
date: '2025-10-11'
|
||||
tag: '20251011'
|
||||
bannerAlt: Laura idle posing
|
||||
---
|
||||
<script lang="ts">
|
||||
import Video from "$lib/video.svelte";
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
title: Growing Pains
|
||||
date: '2025-10-22'
|
||||
tag: '20251022'
|
||||
bannerAlt: Close-up of Laura blinking
|
||||
---
|
||||
I realise there's still a lot of comparing between the old and the new in this update, but I promise there'll be new stuff soon... hopefully. Right now, I just want to go over the improvements I made, because creating Laura has been a huge learning process for me and I honestly think it's been quite successful, which I'm really happy about.
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
subtitle="Project N5 Devlog"
|
||||
date="{data.date}"
|
||||
banner="preview.webp"
|
||||
bannerAlt="Close-up of Laura blinking"
|
||||
bannerAlt="{data.bannerAlt}"
|
||||
/>
|
||||
|
||||
<ContentSidebar>
|
||||
|
||||
@@ -4,6 +4,7 @@ export async function load({ params }) {
|
||||
title,
|
||||
date,
|
||||
tag,
|
||||
bannerAlt,
|
||||
} = post.metadata;
|
||||
const content = post.default;
|
||||
|
||||
@@ -12,5 +13,6 @@ export async function load({ params }) {
|
||||
title,
|
||||
date,
|
||||
tag,
|
||||
bannerAlt,
|
||||
};
|
||||
}
|
||||
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 110 KiB After Width: | Height: | Size: 110 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 77 KiB After Width: | Height: | Size: 77 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 74 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 185 KiB After Width: | Height: | Size: 185 KiB |
|
Before Width: | Height: | Size: 168 KiB After Width: | Height: | Size: 168 KiB |
|
Before Width: | Height: | Size: 167 KiB After Width: | Height: | Size: 167 KiB |
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 57 KiB |
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 66 KiB |