From 50b7737df545aa0f8a1631f41d86adf2f4f1e392 Mon Sep 17 00:00:00 2001 From: rowan Date: Tue, 3 Dec 2024 15:15:45 -0600 Subject: [PATCH] formatting changes and stuff :3 --- content/blog/45dr-postmortem/index.md | 2 -- .../blog/a-query-about-game-state/index.md | 28 +++++++++++++------ content/blog/a-roxy-update/index.md | 2 -- .../blog/convenient-unity-attributes/index.md | 2 -- .../index.md | 1 - .../simplifying-code-with-components/index.md | 2 -- layouts/post.html | 18 +++++++++--- package.json | 5 ++-- static/css/main.css | 5 ++++ dev => watch | 0 10 files changed, 42 insertions(+), 23 deletions(-) rename dev => watch (100%) diff --git a/content/blog/45dr-postmortem/index.md b/content/blog/45dr-postmortem/index.md index 086eb06..4db1cbd 100644 --- a/content/blog/45dr-postmortem/index.md +++ b/content/blog/45dr-postmortem/index.md @@ -2,8 +2,6 @@ {% import "../../../layouts/macros.html" as macros %} {% block article %} -# 45 Day Rogulike Postmortem - I worked on a Roguelike game from 8 March 2022 to 22 April 2022. My motivations were to teach myself new things, develop my existing skills, and have fun with the development process. Two out of three isn't bad. [Give it a try.](https://mochancrimthann.itch.io/45dr) Starting a new project is always exciting, so I put in many hours in the first couple of weeks. There's no shortage of inspiring roguelike games, but most of my inspiration was directly from [DCSS](https://crawl.develz.org/). I completed procedural generation, movement, tile visibility, combat, items, enemy AI, and a character controller within the first week and a half. Most of the development was straightforward to reason. I decided early in development to create a new component for each feature to avoid breaking previous ones. Nothing drains my motivation like a week-long bug-fixing marathon. diff --git a/content/blog/a-query-about-game-state/index.md b/content/blog/a-query-about-game-state/index.md index d5d04b9..75fef39 100644 --- a/content/blog/a-query-about-game-state/index.md +++ b/content/blog/a-query-about-game-state/index.md @@ -1,7 +1,6 @@ {% extends "../../../layouts/post.html" %} {% block article %} -# A Query about Game State ## Preface I'm an indie game dev that has an interest in making tools that I think would improve my life as a game developer in the hopes that it can help others. I'm not an expert in any of the topics that this article covers. I have no formal education in game engine development or architecture, systems programming, or anything else. I went to university for Computer Science with a specialization in game design & development when I was in my early 20s and the only thing I learned is that there are better ways to spend tens of thousands of dollars. @@ -39,7 +38,7 @@ Seasoned game devs, disciplined object-oriented programmers, and existing ECS de How do we add a Spiked Shield item -- one which derives the behaviors of `Weapon` and `Armor`? If we were using a language which supports multiple inheritance this could potentially be a nonissue: except that multiple inheritance is often [purposefully missing](https://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem) in many languages. We could decide that the item belongs more to one class than the other and just duplicate the missing behavior but these types of decisions often introduce unforeseen complexity: will the damage algorithm need to do a specific type check for `SpikedShield`? What about the equipment screen? And of course, what happens when we need to implement a damaging potion? -Perhaps the most appropriate solution this case would be to forgo the inheritance pattern in favor of [composition](https://en.wikipedia.org/wiki/Composition_over_inheritance). In C#, this could be achieved with interfaces and default implementations. +Perhaps the most appropriate solution for this case would be to forgo the inheritance pattern in favor of [composition](https://en.wikipedia.org/wiki/Composition_over_inheritance). In C#, this could be achieved with interfaces and default implementations. ```cs interface ICollectable { @@ -80,12 +79,17 @@ public class DamageEventArgs : EventArgs { public readonly float Value; } -public delegate void DamageEventHandler(object sender, DamageEventArgs args); +// only one of these should exist and should be globally +// accessible so we make it a singleton +class DamageEvent { + private static readonly DamageEvent instance = new Instance(); + public static DamageEvent Instance => instance; -class DamageEventQueue { private PriorityQueue queue = new(); - private void OnHandleDamageEvent(object sender, DamageEventArgs args) { + private void Raise(DamageEventArgs args) { + // before enqueuing, determine the priority + // based on the object dealing damage var priority = args.Source switch { Player => 2, Enemy => 1, @@ -96,18 +100,26 @@ class DamageEventQueue { } private void OnTick(float deltaTime) { + // for simplicity we'll dequeue everything each frame + // and pass it to the damage handler while(queue.TryDequeue(out var e, out int priority)) { e.Source.ApplyDamage(e.Target, e.Value); } } } -DamageEvent.Invoke(this, new DamageEventArgs(bossEnemy, player, 10)); -DamageEvent.Invoke(this, new DamageEventArgs(player, bossEnemy, 10)); +// bossEnemy's damage should be processed after player's damage +// if they're raised during the same frame +DamageEvent.Raise(new DamageEventArgs(bossEnemy, player, 10)); +DamageEvent.Raise(new DamageEventArgs(player, bossEnemy, 10)); ``` -There's a lot of issues with this code that I'm going to pretend were deliberate decisions for brevity. The point of this example is to show that we can ingest events and sort them arbitrarily based on the requirements of our games. We've made a step in the right direction by identifying a need to explicitly order these events. Even if this implementation isn't ideal, it properly encodes the requirements of the design (ie. player damage should be processed before all other types). +There's a lot of issues with this code that I'm going to pretend were deliberate decisions for brevity. The point of this example is to show that we can ingest events and sort them arbitrarily based on the requirements of the game. We've made a step in the right direction by identifying a need to explicitly order these events. Even if this implementation isn't ideal, it properly encodes the requirements of the design (ie. player damage should be processed before all other types). + +There is still a timing issue with this approach however. Events can be raised at any point: before, during, or after `DamageEvent` queue has already done its work for the frame. If `bossEnemy` raises its damage event before `DamageEvent` processes its queue but `player` raises their event after, we still have the original issue. + +Depending on the engine and implementation, there may be a few options for solving this. Rather than using `OnTick`, the damage can be handled in `OnLateTick` which runs after all `OnTick` systems have been processed (Unity's version of these methods are `Update` and `LateUpdate`). In Unity the `DamageEvent` singleton script could have its order explicitly modified in the settings or with the `DefaultExecutionOrder` attribute. In Godot, this would likely be resolved by moving the `DamageEvent` node lower in the tree since nodes are processed from top to bottom while resolving children first. ## In search of loot Managing game state is difficult. As a game grows, so too does the amount of objects active at any given time. Dozens, hundreds, or even thousands of entities each with their own behaviors, goals, and concerns that interact with each other in different ways. This explosion in complexity can be exceedingly hard to manage even in games that are small in scope. Games, even at their simplest, tend to be *highly* complex. diff --git a/content/blog/a-roxy-update/index.md b/content/blog/a-roxy-update/index.md index 665d72e..780ea64 100644 --- a/content/blog/a-roxy-update/index.md +++ b/content/blog/a-roxy-update/index.md @@ -1,8 +1,6 @@ {% extends "../../../layouts/post.html" %} {% block article %} -# A Roxy Update - I released a new version of Roxy over at [fem.mint.lgbt](https://fem.mint.lgbt/kitsunecafe/roxy-cli). I've been working on it for a few months now, one part because it's more complex than the original, and another part because I had to learn a lot. I want to make a quick rundown of the changes. ## Philosophy diff --git a/content/blog/convenient-unity-attributes/index.md b/content/blog/convenient-unity-attributes/index.md index a39e423..7079236 100644 --- a/content/blog/convenient-unity-attributes/index.md +++ b/content/blog/convenient-unity-attributes/index.md @@ -2,8 +2,6 @@ {% import "../../../layouts/macros.html" as macros %} {% block article %} -# Convenient Unity Attributes - Unity offers a range of convenient ways to manipulate and hack its inspector. Unfortunately, thanks to the size of Unity's documentation, these types of methods go unnoticed. I won't attempt to iterate every useful attribute in Unity's library. I encourage you to explore Unity's documentation. diff --git a/content/blog/making-a-static-site-generator-also-a-new-site/index.md b/content/blog/making-a-static-site-generator-also-a-new-site/index.md index 47d3658..0388011 100644 --- a/content/blog/making-a-static-site-generator-also-a-new-site/index.md +++ b/content/blog/making-a-static-site-generator-also-a-new-site/index.md @@ -1,7 +1,6 @@ {% extends "../../../layouts/post.html" %} {% block article %} -# Making a Static Site Generator (Also a New Site) I decided to give my site a much-needed redesign, so in the spirit of making things harder than they need to be, I decided to make a static site generator. You might see "Made with Roxy" at the bottom of this page (unless you're reading this so far in the future that I've changed it again). Roxy is what I've decided to call this generator. I wanted to write a little about my experiences creating it. ## The Plan diff --git a/content/blog/simplifying-code-with-components/index.md b/content/blog/simplifying-code-with-components/index.md index 0286030..1ea0dbc 100644 --- a/content/blog/simplifying-code-with-components/index.md +++ b/content/blog/simplifying-code-with-components/index.md @@ -1,8 +1,6 @@ {% extends "../../../layouts/post.html" %} {% block article %} -# Simplifying Code with Components - Unity is a component-based game engine. Without any context, "component" is a nebulous and vague term. Understanding what a component *is* becomes crucial to understanding Unity. In Unity's [Introduction to components](https://docs.unity3d.com/Manual/Components.html), they provide an unsatisfactory definition of a component. > Components define the behaviour of that GameObject. diff --git a/layouts/post.html b/layouts/post.html index d8058ef..313fdae 100644 --- a/layouts/post.html +++ b/layouts/post.html @@ -1,7 +1,17 @@ {% extends "page.html" %} {% block content %} - {% block article %} - {% endblock %} -{% endblock %} - +{% set date_format = "%d %B, %Y" %} +
+
+

{{ this.title }}

+ + + +
+ {% block article %} + {% endblock %} +
+{% endblock %} \ No newline at end of file diff --git a/package.json b/package.json index 4e713e7..07caa95 100644 --- a/package.json +++ b/package.json @@ -5,8 +5,9 @@ "scripts": { "copy:static": "ln -sfn $(realpath static) dist/static 2>/dev/null", "build": "roxy_cli content dist && npm run copy:static", - "watch": "./dev", - "dev": "npm run build && npm run watch & wrangler pages dev --live-reload && fg", + "watch": "./watch", + "serve": "wrangler pages dev --live-reload", + "dev": "parallel -u -j3 \"npm run\" ::: build watch serve", "deploy": "wrangler pages deploy --project-name kitsunecafe" }, "keywords": [], diff --git a/static/css/main.css b/static/css/main.css index ace1be3..4f9dfbf 100644 --- a/static/css/main.css +++ b/static/css/main.css @@ -152,6 +152,11 @@ nav li::before { content: ''; } +article header { + margin-top: 1rem; + margin-bottom: 1rem; +} + @media only screen and (min-width: 740px) { nav.main-nav { flex-direction: column; diff --git a/dev b/watch similarity index 100% rename from dev rename to watch