Help with "combo" mechanics.

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Xugro
Party member
Posts: 117
Joined: Wed Sep 29, 2010 8:14 pm

Re: Help with "combo" mechanics.

Post by Xugro »

RNavega wrote: Sun Apr 06, 2025 6:55 am This means that you can structure the key sequences like a tree (like "pathways", like a river), and each node in this tree represents each key in the sequence, and each node also points to the other nodes that there are special moves for.
Yes, but this might be problematic if you start one sequence and when still inside start another sequence. Here is an example:
  • Combo 1: up, down, left, right
  • Combo 2: down, down, up
If the players presses up, down, down, up, it should trigger Combo 2, but with your implementation it does not.

But I really like you implementation RNavega. I had the same idea yesterday and a nearly identical implementation in my head.
Xugro
Party member
Posts: 117
Joined: Wed Sep 29, 2010 8:14 pm

Re: Help with "combo" mechanics.

Post by Xugro »

I would propose a different idea:

Use a buffer to remember the last n keystrokes. Where n is the length of the longest combo. Every time the player presses a button, we add the key to the buffer and remove the oldest entry. So if the player has pressed up, down, left and right and now presses kick we add kick to the buffer and remove up.
buffer_of_pressed_keys.png
buffer_of_pressed_keys.png (17.09 KiB) Viewed 1461 times
Then we model the combos as a tree, but backwards. We start at the top and for every button pressed, starting with the newest going to the oldest, we traverse the tree. When we hit a leaf-node we trigger the combo.
combo_tree.png
combo_tree.png (30.99 KiB) Viewed 1461 times
MrFariator
Party member
Posts: 578
Joined: Wed Oct 05, 2016 11:53 am

Re: Help with "combo" mechanics.

Post by MrFariator »

Xugro wrote: Sun Apr 06, 2025 11:14 am Use a buffer to remember the last n keystrokes. Where n is the length of the longest combo. Every time the player presses a button, we add the key to the buffer and remove the oldest entry. So if the player has pressed up, down, left and right and now presses kick we add kick to the buffer and remove up.
It's better to have the buffer be longer than the longest recognized move, because otherwise it will be harder to perform the longest move (because the buffer would need to match exactly). This sort of buffer approach you're suggesting works fine for more digital inputs, like for cheat codes that you input one-by-one in some static place (title screen, menus, etc), but during gameplay player will also be moving while trying to do these inputs. That can make it harder to keep inputs "clean".

Generally, fighting games' command interpreters work something like what RNavega suggests. However, depending on game, they tend to be a bit more naive brute-forcey approach than a node structure, in that they simply check that if any move's directions have been pressed within the timeframe the game allows (some more strict than others). If there is overlap (ex: quarter circle for hadoken, vs double quarter circle for a super), use some sort of priority system. This is why some fighting games may get a bit overzealous and have player's character perform a shoryuken (forward, down, down-forward, button) when player might have intended to walk forward and then hadoken (hold forward for a bit, down, down-forward, button).
User avatar
dusoft
Party member
Posts: 792
Joined: Fri Nov 08, 2013 12:07 am
Location: Europe usually
Contact:

Re: Help with "combo" mechanics.

Post by dusoft »

Xugro wrote: Sun Apr 06, 2025 11:14 am I would propose a different idea:

Use a buffer to remember the last n keystrokes. Where n is the length of the longest combo. Every time the player presses a button, we add the key to the buffer and remove the oldest entry. So if the player has pressed up, down, left and right and now presses kick we add kick to the buffer and remove up.
buffer_of_pressed_keys.png

Then we model the combos as a tree, but backwards. We start at the top and for every button pressed, starting with the newest going to the oldest, we traverse the tree. When we hit a leaf-node we trigger the combo.
combo_tree.png
Well, you just described a stack that I mentioned before. So basically an ordered Lua table.
TheFoxyHu3
Prole
Posts: 13
Joined: Sun Mar 17, 2024 10:05 pm

Re: Help with "combo" mechanics.

Post by TheFoxyHu3 »

RNavega wrote: Sun Apr 06, 2025 6:55 am
TheFoxyHu3 wrote: Fri Apr 04, 2025 2:11 pm Well, I like to do by myself (for learnment*). How can I bether that?
I like that attitude.
I thought of this: you already know all the special moves that you can do in your game. It's a finite set.
This means that, in your code, you can structure this information in a way that's easy/fast for the machine to test if a special move should be made or not.
...
Hello! I see your code and I want to know what you did this...

Code: Select all

       ...
       for index = 1, select('#', ...) do
       ...
The for loop limit, can it be a function value? I don't understand this piece! If you could explain me, I'll be very grateful.
For anyone who not understand me, I'm not a anglo-ish speaker...
RNavega
Party member
Posts: 465
Joined: Sun Aug 16, 2020 1:28 pm

Re: Help with "combo" mechanics.

Post by RNavega »

Xugro wrote: Sun Apr 06, 2025 10:53 am If the players presses up, down, down, up, it should trigger Combo 2, but with your implementation it does not.
That's a great catch Xugro, thanks for finding it.
I like your buffer idea (Edit: and Dusoft's stack as well) -- I was also considering using an FFI byte array with each byte as the pressed key history, and then using memcmp() to quickly compare the sequence bytes to see if any matches, but that would require using a loop to test each special move, which I was trying to avoid using (just for the challenge).

After sleeping on it I think the branching problem that you described can be solved by improving the tree data structure, making the tree smarter.
Its use would remain almost the same: you'd build the tree as it was in that demo by registering all possible key sequences, then finally before you start using it you'd call another function to "finalize" the tree.
This finalization is done using an algorithm based on "crawlers" that add secondary/fallback connections to all nodes on the way as long as the crawlers had been performing the same sequences up to that point. At the end, all nodes will not only point to the next node in the original sequence as well as all possible sequences that could begin from that position, like in your up->down->left->right vs down->down->up problem. In this case the 'down' node of the first sequence would have a fallback connection to the first 'down' of the second sequence.

At the moment I don't have the motivation to implement this though, if I ever get to it I'll post it here.

PS Now that I think about it, it's better if we use FORWARD / BACKWARD for the horizontal direction instead of RIGHT / LEFT, because in fighting games, when the characters jump over each other and switch places on screen, they turn around to face the other side. So using an ambiguous name like this would let you define a sequence once and have it work no matter which side the character is facing.
TheFoxyHu3 wrote: Sun Apr 06, 2025 5:08 pm The for loop limit, can it be a function value? I don't understand this piece! If you could explain me, I'll be very grateful.
That's right, the "numerical for" (which iterates on a range of numbers) accepts expressions as the initial, the target and the (optional) step values. As long as those expressions evaluate to numbers then you can put anything inside those expressions like function calls, math, parenthesis etc.
This is valid Lua:

Code: Select all

for my_variable = (a + b * this_function(c)), other_function(d) do
    -- Do something with 'my_variable' in here.
end
As long as those expressions evaluate to actual numbers, like 3 and 57.6134 for example, then you're good.
Last edited by RNavega on Tue Apr 08, 2025 9:53 pm, edited 1 time in total.
TheFoxyHu3
Prole
Posts: 13
Joined: Sun Mar 17, 2024 10:05 pm

Re: Help with "combo" mechanics.

Post by TheFoxyHu3 »

RNavega wrote: Tue Apr 08, 2025 6:11 am That's right, the "numerical for" (which iterates on a range of numbers) accepts expressions as the initial, the target and the (optional) step values. As long as those expressions evaluate to numbers then you can put anything inside those expressions like function calls, math, parenthesis etc.
This is valid Lua:

Code: Select all

for my_variable = (a + b * this_function(c)), other_function(d) do
    -- Do something with 'my_variable' in here.
end
As long as those expressions evaluate to actual numbers, like 3 and 57.6134 for example, then you're good.
Wow. Thank you! Well, that's all I need for now. Thanks for everyone too!
For anyone who not understand me, I'm not a anglo-ish speaker...
Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot], Google [Bot] and 7 guests