Phaser Making a fade to black reaction, having trouble with repeating events

51 Views Asked by At

I'm trying to add a fade to black event to my game. It triggers after a certain dialogue is triggered, and causes the screen to fade to black and then switch to another scene. I started by creating a big, black sprite that covers the entire screen, the set its alpha to 0. Here is the code that makes the fade work:

            this.line1.setText('Scally: Its been a long day Peef. Ready to hit the hay?');
            this.line2.setText('Press A for: Yeah I am ready to sleep. or Press D for: Naw, I am gonna stay up a bit more.');
            this.time.addEvent({
                delay: 2500, 
                callback: () => this.blackFade.setAlpha(0.2),
                callback: () => console.log("1"),
                callbackScope: this, 
            });
            this.time.addEvent({
                delay: 4500, 
                callback: () => this.blackFade.setAlpha(0.4),
                callback: () => console.log("2"),
                callbackScope: this, 
            });
            this.time.addEvent({
                delay: 6500, 
                callback: () => this.blackFade.setAlpha(0.6),
                callback: () => console.log("3"),
                callbackScope: this, 
            });
            this.time.addEvent({
                delay: 8500, 
                callback: () => this.blackFade.setAlpha(0.8),
                callback: () => console.log("4"),
                callbackScope: this, 
            });
            this.time.addEvent({
                delay: 10500, 
                callback: () => this.blackFade.setAlpha(1),
                callback: () => console.log("5"),
                callbackScope: this, 
            });
            this.time.addEvent({
                delay: 12500, 
                callback: () => this.scene.switch('bedRoomDay2'),
                callbackScope: this, 
            });

As I have this code in the update method, I'm having an issue where the timer events are triggered multiple times, causing the screen to only darken a little with occasional darker flashes before switching scenes, never becoming completely black. Is there a way to ensure that the timer events only trigger once, preferably without moving the code out of the update method?

If it helps, I'm using Phaser 3 in VSCode employing arcade physics.

1

There are 1 best solutions below

3
winner_joiner On BEST ANSWER

Well you would need a helper variable to prevent multiple calls, and instead of the timer, I would recommend using one simply tween call, since the tween would update the alpha property in a smooth fashion.

Both mentioned concepts are demonstrated in the following example.

Small fade-out Demo:

document.body.style = 'margin:0;';

var config = {
    width: 536,
    height: 183,
    scene: {
        create, 
        update,
    }
}; 

function create () {
    this.label = this.add.text(10,10, 'Use Spacebar, to Fade WhiteBox')
        .setScale(1.5)
        .setOrigin(0)
        .setStyle({fontStyle: 'bold', fontFamily: 'Arial'});

    // Fade Status Varible Initialize
    this.isFading = false;
    this.spacebar = this.input.keyboard.addKey('space');
    
    // Game Object to fade
    this.add.rectangle(268, 91, 200, 50, 0xffffff);
    this.blackFade = this.add.rectangle(268, 91, 200, 50, 0);
    this.blackFade.setAlpha(0);
}

function update(){
    // Only start fading, if fading is not taking place
    if(!this.isFading && Phaser.Input.Keyboard.JustDown(this.spacebar)){
        if(this.blackFade.alpha == 0){
            this.isFading = true;
            this.tweens.add({
                targets: this.blackFade,
                alpha: 1,
                duration: 6000,
                onComplete: () => {
                  // reset variable
                  this.isFading = false;
                  this.label.setText('Use Spacebar, to show WhiteBox');
                },
                repeat: 0,
            });
        } else {
            // fade reset only for demo
            this.blackFade.alpha = 0;
            this.label.setText('Use Spacebar, to Fade WhiteBox');
        }
    }
}

new Phaser.Game(config);
<script src="//cdn.jsdelivr.net/npm/phaser/dist/phaser.min.js"></script>

Update:

There are several way to let the black screen linger, but the easy one is simply to increase the duration and/or the alpha value of the tween. the alpha value will the

Small fade-out & linger Demo:

Setting alpha to 2 this means, that half of the tween duration about ~3000ms the screen will be black. if you need less us can adjust the alpha property.

document.body.style = 'margin:0;';

var config = {
    width: 536,
    height: 183,
    scene: {
        create, 
        update,
    }
}; 

function create () {
    this.label = this.add.text(10,10, 'Use Spacebar, to Fade WhiteBox')
        .setScale(1.5)
        .setOrigin(0)
        .setStyle({fontStyle: 'bold', fontFamily: 'Arial'});

    // Fade Status Varible Initialize
    this.isFading = false;
    this.spacebar = this.input.keyboard.addKey('space');
    
    // Game Object to fade
    this.add.rectangle(268, 91, 200, 50, 0xffffff);
    this.blackFade1 = this.add.rectangle(218, 91, 100, 50, 0);
    this.blackFade1.setAlpha(0);
    
    this.blackFade2 = this.add.rectangle(318, 91, 100, 50, 0);
    this.blackFade2.setAlpha(0);
}

function update(){
    // Only start fading, if fading is not taking place
    if(!this.isFading && Phaser.Input.Keyboard.JustDown(this.spacebar)){
        if(this.blackFade1.alpha == 0){
            this.isFading = true;
            this.tweens.add({
                targets: this.blackFade1,
                alpha: 2,
                duration: 8000,
                onComplete: () => {
                  // reset variable
                  this.isFading = false;
                  this.label.setText('Use Spacebar, to show WhiteBox');
                },
                repeat: 0,
            });
            
             this.tweens.add({
                targets: this.blackFade2,
                alpha: 1,
                duration: 8000,
                onComplete: () => {
                  // reset variable
                  // this.isFading = false;
                  // this.label.setText('Use Spacebar, to show WhiteBox');
                },
                repeat: 0,
            });
        } else {
            // fade reset only for demo
            this.blackFade1.alpha = 0;
            this.blackFade2.alpha = 0;
            this.label.setText('Use Spacebar, to Fade WhiteBox');
        }
    }
}

new Phaser.Game(config);
<script src="//cdn.jsdelivr.net/npm/phaser/dist/phaser.min.js"></script>

Or: simply call a timer from the onComplete callback.