Search code examples
javascripteventsdelayphaser-framework

how can i decrease delay in this.time.addEvent in phaser.js, based on score?


Someone already asked that question, but they didn't seem to get the right answer.

This is my code:

const eggGenLoop = this.time.addEvent({
        delay: 1500 - (gameState.score * 100),

        callback: eggGen,

        callbackScope: this,

        loop: true,
    });

so the delay doesn't change, clearly phaser just takes the initial gameState.score which is 0. two months ago i tried to make the same game, using plain JavaScript and setTimeout() / setInterval(), but i stumbled at the same obstacle, i hoped with phaser.js it would be easier.


Solution

  • As you mentioned, using this.time.addEvent and setting delay won't work, the reason is because the TimerEvent is created once, on the call this.time.addEvent(...).

    I see two simple options (personally I would choose option 2):

    Option 1)
    You could instead use setTimeout and call it recursively, and update the delay on each call.

       function setTimoutWithVariableDelta( score ){
            setTimeout(
                _ => {
                    // ... do some stuff
                    setTimoutWithVariableDelta( gameState.score );
                },
                1500 - (score * 100));
        } 
    

    Depending on your code, this option might not work well (and btw.: setTimeout, doesn't stop when the browser is in the background).

    Option 2)
    Or you could use the Scene update function.
    I put the logic for this type of dynamic delay into the function callOnMuliplierInterval, it should be straight forward. Just using the time parameter of the update function to keep track of the delay. (here the link to the documentation)

    Here is a possible example:
    (Sorry it got abit long, I got carried away)

    • Just click the buttons to change the score multiplier.

    document.body.style = 'margin:0;';
    
    var config = {
        type: Phaser.AUTO,
        width: 536,
        height: 203,
        scene: { create, update },
        banner: false
    }; 
    
    let interval = 2000;
    
    let lastRun = -1;
    let statusText;
    let score = 1;
    let currentDelta = 1;
    let callsCount = 0;
    
    function create () {
        statusText = this.add.text(220, 20, `Score multiplier: ${score}`)
            .setFontFamily('Arial')
            .setFontStyle('bold')
            .setFontSize('20px');
        
        createButton(this, 40, 20, 0xff0000, '#ffffff', .33);
        createButton(this, 40, 80, 0x0000ff, '#ffffff', .66);
        createButton(this, 40, 140, 0x008800, '#ffffff', 1);
        
    }
    
    // demo helper function for creating buttons
    function createButton(scene, x, y, color, textColor, multiplier){
        let button = scene.add.rectangle(x, y, 140, 40, color)
            .setOrigin(0);
        let buttonText = scene.add.text(0, 0, `Score: ${multiplier}`)
            .setFontFamily('Arial')
            .setFontStyle('bold')
            .setFontSize('20px');
        
        Phaser.Display.Align.In.Center(buttonText, button);
        
        button
            .setInteractive()
            .on('pointerdown',  _ => score = multiplier);
    }
    
    // this function contains the important logic
    function callOnMuliplierInterval(time){
        let newMessage = `Score multiplier: ${score}\n`; 
         newMessage += `ElapsedTime: ${(time / 1000).toFixed(0)}s\n\n`;
         newMessage += `CurrentDelay: ${currentDelta}\n`;
        newMessage += `NextDelay: ${interval * score}\n\n`;
       
        newMessage += `TimesCalled: ${callsCount}`;
    
        // Execute on: first Run or when the delay has passed
        if( lastRun == -1 || lastRun + currentDelta <= time ){
            lastRun = time;
            currentDelta = interval * score;
            // HERE YOU WOULD DO THE ACTION
            callsCount++;
        } 
        
        // Just update the message
        statusText.setText(newMessage);
    }
    
    function update(time, delta){
       callOnMuliplierInterval(time);
    }
    
    new Phaser.Game(config);
    <script src="https://cdn.jsdelivr.net/npm/phaser@3.55.2/dist/phaser.js"></script>