Input is something that is not unique to combat systems. A good input system is going to be an important part of any game you work on. However, because of the fast paced nature of many combat games getting it wrong can destroy even the best designed systems. The controls need to feel responsive so that the player feels like the game is doing want he or she wants, which is not as easy as it sounds. In fact, in my opinion, the best gameplay experiences are the ones where I forget I’m even using an input device and feel that the character is just an extension of my body that I can make move like an arm or a leg.
On a macro scale, input seems like the most straight forward thing: “When the player presses this button, that action happens.” However, when it’s time to get down into the implementation it’s very easy to get lost and overwhelmed by all the nuances and minutia. It’s not so bad once you’ve figured it out, but if you’re trying to get it done for the very first time there are many pitfalls one can fall into, and just to be clear, these pitfalls are all on the design side. Probably one of the most frustrating things a developer will encounter when implementing an input system is when he creates his system, it works completely as intended, there are no bugs, but when players play the game they all complain about irresponsiveness and the game not doing what they told it to. You might hear complaints like “I did that combo right” or “I totally hit the block button”. The problem isn’t in the programming of the system but rather in the design of how it should behave.
You see, the trick is that a good input system behaves to anticipate and execute what the player intends to do rather than explicitly doing what the player actually does. I’m certainly not suggesting doing the impossible like reading the player’s mind or something like that, but a little observation reveals some common situations in which the player’s intent can be interpreted from his input. Let’s start by taking a look at the following set of combos.
|Combo A||Button 1, Button 1, Button 1||Move 1 → Move 2 → Finish A|
|Combo B||Button 1, Button 1, Button 2||Move 1 → Move 2 → Finish B|
|Combo C||Button 1, Button 2, Button 1||Move 1 → Move 3 → Finish C|
So now let’s say the player wants to
execute Combo C. How does he do it? Well, like I said earlier, on the macro
scale this is very straight forward: first he presses button 1, then button 2,
and finally button 1 again. Ok, simple enough, but remember that the three hit
Combo C consists of three animations that all take some amount time, say 10
seconds. When, exactly, should the player press each button to do the combo? This
is where it starts to get tricky. If you’re the player you’ll want to instinctively
say the buttons should be pressed one right after the other like this.
However if you’re a developer you may be tempted to intuitively say that the button to execute each move in the combo should be pressed when the previous move ends, like this.
So there are some real problems with both of these models. When reading button combinations from a command list it does seem like the game is instructing the player to hit buttons one right after the other, but if a game really implemented this sort of system it wouldn’t take very long before the player experienced the unmistakable weirdness of input lag where the action associated with an input happens a noticeable amount of time after the actual input press. We’ll see that very small amounts of input lag are useful and in fact necessary, but when a button press causes an action several whole seconds later it feels very sluggish and is the very definition of non-responsive. Furthermore, a lot can happen between the input and the action if that time is so long. The tactical situation may change, and under this model the player would have to wait until the entire combo finishes before he can perform his next action even if he pressed the button the moment the situation changed. This prevents the player from being able to react to the situation despite being aware of it, which again is the very definition of non-responsive controls and is very frustrating. You could attempt to implement some sort of combo interrupt mechanic, but that would mean that you’re letting your input dictate your design instead of implementing your design’s input.
The second system is a complete system from a technical stand point. It implements the desired functionality and has no ambiguities. The problem with this system is that it’s really hard to use. First off it’s very possible that the player may take some time to figure out that the button input needs to be pressed at the end of the move, having to resort to trial and error to find the right timing. You could include a quick tutorial about how to use it, but I personally believe that the input should be intuitive enough to not need such a thing. Beyond that, the simplest play test sessions show that players don’t tend to wait so long between button presses. The bottom line is that despite its technical completeness, this system just isn’t fun.
Ok, it’s now becoming apparent that the issue of input is not as straight forward as it appeared at
first. To find the answer we’ll need to look at some actual implementations of
input systems. To start off, let’s examine the following situation. In a real
world setting players will generally continuously press buttons until their
desired action happens then switch. The input timeline would look like this.
This is what some people affectionately call “strategic button mashing”. However, the idea we’re dealing with is that every action has a single input that caused it. Here we have three actions, which means there were three button inputs that caused them. The rest are just considered noise and don’t execute any actions. The question is: which three buttons? In the above situation the three inputs that get processed will determine which combo gets executed, Combo A or Combo B. The first Button 1 input at t=0 causes move 1, that’s simple enough to identify. Now it’s not clear which of following Button 1 inputs causes move 2, but since the player is mashing away at Button 1 it would be pretty weird if the first part of the combo didn’t correspond to a Button 1→Button 1 input. The finish move, however, is a mystery. Will the super long string of Button 1 inputs at the beginning of the combo execute Combo A, which has input (Button 1, Button 1, Button 1)? Or, will the later Button 2 inputs execute Combo B, which has input (Button 1, Button 1, Button 2)?
Here is a case where the player’s intent can be gleamed from his inputs. Regardless of which combo actually comes out it is clear to me that the player intended for Combo B to come out. As such, the input system should be designed to accommodate the player’s expectation. So the question still remains: which Button 2 input caused the combo’s finishing move?
Is it this one?
If that’s the input that finishes the combo then what happens when the player mashes the buttons slightly differently and where the player previously pressed Button 2 he now presses Button 1 an extra time.
So what algorithms and rules should we use to choose which inputs execute an action and which do we consider just noise? As a self exercise why don’t you try and create a system to handle inputs and then apply it to the above example and see which three buttons caused the actions under your system. After you do that, take your same system and see how it handles the following three examples. If your system requires information that is not provided with these timelines, feel free to insert that information as you see fit.
Example 3.(Here's the tricky one)
How’d your system do? Were there any indications in the example as to what the player wanted to do? Did the actions executed in your system match what you believed the player wanted to do?
I’m going to start with what not to do. When creating an input system one of the
most basic things that needs to be avoided is processing an input only in the frame
that it was received. This is bad because it is nearly impossible for a human
being to time this properly. Let’s pretend that we’re using an input system
that causes these three inputs to be the valid ones.
This is the same system as before where the input for a move needs to be pressed when the previous move ends. The code snippet for a system like that might look like this.
Given an implementation that
looks like this, the difficulty is that DoNextCombo(),
which will cause the combo to continue, will only run when both of the
following lines are true.
messageRecieved == BUTTON2_PRESSED
So the combo will only continue if the animation for the current move is at an end and if Button 2 is being pressed. EndOfAnimation() will only be true on the frame an animation ends. The reason being is that by the next frame a new animation will have begun and will not be at its end. At 60 frames per second a single frame lasts only about 16 milliseconds.
messageReceived == BUTTON2_PRESSED is also a single frame event. Please note that there is a difference between a button being pressed and a button being held down. A button is considered to be “pressed” only on the frame that the voltage from the input device was first received (often referred to as “button_down”). For that button to be considered “pressed” again that button needs to be released and then depressed again (the release is often referred to as “button_up”). A button is considered to be held during the entire time between a button_down and a button_up. Most of the time we don’t use BUTTON_HELD to execute actions in melee combat because that would mean a player could keep attacking by holding down the attack button. There is no real reason for that to be a bad thing, but I personally feel it’s not conducive to the twitchy, action packed pace a cool melee system should have.
So given this information, with an input implementation as given above, the player has about 16 milliseconds to press a button. Pressing a button itself takes time as well because your finger or thumb needs to travel the few millimeters from a button’s neutral position to its electronic contact within the input device. I timed myself to see how fast I could do this and came up with roughly 70 milliseconds or 1/14th of a second. So all in all this implementation gives the player a 16 millisecond window to complete an action that takes 70 milliseconds. This means the player has to time his button press to start anywhere between 69 and 53 milliseconds before the end of the current attack’s animation. This is like trying to split a hair with a Javelin. This is no good.
Any input system is going to need to take two things into consideration:
1) When can an action be executed
2) When can an input be received to execute that action.
In order to avoid the hair splitting problem I just described we’ll have to extend one of those two times to be greater than a single frame. In previous sections I’ve described the different situations we want the player to be able to execute an action. This includes the entire Idle state, which is a very extended period of time, and also when executing fixed combos where we transition from the Attack state to itself without going through the Idle state. Depending on the game, this window of time may be determined by the balancing math and the animation, so we might not want to extend the time a new action can be initiated. For this reason a good input system will extend the time an input can be received to execute an action.
The most common way to do this
is to explicitly define a window for each move when an input will be valid,
often times called a combo window.Looking at our example the combo window for each move will be
highlighted in blue
Under this system any input that is received inside the combo window will be a valid input. All others are considered noise and will be ignored. When an input is processed within a combo window it determines the next action that will be taken, but only the next action. Later actions are determined by later combo windows. With this information we can now identify many of the noisy inputs that don’t cause actions.
During this combo we can now say conclusively that the final move in this combo will be finish B since all the Button 1 inputs from earlier are outside Move 2’s combo window.
We’ve managed to identify most of the noise, but there is a
piece missing from our system. There are still three inputs within Move 1 and
Move 2’s combo window. Which ones are
the inputs that executed the moves? Well at this point there are two common
choices: a FIFO (First In First Out) system or a LIFO (Last In First Out)
system. A FIFO system says that earlier
button inputs take precedent over later ones. A LIFO system says that the later
inputs override the earlier ones. Different people prefer different systems for
different reasons. Each has its pros and cons. A FIFO system is more intuitive
to use and a LIFO system allows the player to change his or her mind about what
action to perform based on changing circumstances. I prefer to use a FIFO
system. So given that last bit of
information our example finally ends up looking like this.
There is also an alternative method that can be used to achieve the same effect.
Instead of defining a combo window for every move you can give the input signals
themselves a lifespan. This means that even though an input was received at time=X,
it is valid until time=X+lifespan. Let’s take a look at our example one more
time, and this time we’re going to represent an input’s lifespan as a line
underneath each input.
With this method the ends of the lines represent where a given inputs dies and becomes invalid. These dead inputs do not execute any actions and are considered noise. So let’s remove the inputs that are dead at the end of each move.
They could even have the window start, end, then start again later in the move.
Another plus to defining the combo window for every move is that data can be embedded within the combo window. Data like what action a given input would execute. For example if a move had multiple combo windows a different combo could be executed depending on which combo window was active at the time of the input: press a button at the beginning of the move and Combo A is executed; press it at the end and Combo B is executed.
The downside is that this increases the amount of work that needs to be done, because every move needs to be tagged. Furthermore, if changes, modifications, or tweaks need to be made it can be difficult to track down the right combo windows and balance them when there are dozens or even hundreds of moves.
Using the input lifespan method
provides consistency and predictability to the input. To the player this means
that he or she only needs to learn one timing and can then apply it to all
situations. Input lifespans are also
more portable. They can apply to systems in the game other than combat. For
example if the player pauses the game to bring up a character menu then
un-pauses the game, the player can begin his input entry before the menu
completely disappears. This would mean that the instant the menu fully
disappears the input will still be alive, get processed, and then the action
will be executed at the earliest possible moment.
This guarantees an uninterrupted game experience. The same is true with any
situation where normal actions cannot be executed due to some transition. For
example if the player pulls a lever in a level and wants to attack the moment
the lever pulling animation ends. Or if the player is opening a door, switching
weapons, picking up an item, etc. One system for all occasions. Another
important place where this situation occurs is when the player hit reacts. The
player may want to execute a counter attack or some other action the instant
the hit reaction ends. We already discussed that it is nearly impossible for a
human being to time his input to coincide with a particular instant, but the
same lifespan method that solved this problem before works for this scenario as
Above we see that the player pressed his input before the enemy attacked him so the player is committed. However we see that the Wind up for the player’s Move 1 and the enemy’s attack are at almost the same instant. If the player had executed his Move 1 any amount of time later the enemy would have landed his attack. Thanks to the fact that the player can begin his input before the end of his hit reaction he has a reasonable window of opportunity to send the input that will cause his Move 1 to execute as soon as possible. To do the same thing by tagging combo windows would mean that not only would all moves have to be tagged, but all hit react animations, and all other situations where the player will want to time his action to occur at the end of some transition. That just doesn’t scale, and for these reasons, I personally prefer to use the input lifespan method.
The next question we have to ask ourselves is how long to make
the lifespan of the input. This is a very tricky question. This lifespan can
change the pace of your game and will definitely be a factor in the game’s
accessibility to players. The General rule of thumb is the shorter the lifespan
the less accessible the input becomes for players of low and moderate skill;
the longer the lifespan the more unsettling the input lag effect becomes. You want your lifespan to be longer than
average human response time (~200 milliseconds). A lifespan shorter than this
will be almost as bad as the hair splitting problem. You’ll want to have a
lifespan that is shorter than the shortest move in the player’s move set. Remember
that players tend to hit buttons until their desired action occurs then switch
which button they input. If the lifespan of an input is longer than a move then
you run the risk of having an input that was received before that move executes
decide which action will occur after it finishes.
With a Lifespan that is too long we have these three inputs executing the three moves. As you can see a Button 1 input received while Move 1 is still active will be the earliest living input at the end of Move 2 and execute Finish A. This pattern of inputs suggests that player intends his Button 2 Input to execute Finish B, but that’s not what happens. At best this causes the input lag effect for the player and at worst makes the player feel as if the game is not doing what he or she wants. There’s no magic number for a lifespan length, but personally I find that a life span of about 400-700 milliseconds is very satisfying.
Ok, this system can now handle all the immediate needs of an input system without ambiguity. It will execute the player’s intended actions with fidelity without forcing them to have superhuman timing. However in practice there is another problem that is commonly encountered. I mentioned before that one of the most frustrating things that can happen when designing an input system is when your system works as intended, there are no bugs, but players still complain that they hit a button, and the move didn’t occur. This problem arises mostly with what I call priority moves. Priority moves are usually defensive moves of some kind: blocks, counters, dodges, etc. Some people affectionately refer to them as “Oh Crap!” moves. Essentially they are moves that are supposed to get you out of a potentially bad situation, which is why people tend to focus on them more when they fail. They’re increasingly becoming central gameplay features in modern combat games. Games that showcase these kinds of moves include Batman: Arkham Asylum, Bayonetta, and even God of War.
In these games the gameplay experience is to be fighting a group of enemies, and
while you’re executing attacks on one enemy another will try to attack you from
behind, as discussed in earlier sections. At this point the player may want to try
and counter the incoming move with an appropriately quick move from his move
set. However there may be times when he has no suitable attack, he didn’t
notice the attack soon enough, or maybe even the player will panic at the
attack and execute his “Oh Crap!”
move. With our current input system, depending on when the player noticed the
change in tactical situation, he may not be able to execute this move even
though the button was pressed in time. This is due to the fact that our FIFO
system is set up to have earlier button inputs take precedence over later ones.
This becomes an even bigger problem if the input lifespan is long, as is often
the case with these kinds of games. Let’s take a look at the following example.
So here we have a common combat scenario for the player. He’s trying to execute combo B as usual. He hits Button 1 to execute Move 1, continues to press Button 1 until Move 2 comes out then switches to mashing Button 2. However somewhere in the middle of Move 2 an enemy starts to attack the player from behind. It takes the player a moment to notice the attack, but because he’s mashing Button 2 he continues to press it a few times before responding to the attack and switches to mashing the Defense Button to initiate a dodge move. Now when we analyze this input pattern the inputs of interest are as follows.
The beginning of the phrase is the same as before, but when we look at which move we initiate last we see two inputs of interest. There is a Button 2 input and a defense button input. Now, using our FIFO input system it’s clear that the Button 2 input will take precedence and the finish move will be Finish B, thus completing Combo B. In that case, though, the enemy’s attack will land long before Finish B’s wind up ends. This means that even if the player was able to switch the target of his combo to be the new aggressor, he’s still going to get hit. The player saw the attack, responded to it before the end of his current attack, but still got hit. As I mentioned before this is the case where players get frustrated claiming that they hit the button in time. The input system is functioning as designed but the player still feels the controls to be unresponsive. The solution to this is to give priority moves priority. Under normal circumstances inputs are processed as first come first serve, like standing in line at the register. If you’re new to the queue you have go to the back of the line. Now, let’s say one of these priority inputs is received, what we’ll do is let it cut to the front of the line so it gets processed first.
With this method we’ve effectively combined the strengths of both a LIFO system and a FIFO system. Players can change override earlier inputs based on changing tactical circumstances during critical and high priority instances, without sacrificing an intuitive control scheme the other 90% of the time.
This should complete our input system. We now have a system of rules that is intuitive to use, contains no ambiguities, and is responsive to the player’s intentions. You might think that the system is too complex for your average player to learn, but remember that all of these technical details are hidden from the player. From his perspective, he’s pressing Button X and Action Y happens; the game is just doing what he tells it to. After all, the best systems are the ones you don’t even realize are there.
Just as a reminder, this article is meant to go over only the basics and fundamentals of combat design. The concepts covered are proven techniques, but that doesn’t mean that they are the end all be all. New and innovative systems will be created by modifying the rules of melee combat, adding them, or even removing some. The Combat State Machine I presented is a good jumping off point, but adding to it is highly encouraged. You may think of adding a transition that goes from the Hit React state to the Defense State or even to the Attack State if you can think of some interesting enough rules. If you’re new to combat design, I hope this article has given you an understanding of the parts that are involved in creating your own combat system. If you’re a seasoned designer or gameplay engineer I hope there was some useful information that you hadn’t considered or weren’t aware of before.