Most of the past 4 weeks was working on ‘providing for the family’ on my main job. But I managed to pull off some interesting pieces of code.
And the guys that help me with the models did their part too… but that’s for another time.
This blog is about a few code things and my new GIT branching strategy.
A short video demonstrating the new AI behavior. See this lovely gnome walk around and (try) to hide behind a tree stump or hide in the vase. And notice the sparkles FX for a bit of vibe.
As you can see in the video that accompanies this blog post, I have added a mechanic where gnomes can run around.
Technically this was a deceivingly easy system. I started with a normal ‘rotate around point’. That part was easy. But the hard part was to get multiple gnomes to walk, with their walk speed constant independent of the circle size, a minimum distance to each other, entering the circle on a random spot but at the right distance to each other… and all this while the gnome can still be catched while walking.
In my code, this ‘RunInCircles’ script manages the registering/deregistering and around. It works together with a ‘RunInCirclesState’ script that manages the events and keeps track of the state (IsFull). The storage of the gnome data is in a ‘HidingspotSet’ script that both makes it so we can start with a set of gnomes in it or can serialize the state when we want to make a save game (I save only the gnome being on this circle, not things like where it is on the circle, no need for so much detail)
But from a gameplay mechanics point of view: this circle still needs a bit of tuning. It is part of an overflow system so the gnomes always have something to run to, but currently it is using it too much. And it is too long in this circle. And maybe it was more fun if the run around with their hands in the air like ‘whaaa, I dont know what to do’.
I also changed the ‘normal’ hidingspot to function more like the obfuscation spots and the circles scripts. So these hidingspots now too can be ‘full’ and thus keep state and use events.
I use the same patterns on all my interactions the gnomes can move to and hide in. But I try not to add too much coupling between different mechanics so my scripts are often specialized without base classes or libraries for re-use of code.
This makes that my gnome has an AI script that needs to behave differently and call different scripts when going to different places. For that I use a simple state machine that switches out logic depending on where its heading to. To keep things simple and tidy, and not too many ‘if this then that’ that could clutter up code and make things unreadable.
One note on the (non existing) vase animations: in general all animating needs rework. I am saving it for later when there is more to do, going to hire someone to do it in one big sweep.
New gnome behavior
I already hinted at reworking the gnome AI behavior with the hidingspot upgrades.
Previously I had 1 gnome model for each behavior. One did hide in hidingspots, one other did hide behind obstacles. And I was planning for more different gnomes, with each a unique model to make the player recognize them.
And I had 2 types of hidingspots where gnome could hide in. One of it you could open always, but the other one required the right timing on when a certain animation played.
From a code perspective this meant setting up behavior and animating in a generic way. For both the gnome and its corresponding hidingplace types it would use. That worked well.
However, from a gameplay perspective it wasn’t as interesting as I imagined it to be. During playtesting, it became clear to me that the hidingplace mechanics are more interesting than the gnomes themselves: Gnomes popping up everywhere and hiding everywhere is much more interesting (instead of using 1 type of hidingspot).
There is still variation, but its now only the hidingspots that can differ from interaction types.
Added benefit of this consolidation of behavior of gnomes into 1 gnome is that it the AI can be more intelligent. It now tries to find a place to hide in, subscribes it selves to that place. And if on the way something happens to it (got full, locked, player just touched it, or is in plain sight now), it immediately knows this and tries to find a new place.
This makes for emergent gameplay because now if you want to catch a gnome and it tries to enter a hidingspot, you can just put it in plain sight or click it and the gnome has to adjust course. This gives your helicopter more time to move in and catch the gnome.
GIT Branching strategy
That brings me to my latest point: with all these code updates I got annoyed with the amount of builds my pipeline was creating.
I currently have my Azure DevOps (with GIT repo) setup so that the main branch triggers releases. And I push to main branch only. And I manually added each commit to the accompanied issue, to track my changes.
While this is a very lean approach to software development and certainly CI/CD, its a bit too much of it. I just had too many updates cluttering my main branch and triggering releases that weren’t that interesting. And there were just too many commits to properly bound to an issue.
So I added manditory pullrequests. With a separate cheap and fast pullrequest build pipe. And the pullrequest requires an Azure DevOps issue to be assigned to it. And it will automatically squash merge all branch commits into 1 commit, further reducing the clutter.
I use the Azure DevOps issue flow now where you can start a branch from an issue. Makes it all much more convenient.