From 515a0cb0b538da679d359b6644b41934f779727d Mon Sep 17 00:00:00 2001 From: Gabriel Kaszewski Date: Thu, 20 Aug 2026 02:08:09 +0200 Subject: [PATCH] feat: remove "Beyond 'It Works'" post to streamline content --- posts/beyond-it-works.mdx | 172 -------------------------------------- 1 file changed, 172 deletions(-) delete mode 100644 posts/beyond-it-works.mdx diff --git a/posts/beyond-it-works.mdx b/posts/beyond-it-works.mdx deleted file mode 100644 index bad5760..0000000 --- a/posts/beyond-it-works.mdx +++ /dev/null @@ -1,172 +0,0 @@ ---- -title: "Beyond 'It Works': A Deep Dive into Game Jam Architecture" -date: "2025-09-04" -description: "Exploring the importance of good architecture in game jams and how it can lead to powerful features like modding support." ---- - -# Beyond "It Works": A Deep Dive into Game Jam Architecture - -## The Countdown Begins - -The timer starts. 48 hours. That seems like a lot of time, but when you have a goal at the end, it turns into a frantic sprint. The theme is announced: **"Your cure is your curse."** My mind draws a blank. Tick... tock... A mix of excitement and a little bit of panic takes over. - -Every game jam begins this way for me. It’s a mad dash from a single idea to a playable _thing_. But amidst the chaos, there’s a method. Over several jams, I’ve developed a personal playbook for turning that panic into a product. In this post, I’m going to pull back the curtain on my process, focusing on the backbone of it all: the **code**, the **structure**, and the **composition** that holds the game together. - ---- - -## My Golden Rule: Scope, Scope, and Scope It Down Again - -Before I write a single line of code, I have to talk about the most critical skill in a game jam: **managing scope**. - -You're not going to complete your entry if you try to recreate _World of Warcraft_. Your idea must be small enough to be completed and polished in about **60%** of the allotted time. The other **40%** will be devoured by bugs, unforeseen problems (like exporting builds—web builds take a _really_ long time, apparently), and the desperate need for sleep. Every technical decision I make is guided by this principle. - ---- - -## The "Just Make it Work!" Counter-Argument - -This summer, I started doing game jams with my friends. The goal was simple: actually finish and release small games. I've now managed to release two ([Broberry](https://gabrielkaszewski.itch.io/broberry) and [Parasitic God](https://gabrielkaszewski.itch.io/parasitic-god)) and, in the process, I've found my own development rhythm. My mindset is always to keep the code as clean and maintainable as possible, even under pressure. - -This approach isn't always popular. - -When I talk to my friends, they often say, "Proper architecture takes too much time! Players don't care about code; they care about the game." They have a point. A beautiful codebase is worthless if you don't have a game to show for it. - -But here’s my counter-argument: **good architecture doesn't slow you down; it speeds you up.** A clean, modular structure isn't a chore. It's a powerful tool that allows you to iterate, debug, and add features faster than you could with messy "spaghetti code." - -Let me show you how. - ---- - -## My Process: From Theme to Systems - -When the theme drops, I spend a few minutes thinking about what kind of game I want to create. Once I have a rough idea, I immediately start thinking about the **systems**. What modular pieces will I need? Can I build a weapon system where I can easily create a sword that deals poison damage or a gun that shoots healing bullets? - -Thinking in terms of systems and reusable parts is the key. This naturally leads to my favorite design pattern for game development. - -### My Secret Weapon: Building with LEGOs (Composition) - -In programming, there's a principle: **"prefer composition over inheritance."** In a game jam, I treat this as law. For those who aren't familiar with the terms, here's a quick breakdown. - -#### The Inheritance Trap - -Inheritance is what we're often taught first. It's an "**is-a**" relationship. A `Cat` **is an** `Animal`. A `Dog` **is an** `Animal`. This creates a rigid family tree. - -```csharp -// The "is-a" relationship -public class Dog : Animal { ... } -``` - -This works for simple things, but it falls apart with complex game mechanics. Let's use a weapon example. You might start with this: - -```csharp -public class Weapon { ... } -public class MeleeWeapon : Weapon { ... } -public class RangedWeapon : Weapon { ... } -``` - -Easy, right? But now you want a **sword that also shoots projectiles**. Uh oh. Does it inherit from `MeleeWeapon` or `RangedWeapon`? What if you want a **gun that sets enemies on fire**? Do you make a `FieryRangedWeapon` class? What about a **healing, fiery, projectile-shooting sword**? - -You end up in a tangled mess of classes. This is the inheritance trap, and it's a nightmare under a 48-hour time limit. - -#### The Composition Solution: Think LEGOs - -Composition is a "**has-a**" relationship. Instead of saying an object _is_ something, you say it _has_ functionalities. - -Think of a `GameObject` in Unity or a `Node` in Godot as a single LEGO brick. On its own, it does nothing. The magic happens when you start snapping other bricks—**components**—onto it. A "weapon" in my game isn't a complex class; it's an empty object that **has** a collection of scripts defining its behavior. - -Let's rebuild our crazy weapon idea with composition: - -- We create small, single-purpose scripts (our LEGOs): - - `DealDamageOnHit.cs`: **Has** a damage value. - - `SwingAttack.cs`: **Has** a swing animation. - - `ShootProjectile.cs`: **Has** a bullet prefab. - - `ApplyFireEffect.cs`: **Has** a burn duration. - -Now, we can build any weapon just by mixing and matching: - -- **Simple Sword**: `GameObject` + `DealDamageOnHit.cs` + `SwingAttack.cs` -- **Flamethrower**: `GameObject` + `DealDamageOnHit.cs` + `ShootProjectile.cs` + `ApplyFireEffect.cs` - -Suddenly, you're not writing new classes; you're just assembling new objects. It’s fast, flexible, and exactly what you need when the clock is ticking. - ---- - -## The Payoff: Modding Support for Free - -So, what’s the ultimate benefit of this LEGO-based approach? You get powerful features that seem impossible in a 48-hour jam. For my game _Parasitic God_, this architecture meant I could implement a full-blown **modding system** with very little extra effort. - -It wasn't a feature I planned for. It was a natural, almost free, consequence of the data-driven design I had already built. - -### The Core Idea: Game Content is Just Data - -The central principle is that the "things" in my game—miracles, events, and upgrades—are not hardcoded. They're defined in simple **JSON text files**. - -The C# code is just an **engine** that reads and interprets that data. My `GameLogic.cs` doesn’t know what a "Miracle of Growth" is; it only knows how to process a list of abstract `Effect` resources. This separation is what unlocks modding. - -It’s built on three pillars: - -#### Pillar 1: JSON as the Blueprint - -Instead of coding a miracle's properties, I define its structure in a "Data Transfer Object" (DTO) like `MiracleDto.cs`. This means anyone can define a new miracle in a simple `.json` file—no compiler needed. - -```json -{ - "Name": "Gift of Life", - "FaithCost": 25.0, - "Effects": [ - { - "Type": "AddResource", - "TargetResource": "Followers", - "Value": 50.0 - } - ] -} -``` - -#### Pillar 2: The Universal Loader - -The game's `MiracleLoader.cs` finds and loads these JSON files. The trick is that it looks in two places: the game's internal `res://` directory for my default files and the player's special `user://` data folder for mods. The loader code simply loads the defaults and then loads the user's mods, allowing players to add new content or overwrite existing files. - -```csharp -// From Core/MiracleLoader.cs -public static Dictionary LoadAllMiracles() -{ - var loadedMiracles = new Dictionary(); - - // 1. Load the default game content - LoadMiraclesFromPath("res://Mods/Miracles", loadedMiracles); - - // 2. Load the user's mods, overwriting defaults if names match - LoadMiraclesFromPath("user://Mods/Miracles", loadedMiracles); - - return loadedMiracles; -} -``` - -#### Pillar 3: The Reusable LEGOs (Effect System) - -This is where it all ties back to composition. How can a JSON file actually _do_ things? The `"Effects"` array in the JSON is a list of commands. Each command tells my C# engine which LEGO brick to use. The `MiracleLoader.cs` reads the `"Type"` string (e.g., `"AddResource"`) and creates an instance of the corresponding C# `Effect` class. - -A modder can create a complex new miracle—modifying stats, applying buffs, and unlocking other content—all without writing a single line of C# code. They just assemble the available `Effect` LEGOs in a JSON file. - ---- - -## The Final Result & What's Next - -This system is the ultimate proof that good architecture pays for itself. The time I spent separating data from logic wasn’t a detour; it was a direct path to a more robust, flexible, and feature-rich game. - -So when my friends say, “Just make it work,” I say, “Let’s make it work _right_.” Because sometimes, working right from the beginning means you get incredible features like a modding system, not as a massive time sink, but as a happy accident. - -Going forward, I'm definitely going to take part in more game jams. While I'm happy with my coding practices, I've realized I need to grow as a **game designer**. My games work, but they often lack that certain _oomph_. That's the crucial skill I need to develop to create better experiences for players. - -In a perfect world, I'd find a team where I could focus on what I love: coding and creating tools for designers to bring their visions to life. - ---- - -### References - -- [**Itch.io**](http://Itch.io) **Pages:** - - [Broberry](https://gabrielkaszewski.itch.io/broberry) - - [Parasitic God](https://gabrielkaszewski.itch.io/parasitic-god) -- **Source Code:** - - [Broberry on Gitea](https://git.gabrielkaszewski.dev/GKaszewski/broberry) - - [Parasitic God on Gitea](https://git.gabrielkaszewski.dev/GKaszewski/parasitic-god) \ No newline at end of file