Developing a tactics engine in Godot

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
so I've decided I want to revisit the tactic genre for my next big project so here's a look at how I'm designing the engine and game Flow for this project if you've seen my video about LMX then some of this will be familiar to you though I have made some changes to that implementation I've also been playing around with some different ideas in the early stages of development so you'll see two different prototypes today a Sci-Fi pixel art game and a Kaiju Clash Style game these are both built on the same conceptual framework for the code so I'll largely show them interchangeably though the actual implementation isn't one-to-one as the Sci-Fi game is running in Godot 3 and the Kaiju Clash prototype is running in ghetto 4. I'll talk more about that difference in a bit but first let's establish what kind of game I'm making and dive into the general game structure as previously mentioned this will be a tactics game specifically a turn-based one similar to x-com into the breach and so on all units on your team perform actions all units on one or more AI controlled teams perform actions and repeat until everyone's dead or the mission's been completed these games also usually have an action point or AP system of some sort whether that be a fairly straightforward allotment of one movement and one other action per turn or something more in depth with a pool of points that are spent on various actions since I don't really care for number crunchy games I'm going with something like the former it may not seem like it at first but that quick overview pretty thoroughly informs the high-level designs of the game's code taking the above information and adding in some Supporting Cast here's what the node structure looks like for a level the top node is very lightweight and really just acts as a high level coordinator of other nodes it mostly just injects dependencies and cause initialization functions on its children and then emits a signal that combat is ready to begin once a mission is over regardless of its outcome which will be determined elsewhere it'll do the inverse and emit a signal that combat is over service nodes are where the messy questions get answered I.E those that require a lot of data from a lot of different places pathfinding which I Implement using godot's built-in a-star implementations is one such example as on top of needing knowledge about the level's tile map to navigate navigation could also be blocked by another unit an object or an environmental condition of some sort that's a lot of places data could come from and rather directly letting each entity talk to everything else the navigation service is responsible for keeping track of these things adjusting navigation data appropriately and answering questions about pathfinding lines of sight and so on similarly the combat service answers questions about combat such as what enemies do I have line of sight to or what's the nearest Ally since a lot of these questions require knowledge that the navigation service holds the combat service talks to the navigation service a fair bit but not so much vice versa the result of this is that the chaos is contained within each service and I'm able to keep my game objects decoupled from one another the services just expose functions like get so path or git closest Ally and let any object that needs such information to call them I'm not certain if I'll need another service or not in the future maybe for something like handling mission objectives but if I do it'll be for similar reasons confining the chaos of wide reaching data requirements to a single location environment nodes are just that tile Maps objects in the level Etc any entity that's not a unit goes here eventually some items will be destructible or interactable but for now other than impacting pathfinding or action targeting there's really nothing too special about these nodes combatants and its child nodes are where the core game Loop occurs and I'm going to explain this one from the bottom up units which I'll discuss more in just a moment are the actual entities you control and fight against each unit belongs to a combat Group which is a collection of units that should be controlled together this of course includes the player and one or more groups of enemies but it could also be used for neutral or friendly NPCs additionally there is an allegiance property that allows for groups to specify their alignment in a battle so while the default state is that each group is the enemy of all others it's possible to make multiple groups work together as if in one big group just by giving them matching allegiances other than acting as an organizational entity combatant groups have two primary functions manage turn execution at A Team level and answer questions about its units management involves things like removing defeated units from the turn order signaling units when it's their turn to take an action and so on questions the combatant group can answer are things like do you have any units at this location or where are all of your currently active units and that brings us up to the combatants node which coordinates turn order between groups it tells a group when it's time to take a turn and listens for when that group has completed its turn and then goes on to the next group in the order UI is exactly what it sounds like as it's still pretty early in development to have much UI there's not a whole lot to say about this node other than that this is specifically for UI elements that should not appear in the game World menus Huds Etc in World UI such as highlighting a tile or previewing where an attack will land go into the environment node so that it can optionally be y sorted occluded by objects Etc what's not shown in this diagram that helps provide the connecting glue to all of this is a couple of event buses these are Auto loaded scripts that allow for sending signals from various parts of the application without coupling things too tightly so when the player needs to select an action for a unit that unit fires a signal via the UI event bus at the appropriate UI nodes are subscribed to and can respond to by showing the list of available actions for that unit there are also signals for things like telling the camera to pan to a location updating the list of current unit positions based on movement Etc basically if a signal needs to travel more than just a node or two away in the scene tree I tend to reach for an event bus since connecting distant objects directly adds a lot of coupling I don't like and bubbling up signals through four or five nodes is a pain and still feels a bit fragile for my taste if the concept of an event bus is unfamiliar to you I talk about it more in my video on the Observer pattern and that's how the game operates at a high level so let's dive into units now if we ignore artwork which obviously vary significantly between these two prototypes but doesn't really impact the overall implementation the general structure of a unit looks like this similar to a level the unit node itself doesn't really do a whole lot it just does some dependency injection runs initialization logic listens for and fires a few signals but the first to the other components for any real logic controllers are where the bulk of the unit's logic resides these components are responsible for one piece of a unit's operations the AI controller for instance decides what action an AI controlled unit should take the action controller is in charge of any logic directly involving actions this is things like deciding what potential actions a unit can take when any requirements such as AP costs are taken into consideration executing a chosen action resolving any effects it may have and deciding whether to kick action selection to the UI for player controlled units or to the AI controller for all others the stats controller manages a unit stats which includes things like Health the action Point Pool defense and so on the animation controller is as the name suggests responsible for playing animations but animations in this game are a bit more than just visual animations also Define when effects should resolve so that when a unit fires a gun for instance the target won't react until the animation of the gun firing is actually at a point that the bullet would have left the weapon but not every action that needs to be taken fits nicely within a track with a predefined length and set of animations and that's where action overrides come in these components are essentially Escape hatches for actions that don't fit nicely into a pre-canned animation take movement for example the length of the animation the orientation of the unit during that animation and the positions to animate through will all vary based on where the unit is and where it's going so when a movement action is selected rather than following the normal path of playing an animation the animation controller sends the relevant info to the movement override along with a callback function it can call when movement is over the movement override can then parse that data and do whatever it needs to with it including animating the unit and moving across the level when everything's done the movement component calls a callback function and the animation controller resumes its control and normal flow for when an animation completes so now let's talk actions which are where the real complexity requirements live and the differences in Godot versions comes into play as mentioned earlier the Sci-Fi game is running in good O3 while the Kaiju Clash prototype is in good04 and there's a few reasons for this difference the first and simplest reason is that the Sci-Fi game came first Godot 4 was still in beta when I started the project but when I started exploring the Kaiju Clash prototype the engine was in the release candidate stage so I was open to at least checking it out if I had a reason to do so which kind of leads me into my next reason for a data heavy game made by someone who dislikes Dynamic typing Godot 3 was getting on my nerves a bit trying to manage things and develop the game how I wanted to additionally godot's way of handling custom resources and data types felt limiting and I had to come up with a few workarounds including developing a custom plugin for data management which while an interesting experience largely didn't do anything significantly time saving over what Godot 4 can do out of the box I may revisit plugins more in the future as there's obvious benefits to having an editor that is custom tailored to the game's unique needs but for now Godot Forest handling things nicely the other reason why the Kaiju Clash prototype is in Godot 4 is that I found that Godot 4 by default did a better job rendering and scaling the higher resolution Kaiju Clash Graphics then Godot 3 did I'm not 100 certain why that is but this combined with the workflow issues ultimately pushed me to four for the Kaiju Clash prototype I expect that by the time this game is done Godot 4.1 and even 4.2 may be out so any of The Oddities and bugs I've ran into with the early versions of Godot 4 shouldn't be a significant issue in the long run despite the workflow differences the overall structure of actions is the same each action exposes several configuration properties such as what kind of targeting it uses and what stats affect it along with a list of effects which each represent a singular thing that an action does so an action that deals damage to a Target and boosts the acting unit's defense would have two effects one for dealing damage and one for boosting defense one thing worth noting is that actions themselves are largely just data containers and this is further reinforced by the fact that all actions are implemented as Godot resources which as a quick refresher are only loaded into memory once and then shared by all objects that need access to it effects are also data containers and therefore resources but they do additionally contain the necessary logic to resolve themselves based on their configuration and the data provided to them so when damage should be applied to a target for example they can calculate how much damage to do and apply it to that Target effects can also support a bit of complexity in their orchestration as each effect can optionally belong to an effect Group which defines a set of effects that should be resolved together for example during an actions animation a keyframe could exist to resolve effects in group a at frame 15 followed by a keyframe at frame 30 to resolve effects in group b this makes it easy to sync effects to their Associated animations and to support more complex actions and therefore affect resolutions than just playing an animation and then applying all effects at once at the end and that's a look at how I'm building out the code base for this game let me know what you think ask questions down below or maybe just let me know if you see something wonky or weird and next time I'll share more specifics about the game itself and its development [Music]
Info
Channel: The Shaggy Dev
Views: 160,777
Rating: undefined out of 5
Keywords:
Id: 8fLbf7n9I9I
Channel Id: undefined
Length: 11min 58sec (718 seconds)
Published: Wed Jul 05 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.