Jump to content

Hadouken Motion detection (Down, Right, Q button)


mkhan074
 Share

Recommended Posts

Hi everyone, 

As you guys might know, I am working on a fighting game, and I want to be able to throw a hadouken (a fireball) when down, right, and the Q button is entered.

I have a two methods I call from the update method. (Btw, I am an ASP.NET Developer so I will use the words method and function interchangeably)

1) I have a string variable I concatenate to whenever I press an input, this is what the variable inputString is for. 

function inputTracker()
{
    if (cursors.left.downDuration(1)) {       
        inputString += "L";
    }
    else if (cursors.right.downDuration(1)) {     
        inputString += "R";
    }
    else if (cursors.down.downDuration(1)) {       
        inputString += "D";
    }
    else if (mediumPunchInput.downDuration(1)) {       
        inputString += "[MP]";
    }
    else if (lightPunchInput.downDuration(1))
    {
        inputString += "[LP]";
      
    }
    
}

2) I have another method that determines if the user has done any special moves (Hadouken, tatsu, shoryuken)

function specialMovesTracker() {


    if (inputString.includes("DR[LP]")) {
        console.log('hadouken');
        inputString = "";   
    } 


}

 

The way it is implemented works, but the only issue is that there is no time constraint. I would like to press down, right, Q (which is LP -- light punch) in a fluid motion and throw a hadouken. there needs to be a time constraint. But I am not sure how to implement that in javascript. I was thinking of an array that contains the input along with the time, but array comparisons are not as flexible as it is in C# and other OOP languages.

 

Link to comment
Share on other sites

Hi everyone, I think I figured it out and I want to share with everyone. There might be a better way, so I'm not sure.

I have a function called InputHandlers within my update method, as shown: 


function inputHandlers() {

    //TODO: Neutral jump:
    //   playerKen.body.velocity.y = -50;
    //    playerKen.animations.play('neutralJump', 7, false);

    if (cursors.left.isDown && cursors.down.isUp) {    
        lastLeftInput = this.game.time.totalElapsedSeconds();
        walkLeft();
    }
    else if (cursors.right.isDown) {
        lastRightInput = this.game.time.totalElapsedSeconds();
        walkRight();
      
    }
    else if (cursors.down.isDown) {
        lastDownInput = this.game.time.totalElapsedSeconds();
        crouch();
    }
    else if (mediumPunchInput.isDown) {
        lastMediumPunchInput = this.game.time.totalElapsedSeconds();
        mediumPunch();
    }
    else if (lightPunchInput.isDown) {
        lastLightPunchInput = this.game.time.totalElapsedSeconds();
        lightPunch();

    }
    else {
        standing();
    }
}

It keeps track of the last time you have put that input in. 

The logic in the below code is it detects whether your inputs are in a certain way. A nested if statement is below that which calculates whether you have hit that input fast enough to the the fireball. 

function specialMovesTracker() {
    if (inputString.includes("DR[LP]")) { 
        if ((lastDownInput - lastLightPunchInput) < 0.44425) {
            console.log('hadouken');
            inputString = "";
        }
        else
        {
            console.log('Do not do hadouken, users inputs are too slow.');
        }
    }
    else if (inputString.includes("DRD[LP]")) //Shoryuken (Dragon Punch)
    {
         
      
        if ((lastDownInput - lastLightPunchInput) < 1.5) {
            console.log('shoryuken');
            inputString = "";
        }
    }
    else
    {
        console.log("No Special moves detected.");
    }

}

 

Link to comment
Share on other sites

Maybe it's all the same to you, but I would have called the string 'inputHistory', so that I can clearly decouple inputs that are currently pressed from inputs that have been pressed in the past. That could be an array with the input pressed and the date at which it was pressed. This way, you can check at anytime if the input history contains a potential combo and if the time frame is short enough to allow that combo. And of course, empty the input history queue from inputs that are older than X seconds.

For example : 

inputHistory = [{input: 'left', date: 10}, {input: 'right', date: 15}, {input: 'A', date: 50}, etc.]

Very interested in your project though! Don't forget to share it on the forum once you have something playable! :D

Link to comment
Share on other sites

I have a couple of key helpers (not linked to Phaser stuff). I've got it all going through streams but thats an implementation detail, a simpler view is its just an event emitter, so a keydown event outputs the key that was pressed and a map (you could use an array) of all currently pressed keys (my implementation tracks keydown and keyup events and for each key ignores the key repeat events that the browser wants to fire, I additionally fire a keypress event each tick, tied to requestAnimationFrame, as the browser key repeat behaviour is unacceptable in my case). To test for a combo I can use this method to test all currently pressed keys.

This is a good and simple implementation but not suitable in your case, nor mine.

So, I have another stream for combos. Each keydown comes with a timestamp, I have a function that runs each tick when a key is pressed (I'm using streams, so this is a fold/scan function, very easy this way), when a new key comes in it adds it to the array with the timestamp and kills any keys that are older than a set variable (say, 100ms, whatever you need). This stream emits events with all the keys, in date order, pressed in the last X ms. To compare I usually just .join('') on the pressed keys and compare to a string i.e.

event.pressed.join('') === 'ASD<space>`

As they are time ordered if the user hit a different key in the middle of the combo then it wouldn't match the string, similarly, as older keypresses get removed from the list if you take too long over the combo it wont match.

This isn't a perfect solution either, but its more than good enough for all of my use-cases, and probably yours too I think.

From the game point of view, its dead simple, I simply attach a function to the stream to compare against a combo string (i.e. a `<left><down><right>Z`) which emits an event only when that combo matches, then listen for that event and do whatever you need to do.

I have it available publicly on npm and this is the relevant source code, very small and simple (if you're up to speed with functional programming or understand how streams emit and event). It's not quite ready for public consumption, I need to just change how it gets built and you'll see I need to write some documentation and proper tests, but the source might help you and you can use it now if necessary (I do in a separate small project). All the streams emit plain objects (containing `type` and `keys` properties), `keystream` emits down, up and pressed events, `timedKeySequence` emits the last 10 keypresses in the last 200ms (both configurable), you'd add a combo comparison function to filter events coming out of that stream, super simple.

edit: I just remembered there is an example of using the `timedKeySequence` here, if you run that example it'll output `Hadoken` to the screen when you hit 'ASD<enter>'! Literally a one-liner to compare combos.

Link to comment
Share on other sites

You guys do games that heavily rely on keyboard inputs : did you notice any major fuck up with Edge or Safari? In my game keyboard behaves poorly (some key events are completely ignored), and I highly doubt it is because of my code. Did you notice anything with these browsers?

Link to comment
Share on other sites

@Skeptron I'm not using any of my stuff in production, so, at this stage I dont know. In my case I'm grabbing some stuff from the raw browser key events which might not exist in each browser (should do with modern ones though).

I just tried my little example in safari (ha ha, it blew up on accessing window.screen.orientation, but after removing that... frustratingly safari and iOS safari do not support this, or the orientation call back, which is very frustrating as its particularly useful in iOS safari) and abused the keyboard pretty heavily, didn't notice any event drops. I don't have a nice (or quick) way to test Edge.

Link to comment
Share on other sites

 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...