How the abilities work in War Robots





Hello! My name is Vladimir Popov and I am a client developer on the War Robots project.



War Robots has been around for several years: during this time, dozens of new mechs have appeared in the game. And, of course, none of them would be unique without their own set of abilities.



I will tell you in this article how the system of abilities in our game works and how it evolved, simply and without any technical details.



First, let's dive into history and look at the old implementation - now it is no longer used on the project.



The old abilities were very trivial: they had one component that was hung on the robot. It was a monolithic construct in which the programmer fully described how the ability works: its flow, how and with what it interacts. All logic is described inside one component, which the game designer could simply hang on the robot and adjust the parameters. There was no way to change flow abilities - game designers could only change parameters and timings.



The old ability could only exist in two states: active and inactive. Each state could be assigned its own action.







Consider the example of the Jammer ability. She was at one time, for example, the robot Stalker. She worked as follows:



  1. If the ability is active, the animation plays and the robot enters the Jammer state. In this state, the robot cannot be targeted.
  2. If the ability is inactive, nothing happens.
  3. When you try to activate the ability, it is checked whether more than n seconds have passed since the last activation.
  4. Deactivation occurs automatically after m seconds.


For a long time, this functionality was enough for us. But over time, everything changed: both game designers and programmers were no longer satisfied with this approach. It was difficult for programmers to maintain such abilities, because the code became monstrous - with a very long chain of inheritance, where each situation had to be described. Game designers lacked system flexibility. That is, for the sake of any change in an ability, they had to order revision from the programmers, even if exactly the same functionality existed in the neighboring ability.



Then we realized that we needed to change something. And they developed a new system. In it, each ability began to be represented as a set of several related objects. The function was divided into states, abilities and components of states.



How it works?



Any ability has a master . This is her central object. It connects the rest of the ability objects to the outside world and vice versa. And he also makes all the main decisions.



There can be any number of states . In essence, the state here is not much different from the "active" / "inactive" state in the old version. But now there can be any number of them, and their purpose has become more abstract. Only one state can be active at a time.



The main innovation over the old system is the components . The component describes some kind of action. Each state can have any number of components.







How do new abilities work?



The ability can only be in one of the states at a time. The master is engaged in switching them. The components that link to the state react to the activation / deactivation of the state and, depending on this, can either start performing an action or stop performing it.



All objects are now customizable. The game designer can mix states and components with each other in any way and thus get a new ability from the pre-installed blocks. Programmers are now needed only to create a new component or state, which greatly facilitates writing code. Now they work with small entities, describe some simple elements and do not assemble the ability themselves - game designers have begun to do this.



Flow became like this:



  1. The master activates the first state;
  2. ;
  3. ;
  4. ;
  5. ;
  6. ;
  7. .


Subsequently, this procedure is repeated again and again. For ease of use, a state is not only a container for components, but it also determines when to switch to another state and asks the master to switch.



Over time, this became not enough for us, and the scheme of the ability was transformed into the following form:







Master, state and components remained in their places, but new elements were added to them.



The first thing that catches your eye is that we have added conditions to each state and component. For states, they define additional requirements for leaving the state. For components, they determine whether the component can perform its action.



A container of charges (charges) contains charges, recharges them, stops recharging when necessary, and provides charges to states for use.



The timer is used when several states must have a common execution time, but their own execution time is not defined.



It is important to note that all ability objects are optional. Technically, only the master and one state are enough for the ability to work.



There are not so many abilities that are completely assembled without the involvement of programmers, but development in general has become noticeably cheaper, because programmers now write very small things: for example, one new state or two components, the rest is reused.



Let's summarize what constituent parts of the abilities we have and what they are:



  • The master acts as a state machine. It provides states and components with information about the world, and the world - information about an ability. The master serves as a link between the states, components and service parts of an ability: charges and external timers.
  • The state listens to the commands for activation and deactivation from the master and, accordingly, activates and deactivates the components, and also asks the master to switch to another state. State decides when he needs to switch to the next one. To do this, he uses his internal condition: whether the player clicked on the ability button, whether a certain time has passed since the activation of the state, etc., and external conditions linked to the state.
  • : . : , , .
  • , , . . , . , . — , .
  • A container of charges contains charges, recharges them, stops recharging when needed, and grants charges to states. It is used in multi-charge abilities when you need to give the player the opportunity to use it several times, but no more than n times in a row.
  • The timer is used when several states have a common duration, but it is not known how long each of them is valid. Any state can start a timer for n seconds. All interested states subscribe to the event about the end of the timer and do something when it ends.


Now let's get back to the ability diagram. How did she start to act?



  1. At the start of the game, the master chooses the first state and activates it;
  2. State activates all of its components;
  3. ;
  4. ;
  5. , ;
  6. ;
  7. .


States can use charges as an additional transition condition. If such a transition takes place, the number of charges decreases. Also, states can use a common timer. In this case, the total time of their execution will be determined by the timer, and each state individually can last any time.



We didn’t come up with something completely new for the UI. It is arranged like this with us.



The master has its own UI. It defines some elements that should always be in the UI and do not depend on which state is currently active.



Each statethere is a couple in the UI. The state UI is displayed only when its state is active. He receives data about his state and can display them in one way or another. For example, duration states usually have a bar and text in their UI that represent the remaining time.



In the case when the state is waiting for an external command to continue the ability, its UI displays a button. And pressing it sends the command to the state.







Now let's look at the work of abilities using specific examples. Let's start with a robot called Inquisitor.



We have four states that change one after another. Above the states, you can see their display in the UI. In two of them, you can see the components that refer to them. The other two states simply have no components.



Ability work flow:



  1. WaitForClick. .
  2. , . WaitForGrounded.
  3. . , . , , Jammer, .
  4. .
  5. : Sound Jammer, Shake, n.
  6. Duration, n , .
  7. Duration, : .
  8. Upon completion, the ability returns to the first state.






Another example is Phantom. Much happens here similarly to Inquisitor, but there are still some nuances:



  1. We start with WaitForClick.
  2. Then the Duration, in which the teleporter is set, the stats of the mech change, sound and animation are played.
  3. After that - DurationOrClick, in which fur stats are changed, animation and FX are played.
  4. If a click was made, we go to another Duration, in which the fur is teleported, the stats are changed, the animation, FX and sounds are played.
  5. After this state or after the end of the DurationOrClick time, we go to Duration.


The main difference is that branching states appear here. DurationOrClick goes to state a if the specified time has passed, or to state b , if the player had time to click on the ability button before.







Thus, it would seem that our system has evolved from simple to complex, but thereby simplified the life of both programmers and game designers. The help of the former is now mostly needed when adding small components, while the latter have received greater autonomy and can now independently assemble new abilities from existing states and components. At the same time, the players also received a profit in the form of more diverse and complex abilities of the mechs.



All Articles