Search code examples
javascriptgame-enginephaser-framework

How to update my score text correctly in Phaser 3?


I have my score variable updating in my Archery game. However, I cannot get the score to update correctly. Every time it updates, the new text just pastes over the old text.

I have tried it inside of the getMedal() function, outside of the getMedal() function, inside the render() function.

<!DOCTYPE html> 
<html lang="en"> 
<head> 
    <meta charset="UTF-8" />
    <title>Video Game</title>
    <script src="//cdn.jsdelivr.net/npm/phaser@3.11.0/dist/phaser.js"></script>
    <style type="text/css">
        body {
            margin: 0;
        }
    </style>
</head>
<body>

<script type="text/javascript">
    //Configurations for the physics engine
    var physicsConfig = {
        default: 'arcade',
        arcade: {
            debug: false //CHANGE THIS TO TRUE TO SEE LINES
        }
    }
    //Configurations for the game itself
    var config = {
        type: Phaser.AUTO,
        width: 800,
        height: 600,
        physics: physicsConfig,
        scene: {
            preload: preload,
            create: create,
            update: update,
            render: render
        }
    };
    //Start the game
    var game = new Phaser.Game(config);

    function preload ()
    {   
        //Images
        this.load.image('sky', 'assets/images/sky.png');
        this.load.image('target', 'assets/images/target.png');
        this.load.image('ground', 'assets/images/ground.png');
        this.load.image('arrow', 'assets/images/arrow.png');
        this.load.image('gold_medal', 'assets/images/goldmedal.png');
        this.load.image('silver_medal', 'assets/images/silvermedal.png');
        this.load.image('bronze_medal', 'assets/images/bronzemedal.png');
        //Spritesheets
        this.load.spritesheet('archer', 'assets/spritesheets/archer_sprites.png', {frameWidth: 128, frameHeight: 128});
        this.load.spritesheet('rings', 'assets/spritesheets/rings_sprite.png', {frameWidth: 320, frameHeight: 320});
        //Audio
        this.load.audio('arrow_shot', 'assets/sounds/arrow_shooting.mp3');
    }
    function create ()
    {   
        //Load all the images that won't move
        this.add.image(400, 300, 'sky');
        this.add.image(210, 200, 'ground');

        //Create the archer/player
        this.player = this.physics.add.sprite(100, 410, 'archer');
        this.player.setBounce(0.2);
        this.player.setCollideWorldBounds(true);

        //Shooting animation
        this.anims.create({
            key: 'shoot',
            frames: this.anims.generateFrameNumbers('archer', {start : 0, end: 4}),
            frameRate: 20,
            repeat: 0
        });

        //Rings animation
        this.anims.create({
            key: 'rings_anim',
            frames: this.anims.generateFrameNumbers('rings', {start : 0, end : 69}),
            frameRate: 10,
            repeat: 0
        })
        //Play the animation on start
        this.rings = this.physics.add.sprite(300, 40, 'rings');
        this.rings.anims.play('rings_anim', true);

        //Create the target
        this.target = this.physics.add.sprite(530, 365, 'target');
        this.target.setSize(115, 95).setOffset(70, 130); //TARGET HITBOX
        this.target.enableBody = true;
        this.target.setImmovable();

        //Create an array for arrows for later
        this.arrows = [];

        //Create an array for medals for later
        this.medals = [];

        //Get keypresses
        this.cursors = this.input.keyboard.createCursorKeys();
        //Assign input for spacebar
        this.spacebar = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.SPACE);

        //Play sound when the arrow is shot
        this.arrowSound = this.sound.add('arrow_shot');

        //Make the arrows collide with the target
        this.physics.add.collider(this.arrows, this.target)

    }
    function update ()
    {   
        //Declare constants for movement
        const playerMoveAmt = 200;
        const arrowMoveAmt = 1500;
        this.player.setDrag(2000);

        //Declare variables for the score
        var score = 0;
        var scoreBoard;

        //Add the scoreboard in
        //Scoreboard
        scoreBoard = this.add.text(440, 40, "SCORE:0", 
        {fontSize: '32px', fill: '#fff'});

        //Rotation of the player
        if (this.cursors.up.isDown && this.player.angle > -45) {
            this.player.angle -= 1;}

        if (this.cursors.down.isDown && this.player.angle < 0) {
            this.player.angle += 1;}

        //Shooting with the spacebar
        if (Phaser.Input.Keyboard.JustDown(this.spacebar)) {

            //Animate the shooting
            this.player.anims.play('shoot', true);

            //Arrow shooting
            let arrow = this.physics.add.sprite(this.player.x, (this.player.y + 20), 'arrow');
            arrow.enableBody = true;
            arrow.body.immovable = false;

            //Edit arrow hitbox 
            arrow.setSize(50, 15).setOffset(5, 50);

            arrow.setGravityY(3600); //Gravity will affect the arrows

            //Arrow speeds
            arrow.setVelocityX(arrowMoveAmt);
            arrow.setVelocityY((this.player.angle * 50));

            this.arrows.push(arrow); //Add arrow to the arrow created earlier
            this.arrowSound.play(); //Play the sound

        }

        else if( this.target.body.touching.left) {

            let i = 0;

            //Set initial position of new medals
            let arrowOnTargetPositionX = 200;

            //Loop to create multiple arrows
            while (i < this.arrows.length) {
                newArrows = this.arrows[i];
                newArrows.setGravityY(0);
                newArrows.setVelocityX(0);
                newArrows.setVelocityY(0);

                //Add 30 to the new medal's x position
                arrowOnTargetPositionX = arrowOnTargetPositionX + 40;

                //Call the function to determine medal and pass the variable
                if(this.arrows.length <= 5) {
                    getMedal(arrowOnTargetPositionX);
                }

                i++;
            }
        }

        getMedal = (value) => {
            //Gold medal
            if (410 < newArrows.y && newArrows.y < 435) {
                this.add.image(value, 170, 'gold_medal');
                score += 5;
                this.player.angle = 0;
            }
            //Silver medal
            else if (395 < newArrows.y && newArrows.y < 450) {
                this.add.image(value, 170, 'silver_medal');
                score += 3;
                this.player.angle = 0;
            }
            //Bronze medal
            else if (380 < newArrows.y && newArrows.y < 460) {
                this.add.image(value, 173, 'bronze_medal');
                score += 1;
                this.player.angle = 0;
            }
        }
    }

    function render() {
    }
</script>
</body>
</html>

I expect it to show the score, with only one set of text, rather than pasting over the "SCORE: 0" over and over.


Solution

  • I have found the solution:

    • First, set the score variables outside of the update() method, you should set them before the preload() function.
    • Second, add scoreBoard = this.add.text(440, 40, "SCORE: 0", {fontSize: '32px', fill: '#fff'}); in the create() method.
    • Third, set scoreBoard.setText('Score: ' + score) after the last else if statement inside the getMedal() function.

    The final code would be like so:

    <script type="text/javascript">
        //Configurations for the physics engine
        var physicsConfig = {
            default: 'arcade',
            arcade: {
                debug: false //CHANGE THIS TO TRUE TO SEE LINES
            }
        }
        //Configurations for the game itself
        var config = {
            type: Phaser.AUTO,
            width: 800,
            height: 600,
            physics: physicsConfig,
            scene: {
                preload: preload,
                create: create,
                update: update,
                render: render
            }
        };
    
        //Declare  score variables
        let score = 0;
        let scoreBoard;
    
        //Start the game
        var game = new Phaser.Game(config);
    
        function preload ()
        {   
            //Images
            this.load.image('sky', 'assets/images/sky.png');
            this.load.image('target', 'assets/images/target.png');
            this.load.image('ground', 'assets/images/ground.png');
            this.load.image('arrow', 'assets/images/arrow.png');
            this.load.image('gold_medal', 'assets/images/goldmedal.png');
            this.load.image('silver_medal', 'assets/images/silvermedal.png');
            this.load.image('bronze_medal', 'assets/images/bronzemedal.png');
            //Spritesheets
            this.load.spritesheet('archer', 'assets/spritesheets/archer_sprites.png', {frameWidth: 128, frameHeight: 128});
            this.load.spritesheet('rings', 'assets/spritesheets/rings_sprite.png', {frameWidth: 320, frameHeight: 320});
            //Audio
            this.load.audio('arrow_shot', 'assets/sounds/arrow_shooting.mp3');
        }
        function create ()
        {   
            //Load all the images that won't move
            this.add.image(400, 300, 'sky');
            this.add.image(210, 200, 'ground');
    
            //Create the archer/player
            this.player = this.physics.add.sprite(100, 410, 'archer');
            this.player.setBounce(0.2);
            this.player.setCollideWorldBounds(true);
    
            //Shooting animation
            this.anims.create({
                key: 'shoot',
                frames: this.anims.generateFrameNumbers('archer', {start : 0, end: 4}),
                frameRate: 20,
                repeat: 0
            });
    
            //Rings animation
            this.anims.create({
                key: 'rings_anim',
                frames: this.anims.generateFrameNumbers('rings', {start : 0, end : 69}),
                frameRate: 10,
                repeat: 0
            })
            //Play the animation on start
            this.rings = this.physics.add.sprite(300, 40, 'rings');
            this.rings.anims.play('rings_anim', true);
    
            //Create the target
            this.target = this.physics.add.sprite(530, 365, 'target');
            this.target.setSize(115, 95).setOffset(70, 130); //TARGET HITBOX
            this.target.enableBody = true;
            this.target.setImmovable();
    
            //Create an array for arrows for later
            this.arrows = [];
    
            //Create an array for medals for later
            this.medals = [];
    
            //Get keypresses
            this.cursors = this.input.keyboard.createCursorKeys();
            //Assign input for spacebar
            this.spacebar = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.SPACE);
    
            //Play sound when the arrow is shot
            this.arrowSound = this.sound.add('arrow_shot');
    
            //Make the arrows collide with the target
            this.physics.add.collider(this.arrows, this.target)
    
            //Add the scoreboard in
            scoreBoard = this.add.text(440, 40, "SCORE: 0", {fontSize: '32px', fill: '#fff'});
    
        }
        function update ()
        {   
            //Declare constants for movement
            const playerMoveAmt = 200;
            const arrowMoveAmt = 1500;
            this.player.setDrag(2000);
    
            //Rotation of the player
            if (this.cursors.up.isDown && this.player.angle > -45) {
                this.player.angle -= 1;}
    
            if (this.cursors.down.isDown && this.player.angle < 0) {
                this.player.angle += 1;}
    
            //Shooting with the spacebar
            if (Phaser.Input.Keyboard.JustDown(this.spacebar)) {
    
                //Animate the shooting
                this.player.anims.play('shoot', true);
    
                //Arrow shooting
                let arrow = this.physics.add.sprite(this.player.x, (this.player.y + 20), 'arrow');
                arrow.enableBody = true;
                arrow.body.immovable = false;
    
                //Edit arrow hitbox 
                arrow.setSize(50, 15).setOffset(5, 50);
    
                arrow.setGravityY(3600); //Gravity will affect the arrows
    
                //Arrow speeds
                arrow.setVelocityX(arrowMoveAmt);
                arrow.setVelocityY((this.player.angle * 50));
    
                this.arrows.push(arrow); //Add arrow to the arrow created earlier
                this.arrowSound.play(); //Play the sound
    
            }
    
            else if( this.target.body.touching.left) {
    
                let i = 0;
    
                //Set initial position of new medals
                let arrowOnTargetPositionX = 200;
    
                //Loop to create multiple arrows
                while (i < this.arrows.length) {
                    newArrows = this.arrows[i];
                    newArrows.setGravityY(0);
                    newArrows.setVelocityX(0);
                    newArrows.setVelocityY(0);
    
                    //Add 30 to the new medal's x position
                    arrowOnTargetPositionX = arrowOnTargetPositionX + 40;
    
                    //Call the function to determine medal and pass the variable
                    if(this.arrows.length <= 5) {
                        getMedal(arrowOnTargetPositionX);
                    }
    
                    i++;
                }
            }
    
            getMedal = (value) => {
                //Gold medal
                if (410 < newArrows.y && newArrows.y < 435) {
                    this.add.image(value, 170, 'gold_medal');
                    score += 5;
                    this.player.angle = 0;
                }
                //Silver medal
                else if (395 < newArrows.y && newArrows.y < 450) {
                    this.add.image(value, 170, 'silver_medal');
                    score += 3;
                    this.player.angle = 0;
                }
                //Bronze medal
                else if (380 < newArrows.y && newArrows.y < 460) {
                    this.add.image(value, 173, 'bronze_medal');
                    score += 1;
                    this.player.angle = 0;
                }
                scoreBoard.setText('Score: ' + score)
            }
        }
    
        function render() {
        }
    </script>
    

    EDIT:

    The OP asked me to fix an extra issue with the score amount which was not displaying the right score. I fixed it by removing the getMedal() function & its if statement wrapper outside of while loop like so:

    //Loop to create multiple arrows
    while (i < this.arrows.length) {
        newArrows = this.arrows[i];
        newArrows.setGravityY(0);
        newArrows.setVelocityX(0);
        newArrows.setVelocityY(0);
    
        //Add 30 to the new medal's x position
        arrowOnTargetPositionX = arrowOnTargetPositionX + 40;
    
        i++;
    }
    //Call the function to determine medal and pass the variable
    if(this.arrows.length <= 5) {
        getMedal(arrowOnTargetPositionX);
    }