Inspector, death and beyond
Handling death
What happens when an entity dies? Do they go to entity heaven? Nope, it's more like reincarnation, given the I'm using pooling strategies for reusing some objects. But what happens to the entity with regards to the game? When I originally had these questions, I didn't overthink it much.
But first of all, a quick description of how location works in Sigil of Kings. There's a "location" component that stores 1) a 2D integer, 2) an entity id and 3) a location type. The location type could be "level", "overworld", "city" or "invalid". The entity id would be the city/level entity for cities/levels. So, in a great moment of wisdom (that's sarcastic), I thought "set the location type to invalid for dead entities".
Initially that worked fine, but it causes a few headaches when handling resurrection, corpses and of course player death. Simple example: the player is the sensor. When the sensor changes location, we switch graphics to what the sensor can see in this new location. When the sensor is the player and the player dies, there's ... darkness. The void. No entity heaven in sight, just "invalid location". So, need to handle this. I set for myself a 3-tiered TODO list (I'm a hardcore list writer) for how to handle player death:
- Now: Still allow UI to inspect state (player or whatever we have explored). Esc starts new player in the world, and F8 loads the last quicksave as usual
- Later: Death screen overlay, with options: Inspect, New, Quickload, Main menu
- Much later: Death screen overlay, with the options above, but also thing like "New World" or "Wait for help"
So far, the "now" goal is going alright, and what happens is the following (to accomodate how my code works): when the player dies, we immediately clone the player entity (before it gets destroyed), rename to "ghost", change the sprite and tag the entity as a ghost, so that it's never detected. It's a bit hacky, but this currently results in a happy ghost that can walk around, and unfortunately, get stuck in webs etc. Could turn into a fun minigame, who knows. The player entity dies and goes into a "dead entity" special pool, where all destroyed entities go. That's a temporary solution because it does not scale. I could use that pool for resurrection later on.
Dear ImGUI Inspector
Dear ImGUI needs no introduction at least for programmers of interactive applications in C++, as it's pretty much the holy grail in the dev/debug tool department. Bindings exist for more languages/frameworks, including C#, and even Godot!
So I've been using it more and more lately in Godot/C# to make more powerful inspection capabilities. Within a game engine, embedded inspection capabilities typically happens at the node level, but since my game is mostly in C#, I don't get to benefit from any of that. But with ImGui and a bit of reflection, it's easier than ever to write a generic and extensible-as-needed inspector. One important note: the generic inspector should not be able to modify values, because that can be catastrophic: some values in objects are only meant to be changed through functions etc. Modification can always be supported with a dev console anyway (which exists in some form already).
This week I put quite a bit of work in the inspector, and this part I consider as porting Unity editor windows for selecting/viewing entity information etc. I have a common way of visualising entity data: I can either middle-click on a tile and get the entities in that tile (plus tile info) in their own area at the ImGui hierarchy, when I can expand/fold as I see fit, or I can quickly press F1 while hovering over a tile and see the exact same data, force-expanded up to 3 levels, for quick checks. It was a bit of a PITA to handle the size of ImGui tooltips to grow with the content, and I still get it wrong: I kinda made it work with PushItemWidth but the value is hardcoded
The other beautiful thing with the ImGui integration is that I can go through my mega entity list in the inspector, hover over entity entries in the inspector, and the corresponding entities can be highlighted on the map! Well, anyway, I'm super-excited about things like that. And another awesome thing is that in Unity's inspector, because of how they did serialization, you couldn't have potentially endless chains, e.g. an entity containing entities containing entities etc. Well, with ImGui you can. And before you say "sounds like a horrible idea" remember that an entity containing entity IDs is certainly not a bad idea, and in the eyes of the inspector, entities and IDs can both directly expand to the entity's contents.
Future work: If you've paid attention to some of my ramblings at the blog and here over the years, you might have noticed I sometimes develop some tools for the game in C++ (using imgui) or python (using tkinter). Well, now I can write them directly embedded in the game framework! This is going to ease development of tools that need understanding of game code/classes: instead of replicating stuff in C++ or python, now I can write the tools directly in C#. This includes prefab editors, json database editors etc. But that's for later.
Save/Load Heisenbugs
I got a bunch of bugs that were thankfully the same bug under the hood, which had to do with loading. I'd save, then load and play a bit multiple times, and randomly in one of those loaded sessions I'd get very weird crashes/errors. After a bit of investigation, it became clear that there was some "old" state before the load that was messing with the post-load state. After more investigation, I shamefully discovered the source of bugs, which was a "I'll handle this later" moment during the port a month ago or so: I was loading the game within the system update loop, which caused two system objects to exist and interfere with each other. The fix is super simple of course: a quickload/quicksave action is only getting scheduled during the system loop, and the actual load/save happens completely outside the loop.
Misc
- Creatures/objects/effects now visible.
- Fixed some time-of-day gradient bugs.
- Fixed a bug in the fog of war on borders.
- Heat haze is reduced when raining.
- Entity cloning.