Fighting Game Combo/Input System (Looking for Feedback)

Started by
19 comments, last by Wyrframe 4 years, 9 months ago

I want to implement a Tekken-Style Combo-/ Input-System.

The basic system i want to realize is, processing a timed sequence of inputs. Example: In Tekken, I have 4 Input Buttons(excluding directional Buttons). Each of them corresponds to a basic Character Action.
Square = Left Jab
Triangle = Right Jab
Circle = High Kick
X = Low Kick
When pressing one of those Buttons the Action executes. For a short period of time after that, the Character is in a state in which each of the Input Buttons (or only a subset of them, depending on the Character's move list) corresponds to a different Character Action. If I manage to press a Button in time the Combo and this Pattern continues until the end of the Combo. If i fail to push a Button in time, the Character returns to it's idle state.

I had the idea of using a Tree to represent all Combos of a Character as a Datastructure.
The buliding blocks are the following...

1. Input(Type: enum): For example the square on a PS4 Controller.
2. Action(Type: enum): A command that is send to the Character when an Input is given.
3. Timing(Type: float or int): A time window for a specific Input of a ComboNode.
4. ComboNode(Type: user defined): Several Inputs where each Input maps to a Triple.
5. Triple (Type: user defined): An Action, a Timing and a set of ComboNodes(ChildComboNodes).
 

image.thumb.png.ec8fb22fa8f9a3682874e77d738a581b.png

How the Tree would update itself:
1. Check for inputs in current ComboNode while at least one timing is still valid.
2. Pressed Input.
3. Send corresponding Action to Character.
4. Set current to ChildComboNode.
5. Repeat until Combo ends or no timings are valid. In those 2 cases, return to root.

 

I would appreciate advice or comments :)

Advertisement

Looks fine. You can also see each node in the tree as a state, so you don't go "down" to child nodes, you go to the "next" state. Mostly just word-play though, but it shifts the viewpoint a little.

It may make it simpler to see that you don't need an "end-of-combo" notion. Instead have another arrow (jump to "child") that triggers when no other case triggers any more, which simply jumps back to the first node (first state). In other words, you cycle endlessly around through the nodes.

This may make it also easier to see that you can share child nodes from different directions if they perform the same things. Bot sure if you have that though.

 

Another "change" could be to put the conditions and actions on the arrows instead of in the node. May be simpler for layout if you have lots of different directions you can go from one node.

Hi, fighting game input can be quite complicated. I've revisited this recently and implemented a fighting game input and combo system. The thing you are looking for is a state machine. This is a structure of connected nodes, each representing a state. You start in idle state, and you can move to a number of other states from this with a button press. If you press nothing, the state repeats back into itself. Or an other character can hit you and you enter a staggered state for example, from which you will not recover until the animation ends. My point is, that there can be a number of different event types which force your character into a particular state. This requires a pretty flexible system. My approach was to write it in Lua script because it is so well suited for writing this kind of flexible state machine. Basically each state has a connection to each state and a condition function that returns a boolean. Now the boolean that this function returns could check for a particular button press, or velocity, character position, anything really that you can access from the script. When the update loop runs, the current state's every connection's requirement fuction is checked and the first that returns true, its state is triggered as the new active state.

You can check out my fighting game script here: https://github.com/turanszkij/WickedEngine/blob/master/scripts/fighting_game.lua (It is a single LUA file and quite long, so I don't know how useful it is to you)

Looks pretty well

To make it more functional you could add some properties to your nodes so its more dynamic and clear, example: a finishing move node. So that "end of combo" can happen at any tier of the tree (being second hit or fifth hit is not what ends the combo, but the final <usually more powerful> move)

Also, you could prototype your timing in a more fashionable way: you can make use of the grid you have there to represent the timing. It's easier to see than just adding numbers through the nodes.

You could also add a color code instead of writing which button is pressed (if the node is green it's clearly triangle, pink: square, etc) and its more fluent to read.

In short: everything that makes you read less and its more visual will be helpful for you and others to understand easily.

1 hour ago, Alberth said:

Looks fine. You can also see each node in the tree as a state, so you don't go "down" to child nodes, you go to the "next" state. Mostly just word-play though, but it shifts the viewpoint a little.

It may make it simpler to see that you don't need an "end-of-combo" notion. Instead have another arrow (jump to "child") that triggers when no other case triggers any more, which simply jumps back to the first node (first state). In other words, you cycle endlessly around through the nodes.

This may make it also easier to see that you can share child nodes from different directions if they perform the same things. Bot sure if you have that though.

 

Another "change" could be to put the conditions and actions on the arrows instead of in the node. May be simpler for layout if you have lots of different directions you can go from one node.

Thanks for the reply. I will model the system as a State Machine and see if that fits it better. Removing redundancy by sharing states is a good idea.

1 hour ago, turanszkij said:

Hi, fighting game input can be quite complicated. I've revisited this recently and implemented a fighting game input and combo system. The thing you are looking for is a state machine. This is a structure of connected nodes, each representing a state. You start in idle state, and you can move to a number of other states from this with a button press. If you press nothing, the state repeats back into itself. Or an other character can hit you and you enter a staggered state for example, from which you will not recover until the animation ends. My point is, that there can be a number of different event types which force your character into a particular state. This requires a pretty flexible system. My approach was to write it in Lua script because it is so well suited for writing this kind of flexible state machine. Basically each state has a connection to each state and a condition function that returns a boolean. Now the boolean that this function returns could check for a particular button press, or velocity, character position, anything really that you can access from the script. When the update loop runs, the current state's every connection's requirement fuction is checked and the first that returns true, its state is triggered as the new active state.

You can check out my fighting game script here: https://github.com/turanszkij/WickedEngine/blob/master/scripts/fighting_game.lua (It is a single LUA file and quite long, so I don't know how useful it is to you)

Very cool, thanks! I have never touched LUA before, but I will see what I can get from it :)

29 minutes ago, Vronim said:

Looks pretty well

To make it more functional you could add some properties to your nodes so its more dynamic and clear, example: a finishing move node. So that "end of combo" can happen at any tier of the tree (being second hit or fifth hit is not what ends the combo, but the final <usually more powerful> move)

Also, you could prototype your timing in a more fashionable way: you can make use of the grid you have there to represent the timing. It's easier to see than just adding numbers through the nodes.

You could also add a color code instead of writing which button is pressed (if the node is green it's clearly triangle, pink: square, etc) and its more fluent to read.

In short: everything that makes you read less and its more visual will be helpful for you and others to understand easily.

Thanks for you'r reply, aswell. I was actually struggling a bit with notating my ideas as clearly as possible. Color Coding the Buttons and other visual approaches are definetly a good idea. I get the idea of making a diagram easier to "read" by having less to actually read, but for some reason I always have in the back of my mind that I only know how to read a diagram because while making it I have the correct assumptions in my head. It's like looking at other's code or at code you wrote a while ago. You just don't what you meant anymore. So I like to spell it out less ambigous sometimes. But I'll definetly try to change my approach if that's really the better option.

I have remodeled the problem using a State-Machine. I think it's a lot simpler and easier to understand.
image.thumb.png.49e82591ff5f6e680a492cd86b0e0cb2.png

If you are getting to code this, also keep in mind that there might be some input delay until the input arrives for processing so using a timestamp instead of a counter in your state maschine could massively improve the user experience

17 minutes ago, Shaarigan said:

If you are getting to code this, also keep in mind that there might be some input delay until the input arrives for processing so using a timestamp instead of a counter in your state maschine could massively improve the user experience

How would the timestamp exactly work ? Would it be storing the time when the input first arrived in the program and correcting for it when the input arrives at the State Machine for processing ?

Exactly! You store the input together with some timestamp and while processing check the delta between the original timestamp and now. If it fits into certain range (e.g. some milliseconds threshold) then process it. This way you are indipendent from your game loop and possible performance spikes

This topic is closed to new replies.

Advertisement