Buttons
This is the 15th step out of 16 of the Gamedev Phaser tutorial. Instead of starting the game right away, we can leave that decision to the player by adding a Start button they can press. Let's investigate how to do that.
New properties
We will need a property to store a boolean value representing whether the game is currently being played or not, and another one to represent our button. Add these lines below your other properties definitions:
class ExampleScene extends Phaser.Scene {
// ... previous property definitions ...
playing = false;
startButton;
// ... rest of the class ...
}
Loading the button spritesheet
We can load the button spritesheet the same way we loaded the ball's wobble animation. Add the following to the bottom of the preload()
method:
this.load.spritesheet("button", "img/button.png", {
frameWidth: 120,
frameHeight: 40,
});
A single button frame is 120 pixels wide and 40 pixels high.
You also need to grab the button spritesheet, and save it in your /img
directory.
Adding the button to the game
Adding the new button to the game is done by using the add.sprite
method. Add the following lines to the bottom of your create()
method:
this.startButton = this.add.sprite(
this.scale.width * 0.5,
this.scale.height * 0.5,
"button",
0,
);
In addition to the parameters we passed to the other add.sprite
calls (such as when we added the ball and paddle), this time we also pass the frame number, which is 0
in this case. This means that the first frame of the spritesheet will be used for the button's initial appearance.
To make the button respond to various inputs such as mouse clicks, we need to add the following lines right after the previous add.sprite
call:
this.startButton.setInteractive();
this.startButton.on(
"pointerover",
() => {
this.startButton.setFrame(1);
},
this,
);
this.startButton.on(
"pointerdown",
() => {
this.startButton.setFrame(2);
},
this,
);
this.startButton.on(
"pointerout",
() => {
this.startButton.setFrame(0);
},
this,
);
this.startButton.on(
"pointerup",
() => {
this.startGame();
},
this,
);
First, we call setInteractive
on the button to make it respond to pointer events. Then we add the four event listeners to the button:
pointerover
—when the pointer is over the button, we change the button's frame to1
, the second frame of the spritesheet.pointerdown
—when the button is pressed, we change the button's frame to2
, the third frame of the spritesheet.pointerout
—when the pointer moves out of the button, we change the button's frame back to0
, the first frame of the spritesheet.pointerup
—when the button is released, we call thestartGame
method to start the game.
Now, we need to define the startGame()
method referenced in the code above:
class ExampleScene extends Phaser.Scene {
// ...
startGame() {
this.startButton.destroy();
this.ball.body.setVelocity(150, -150);
this.playing = true;
}
}
When the button is pressed, we remove the button, set the ball's initial velocity, and set the playing
property to true
.
Finally for this section, go back into your create
method, find the this.ball.body.setVelocity(150, -150);
line, and remove it. You only want the ball to move when the button is pressed, not before!
Keeping the paddle still before the game starts
It works as expected, but we can still move the paddle when the game hasn't started yet, which looks a bit silly. To stop this, we can take advantage of the playing
property and make the paddle movable only when the game has started. To do that, adjust the update()
method like so:
class ExampleScene extends Phaser.Scene {
// ...
update() {
// ...
if (this.playing) {
this.paddle.x = this.input.x || this.scale.width * 0.5;
}
// ...
}
// ...
}
That way the paddle is immovable after everything is loaded and prepared, but before the start of the actual game.
Compare your code
Here's what you should have so far, running live. To view its source code, click the "Play" button.
Next steps
The last thing we will do in this article series is make the gameplay even more interesting by adding some randomization to the way the ball bounces off the paddle.