In this section, you will learn how to build a complete game in Phaser by following a structured, step-by-step approach. We will apply the concepts learned throughout the course, from setting up scenes to handling input, managing game state, and adding polish. By the end, you’ll have a playable game and a clear understanding of how to structure your own projects.
- Planning the Game Structure
Before coding, it’s crucial to outline the game’s structure:
- Game Genre: Platformer (player jumps and collects stars)
- Core Features:
- Player movement and jumping
- Collectible items (stars)
- Score tracking
- Simple enemy
- Game over and restart
Game Flow Table:
| Step | Description |
|---|---|
| 1. Boot/Preload | Load assets |
| 2. Main Menu | Start game, show instructions |
| 3. Gameplay | Player controls, collect stars, avoid enemy |
| 4. Game Over/Win | Show score, option to restart |
- Setting Up the Project
Directory Structure:
index.html Example:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Phaser Platformer Game</title> <script src="https://cdn.jsdelivr.net/npm/phaser@3/dist/phaser.js"></script> </head> <body> <script src="main.js"></script> </body> </html>
- Creating the Game Scenes
We’ll use three scenes: PreloadScene, MenuScene, and GameScene.
3.1 PreloadScene
Loads all assets.
class PreloadScene extends Phaser.Scene {
constructor() {
super('PreloadScene');
}
preload() {
this.load.image('background', 'assets/background.png');
this.load.image('player', 'assets/player.png');
this.load.image('star', 'assets/star.png');
this.load.image('enemy', 'assets/enemy.png');
}
create() {
this.scene.start('MenuScene');
}
}3.2 MenuScene
Displays the main menu and starts the game.
class MenuScene extends Phaser.Scene {
constructor() {
super('MenuScene');
}
create() {
this.add.text(100, 100, 'Platformer Game', { fontSize: '32px', fill: '#fff' });
this.add.text(100, 150, 'Press SPACE to Start', { fontSize: '24px', fill: '#fff' });
this.input.keyboard.once('keydown-SPACE', () => {
this.scene.start('GameScene');
});
}
}3.3 GameScene
Handles the main gameplay.
class GameScene extends Phaser.Scene {
constructor() {
super('GameScene');
this.score = 0;
}
create() {
// Background
this.add.image(400, 300, 'background');
// Player
this.player = this.physics.add.sprite(100, 450, 'player');
this.player.setCollideWorldBounds(true);
// Stars group
this.stars = this.physics.add.group({
key: 'star',
repeat: 5,
setXY: { x: 120, y: 0, stepX: 120 }
});
// Enemy
this.enemy = this.physics.add.sprite(400, 500, 'enemy');
this.enemy.setVelocityX(100);
this.enemy.setCollideWorldBounds(true);
this.enemy.setBounce(1, 0);
// Score text
this.scoreText = this.add.text(16, 16, 'Score: 0', { fontSize: '24px', fill: '#fff' });
// Input
this.cursors = this.input.keyboard.createCursorKeys();
// Collisions
this.physics.add.overlap(this.player, this.stars, this.collectStar, null, this);
this.physics.add.overlap(this.player, this.enemy, this.hitEnemy, null, this);
}
update() {
// Player movement
if (this.cursors.left.isDown) {
this.player.setVelocityX(-160);
} else if (this.cursors.right.isDown) {
this.player.setVelocityX(160);
} else {
this.player.setVelocityX(0);
}
if (this.cursors.up.isDown && this.player.body.touching.down) {
this.player.setVelocityY(-330);
}
}
collectStar(player, star) {
star.disableBody(true, true);
this.score += 10;
this.scoreText.setText('Score: ' + this.score);
// Win condition
if (this.stars.countActive(true) === 0) {
this.scene.restart();
alert('You win! Final Score: ' + this.score);
}
}
hitEnemy(player, enemy) {
this.physics.pause();
player.setTint(0xff0000);
this.scoreText.setText('Game Over! Final Score: ' + this.score);
this.input.keyboard.once('keydown-SPACE', () => {
this.scene.restart();
});
}
}
- Initializing the Game
main.js Example:
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
physics: {
default: 'arcade',
arcade: {
gravity: { y: 300 },
debug: false
}
},
scene: [PreloadScene, MenuScene, GameScene]
};
const game = new Phaser.Game(config);
- Testing and Iterating
- Test: Open
index.htmlin your browser. - Iterate: Adjust player speed, add more stars, tweak enemy behavior, or improve visuals as desired.
- Exercise: Add a Double Jump Feature
Task:
Modify the player so they can jump twice before landing.
Hint:
Track the number of jumps and reset it when the player lands.
Solution:
// In GameScene class
create() {
// ... existing code ...
this.jumpCount = 0;
// ... existing code ...
}
update() {
// ... existing code ...
if (this.cursors.up.isDown && (this.player.body.touching.down || this.jumpCount < 2)) {
if (this.player.body.touching.down) {
this.jumpCount = 0;
}
if (!this.jumpPressed) {
this.player.setVelocityY(-330);
this.jumpCount++;
this.jumpPressed = true;
}
} else if (!this.cursors.up.isDown) {
this.jumpPressed = false;
}
if (this.player.body.touching.down) {
this.jumpCount = 0;
}
}Common Mistake:
Forgetting to reset jumpCount when the player lands, which prevents further jumps.
- Summary
You have now built a simple but complete game using Phaser, applying all the core concepts: scenes, sprites, input, physics, collisions, and game state management. You also learned how to extend gameplay with new features. This step-by-step approach can be adapted to create more complex games. In the next section, you’ll learn how to polish and finalize your game for release.
Phaser - Game Development with JavaScript
Module 1: Introduction to Game Development and Phaser
- What is Game Development?
- Overview of Phaser
- Setting Up Your Development Environment
- Your First Phaser Project
Module 2: Phaser Basics
- Understanding the Game Loop
- Game Configuration and Scenes
- Loading and Displaying Images
- Working with Text
- Handling Input (Keyboard and Mouse)
Module 3: Sprites and Animation
Module 4: Game Physics and Interactivity
- Introduction to Physics in Phaser
- Enabling Physics on Sprites
- Collisions and Overlaps
- Interactive Objects and Events
