How to create Key Combo with Custom Buttons?

I have custom buttons on game screen(Y, X, B, A) and metronome time event(1 tact in 1 second). How can i do for example this combo: А| А| YY| A ? Buttons must be pressed in metronome tact.

My metronome and buttons code:

export default class DemoScene extends Phaser.Scene {
constructor() {
super(‘Demo’);

    this.canClick = false;
}
create() {
    this.metronome();

   new ControllButtnos(this);
}
update() {
    if (
        Math.floor(this.metronomeTween.getElapsed()) >= 900 ||
        (Math.floor(this.metronomeTween.getElapsed()) >= 0 &&
            Math.floor(this.metronomeTween.getElapsed()) <= 150)
    ) {
        this.canClick = true;
    } else {
        this.canClick = false;
    }
}
metronome() {
    const border = this.add.graphics();
    border.lineStyle(3, 0xffffff, 1);
    border.strokeRect(
        5,
        5,
        this.sys.game.config.width - 10,
        this.sys.game.config.height - 10
    );

    const borderTween = this.tweens.add({
        targets: border,
        alpha: 0,
        duration: 500,
        repeat: 0,
        yoyo: false
    });
    borderTween.pause();

    this.metronomeTween = this.time.addEvent({
        delay: 1000,
        callback: () => {
            borderTween.play();
        },
        loop: true
    });
}

}

Buttons Class:

export default class ControlButtons extends Phaser.GameObjects.Group {
    constructor(scene) {
        super(scene);
        this.scene = scene;

        this.createButtons();
    }
    createButtons() {
         // Controll buttons events
        buttonY.on('pointerdown', () => {
            console.log('Y');
        });
        buttonX.on('pointerdown', () => {
            console.log(this.scene.canClick);
            if (this.scene.canClick) {
                console.log(Math.floor(this.scene.metronomeTween.getElapsed()));
            }
        });
        buttonB.on('pointerdown', () => {
            console.log('B');
        });
        buttonA.on('pointerdown', () => {
            console.log('A');
        });
     }
}

I see many flaws in your code I dont know how to help Is this code working for you?
One possible solution can be to implement a state machine working on states…
so from a=>b b=>c d=> etx and in then in update work with time state.go(b,(deltatime)=> if(deltatime etx)
return true.
I worked with rxjs too maybe it is more simple you just measure the scanned accumulated time between every click, but I dont know how to use it with phaser uum maybe try this

Thanks for the answer. I have laid out only the necessary part of the code from the class, since I do not want to put some details on a general review (this is a commercial project). Yes, this code works. If you can give a more detailed answer, I can send you the full code.

Okay, I dont know other way than i mentioned…
try to explain more detailed how it supposed to work, like in math., every second i get 0,2 sec time to click and next click accumulates till i miss click and break the combo?
I am clueless Mate

This is me just spit-balling here, but if I was to approach this I would at least consider simply recording every button press along with a “timestamp” (probably your own in-game millisecond counter) of when that button was pressed. Then I would analyze this stream of presses to see what was on the metronome and what wasn’t. This is oftentimes how other timing-based key combinations such as special moves in fighting games are handled, rather than trying to write logic to determine at the time of press if a special move was performed.

Hi @AntonPiniaz,
A possible solution would be to use a string in which both the metronome and the pressed keys will modify it.
This string would be verified from the metronome in each tac.
In this code I am using the cursors and looking for the combo “L | L | RR | L” (left left right …):

class GameScene extends Phaser.Scene{
  constructor(){
    super('gameScene');
  }
  
  create(){
    this.combo = '';
    this.metronome();
    this.cursors = this.input.keyboard.createCursorKeys();
    this.info = this.add.text(100,100,'');
  }
  
  update(){
    if(Phaser.Input.Keyboard.JustDown(this.cursors.left)){
      this.combo += 'L';
    } else if(Phaser.Input.Keyboard.JustDown(this.cursors.right)){
      this.combo += 'R';
    }
  }
  
  metronome() {
    const border = this.add.graphics();
    border.lineStyle(3, 0xffffff, 1);
    border.strokeRect(
        5,
        5,
        this.sys.game.config.width - 10,
        this.sys.game.config.height - 10
    );

    const borderTween = this.tweens.add({
        targets: border,
        alpha: 0,
        duration: 500,
        repeat: 0,
        yoyo: false
    });
    borderTween.pause();

    this.metronomeTween = this.time.addEvent({
        delay: 1000,
        callback: () => {
            borderTween.play();
            this.combo +='|';
            this.checkCombo('L|L|RR|L');
        },
        loop: true
    });
}
  
  checkCombo(comboString){
    if(this.combo.indexOf('||') != -1){
      this.combo = '';
      return;
    }
    if(this.combo.indexOf(comboString) != -1){
      this.combo = '';
      this.info.setText(`combo ${comboString} activated`);
      setTimeout(()=>{this.info.setText('')},1500);
    }
  }
}

Code and demo: https://codepen.io/jjcapellan/pen/EzGRgv

Regards.

1 Like

Thank you, this is exactly what I need. I implement this solution for my buttons.
True, I have already solved this problem earlier, but your approach is more concise and clear.

cool I had another solution maybe you found the solution
cheers =)
I don’t know if to post it but I do it anyway this is how I solved it sort of in observables which I don’t know if they can be implemented
Hi Jack… I wanted to help but I am pretty new to Phaser 3 and have a headache but I made this in … observables maybe helps a little

         //x=this.paddlepos;
   switch (event.keyCode) {
       case PADDLE_KEYS.left:
        //x+=1;
return 0
       case PADDLE_KEYS.right:
     return 2
       default:
           //return null;
           return 1
   }
   return null
})
this.$animator2 = zip(
  interval(12,animationFrameScheduler).pipe(
    sample(interval(4000))
  ),
  of(43,52,52,25,42,32,22,24)
  , $press.pipe(
    map((f)=>({
      delta:f,
combo:null

    })),
scan((f,ff)=>({
  delta:f.delta,
combo:f.delta+ff.delta

  })

  )),
  
  (x,y,s) =>s,
)
I don't know as I said if it is to any help but it records every clicks and emits an object every four seconds and scans =accumulates the combo in 2 steps like for example two left is zero two right is 4.,... um yes,
and I'm still a bit noob to phaser3 but its suppose to be implemented somehow
so the latest click combined with 4 seconds plus the click with the 4 seconds before. in phase 3 you have the update function, but this way no break combo is implemented, but for example, if two left breaks the combo just put some logic the "of " is just for a demo like if the first combo is an "a" next combo is "a" +"previous"
cheers mate