Question about creating input chains and executing them

I’m starting a fighting game and I want to include complex input chains to pull off moves but I don’t quite know how to approach it. What I’m talking about is stuff like down, downright, right then a button in a short amount of time to shoot a fireball and stuff like that. Is there any way to log inputs and then execute based on certain things that you do? If anyone could help, I would definitely appreciate it.

I’m doing the EXACT same thing!

I have a feeling Gates are the answer; I’ll try it out in a few hours and let you know what I come up with.

You guys should try arrays: one holds timer range since last (previous) input, second holds which key/button was pressed.
Then you have same 2 arrays for what player has done. But in this you collect input data in realtime and remember it.
And you compare both arrays, ie template with what player did.
If there is no match you flush player input array and start from beginning.
Then at flush event you can decide how much % of combo he succeed.

Gates and execution path will get more to cthulu side of bp programming, when you have more than one combo starting with same sequence.

I’m using something similar in my game (albeit MUCH simpler; it’s a 3D game but stuff like forward, forward attack needs to be parsed) and I’ll tell you what the problem is:

Handling analogue inputs.

For pure digital inputs (i.e. d-Pad, arrow keys) it’s almost trivially easy to do this; have an array of Name values, and come up with a name value that signifies each input.

Whenever an input is pressed, set a timer (this timer represents your “gap”, i.e. how long is too long between input presses). You add each input to the array of input names, and clear that array whenever the timer reaches 0.

i.e. Press Down. This sets a 0.25 second timer, and adds a value of “Down” to the name array. Now press DownRight; this resets the timer from its current time back to 0.25, and adds a value of “DownRight” to the array. Now wait longer than 0.25 seconds and press “Right”; the timer reaches 0 and clears the array, so instead of having the array say “Down, DownRight, Right”, it now just says “Right”.

For performance/sanity reasons, you should also have the array discard its oldest values once the player is well past the maximum input string size (i.e. if the most inputs a player will have to press before attacking is 7, make sure the array discards old values such that it’s never longer than like 10-15 values, just to avoid situations where players who mash buttons get it up to like 6000 entries)

When the player presses “Punch” or “Kick” or whatever, you check the array values in reverse order to look for known input strings (i.e. if Punch is pressed we look for the leading-up-array values to be “Forward, ForwardDown, Down” for a hadouken, “ForwardDown, Down, Forward” for a shoryuken, etc) and branch what the input command does based on these (i.e. if no match, fire Punch, otherwise fire the appropriate special).

Where this gets tricky is that virtually no system that I know of uses 8-way digital input anymore. Keyboards use 4-way digital, and controllers use two-way analogue, so to transform those inputs into 8-way directions you need to find a way to do vector compares. The problem isn’t so much this, now that UE4 uses a tolerance value on its Vector Equal nodes (so you can let two vectors both be treated as the same on an analogue stick if they’re proximal), as it is handling constant input ticking. UE4 constructs an input vector (technically, two floats) every TICK, so the above logic wouldn’t generate “Left, Down”, it would generate “Left left left left left left left left left left zero zero down down down down down down”.

You have to do some fiddling to convert a constant flow of InputAxis floats into discrete on-off events in known directions.

Wow, I’m surprised that I got such a nice response. Really glad this forum is so active.

I’m working out the array triggering in my head and it seems to make sense. I also understand the troubles with digital input. I personally use a DS3 for gaming and programming so I’ll definitely have to figure out how to transform inputs to strict 8 directions.
I was thinking of making booleans based on controller input ranges. They trigger on and off when the sticks are within a certain threshold. This can simplify the direction input as said above.

Timers also make sense because you won’t want a 4 second delayed hadouken. If anyone is working on stuff like this, feel free to share (If you feel inclined to). I definitely plan on working on stuff myself and I’ll post if I make any progress in the right direction.

I can tell you what I did, which works for me in 3D and so should work for you in 2D.

What I do is, first take my InputAxis floats and make them into a vector (for you, as Z and Y, since they control up/down/left/right rather than front/back/ left/right) Then I do a vector length check and feed it to a Select Vector node; if the length = 0, I use a vector of 0,0,0, otherwise I normalize the vector created by the inputs (thus, the stick vector can only either be a unit vector in any direction, or a 0 vector).

Now from here, I do some complicated math which generates a reference frame based on the character’s rotation (i.e. if he’s facing 8° left of center, the 8-way direction quantization needs to be within that reference frame)

but for you, you can skip that step and go right to the fun vector math!

Assume, for the purposes of a 2D game, that X = depth axis (i.e. foreground to background), Y = travel axis (i.e. left to right), and Z = vertical axis.

Get ATan2 Degrees, where the A input is fed by the float “1” (technically this would be a magnitude value but your magnitudes are 1 because all of your vectors are unit normalized) and the B input is fed by the dot product of your input vector and the vector 0,1,0 (i.e. Forward). This gives you the angle between your two vectors. Next, get the cross product of 0,1,0 and your input vector (in that order), get the dot product of the result and the vector 1,0,0 (the plane your inputs exist on), and take the “Sign” operation on that and multiply it by the float from the first part. This is the (positive or negative) degrees difference between your input direction and “Forward”.

The last step is to run two separate checks; first, if the input vector is equal to “0,-1,0”, swap the output above (using a select float) for “-180” (the original math will sometimes treat this exactly parallel opposite angle angle as 0 rather than 180 or -180, this catches that). Second, if the inout vector has a LENGTH of “0”, swap the output for something arbitrary and impossible based on the above math (I like to use 720). This “impossible angle” (outside of one complete rotation) is a placeholder for “no input”.

Now, take this float, which should go from -180 to 180 and then also include 720, and divide it by 45, run a round operation, and then multiply the resulting output by 45. This should quantize the input vector into discrete 45° steps (and 720°, which remember indicates no input).

Finally, you do some Array checking. IF the Input Array has a length of 0 AND the input vector length is nonzero, you want to start your Array-Clearing timer (0.25s or whatever) and add the Int from your vector math to the Input Array. Otherwise get the value in the Input Array at the index defined by Length - 1 (i.e. the last value), and IF the Int from your vector math is NOT equal to this value, add it to your array and reset the Array-Clearing timer

This way, every tick, the game listens to your inputs, which are defined by 8 discrete angles (and one value for NULL). Once you press something, it listens for another value which is not the same as the current one, so you don’t update the array every tick with identical presses.

The trick to using this well is to print the outputs it generates and watch the print log as you perform input sequences. For example, a shoryuken would probably not be possible with “0, -90, -45”; it would probably require (or at least often yield) “0, 720 (NULL), -90, -45”. Forward-Forward isn’t “0, 0”, it’s “0, NULL, 0”. Etc. this way, you can trigger the same “input” twice even though the tick-countering logic demands a value CHANGE before registering it.

You also need to make sure you check your values against the player rotation; this way you can either modify them or check for separate input strings when he’s facing the opposite way.

Hope this helps

I managed to get some parts of this going but I’m having a tough time with others. Would you mind providing visual assistance? I would definitely appreciate it.

Sure; I’m still working on my implementation (I found that I needed to set the minimum threshold for “pressed” much nearer to a length of 1 than 0, as releasing an analogue stick will sometimes cause it to pass into another 45° quadrant as it gets close to its center. But I’ll hopefully have something for you tomorrow to look at (though again, mine is more complex than yours needs to be).

I’ve got some stuff done too. I can post it here so you can take a look at it.
https://drive.google.com/file/d/0B9UvgAy9rgxSU1NZck4wLUdYNXc/view?usp=sharing

So far I’ve got the directions parsed to only fire once. It can do hadouken and shoryuken moves perfect.
I’m currently working on trying to get everything into an array but I have no idea how that works.
Also, is there any way to have combined inputs in an array slot?
Something like Hard+Medium+light pressed at the same time or forward+hard?

Getting things into an array is as simple as adding an array variable and using an “Add” node.

But doing multi-press stuff, that’s a little trickier. The reason for this is that, as you may recall, the input string thing we designed relies on reading the angle values of the last entry in the array and doing a compare (to prevent the InputAxis event from filling the array with duplicates every tick). So it needs angle integers for that to work.

So, just as we used 720 for “null”, we’d need other placeholder values too. A bunch. Like, 765 for Light punch, 810 for Hard punch, etc. Then we’d need some simultaneity logic (since, by definition, no two input events can ever be truly SIMULTANEOUS); basically, what we’d need to do is, every time a value changed, we’d need to measure the time between when it was added to the array and when the last value was added to the array, and if they were within some tolerance, treat them as “simultaneous”.

Honestly, now that I say it, I’m thinking it might even be easier to just create a second array which stores the times between each input press (so the first press is indicated by a value of 0, and every other value by a time which measures elapsed game time between presses). Whatever get node calls the input itself can also call to see how soon it was pressed after the button before it. So if we want forward+hard to do a backhand punch, when the punch event is fired, we can call a Get on ITS value in the Time Elapsed array and check if it’s past some threshold of simultaneity (which, with this method, we can tweak on a per-attack basis) and then call a Get on the value BEFORE it in the Input Pressed array to check for the value corresponding to forward. From those two checks we can determine “forward was pressed 0.X seconds before punch was pressed” and then branch the punch execution to call the backhand logic rather than the standard hard punch logic.

This may present its own problems though. Suppose we want to do MvC type controls and have QCF+LightPunch+HardPunch do a Shinkuu Hadouken. The input string parser only knows to check for separate values; so it sees -90, then -45, then 0, and then LightPunch, and then (probably) sees 0 AGAIN since it’s got a different value than LightPunch’s placeholder, and then sees HardPunch. You could probably work around this by allowing ALL sets of simultaneity values to trigger the attack (i.e. LP, 0, HP; HP, 0, LP; 0, HP, LP; 0, LP, HP) but it can get unwieldy fast.

It might instead make more sense to create custom events for simultaneous press events, and use some boolean switching for that… so that LightPunch as an InputAction never feeds ANYTHING except a bool setter, a branch, and a function call, and can either call the Custom Event “Light Punch” or “Both Punch” depending on whether it sees Heavy Punch has already been pressed 0.X seconds before. And then let the new LightPunch and BothPunch events be the ones that feed the master Input String Parser.

I’m getting the hang of triggering events like QCF and QCB with the array and reading it when a button is pressed. I can trigger things like hadouken movements just fine but I’m having one issue. I’m having a hard time with trying to set timers between inputs. I just have no idea how to approach that. I have all inputs parsed where they are only fired once so all directions/button presses are accurate. I also have the array cleared after a maximum of 16 inputs but I cant figure out how to add time into this. Can someone help me out with that? Sorry if I’m asking for a lot. I haven’t really messed with arrays or timed events yet.

Create a custom event called “ClearInputArray” or whatever and just feed it to a Clear Array node.

In your input string parser, every time a new value is generated in the string, call a Set Timer node, with a time of 0.25 or whatever and a Function Name value of “ClearInputArray”.

A timer will execute its function when it reaches zero, and setting it again will reset it’s current time to the new time.

Excellent. I have everything I need. Thank you very much for your help!