Programing fighting game inputs

hello everyone
I’m not sure if this is the right place to ask this but here we go

so I’m trying to program a fighting game just for a proof of concept project and I’m not quite sure what’s the best way to interpret quarter circle, srk, half circle and such commands.

I’ve been testing different fighting games that i have and I’ve noticed that my inputs don’t have to exact.
im using the number notation, hope its right
789
456
123

for example i want a srk and do
61236+P, my input goes all the way back and i end in forward but i still get a shoruyken (which i want) instead of a hadouken even though a quarter circle is in that motion

I did some reading on some srk wiki well this one
http://wiki.shoryuken.com/The_King_of_Fighters_XIII/Game_Elements/Command_Interpreter

and the game assigns priority to different moves

so i was thinking would the best way to do it is to read the directions after the button press and determine which move to come out based and the assigned priority?

if anyone knows a thing or two about it I’d love to discuss it, or if you can point me to any more detailed info on how fighting games interpret inputs that would also be great

sorry for wall of text

It might also be insightful to look at how Mugen encodes the commands, you may learn from it and notice things are simpler than they seem.
http://www.infinitymugenteam.com/infinity.wiki/mediawiki/index.php?title=List_of_Command_Perameters
http://www.angelfire.com/ego/heavens/mugen_basicmoves.htm

But the general idea for that kind of thing works like follows. This is not gospel, just the way I have tried in my personal programming experiments and at times simplified for the sake of explanation. I’m gonna use a syntax that’s C#/Java-like because I’m a C# programmer but it’s generic enough that the general principle should make sense for other languages too.

-For clarity’s sake, when I’m talking about input I’m talking about buttons presses, or in other words the state of the pad/stick/keyboard for a given frame. For me it’s usually a series of booleans representing whether 2/4/6/8/lp/mp/hp/lk/mk/hk are pressed. No booleans for the diagonals, instead they’ll be valid if both involved directions are pressed. Using binary flags I can put all that into a 16 bits value and still have room for 6 extra buttons
-When I’m talking about commands I’m talking about the movements you’re gonna look for, ie F,D,FD, mp for a shoryuken. For those I use the U/D/F/B notation because they change depending on your orientation. Rather than not know if it’s gonna be 623 or 421 I’m getting rid of the ambiguity.
-When I’m talking about moves or states I’m talking about the actual move the character will do as a result.

-For each player you keep a buffer that contains the inputs for the last X frames, where X is the maximum duration of an input. ie if a charge move requires 2 seconds of charge or if you’ve decided to be nice and the player can do a srk motion in two seconds you’re gonna keep at least 120 frames of buffer. Usually it’s shorter, of course. Never hurts to have a bit of margin though, you never know
-For now let’s assume the buffer has a magic function that can check if a command was just done by the player (and by just done we mean finished on the current frame), eg inputBuffer.CheckCommand(awesomeShoryukenCommand) that returns true or false.

-Finally, you have a list of all the possible moves that can be done by the player. Each move has a condition that’s usually a check in the character’s current state and whether a command was done, ie for a standing HP it’ll something like “if (character.isStanding && character.canMove && inputBuffer.CheckCommand(HPCommand)) {DoHPMove();}”. If you want a LK->MK chain it’ll be something like “if (character.isDoing(LKmove) && inputBuffer.CheckCommand(MKCommand)) {DoMKMove();}”.
-For each frame you go through that list in order and as soon as you find a valid move you stop iterating entirely. You may have guessed it, that means the orders the moves are in that list is your move priority.
-Any command that entirely includes another move should have higher priority, ie if you have HCF,MP (B,DB,D,DF,F,MP) and QCF,MP (D,DF,F,MP) you want to check the HCF first because when the HCF is true the QCF always will be, so in the reverse order the QCF would always stop the HCF from ever happening. All the moves are in that list, even the normals, blocks and movements. Usually you’ll see a rough order emerging, which is supers, specials, command normals (including throws), normals, movements but it’s pretty flexible.

That takes care of priority. Of course that still means you have to take care of the “magic function”, the one that can check if a command is in the input buffer. I’m not gonna go into that in detail right now but a few pointers:
-The magic function is the one that reverses 4/6 depending on which way your character’s facing.
-The buffer stores the commands per-frame but when reading it you’ll usually be looking for changes. The input may have been down for ten consecutive frames but the interesting moments in a SRK motions will be when it was pressed and if forward was pressed before down was released.
-It’s usually simpler to do it backwards. You start at the end of the buffer (current frame), look if the last button of the command was pressed, then wind up to the previous change, look if it’s the second-to-last button of the command, then to the previous change, check if it’s the antepenultimate (third last, always wanted to use that word) button, and so on until you have all your buttons, in which case it’s a positive. And if you’ve decided a SRK has to be input in less than 20 frames then once you hit the 20th to last frame you drop the check and return a negative.
-input leniency is done through that magic function. When it checks if a part of a command is valid that’s where you’ll build extra tolerance, for example if you’re checking for a skullgirls-like throw with LP+LK and want like two frames of leniency of the simultaneous press you’re gonna check for moves that end not only with LP+LK but also LP,LK or LK,LP. “aah”, you may say, “but those will always have triggered a jab or short already”. Yup. That’s why you need to add kara cancels, ie in this case the throw should be able to start when the player’s standing or moving but also in the first two frames of a jab or short.

That’s mostly it for now, ask questions if it’s not very clear.

awesome thank you soooooo much!

@ Chev

thanks a lot for the response. Im trying to implement it with my limited free time

anyway, I was wondering if you could clarify about the input buffer and go more in depth of the “magic function”

so about the buffer, i’m not sure what type of structure to use for it. Is it just a variable, a list, an array etc?
also when do i clear it or do i just keep adding to it and then add at the beginning of it every x frames

eg. 1 2 3 4
after 20 frames
5 6 7

or

1 2 3 4
after 20 frams
5 6 1 2

if this makes any sense.

sorry if you have to repeat or re explain something. but it would be helpful.
you can always call me a moron if it helps

Assuming you’re talking about motions and not charges.
I only know the capcom’s old engine when I was working on my vsav script.
Capcom set up 2 inputs per character one delayed by a frame to make sure you got the input you wanted.
Then they compare the value to either a constant or a table if it matches it would a timer that is 12 to 16 frames(disregarding turbo aka frame skipping). Loop till the timer runs out or you go to the next input.
That input window timer is also the buffer window meaning if you do the motion you have that many more frames till you press the button.

I won’t call anyone a moron because it took me time to figure it out too.

For the buffer, you add the new inputs to it on each frame right when you read them, you always want it to be up to date so you’ll always be checking for the latest move.

For the underlying structure, it’ll be some sort of array to which you must be able to always add, but there’s plenty of room for the specifics, I’m gonna mention three main approaches.

-you can just do it with one big array, preferrably one that can resize when it’s gonna overflow (so, std::vector in C++, arraylist in java, list in c#, some similar name in other languages) or you do the resizing yourself (rule of thumb: double size when it’s full). You always add the new input at the end, and keep track of where the end is. The drawback is the array may become quite large, but supposing a 10 buttons layout that’d be stored with 1 byte per button (more efficient would be just one bit but let’s go with the simple inefficient one), you’d get 36K per minute, which is still reasonable. The perk here is if you restart the match with the same start data, and just go through this array instead of reading input from the player you get a full replay! So even if you don’t use that one keep it in mind for the day you need a replay.

-you can do a smaller array that’s just size X and on each frame you shift all the content to the left ((for i=0; i<arraylength-1;i++) array[ i ]=array[i+1];) and write the new input at the end (or shift everything to the right and add at the beginning depending which way you prefer, that doesn’t matter). The big pro is the array is a constant size, the con is you rewrite it all on each frame (but since it’s small it won’t be a real problem). However…

-that’s actually a common problem so there is a data structure to avoid that rewrite! It’s called a ring buffer. Long story short (the one on wiki is actually a bit complex for my taste), when you reach the end you just go back to the beginning, so it’s always writing over itself, and you keep track of where you last wrote, then you just need some simple arithmetic ((current index - how many frames behind you want to read) mod array length iirc) to read it like the array above. Only drawback is figuring out the right calculation in the first place, then it’s smooth sailing.

I’ll come back to the magic function in a bit, that one requires a bit more thinking.

EDIT:

So, magic function. Let’s go back to mugen for a bit, 'cause it’s handy for formalizing the notation. In Mugen the commands are a series of presses separated by commas. So a LP hadoken would be something like 2,3,6,LP. So it’s a series of button presses separated by commas, and we can represent it by an array of button presses. For the move to be accepted each of those individual items in the array must be true in turn, with the last press occurring on the current frame. Let’s assume our buffer, no matter how it is implemented, has a method bool ButtonWasDownAtFrame(button, howManyFramesAgo) that can tell us if the button was pressed. ButtonWasDownAtFrame(2,4) would check if down was down 2 frames ago, ButtonWasDownAtFrame(LP, 0) would tell us if the LP button is down at the current frame, etc. This is abstraction: no matter what kind of buffer you chose, at this level it’s already not a problem anymore.

So, to check if LP was pressed at the current frame, your check would be ButtonWasDownAtFrame(LP, 0) && !ButtonWasDownAtFrame(LP,1), ie the button was down this frame but not the previous one. If you want to check a negative edge or button release X frames ago you do !ButtonWasDownAtFrame(LP, X) && ButtonWasDownAtFrame(LP,1), you want (for a charge move) to know if a button was pressed for Y frames before frame X, you loop over the whole range ButtonWasDownAtFrame(LP, X) to ButtonWasDownAtFrame(LP, X+Y) and they must all be true. So with just these basic combinations you can build slightly higher level methods, let’s say ButtonWasPressedAtFrame(button, frame), ButtonWasReleasedAtFrame(button, frame) and ButtonWasHeldAtFrame(button, frame, howLong).

So, now, let’s say you want to know if a LP hadoken (2,3,6,LP) has happened in the last 20 frames. As I said we start from the end, so it goes like this:

-check if LP button was pressed at frame 0 (ie right now)
-if that’s true, go back through frames, and for each frame check if button 6 was pressed until you either find it or you’ve reached frame 20 (ie 20 frames from frame 0), in which case you decide the hadoken was not performed.
-if you found the 6, from the frame right before that press go back through frames, and for each frame check if button 3 was pressed until you either find it or you’ve reached frame 20 (ie 20 frames from frame 0, not the current point from which you started), in which case you decide the hadoken was not performed.
-if you found the 3, from the frame right before that press go back through frames, and for each frame check if button 2 was pressed until you either find it or you’ve reached frame 20 (ie 20 frames from frame 0, not the current point from which you started), in which case you decide the hadoken was not performed.
-if you found the 2, your command is deemed legit.

You can see the loop emerging, right? Your command is a time window and a series of button presses. Check for the last press, then for each previous press go back through your input history searching for a match until you’ve either found them all (in which case the move is valid) or reached the end of the time window the player had to make the move (or of your buffer, for that matter). That can be turned into a while loop with a little work.

Note this is a very lenient method: for the hadoken example it’ll also be true for 2,3,4,6,LP or 2,LP,3,6,LP because it won’t check if buttons that don’t matter to our move were pressed. So depending on the result you may want a stricter check (say, when you go back one frame after you check for the button you’re interested in you also check if the input has changed at all. If so, you’ve got an extra press and may stop because you want the move to be exact). This is a basic framework, you may then tweak and expand it to add functionality as you find its limitations.