Next Broadcast

Building out custom game engine

CatheaD GameDev DK30 Spring 2021 3 3

Description

I’ve been working on a custom game engine for several years (on and off), and finally have an iteration that I feel comfortable fully building out. For the next 30 days, I want to commit to regular work on the engine for the purpose of pursuing my passion project, a small scale starcraft-style RTS.

Recent Updates

CatheaD 5 years ago

Okay, for real this time! The camera actually works now! Not only the camera, but 8 direction border mouse detection, etc. The end result is janky and slow but further refinement (including scroll speed set by configuration) will drastically improve things.

camera works

I’m marking this as completed because the real goals here were input-based (e.g. the amount of hrs spent per week) rather than specific progress on the engine.

I didn’t get done everything I wanted to this month, but my goals had to change due to emergent technical problems so I’m quite proud of what I managed to get done. I even had less time than I was anticipating (let alone planning!) due to significantly more important life events, so overall I’m pretty much ecstatic with where things are!

Next stop is revisiting the command card, which will include properly displaying the units selected (and control groups, which I had working earlier in the month), actions per selected unit, shifting between “active” units, the structure for unit abilities/basic commands, etc. Similarly, the minimap will have to be done too. Once this is all set, the real guts of the RTS are in place! I’ll probably want to spend some time working on the “feel” before going any further; if the movement and selection feel bad, who cares about anything else, that’s more central to RTS than attacking is for sure.

Looking forward to the next DK30 so I can keep showing good progress on this! I’ll be working on it between regardless, maybe I can get the aforementioned command card/minimap structures done before then.

CatheaD 5 years ago

Hey, the uh “camera” works: camera_movement

Regardless, getting closer! Everything should be back on track, better than ever, once I work this piece out!

CatheaD 5 years ago

Good news: the big refactor is underway, the scariest changes have been made, and we compile again! Huge victory. We’re now on the current stable Flutter & Flame, and all of the guts are taking Flame’s lead on things now.

Bad news: something is horribly wrong. The guts aren’t quite taking the “right” lead yet.

Behold, two render systems in their natural habitat, competing for resources: oh_no

More to do!

CatheaD 5 years ago

I didn’t nearly hit my goals this week development-time wise, but I more than made up for it with planning time. There’s a major refactor to do as the RTS engine I’m building upon the Flame engine has drifted slightly from Flame’s guts and needs to be realigned. There’s some conflicting machinery I’ve built that’ll have to be ripped out and replaced, right down to a tuple issue (i’m using a dart built-in tuple class and they have their own special tuple). Wouldn’t you know it, I brought up enginedev in a show opening while discussing DK30 and Day9 made a joke about vector3’s.

On another front, owing to some nice 10x10 sprites from the ever beautiful work of Oryx Design Labs (https://www.oryxdesignlab.com), I have a tileset that I think I can adapt for use in the proof of concept demo. I’ve noticed in the past I can only go so far without placeholder art, and it’s really worth it experience-wise to me. Debugging a geometric clown world gets tiring after a while. Plus I already owned the set and it suits this, in my opinion.

gobbo group

Once I do the engine refactors, I’ll be able to utilize a camera system built into Flame, and then we’re really in business. From there, UI-wise: a minimap on the left side to control the camera, and the input box on the right side to control the selected unit/building/whatever, sometimes called a “command card” . File loading/saving is already covered, as I took care of this in the engine prototype and can just port it right over, so we’ll already have maps (to which I also already have a good-enough-for-now-map editor from a previous generation of iterations) and similarly the ability to load/save game state. This whole piece feels like it’ll have to move around a little as I go with the command card, so it will probably deserve more than a first pass refactor-wise.

After those pieces are done, we can really get into the meat; resources (on the ground & the associated UI), buildings & a basic construction mechanic. We at some point need to double back into unit pathfinding because it’s naked a-star right now and feels strange; there’s a big TL post about this. Anyway, lots to do.

CatheaD 5 years ago

What a crazy week! My week was derailed by unexpected pet health and job issues (took an extra PTO day and got less done than last week!), so I didn’t come close to hitting my hour goals, but nevertheless: control groups are in! Also, visual display of selection.

control groups

This RTS control layer on top of the input system is really coming together!

Will post more detail in updates this week, but overall I’m happy with progress so far!

CatheaD 5 years ago

… well, that’s why collision broke; I turned it off. Things working pretty well now!

boxing and movement

And with moving groups of units:

groups and collision

CatheaD 5 years ago

My schedule has been pretty stable; up until this week, of course! No matter though, it’ll be more uniform next week and I’ve gotten a good chunk of work done at other times nonetheless.

Now for more engine specifics!

The game space of the engine is all tile-based. This is to say, while there are real pixel coordinates “underneath” (for rendering, etc), all of the game logic is done on a grid of integers (e.g. [0,0], [1,0], etc). This naturally has a dramatic effect on all uses of the engine as all movement is orthogonal on a square grid, like on a chess board. An entity can only move up, right, down, or left at any given movement opportunity.

I rather like this restriction though as it radically simplifies understanding any given moment, which I’ve found to be really important for a project where the full team (design, development, Q/A, etc) is just myself. In a world where I was working on this full time, sure, maybe I’d design something with fully free movement, maybe. I just don’t think it’s as comparatively feasible for me as a solo developer, at least right this second. Plus I’m obsessed with the idea currently so I really want to see where this goes. The engine up until this point was designed around arcade games, where this made more sense (think Pacman, Wizard of Wor, etc), but finally I realized all I’m consistently interested in these days is RTS, and then the idea caught fire in my head. I’ve since made it more of a slow burn, gotta keep this going for the long haul.

Regarding what I’ve actually gotten done this week:

The engine was already relatively well formed. We have a fully functioning update/render loop, it can handle moving between different screens (as a very simple finite state machine), input detection, entities tracked by the game loop, with independently updating animations, etc. I had already made a working proof of concept in Flutter of a previous game idea (not RTS), and then revised it into this engine (and made yet another, different, proof of concept), so on some level it does just “work”. But a lot of adapting needed to happen.

Specifically, I worked out mouse input this week. Everything prior was designed for controller input, with just the minimal keyboard processing for debugging. Now we have left click, right click, panning, and hooks built in for watching/overriding the start/end of all of these.

The end result is now we can box! Boxing

On this screen you can see a couple of things. Firstly, the game space, with each “tile” clearly marked. The graphics are all placeholders and the tile pattern is only for debugging, while I ram my skull against the ever-finicky entity movement systems. You can also see some of the debug information at the console in the bottom, displaying the far right corner of the current mouse drag, forming the RTS mouse “box” out of the initial left click coordinates + the latest drag coordinates.

When you release the drag, any entity inside the box gets selected! I thought this was going to take way more time to get done, but it just kind of came together! My desire to prematurely optimize was strong, but I said screw it, and just detect all orthogonal pairs under the selection (e.g. mouse drag contains [1,1], [1,2], [2,1], etc), then loop through every entity and see of their "tileX"and “tileY” match up to any of those pairs. Once I implement the camera, I want to revisit this and find a way to only care about entities on screen, as I imagine processing every single tile and every single entity ON EVERY MOUSE DRAG is going to be a rather severe bottleneck. But we’ll get there when we get there (I’m imaging having each tile hold onto a reference of it’s “occupier”, and having only the tiles on screen report their “occupiers” when asked to process, but how memory is done in the Flutter environment is a nebulous thing and I’m not sure yet whether this will be an improvement or not. Thoughts for later down the road).

Marching down the road, I decided to tackle pathfinding immediately too. I usually write my own implementations but because it’s such a pain in the ass (to me), I did a quick search and found a nice A* implementation someone already did!

Here’s the link: https://pub.dev/packages/pathfinding

Now essentially what happens is that when a mouse drag finishes, any entity inside gets selected. When a right click happens, on a conceptual level, any selected entity is move commanded to a specific coordinate. This really happens in two steps:

  1. When the right click is done, that entity gets a “path” built to the clicked destination (the raw coordinates are first transformed into the orthogonal coordinates). The library I linked gets fed with my current map (transformed to just be walkable/non-walkable spaces), the entities current location, and the desired destination. Then it spits out a sequence of next steps the entity can take.

  2. In the engine’s update loop, the entity notices A. it has a path, and B. it is not already moving. It is then forced by the whims of fate to begin traversing its path. The movement systems are all already worked out to some degree, though they definitely need work.

Movement

As you can see, the entity was selected and move commanded somewhere to the southwest of its current position. The green represents squares it occupied/is occupying as it moves, so for debugging purposes I can visually see the whole path as it happens on the grid. You can also see the raw coordinates in the console at the bottom, for tracing by hand.

Currently, it’s totally god damn broken. The entity never really stops moving in the first direction it gets, although sometimes when it hits a wall, it’ll get the next direction. I kind of thought it would be; I always have a bit of a wrinkle integrating pathfinding, but once it’s worked out, it’ll just work. I think the processing of the next step of the path and the actual move are out of sync somehow. It has a bit of complication as each entity processes “commands”, so that I can keep a history of them per entity, so that later down the road I can do things like replays, etc. This is a remnant worked out from an earlier proof of concept that I really feel like is a good and helpful structure, so I’m excited to get it all working. If you keep move commanding, it rebuilds the path, so you can kind of get some brood war-like behavior where spam clicking actually helps it get where you want it to get. Really not what I was intending when I thought “hey, wouldn’t orthogonal movement kind of force brood war-like group movement patterns”.

That’s sort of the impetus behind this; I think managing groups of units in an orthogonal movement system could be cool and take some mechanical skill. Hopefully it doesn’t just straight up feel BAD though. I imagine it will without tuning, I’m just holding onto the idea that there will be enough play programming-wise to make it feel good. I definitely feel like there’s things I can do though. Maybe units move more strictly in formation, to avoid stepping all over each other, stuff like that. No matter what, I can’t imagine it will be as clean-cut as SC2, which is good in my book. Don’t get me wrong, I love SC2 and it’s mostly what I play today (I’m way more up on the meta/how to play it and the matchmaking is fast and good for US East), but I grew up with brood war and when I imagine an RTS I’d want to make, it has a unit feel reminiscent of BW.

Anyway, progress is good! Very excited to keep working!

CatheaD 5 years ago

The project itself is being written in Google’s cross-platform “Flutter” framework, as well as the glorious general-purpose game engine library “Flame”.

Flame provides a wealth of functionality game-wise right out of the box. It handles critically important things such as the managing the update/render loop, drawing to the screen, handling input, playing audio, etc. I’ve written most of these pieces from scratch in previous iterations, but they tend to become entire projects on their own, and Flame’s implementations are way more flexible than other similar libraries I’ve used in the past (let alone my hand-rolled ones). I haven’t had any major issues to work around with Flame yet, and even some really weird cases I wanted to support were doable without significant pain, so I really can’t rave about Flame enough.

When I say “game engine” regarding this project though, I’m referring more to the specific architecture of the game itself. That is to say, everything from the actual in-game entities (e.g. units, buildings, resources) and how they’re tracked, to how the different “screens” are organized and traversed by a user (e.g. the title screen, navigating menus, setting up matches, and the game loop itself).

Because I’m a unrepentant masochist, I’ve written several different versions of this engine over the years in various languages/frameworks, but nothing really stuck until now. Each version had major implementation flaws and most had questionable paths to deployment/publishing. There was also like the full year I spent writing this all in C++, and in a fraction of the man-hours I replicated it all in Flutter in a way that I like much more and is significantly faster/easier to develop in (which is a primary issue for me, being a solo developer). Flutter really provided the environment I had been looking for though and has since won me over completely. I finally have the game code and the engine code split into separate “projects”; this way, I can develop the game and the underlying engine independently from each other. This may not seem like too much on paper, but functionally having these decoupled from each other not only makes each piece easier to think about, but it makes things dramatically easier to debug too. For example, if there’s a bug with how a unit is moving, I can go straight to the engine; the “game” code only contains the instructions for ‘when’ to move rather than ‘how’. Of course, the ‘when’ can cause plenty of problems too, and some of those may look like ‘how’ problems symptom-wise, but, such is life.

Estimated Timeframe

Mar 1st - Mar 31st

Week 1 Goal

Split across Monday/Wednesday/Friday mornings:

  • At least 6hrs of development time per week
  • At least 2hrs of design/planning per week, or more as needed

Week 2 Goal

Split across Monday/Wednesday/Friday mornings:

  • At least 6hrs of development time per week
  • At least 2hrs of design/planning per week, or more as needed

Week 3 Goal

Split across Monday/Wednesday/Friday mornings:

  • At least 6hrs of development time per week
  • At least 2hrs of design/planning per week, or more as needed

Week 4 Goal

Split across Monday/Wednesday/Friday mornings:

  • At least 6hrs of development time per week
  • At least 2hrs of design/planning per week, or more as needed

Tags

  • gamedev
  • engine