How to update my score text correctly in Phaser 3?
Asked Answered
I

1

6

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/[email protected]/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.

Inception answered 19/10, 2019 at 20:51 Comment(0)
L
7

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);
}
Lakisha answered 20/10, 2019 at 2:33 Comment(7)
it displays correctly, however, the score does not go up like I thought It would. I need the score to go up 5 whenever a gold medal is added, 3 for a silver, and 1 for a bronze. (Ex. if you get 2 gold medals, one silver, one bronze, and you miss the last arrow, your score would be 14) The score does not behave this way. Where should I move the "score +=" statements?Inception
@RobertSmith , I have updated my answer with the fixed score amount.Lakisha
thank you again and sorry to keep bothering. But now, sometimes when I get two gold medals, the score won't change, or when I miss with an arrow, the score resets back to one. Do you know why this is? Should I just create an array for the medal objects and just use the array to determine the score?Inception
and when you say you removed the "getMedal()" function, do you mean completely removed?Inception
No, I meant to take it off from the while loop along with its if statement. Just copy paste the last code snippet above concerning the while loop.Lakisha
@RobertSmith I just double-checked & it works when you follow the instruction above. Let me know, if you got any questionsLakisha
Let us continue this discussion in chat.Inception

© 2022 - 2024 — McMap. All rights reserved.