"I have a simple idea for a game" 🤔
That's how all games start. How hard could it be to create a Pokémon clone after all?
And then you get smashed by complexity on your first step 🫠
This is what you are facing 👇
Why things need to be mutable?
My conflict with game development is all around mutability (or maintainability in a broader sense).
I know for a fact that code complexity originates from unpredictable/dynamic logic. In fact, for standard apps you can get close to 100% type safety and sail safe 🚣
But not game development. Games are the wild west of mutable and scattered code. Deceptively not indie-friendly (despite so many indie games out there).
That's (part of) the origin of years and years of development for even simple games when you go solo 🤯
The complexity of an object moving on the screen
A game starts with getting something moving on the screen.
Even at this step you are flooded by complexity:
- Game loop: in sync with the platform, synchronous, working on any machine
- Collisions: good luck manually dealing with physics
- Assets: asynchronous loading and performance optimization
- Animations: state machines and sync them with frame rate and game loop
My context is mostly the web, therefore
Promise
,requestAnimationFrame
, and static assets 🏗️
All of these get you a player moving on the screen, with a decent walking animation, stopping when hitting a wall. Not much 🫠
Adding features
This is how your future looks like:
- Sprite rendering
- Player movement and animation
- Tile map loading and rendering
- Collision detection with map
- Basic camera following player
- NPCs placed on map (static, non-moving)
- Simple interaction (press button to start dialogue)
- Basic event system (trigger dialogue, get items)
Can you spot the trick?
Each of these systems is related/dependent to each other 🔗
Some innocuous examples:
- What if an NPC is moving but you want to interact with it?
- What if you start moving on an empty tile but at the same time an NPC is moving there as well?
- Should you be able to move behind a building (tile map layers)?
And when everything can depend on everything else, complexity spreads to the whole system 🤯
Tame complexity with types
Outside of game dev, libraries like effect
tame complexity with types.
Dependencies and errors are tracked on a type level. You control their spread, and deal with it 🫡
Can this be done as well with games? I am in the process of finding out 🤔
First step was building an ECS library (@typeonce/ecs
). It solves some problems, but not others:
- Values are still mutable
- Async code is not "expected"
- Dependencies are mostly implicit (not typed)
The more I ventures into these flaws, the more it all started to resemble
effect
🙌
export class SnakeGrowSystem extends SystemFactory<{}>("SnakeGrow", {
dependencies: ["Collision"], // 👈 Dependency, but not on the type
execute: ({ poll }) => {
// ...
},
}) {}
Alas, I started a possible implementation of a game loop with effect
(and more).
Guess I have to build a game engine in @EffectTS_ now. Nerd sniped by @ethanniser's effectis talk.
My initial goal would be to have a playable website, with type safe and maintainable game code, with
effect
🫡
At the moment I am still struggling with the main game loop (requestAnimationFrame
), I will keep you posted 🔜
Published a new article on my personal blog: Creative Constraints.
I have so many ideas Where do I start? Let's think, think, think, complete freedom Yeah, but no action If that's you, you need less freedom, not more Constraints 👇 sandromaglione.com/articles/creat…
The next (big) event of the year is approaching: localfirstconf. See you in Berlin at the end of May if you plan to join 🔜
See you next 👋