added all devlogs
@@ -18,7 +18,7 @@
|
||||
<h1 class="title">{title}</h1>
|
||||
</div>
|
||||
{#if subtitle}
|
||||
<h1 class="subtitle">{subtitle}</h1>
|
||||
<h1 class="subtitle">» {subtitle}</h1>
|
||||
{/if}
|
||||
<SeparatorLine />
|
||||
|
||||
|
||||
93
src/lib/devlog-posts.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
export interface DevlogPost {
|
||||
title: string;
|
||||
subtitle: string;
|
||||
date: number;
|
||||
banner?: string;
|
||||
};
|
||||
|
||||
export const posts: DevlogPost[] = [
|
||||
{
|
||||
title: "Refactoring",
|
||||
subtitle: "2025-03-16",
|
||||
date: 20250316,
|
||||
banner: "fishmonger.webp",
|
||||
},
|
||||
{
|
||||
title: "The Making of a Protagonist, Part III",
|
||||
subtitle: "2025-02-03",
|
||||
date: 20250203,
|
||||
banner: "lauras-imposing.webp",
|
||||
},
|
||||
{
|
||||
title: "The Making of a Protagonist, Part II",
|
||||
subtitle: "2024-12-22",
|
||||
date: 20241222,
|
||||
banner: "laura-header.webp",
|
||||
},
|
||||
{
|
||||
title: "The Making of a Protagonist, Part I",
|
||||
subtitle: "2024-11-27",
|
||||
date: 20241127,
|
||||
banner: "hands.webp",
|
||||
},
|
||||
{
|
||||
title: "Visual Update",
|
||||
subtitle: "2024-11-03",
|
||||
date: 20241103,
|
||||
},
|
||||
{
|
||||
title: "Returnal Update",
|
||||
subtitle: "2024-10-12",
|
||||
date: 20241012,
|
||||
},
|
||||
{
|
||||
title: "WHERE HAVE I BEEN?? Update",
|
||||
subtitle: "2024-07-13",
|
||||
date: 20240713,
|
||||
},
|
||||
{
|
||||
title: "Behind-The-Scenes Update",
|
||||
subtitle: "2024-04-01",
|
||||
date: 20240401,
|
||||
},
|
||||
{
|
||||
title: "Arena Update",
|
||||
subtitle: "2024-03-24",
|
||||
date: 20240324,
|
||||
},
|
||||
{
|
||||
title: "2024-03-23",
|
||||
subtitle: "",
|
||||
date: 20240323,
|
||||
},
|
||||
{
|
||||
title: "2024-03-12",
|
||||
subtitle: "",
|
||||
date: 20240312,
|
||||
},
|
||||
{
|
||||
title: "2024-02-10",
|
||||
subtitle: "",
|
||||
date: 20240210,
|
||||
},
|
||||
{
|
||||
title: "December 2023",
|
||||
subtitle: "",
|
||||
date: 202312,
|
||||
},
|
||||
{
|
||||
title: "November 2023",
|
||||
subtitle: "",
|
||||
date: 202311,
|
||||
},
|
||||
{
|
||||
title: "October 2023",
|
||||
subtitle: "",
|
||||
date: 202310,
|
||||
},
|
||||
{
|
||||
title: "September 2023",
|
||||
subtitle: "",
|
||||
date: 202309,
|
||||
},
|
||||
];
|
||||
@@ -1 +0,0 @@
|
||||
// place files you want to import through the `$lib` alias in this folder.
|
||||
@@ -29,6 +29,10 @@
|
||||
--color-background-highlight-hover: color-mix(in srgb, var(--color-highlight) 60%, transparent);
|
||||
|
||||
--color-waters: #2b2b2b;
|
||||
|
||||
--notch-size: 32px;
|
||||
--notch-size-small: 16px;
|
||||
--notch-size-link: 10px;
|
||||
}
|
||||
|
||||
html {
|
||||
@@ -91,5 +95,31 @@
|
||||
margin-bottom: 8px;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.notched {
|
||||
clip-path: polygon(
|
||||
0% var(--notch-size),
|
||||
var(--notch-size) 0%,
|
||||
calc(100% - var(--notch-size)) 0%,
|
||||
100% var(--notch-size),
|
||||
100% calc(100% - var(--notch-size)),
|
||||
calc(100% - var(--notch-size)) 100%,
|
||||
var(--notch-size) 100%,
|
||||
0% calc(100% - var(--notch-size))
|
||||
);
|
||||
}
|
||||
|
||||
.notched-small {
|
||||
clip-path: polygon(
|
||||
0% var(--notch-size-small),
|
||||
var(--notch-size-small) 0%,
|
||||
calc(100% - var(--notch-size-small)) 0%,
|
||||
100% var(--notch-size-small),
|
||||
100% calc(100% - var(--notch-size-small)),
|
||||
calc(100% - var(--notch-size-small)) 100%,
|
||||
var(--notch-size-small) 100%,
|
||||
0% calc(100% - var(--notch-size-small))
|
||||
);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -22,6 +22,10 @@
|
||||
};
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>denizk0461's website</title>
|
||||
</svelte:head>
|
||||
|
||||
<h1><i>Moin!</i> ~ welcome to my website :)</h1>
|
||||
|
||||
<div class="container">
|
||||
|
||||
@@ -16,6 +16,10 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Projects | denizk0461</title>
|
||||
</svelte:head>
|
||||
|
||||
<BannerTitle title="My Disordered Projects" banner="projects/banner.webp" />
|
||||
|
||||
<p>This is a listing of some of my more noteworthy projects that can be found on the web.</p>
|
||||
|
||||
@@ -1,7 +1,109 @@
|
||||
<script lang="ts">
|
||||
import BannerTitle from "$lib/banner-title.svelte";
|
||||
import type { DevlogPost } from "$lib/devlog-posts";
|
||||
import { posts } from "$lib/devlog-posts";
|
||||
</script>
|
||||
|
||||
<BannerTitle title="Devlog Posts" />
|
||||
<svelte:head>
|
||||
<title>Project N5 Devlog | denizk0461</title>
|
||||
</svelte:head>
|
||||
|
||||
<a href="devlog/20250316">asdasdfasdfsdf</a>
|
||||
<BannerTitle title="Project N5; Development Log" />
|
||||
|
||||
<p>This is the development log for my game <strong>Project N5</strong>! It's an action-adventure jump-and-run game heavily inspired by games such as Ratchet & Clank. Development started on <b>2023-09-16</b>.</p>
|
||||
|
||||
<p>2023 progress updates summarise an entire month's work, respectively. Progress updates thereafter denote noteworthy achievements in a more collected format.</p>
|
||||
|
||||
<div class="post-container">
|
||||
{#each posts as post}
|
||||
{@render devlogPost({post})}
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
|
||||
{#snippet devlogPost({post}: {post: DevlogPost})}
|
||||
<a href="{post.date}/" class="post">
|
||||
{#if post.banner}
|
||||
<img class="post-img notched" src="/projects/projectn5/devlog/{post.date}/{post.banner}">
|
||||
{:else}
|
||||
<img class="post-img notched" src="/projects/projectn5/devlog/previews/{post.date}.webp">
|
||||
{/if}
|
||||
<div class="post-text-container">
|
||||
<p class="post-date">{post.subtitle}</p>
|
||||
<p class="post-title">{post.title}</p>
|
||||
</div>
|
||||
</a>
|
||||
{/snippet}
|
||||
|
||||
<style>
|
||||
.post-container {
|
||||
max-width: 1200px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
|
||||
}
|
||||
|
||||
.post {
|
||||
width: 40%;
|
||||
text-decoration: none;
|
||||
background-color: #00000044;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
padding: 16px;
|
||||
transition: background-color 0.16s ease-in-out;
|
||||
margin: 4px;
|
||||
|
||||
--notch-size-devlog: 40px;
|
||||
clip-path: polygon(
|
||||
0% var(--notch-size-devlog),
|
||||
var(--notch-size-devlog) 0%,
|
||||
calc(100% - var(--notch-size-devlog)) 0%,
|
||||
100% var(--notch-size-devlog),
|
||||
100% calc(100% - var(--notch-size-devlog)),
|
||||
calc(100% - var(--notch-size-devlog)) 100%,
|
||||
var(--notch-size-devlog) 100%,
|
||||
0% calc(100% - var(--notch-size-devlog))
|
||||
);
|
||||
}
|
||||
.post:hover {
|
||||
background-color: var(--color-background-highlight-hover);
|
||||
}
|
||||
|
||||
.post:hover .post-title, .post:hover .post-date {
|
||||
color: var(--color-text-dark);
|
||||
}
|
||||
|
||||
.post-img {
|
||||
width: 150px;
|
||||
height: 120px;
|
||||
margin: 0;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.post-text-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding-left: 24px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.post-date, .post-title {
|
||||
font-family: 'Space Mono', monospace;
|
||||
margin: 4px 0;
|
||||
transition: color 0.16s ease-in-out;
|
||||
}
|
||||
|
||||
.post-date {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.post-title {
|
||||
font-size: 1.3rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
</style>
|
||||
97
src/routes/projects/projectn5/devlog/202309/+page.svelte
Normal file
@@ -0,0 +1,97 @@
|
||||
<script>
|
||||
import BannerTitle from "$lib/banner-title.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>
|
||||
|
||||
<BannerTitle title="Project N5 Progress Update: 2023-09" subtitle="" banner="/projects/projectn5/devlog/previews/202309.webp" />
|
||||
|
||||
<p>My progress in September 2023. Updates are shown in chronological order.</p>
|
||||
|
||||
<TableOfContents />
|
||||
|
||||
<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="/projects/projectn5/devlog/202309/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="/projects/projectn5/devlog/202309/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="/projects/projectn5/devlog/202309/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="/projects/projectn5/devlog/202309/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="/projects/projectn5/devlog/202309/2023-09-23_00.mp4" />
|
||||
<img src="/projects/projectn5/devlog/202309/2023-09-23_01.webp">
|
||||
|
||||
<h2>A Gun</h2>
|
||||
<p>The gun can shoot! Or can it? Well, the bullet doesn't exactly move…</p>
|
||||
<Video src="/projects/projectn5/devlog/202309/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="/projects/projectn5/devlog/202309/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="/projects/projectn5/devlog/202309/2023-09-24_02.mp4" />
|
||||
<img src="/projects/projectn5/devlog/202309/2023-09-24_03.webp">
|
||||
|
||||
<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="/projects/projectn5/devlog/202309/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="/projects/projectn5/devlog/202309/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="/projects/projectn5/devlog/202309/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="/projects/projectn5/devlog/202309/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="/projects/projectn5/devlog/202309/2023-09-30_00.mp4" />
|
||||
|
||||
<h2>Imposing dominance</h2> <!-- get it? -->
|
||||
<img src="/projects/projectn5/devlog/202309/2023-09-29.webp">
|
||||
|
||||
<h2>Learning to Model and Rig a Character</h2>
|
||||
<p>today's task: modelling and rigging a character from scratch</p>
|
||||
<img src="/projects/projectn5/devlog/202309/2023-09-30_01.webp">
|
||||
<p>(Ratchet for scale)</p>
|
||||
<p>whaddya lookin at pinhead</p>
|
||||
<img src="/projects/projectn5/devlog/202309/2023-09-30_02.webp">
|
||||
<p>is it a bird? is it a plane? no, it's arms</p>
|
||||
<img src="/projects/projectn5/devlog/202309/2023-09-30_03.webp">
|
||||
<p>*Mii Maker theme intensifies*</p>
|
||||
<img src="/projects/projectn5/devlog/202309/2023-09-30_04.webp">
|
||||
<p>feet are difficult</p>
|
||||
<img src="/projects/projectn5/devlog/202309/2023-09-30_05.webp">
|
||||
<p>yoooo actually, not half bad</p>
|
||||
<img src="/projects/projectn5/devlog/202309/2023-09-30_06.webp">
|
||||
<p>that one might hurt</p>
|
||||
<img src="/projects/projectn5/devlog/202309/2023-09-30_07.webp">
|
||||
<p>we have a character!!</p>
|
||||
<img src="/projects/projectn5/devlog/202309/2023-09-30_08.webp">
|
||||
<p><i>we've been rigged!</i></p>
|
||||
<Video src="/projects/projectn5/devlog/202309/2023-09-30_09.mp4" />
|
||||
<p><code>we come in peace</code></p>
|
||||
<img src="/projects/projectn5/devlog/202309/2023-09-30_10.webp">
|
||||
<p>brief texture troubles</p>
|
||||
<img src="/projects/projectn5/devlog/202309/2023-09-30_11.webp">
|
||||
<p>my character is now a playable character</p>
|
||||
<img src="/projects/projectn5/devlog/202309/2023-09-30_12.webp">
|
||||
<img src="/projects/projectn5/devlog/202309/2023-09-30_13.webp">
|
||||
66
src/routes/projects/projectn5/devlog/202310/+page.svelte
Normal file
@@ -0,0 +1,66 @@
|
||||
<script>
|
||||
import BannerTitle from "$lib/banner-title.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>
|
||||
|
||||
<BannerTitle title="Project N5 Progress Update: 2023-10" subtitle="" banner="/projects/projectn5/devlog/previews/202310.webp" />
|
||||
|
||||
<p>My progress in October 2023. Updates are shown in chronological order.</p>
|
||||
|
||||
<TableOfContents />
|
||||
|
||||
<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="/projects/projectn5/devlog/202310/2023-10-03_00.mp4" />
|
||||
<p>oops i've had a bit of a tumble</p>
|
||||
<Video src="/projects/projectn5/devlog/202310/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="/projects/projectn5/devlog/202310/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="/projects/projectn5/devlog/202310/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="/projects/projectn5/devlog/202310/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="/projects/projectn5/devlog/202310/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="/projects/projectn5/devlog/202310/2023-10-07_01.webp">
|
||||
<img src="/projects/projectn5/devlog/202310/2023-10-07_02.webp">
|
||||
</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="/projects/projectn5/devlog/202310/2023-10-10_00.webp">
|
||||
<img src="/projects/projectn5/devlog/202310/2023-10-10_01.webp">
|
||||
<img src="/projects/projectn5/devlog/202310/2023-10-10_02.webp">
|
||||
|
||||
<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="/projects/projectn5/devlog/202310/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="/projects/projectn5/devlog/202310/2023-10-22_02.webp">
|
||||
<img src="/projects/projectn5/devlog/202310/2023-10-22_04.webp">
|
||||
<img src="/projects/projectn5/devlog/202310/2023-10-22_05.webp">
|
||||
</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="/projects/projectn5/devlog/202310/2023-10-25_00.mp4" />
|
||||
<Video src="/projects/projectn5/devlog/202310/2023-10-25_01.mp4" />
|
||||
<p>I like my bread with bones, <i>thank you very much.</i></p>
|
||||
<img src="/projects/projectn5/devlog/202310/2023-10-25_02.webp">
|
||||
71
src/routes/projects/projectn5/devlog/202311/+page.svelte
Normal file
@@ -0,0 +1,71 @@
|
||||
<script>
|
||||
import BannerTitle from "$lib/banner-title.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>
|
||||
|
||||
<BannerTitle title="Project N5 Progress Update: 2023-11" subtitle="" banner="/projects/projectn5/devlog/previews/202311.webp" />
|
||||
|
||||
<p>My progress in November 2023. Updates are shown in chronological order.</p>
|
||||
|
||||
<TableOfContents />
|
||||
|
||||
<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="/projects/projectn5/devlog/202311/2023-11-05_00.webp">
|
||||
<img src="/projects/projectn5/devlog/202311/2023-11-03_01.webp">
|
||||
<img src="/projects/projectn5/devlog/202311/2023-11-05_03.webp">
|
||||
</div>
|
||||
<p>Here's an overview of the first model.</p>
|
||||
<Video src="/projects/projectn5/devlog/202311/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="/projects/projectn5/devlog/202311/2023-12-11.webp">
|
||||
<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="/projects/projectn5/devlog/202311/n5blaster_icon.webp">
|
||||
<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="/projects/projectn5/devlog/202311/2023-11-01_01.webp">
|
||||
<img src="/projects/projectn5/devlog/202311/2023-11-01_06.webp">
|
||||
<img src="/projects/projectn5/devlog/202311/2023-11-01_09.webp">
|
||||
</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="/projects/projectn5/devlog/202311/2023-11-06_02.webp">
|
||||
<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="/projects/projectn5/devlog/202311/2023-11-12_04.webp">
|
||||
<img src="/projects/projectn5/devlog/202311/2023-11-12_02.webp">
|
||||
</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="/projects/projectn5/devlog/202311/2023-11-12_00.webp">
|
||||
<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="/projects/projectn5/devlog/202311/2023-11-02_01.webp">
|
||||
|
||||
<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="/projects/projectn5/devlog/202311/2023-11-11_05.webp">
|
||||
<img src="/projects/projectn5/devlog/202311/2023-11-12_01.webp">
|
||||
</div>
|
||||
<p>i love</p>
|
||||
<Video src="/projects/projectn5/devlog/202311/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="/projects/projectn5/devlog/202311/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="/projects/projectn5/devlog/202311/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="/projects/projectn5/devlog/202311/2023-11-25.webp">
|
||||
69
src/routes/projects/projectn5/devlog/202312/+page.svelte
Normal file
@@ -0,0 +1,69 @@
|
||||
<script>
|
||||
import BannerTitle from "$lib/banner-title.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>
|
||||
|
||||
<BannerTitle title="Project N5 Progress Update: 2023-12" subtitle="" banner="/projects/projectn5/devlog/previews/202312.webp" />
|
||||
|
||||
<p>My progress in December 2023. Updates are shown in chronological order.</p>
|
||||
|
||||
<TableOfContents />
|
||||
|
||||
<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="/projects/projectn5/devlog/202312/projectn5-logo-outline.webp">
|
||||
<img src="/projects/projectn5/devlog/202312/hdd.webp">
|
||||
<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="/projects/projectn5/devlog/202312/projectn5-logo-fill-v1.webp">
|
||||
<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="/projects/projectn5/devlog/202312/projectn5-logo-v2.webp">
|
||||
<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="/projects/projectn5/devlog/202312/projectn5-logo-v3.webp">
|
||||
<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="/projects/projectn5/devlog/202312/projectn5-logo-v4.webp">
|
||||
<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="/projects/projectn5/devlog/202312/projectn5-logo-v5.webp">
|
||||
<p>Then I inset the C into the T, creating a neat little cutout effect.</p>
|
||||
<img src="/projects/projectn5/devlog/202312/projectn5-logo-v6.webp">
|
||||
<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="/projects/projectn5/devlog/202312/projectn5-logo-v7.webp">
|
||||
<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="/projects/projectn5/devlog/202312/projectn5-logo-v7-sketch.webp">
|
||||
|
||||
<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="/projects/projectn5/devlog/202312/2023-12-08.webp">
|
||||
|
||||
<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="/projects/projectn5/devlog/202312/2023-12-12_00.webp">
|
||||
<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="/projects/projectn5/devlog/202312/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="/projects/projectn5/devlog/202312/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="/projects/projectn5/devlog/202312/2023-12-12_03.webp">
|
||||
|
||||
<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="/projects/projectn5/devlog/202312/dqt.webp">
|
||||
<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="/projects/projectn5/devlog/202312/simultaneous-animations.mp4" />
|
||||
39
src/routes/projects/projectn5/devlog/20240210/+page.svelte
Normal file
@@ -0,0 +1,39 @@
|
||||
<script>
|
||||
import BannerTitle from "$lib/banner-title.svelte";
|
||||
import Video from "$lib/video.svelte";
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>2024-02-10 | denizk0461</title>
|
||||
</svelte:head>
|
||||
|
||||
<BannerTitle title="Project N5 Progress Update: 2024-02-10" subtitle="" banner="/projects/projectn5/devlog/previews/20240210.webp" />
|
||||
|
||||
<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="/projects/projectn5/devlog/20240210/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="/projects/projectn5/devlog/20240210/sky.webp">
|
||||
<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="/projects/projectn5/devlog/20240210/shadows.webp">
|
||||
<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="/projects/projectn5/devlog/20240210/target.webp">
|
||||
<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="/projects/projectn5/devlog/20240210/quickchange.webp">
|
||||
<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="/projects/projectn5/devlog/20240210/rocketlauncher.webp">
|
||||
<Video src="/projects/projectn5/devlog/20240210/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="/projects/projectn5/devlog/20240210/money.webp">
|
||||
<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="/projects/projectn5/devlog/20240210/vendor.webp">
|
||||
<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>
|
||||
61
src/routes/projects/projectn5/devlog/20240312/+page.svelte
Normal file
@@ -0,0 +1,61 @@
|
||||
<script>
|
||||
import BannerTitle from "$lib/banner-title.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>
|
||||
|
||||
<BannerTitle title="Project N5 Progress Update: 2024-03-12" subtitle="" banner="/projects/projectn5/devlog/previews/20240312.webp" />
|
||||
|
||||
<TableOfContents />
|
||||
|
||||
<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="/projects/projectn5/devlog/20240312/titlescreen.webp">
|
||||
|
||||
<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="/projects/projectn5/devlog/20240312/arena.webp">
|
||||
<div class="image-subtitle-container">
|
||||
<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>
|
||||
</div>
|
||||
<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="/projects/projectn5/devlog/20240312/arena-terminal.webp">
|
||||
|
||||
<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="/projects/projectn5/devlog/20240312/shoulder.webp">
|
||||
<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="/projects/projectn5/devlog/20240312/overview.webp">
|
||||
<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="/projects/projectn5/devlog/20240312/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="/projects/projectn5/devlog/20240312/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="/projects/projectn5/devlog/20240312/sketches.webp">
|
||||
<div class="image-subtitle-container">
|
||||
<span class="image-subtitle">don't judge</span>
|
||||
</div>
|
||||
|
||||
<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="/projects/projectn5/devlog/20240312/kanban.webp">
|
||||
<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="/projects/projectn5/devlog/20240312/alone.webp">
|
||||
<div class="image-subtitle-container">
|
||||
<span class="image-subtitle">staring longingly into the sunset</span>
|
||||
</div>
|
||||
136
src/routes/projects/projectn5/devlog/20240323/+page.svelte
Normal file
@@ -0,0 +1,136 @@
|
||||
<script>
|
||||
import BannerTitle from "$lib/banner-title.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>
|
||||
|
||||
<BannerTitle title="Project N5 Progress Update: 2024-03-23" subtitle="" banner="/projects/projectn5/devlog/previews/20240323.webp" />
|
||||
|
||||
<TableOfContents />
|
||||
|
||||
<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="/projects/projectn5/devlog/20240323/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="/projects/projectn5/devlog/20240323/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="/projects/projectn5/devlog/20240323/high.mp4" />
|
||||
|
||||
<p>After tweaking the speed, I got some nice attracted collectibles.</p>
|
||||
<Video src="/projects/projectn5/devlog/20240323/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="/projects/projectn5/devlog/20240323/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="/projects/projectn5/devlog/20240323/explosion_0.mp4" />
|
||||
<div class="image-subtitle-container">
|
||||
<span class="image-subtitle">boom</span>
|
||||
</div>
|
||||
|
||||
<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="/projects/projectn5/devlog/20240323/joltsettings.webp">
|
||||
|
||||
<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="/projects/projectn5/devlog/20240323/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="/projects/projectn5/devlog/20240323/explosion_test.mp4" />
|
||||
|
||||
<Video src="/projects/projectn5/devlog/20240323/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="/projects/projectn5/devlog/20240323/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="/projects/projectn5/devlog/20240323/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="/projects/projectn5/devlog/20240323/venom_front.webp">
|
||||
<img src="/projects/projectn5/devlog/20240323/venom_back.webp">
|
||||
|
||||
<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="/projects/projectn5/devlog/20240323/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="/projects/projectn5/devlog/20240323/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="/projects/projectn5/devlog/20240323/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="/projects/projectn5/devlog/20240323/firstperson.webp">
|
||||
|
||||
<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="/projects/projectn5/devlog/20240323/unity_overview.webp">
|
||||
103
src/routes/projects/projectn5/devlog/20240324/+page.svelte
Normal file
@@ -0,0 +1,103 @@
|
||||
<script>
|
||||
import BannerTitle from "$lib/banner-title.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>
|
||||
|
||||
<BannerTitle title="Project N5 Progress Update: 2024-03-24" subtitle="The Arena Update" banner="/projects/projectn5/devlog/previews/20240324.webp" />
|
||||
|
||||
<TableOfContents />
|
||||
|
||||
<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="/projects/projectn5/devlog/20240324/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="/projects/projectn5/devlog/20240324/suzannecylinder.webp">
|
||||
|
||||
<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="/projects/projectn5/devlog/20240324/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="/projects/projectn5/devlog/20240324/lookingup.webp">
|
||||
<div class="image-subtitle-container">
|
||||
<span class="image-subtitle">send help</span>
|
||||
</div>
|
||||
|
||||
<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>
|
||||
90
src/routes/projects/projectn5/devlog/20240401/+page.svelte
Normal file
@@ -0,0 +1,90 @@
|
||||
<script>
|
||||
import BannerTitle from "$lib/banner-title.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>
|
||||
|
||||
<BannerTitle title="Project N5 Progress Update: 2024-04-01" subtitle="The Behind-the-Scenes Update" banner="/projects/projectn5/devlog/previews/20240401.webp" />
|
||||
|
||||
<TableOfContents />
|
||||
|
||||
<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 image of an untextured work-in-progress 3D model of a blaster" src="/projects/projectn5/devlog/20240401/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="/projects/projectn5/devlog/20240401/dual_venom_sketch.webp">
|
||||
<img alt="A crude sketch of a blaster resembling the 3D model shown above." src="/projects/projectn5/devlog/20240401/venom_sketch.webp">
|
||||
</div>
|
||||
|
||||
<p>The bolt visible in the first sketch actually makes me consider using <a href="../20240323/#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="/projects/projectn5/devlog/20240401/n5-glow.mp4" />
|
||||
<img alt="An image of the N5 Blaster. Its lights are turned off, and the icosphere in the middle is dimly glowing." src="/projects/projectn5/devlog/20240401/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>
|
||||
34
src/routes/projects/projectn5/devlog/20240713/+page.svelte
Normal file
@@ -0,0 +1,34 @@
|
||||
<script>
|
||||
import BannerTitle from "$lib/banner-title.svelte";
|
||||
import Video from "$lib/video.svelte";
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>The WHERE HAVE I BEEN?? Update | denizk0461</title>
|
||||
</svelte:head>
|
||||
|
||||
<BannerTitle title="Project N5 Progress Update: 2024-07-13" subtitle="The WHERE HAVE I BEEN?? Update" banner="/projects/projectn5/devlog/previews/20240713.webp" />
|
||||
|
||||
<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="/projects/projectn5/devlog/20240713/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="/projects/projectn5/devlog/20240713/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>
|
||||
87
src/routes/projects/projectn5/devlog/20241012/+page.svelte
Normal file
@@ -0,0 +1,87 @@
|
||||
<script>
|
||||
import BannerTitle from "$lib/banner-title.svelte";
|
||||
import TableOfContents from "$lib/table-of-contents.svelte";
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>The Returnal Update | denizk0461</title>
|
||||
</svelte:head>
|
||||
|
||||
<BannerTitle title="Project N5 Progress Update: 2024-10-12" subtitle="The Returnal Update" banner="/projects/projectn5/devlog/previews/20241012.webp" />
|
||||
|
||||
<TableOfContents />
|
||||
|
||||
<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/20240713/">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="/projects/projectn5/devlog/20241012/cone.webp">
|
||||
|
||||
<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="/projects/projectn5/devlog/20241012/aim_helper.webp">
|
||||
|
||||
<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="/projects/projectn5/devlog/20241012/n5-blaster-icon.webp">
|
||||
<img src="/projects/projectn5/devlog/20241012/n5-bomb-launcher-icon.webp">
|
||||
</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="/projects/projectn5/devlog/20241012/ammo.webp">
|
||||
|
||||
<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>
|
||||
147
src/routes/projects/projectn5/devlog/20241103/+page.svelte
Normal file
@@ -0,0 +1,147 @@
|
||||
<script>
|
||||
import BannerTitle from "$lib/banner-title.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>
|
||||
|
||||
<BannerTitle title="Project N5 Progress Update: 2024-11-03" subtitle="The Visual Update" banner="/projects/projectn5/devlog/20241103/101-comparison.webp" />
|
||||
|
||||
<TableOfContents />
|
||||
|
||||
<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="/projects/projectn5/devlog/20241103/node_chain.webp">
|
||||
|
||||
<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="/projects/projectn5/devlog/20241103/sky.webp">
|
||||
|
||||
<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/20241012/#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="/projects/projectn5/devlog/20241103/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="/projects/projectn5/devlog/20241103/planet-mine.webp">
|
||||
|
||||
<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="/projects/projectn5/devlog/20241103/101-comparison.webp">
|
||||
<div class="image-subtitle-container">
|
||||
<span class="image-subtitle">left: new, right: old</span>
|
||||
</div>
|
||||
|
||||
<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="/projects/projectn5/devlog/20241103/101-profile.webp">
|
||||
|
||||
<h2 id="canister">Need Some Ammo?</h2>
|
||||
|
||||
<p>After I introduced a <a href="/projects/projectn5/devlog/20241012/#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="/projects/projectn5/devlog/20241103/canister.webp">
|
||||
|
||||
<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="/projects/projectn5/devlog/20241103/102-profile.webp">
|
||||
|
||||
<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="/projects/projectn5/devlog/20241103/102-explosion.webp">
|
||||
|
||||
<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="/projects/projectn5/devlog/202309/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>
|
||||
101
src/routes/projects/projectn5/devlog/20241127/+page.svelte
Normal file
@@ -0,0 +1,101 @@
|
||||
<script>
|
||||
import BannerTitle from "$lib/banner-title.svelte";
|
||||
import TableOfContents from "$lib/table-of-contents.svelte";
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>The Making of a Protagonist, Part I | denizk0461</title>
|
||||
</svelte:head>
|
||||
|
||||
<BannerTitle title="Project N5 Progress Update: 2024-11-27" subtitle="The Making of a Protagonist, Part I" banner="/projects/projectn5/devlog/20241127/hands.webp" />
|
||||
|
||||
<TableOfContents />
|
||||
|
||||
<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="/projects/projectn5/devlog/20241127/laura-overview.webp">
|
||||
<img src="/projects/projectn5/devlog/20241127/laura-topology.webp">
|
||||
</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>
|
||||
139
src/routes/projects/projectn5/devlog/20241222/+page.svelte
Normal file
@@ -0,0 +1,139 @@
|
||||
<script>
|
||||
import BannerTitle from "$lib/banner-title.svelte";
|
||||
import TableOfContents from "$lib/table-of-contents.svelte";
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>The Making of a Protagonist, Part II | denizk0461</title>
|
||||
</svelte:head>
|
||||
|
||||
<BannerTitle title="Project N5 Progress Update: 2024-12-22" subtitle="The Making of a Protagonist, Part II" banner="/projects/projectn5/devlog/20241222/laura-header.webp" />
|
||||
|
||||
<p>I have lots progress to share!!</p>
|
||||
|
||||
<TableOfContents />
|
||||
|
||||
<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="/projects/projectn5/devlog/20241127/laura-overview.webp">
|
||||
<img src="/projects/projectn5/devlog/20241222/laura.webp">
|
||||
</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="/projects/projectn5/devlog/20241222/laura-young.webp">
|
||||
|
||||
<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="/projects/projectn5/devlog/20241222/laura-hair-flat-1.webp">
|
||||
<img src="/projects/projectn5/devlog/20241222/laura-hair-flat-2.webp">
|
||||
<img src="/projects/projectn5/devlog/20241222/laura-hair-flat-3.webp">
|
||||
</div>
|
||||
|
||||
<div class="horizontally-centre-aligned">
|
||||
<img src="/projects/projectn5/devlog/20241222/laura-hair-flat-4.webp">
|
||||
<img src="/projects/projectn5/devlog/20241222/laura-hair-flat-5.webp">
|
||||
<img src="/projects/projectn5/devlog/20241222/laura-hair-flat-6.webp">
|
||||
</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="/projects/projectn5/devlog/20241222/laura-hair-curves.webp">
|
||||
<img src="/projects/projectn5/devlog/20241222/laura-hair-curves-2.webp">
|
||||
</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="/projects/projectn5/devlog/20241222/laura-hair-flat-new-2.webp">
|
||||
<img src="/projects/projectn5/devlog/20241222/laura-hair-flat-new-3.webp">
|
||||
</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="/projects/projectn5/devlog/20241222/arm.webp">
|
||||
|
||||
<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="/projects/projectn5/devlog/20241222/deform-1.webp">
|
||||
<img src="/projects/projectn5/devlog/20241222/deform-2.webp">
|
||||
</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="/projects/projectn5/devlog/20241222/retiree.webp">
|
||||
101
src/routes/projects/projectn5/devlog/20250203/+page.svelte
Normal file
@@ -0,0 +1,101 @@
|
||||
<script>
|
||||
import BannerTitle from "$lib/banner-title.svelte";
|
||||
import TableOfContents from "$lib/table-of-contents.svelte";
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>The Making of a Protagonist, Part III | denizk0461</title>
|
||||
</svelte:head>
|
||||
|
||||
<BannerTitle title="Project N5 Progress Update: 2025-02-03" subtitle="The Making of a Protagonist, Part III" banner="/projects/projectn5/devlog/20250203/lauras-imposing.webp" />
|
||||
|
||||
<TableOfContents />
|
||||
|
||||
<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="/projects/projectn5/devlog/20250203/../20241222/laura-hair-flat-new-3.webp">
|
||||
<img src="/projects/projectn5/devlog/20250203/laura-head-new.webp">
|
||||
</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="/projects/projectn5/devlog/20250203/laura-uv.webp">
|
||||
|
||||
<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="/projects/projectn5/devlog/20250203/earrings.webp">
|
||||
|
||||
<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="../20241222/#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="/projects/projectn5/devlog/20250203/laura-shader-inengine.webp">
|
||||
|
||||
<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="/projects/projectn5/devlog/20250203/ok.webp">
|
||||
<img src="/projects/projectn5/devlog/20250203/dance.webp">
|
||||
<img src="/projects/projectn5/devlog/20250203/naruto.webp">
|
||||
</div>
|
||||
<div class="horizontally-centre-aligned">
|
||||
<img src="/projects/projectn5/devlog/20250203/shock.webp">
|
||||
<img src="/projects/projectn5/devlog/20250203/reprehension.webp">
|
||||
<img src="/projects/projectn5/devlog/20250203/disgust.webp">
|
||||
</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>
|
||||
@@ -4,6 +4,10 @@
|
||||
import Video from "$lib/video.svelte";
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Refactoring | denizk0461</title>
|
||||
</svelte:head>
|
||||
|
||||
<BannerTitle title="Project N5 Progress Update: 2025-03-16" subtitle="Refactoring" banner="/projects/projectn5/devlog/20250316/fishmonger.webp" />
|
||||
|
||||
<TableOfContents />
|
||||
@@ -91,10 +95,14 @@
|
||||
<h3 id="weapon-icons">Please Appreciate These Wonderful Temporary Weapon Icons</h3>
|
||||
|
||||
<div class="horizontally-centre-aligned">
|
||||
<img src="/projects/projectn5/devlog/20250316/104-icon.webp">
|
||||
<img src="/projects/projectn5/devlog/20250316/106-icon.webp">
|
||||
<img src="/projects/projectn5/devlog/20250316/107-icon.webp">
|
||||
<img src="/projects/projectn5/devlog/20250316/108-icon.webp">
|
||||
<img src="
|
||||
/projects/projectn5/devlog/20250316/104-icon.webp">
|
||||
<img src="
|
||||
/projects/projectn5/devlog/20250316/106-icon.webp">
|
||||
<img src="
|
||||
/projects/projectn5/devlog/20250316/107-icon.webp">
|
||||
<img src="
|
||||
/projects/projectn5/devlog/20250316/108-icon.webp">
|
||||
</div>
|
||||
|
||||
<h2 id="code">Grand Code Overhaul</h2>
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
export interface DevlogPost {
|
||||
title: string;
|
||||
date: Date;
|
||||
imgSrc: string;
|
||||
};
|
||||
|
||||
export const posts: DevlogPost[] = [
|
||||
{
|
||||
title: "title",
|
||||
date: new Date("2025-01-01"),
|
||||
imgSrc: "",
|
||||
},
|
||||
{
|
||||
title: "titasdfle",
|
||||
date: new Date("2025-02-03"),
|
||||
imgSrc: "",
|
||||
},
|
||||
{
|
||||
title: "titl435345e",
|
||||
date: new Date("2025-01-01"),
|
||||
imgSrc: "",
|
||||
},
|
||||
];
|
||||
BIN
static/projects/projectn5/devlog/previews/202309.webp
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
static/projects/projectn5/devlog/previews/202310.webp
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
static/projects/projectn5/devlog/previews/202311.webp
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
static/projects/projectn5/devlog/previews/202312.webp
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
static/projects/projectn5/devlog/previews/20240210.webp
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
static/projects/projectn5/devlog/previews/20240312.webp
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
static/projects/projectn5/devlog/previews/20240323.webp
Normal file
|
After Width: | Height: | Size: 353 KiB |
BIN
static/projects/projectn5/devlog/previews/20240324.webp
Normal file
|
After Width: | Height: | Size: 65 KiB |
BIN
static/projects/projectn5/devlog/previews/20240401.webp
Normal file
|
After Width: | Height: | Size: 8.9 KiB |
BIN
static/projects/projectn5/devlog/previews/20240713.webp
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
static/projects/projectn5/devlog/previews/20241012.webp
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
static/projects/projectn5/devlog/previews/20241103.webp
Normal file
|
After Width: | Height: | Size: 32 KiB |