The first stage in the development of my game was the development of the RTS engine. I plan to write a series of posts about the problems encountered and their solutions in this blog. In this post I will tell you how organized the behavior of units.
Reflecting on where to start this RTS engine at all, I came to the conclusion that it is worth starting with specifics and moving from it to abstraction. The first application that came to mind was the collection of resources, or rather the extraction of wood.
Usually this process in most strategies consists in the fact that an employee, while receiving an edict to cut a tree, goes to a tree, for some time waves an ax with a pickaxe, then goes to the warehouse and starts anew.
So the process looks like this:
So that this picture could really claim the name of the automaton, it lacks conditions for transitions between states and initial and final states.
Everything is simple: the machine is initialized with the state “I am going to chop”, and the end of the work occurs during the time of delivery. We can express transitions between states using the following conditions: “reached a tree”, “chopped up a full armful of firewood”, “reached a warehouse”, “handed over resources”. If the answer is positive, the machine goes to the next state, if it is negative, it remains in the current state.
In each of the states of the automaton, the corresponding action is called during the iteration. The same set of actions can be performed during the transition between states.
For example, during the iteration in the “I pass” state, the resources from the unit's backpack will move to the player’s resource warehouse, and when going from the “I am going to cut” state to the “Ruble” state, the corresponding animation will start.
I also note that walking itself is not an “atomic” operation, it occurs in many behaviors and is itself a behavior, and for this reason, in fact, the behavior of tree extraction uses walking behavior within itself. That is, a new automaton can be obtained by composing several other finite automata.
By writing behaviors in this way, we get an architectural boundary between the details of the implementation of behaviors and the high-level policy of managing these behaviors. Implementations of behavior essentially become plugins for the rest of the game, that is, changes in them will not affect the correctness of high-level logic.
These behaviors work by calling the iteration method from the Update event of objects of type Unit (this event fires every frame). For communication with the rest of the world, call IStateMachineListener‘a methods.
This is an example of the construction machine in my game. When a construction team is received, the unit is sent to the indicated point, and then it goes into the state of direct construction, transferring units of construction to the building. When a building has accumulated enough units of construction, the construction machine ends and the unit receives a new behavior, the default behavior.
That's all. If you like or dislike this format, write about it in the comments!