Phaser framework is a free javascript library created especially for game developers. It contains many ready-made functions and structures and makes it easier for javascript game programmers. Many interactive html5 applications with visual content, not just games, can be created with the help of Javascript-Phaser.
Here we will prepare the Catch Star game step by step. With this activitiy you will catch important gains and tips in the use of Phaser 3 framework. And then you can develop your own game.
IMPORTANT:Before developing this application on your own computer, you must install one of the server applications, such as Xampp, on your computer. Otherwise, you will not see the output of the code.
What will you learn while making this game?
Scenario of the game:
The aim of this game is to reach the door after collecting at least 8 stars with the character that we direct with the arrow keys of the keyboard. While doing this, the bombs should be avoided. Touching the bombs in 10 times will kill you and the game will fail.
Now let's go step by step to the construction of the game.
First of all, the screen dimensions of the game and the coordinate structure in Phaser are as follows:
The coordinate dimensions given in the following coding are according to scaling above.
Since the game is a javascript based structure, we create the basic structure in tags as follows. The basic structure codes and related explanations are given below.
<script type="text/javascript"> var config = { type: Phaser.AUTO, width: 1024, //Defining game scene width height: 768, //Defining game scene height physics: { default: 'arcade', arcade: { debug: false } }, scene: { preload: preload, //Defining preloaded materials create: create, //Defining objects and animations update: update //Events in the flow of the game } }; var game = new Phaser.Game(config); //We create the phaser object whose settings are given in config above function preload () { } function create () { } function update () { } </script>
To access the code above which is embedded in a web page page:
On this page, you can view the source from the right-click menu and see how javascript code is embedded in web page. Also you will see how to import Phaser3 framework to the web page. Please look between tags for this.
You can use softwares such as Atom, Brackets, Notepad ++ for creating the web page. When saving the page, change the extension of web page such as html, htm, php, asp, aspx.
As screenshot above, you can edit your code structure to add the background image and main character to the game as follows:
<script type="text/javascript"> var config = { type: Phaser.AUTO, width: 1024, //Defining game scene width height: 768, //Defining game scene heght physics: { default: 'arcade', arcade: { debug: false } }, scene: { preload: preload, //Defining preloaded materials create: create, //Defining objects and animations update: update //Events in the flow of the game } }; var game = new Phaser.Game(config); //We create the phaser object whose settings are given in config above function preload () { this.load.image('bg', 'images/bg.png'); //The images to be created must be preloaded in this way this.load.spritesheet('bobihorizontal', 'images/bobihorizontal.png', { frameWidth: 114, frameHeight: 300 }); //With this code, we load the sequence of horizontal character images of our character this.load.spritesheet('bobiup', 'images/bobiup.png', { frameWidth: 111, frameHeight: 312 }); //With this code, we load the sequence of up going character images of our character this.load.spritesheet('bobidown', 'images/bobidown.png', { frameWidth: 111, frameHeight: 312 }); //With this code, we load the sequence of down going character images of our character this.load.image('star', 'images/star.png'); this.load.image('bomba', 'images/bomba.png'); this.load.image('doorimg', 'images/door.png'); } function create () { background = this.add.image(512, 384, 'bg'); //We assign value to variable and add to scene bobi = this.physics.add.sprite(100, 450, 'bobihorizontal').setScale(0.3); //We assign preloaded image to variable and add to scene } function update () { } </script>
To access the code above which is embedded in a web page page:
Main character Bobi is coded according to the arrow keys of the keyboard as follows. With this code Bobi can go up,down,left,right.
<script type="text/javascript"> var config = { type: Phaser.AUTO, width: 1024, //Defining game scene width height: 768, //Defining game scene heght physics: { default: 'arcade', arcade: { debug: false } }, scene: { preload: preload, //Defining preloaded materials create: create, //Defining objects and animations update: update //Events in the flow of the game } }; var game = new Phaser.Game(config); //We create the phaser object whose settings are given in config above //We define variables that we will use throughout the game var cursors; function preload () { this.load.image('bg', 'images/bg.png'); //The images to be created must be preloaded in this way this.load.spritesheet('bobihorizontal', 'images/bobihorizontal.png', { frameWidth: 114, frameHeight: 300 }); //With this code, we load the sequence of horizontal character images of our character this.load.spritesheet('bobiup', 'images/bobiup.png', { frameWidth: 111, frameHeight: 312 }); //With this code, we load the sequence of up going character images of our character this.load.spritesheet('bobidown', 'images/bobidown.png', { frameWidth: 111, frameHeight: 312 }); //With this code, we load the sequence of down going character images of our character } function create () { background = this.add.image(512, 384, 'bg'); //We assign value to variable and add to scene bobi = this.physics.add.sprite(100, 450, 'bobihorizontal').setScale(0.3); //We assign preloaded image to variable and add to scene cursors = this.input.keyboard.createCursorKeys(); //We defined keys //Creating characters move events this.anims.create({ key: 'up', frames: this.anims.generateFrameNumbers('bobiup', { start: 0, end: 3 }), frameRate: 10, repeat: -1 }); this.anims.create({ key: 'down', frames: this.anims.generateFrameNumbers('bobidown', { start: 0, end: 3 }), frameRate: 10, repeat: -1 }); this.anims.create({ key: 'left', frames: this.anims.generateFrameNumbers('bobihorizontal', { start: 0, end: 3 }), frameRate: 10, repeat: -1 }); this.anims.create({ key: 'turn', frames: [ { key: 'bobihorizontal', frame: 4 } ], frameRate: 20 }); this.anims.create({ key: 'right', frames: this.anims.generateFrameNumbers('bobihorizontal', { start: 5, end: 8 }), frameRate: 10, repeat: -1 }); } function update () { if (cursors.up.isDown) { bobi.setVelocityY(-160); bobi.anims.play('up', true); } else if (cursors.down.isDown) { bobi.setVelocityY(160); bobi.anims.play('down', true); } else { bobi.setVelocityY(0); } if (cursors.left.isDown) { bobi.setVelocityX(-160); bobi.anims.play('left', true); } else if (cursors.right.isDown) { bobi.setVelocityX(160); bobi.anims.play('right', true); } else { bobi.setVelocityX(0); } if (!(cursors.left.isDown||cursors.right.isDown||cursors.up.isDown||cursors.down.isDown)) { bobi.anims.play('turn'); } } </script>
To access the code above which is embedded in a web page page:
The main character will earn points when he touches the stars we will place, and his life will decrease when he touches the bombs. We will define bombs and stars as "staticGroup" and place them on the stage. Stars and bombs will be placed randomly on the screen each time the game is loaded. We've identified 50 bombs and 15 stars here. You can change these numbers. Here's our code:
<script type="text/javascript"> var config = { type: Phaser.AUTO, width: 1024, //Defining game scene width height: 768, //Defining game scene heght physics: { default: 'arcade', arcade: { debug: false } }, scene: { preload: preload, //Defining preloaded materials create: create, //Defining objects and animations update: update //Events in the flow of the game } }; var game = new Phaser.Game(config); //We create the phaser object whose settings are given in config above //We define variables that we will use throughout the game var cursors; var stars; var bombs; function preload () { this.load.image('bg', 'images/bg.png'); //The images to be created must be preloaded in this way this.load.spritesheet('bobihorizontal', 'images/bobihorizontal.png', { frameWidth: 114, frameHeight: 300 }); //With this code, we load the sequence of horizontal character images of our character this.load.spritesheet('bobiup', 'images/bobiup.png', { frameWidth: 111, frameHeight: 312 }); //With this code, we load the sequence of up going character images of our character this.load.spritesheet('bobidown', 'images/bobidown.png', { frameWidth: 111, frameHeight: 312 }); //With this code, we load the sequence of down going character images of our character this.load.image('star', 'images/star.png'); this.load.image('bomb', 'images/bomb.png'); } function create () { background = this.add.image(512, 384, 'bg'); //We assign value to variable and add to scene bobi = this.physics.add.sprite(100, 450, 'bobihorizontal').setScale(0.3); //We assign preloaded image to variable and add to scene cursors = this.input.keyboard.createCursorKeys(); cursors = this.input.keyboard.createCursorKeys(); //We defined keys bombs = this.physics.add.staticGroup(); for (i = 0; i < 50; i++) { x = Phaser.Math.Between(0, 1024); y = Phaser.Math.Between(0, 768); bombs.create(x, y, 'bomb').refreshBody(); } stars = this.physics.add.staticGroup(); for (i = 0; i < 15; i++) { x = Phaser.Math.Between(0, 1024); y = Phaser.Math.Between(0, 768); stars.create(x, y, 'star').refreshBody(); } //Creating characters move events this.anims.create({ key: 'up', frames: this.anims.generateFrameNumbers('bobiup', { start: 0, end: 3 }), frameRate: 10, repeat: -1 }); this.anims.create({ key: 'down', frames: this.anims.generateFrameNumbers('bobidown', { start: 0, end: 3 }), frameRate: 10, repeat: -1 }); this.anims.create({ key: 'left', frames: this.anims.generateFrameNumbers('bobihorizontal', { start: 0, end: 3 }), frameRate: 10, repeat: -1 }); this.anims.create({ key: 'turn', frames: [ { key: 'bobihorizontal', frame: 4 } ], frameRate: 20 }); this.anims.create({ key: 'right', frames: this.anims.generateFrameNumbers('bobihorizontal', { start: 5, end: 8 }), frameRate: 10, repeat: -1 }); function update () { if (cursors.up.isDown) { bobi.setVelocityY(-160); bobi.anims.play('up', true); } else if (cursors.down.isDown) { bobi.setVelocityY(160); bobi.anims.play('down', true); } else { bobi.setVelocityY(0); } if (cursors.left.isDown) { bobi.setVelocityX(-160); bobi.anims.play('left', true); } else if (cursors.right.isDown) { bobi.setVelocityX(160); bobi.anims.play('right', true); } else { bobi.setVelocityX(0); } if (!(cursors.left.isDown||cursors.right.isDown||cursors.up.isDown||cursors.down.isDown)) { bobi.anims.play('turn'); } } </script>
To access the code above which is embedded in a web page
click here.
The main character who gets enough points in the game will reach the door and the game will end successfully. In this section we will add the door and define the interaction between objects with overlap function. Here's our code:
<script type="text/javascript"> var config = { type: Phaser.AUTO, width: 1024, //Defining game scene width height: 768, //Defining game scene heght physics: { default: 'arcade', arcade: { debug: false } }, scene: { preload: preload, //Defining preloaded materials create: create, //Defining objects and animations update: update //Events in the flow of the game } }; var game = new Phaser.Game(config); //We create the phaser object whose settings are given in config above //We define variables that we will use throughout the game var cursors; var stars; var bombs; var door; var background; var bobi; var health=100; var score=0; var scoreTxt; var healthTxt; var infoTxt; function preload () { this.load.image('bg', 'images/bg.png'); //The images to be created must be preloaded in this way this.load.spritesheet('bobihorizontal', 'images/bobihorizontal.png', { frameWidth: 114, frameHeight: 300 }); //With this code, we load the sequence of horizontal character images of our character this.load.spritesheet('bobiup', 'images/bobiup.png', { frameWidth: 111, frameHeight: 312 }); //With this code, we load the sequence of up going character images of our character this.load.spritesheet('bobidown', 'images/bobidown.png', { frameWidth: 111, frameHeight: 312 }); //With this code, we load the sequence of down going character images of our character this.load.image('star', 'images/star.png'); this.load.image('bomb', 'images/bomb.png'); this.load.image('doorimg', 'images/door.png'); } function create () { background = this.add.image(512, 384, 'bg'); //We assign value to variable and add to scene bobi = this.physics.add.sprite(100, 450, 'bobihorizontal').setScale(0.3); //We assign preloaded image to variable and add to scene cursors = this.input.keyboard.createCursorKeys(); //We defined keys bombs = this.physics.add.staticGroup(); for (i = 0; i < 50; i++) { x = Phaser.Math.Between(0, 1024); y = Phaser.Math.Between(0, 768); bombs.create(x, y, 'bomb').refreshBody(); } stars = this.physics.add.staticGroup(); for (i = 0; i < 15; i++) { x = Phaser.Math.Between(0, 1024); y = Phaser.Math.Between(0, 768); stars.create(x, y, 'star').refreshBody(); } door = this.physics.add.sprite(x, y, 'doorimg').setScale(0.5); //We define the interaction of the main character of the game with other objects by overlap this.physics.add.overlap(bobi, stars, catchStar, null, this); this.physics.add.overlap(bobi, bombs, hitBomb, null, this); this.physics.add.overlap(bobi, door, newScene, null, this); //Creating characters move events this.anims.create({ key: 'up', frames: this.anims.generateFrameNumbers('bobiup', { start: 0, end: 3 }), frameRate: 10, repeat: -1 }); this.anims.create({ key: 'down', frames: this.anims.generateFrameNumbers('bobidown', { start: 0, end: 3 }), frameRate: 10, repeat: -1 }); this.anims.create({ key: 'left', frames: this.anims.generateFrameNumbers('bobihorizontal', { start: 0, end: 3 }), frameRate: 10, repeat: -1 }); this.anims.create({ key: 'turn', frames: [ { key: 'bobihorizontal', frame: 4 } ], frameRate: 20 }); this.anims.create({ key: 'right', frames: this.anims.generateFrameNumbers('bobihorizontal', { start: 5, end: 8 }), frameRate: 10, repeat: -1 }); //Creating texts scoreTxt = this.add.text(16, 16, 'Score: 0', { font: "bold 24px Verdana", fill: "#fff", boundsAlignH: "center", boundsAlignV: "middle" }); healthTxt = this.add.text(16, 46, 'Health: 100', {font: "bold 24px Verdana", fill: "#fff", boundsAlignH: "center", boundsAlignV: "middle"}); infoTxt = this.add.text(this.scene.centerX, this.scene.centerY, '', { font: "bold 64px Verdana", fill: "#fff", boundsAlignH: "center", boundsAlignV: "middle" }) } function update () { if (cursors.up.isDown) { bobi.setVelocityY(-160); bobi.anims.play('up', true); } else if (cursors.down.isDown) { bobi.setVelocityY(160); bobi.anims.play('down', true); } else { bobi.setVelocityY(0); } if (cursors.left.isDown) { bobi.setVelocityX(-160); bobi.anims.play('left', true); } else if (cursors.right.isDown) { bobi.setVelocityX(160); bobi.anims.play('right', true); } else { bobi.setVelocityX(0); } if (!(cursors.left.isDown||cursors.right.isDown||cursors.up.isDown||cursors.down.isDown)) { bobi.anims.play('turn'); } } //Functions that will work with the main characters interaction with other objects function hitBomb (bobi, bombs)function hitBomb (bobi, bombs) { } function hitBomb (bobi, bombs) { } function newScene (bobi, door) { } </script>
To access the code above which is embedded in a web page page:
In the previous step, we have defined the functions that will take place when the main character interacts with other objects with the overlap function. These were BombCarp, StarBalls, and new Stage functions. Tasks of these functions will be as follows;
With hitBomb function;
With catchStar function;
With newScene function;
Check if the main character collects at least 8 stars,
If the main character has collected at least 8 stars, it will come to the center of the screen with its original size,
If the main character has not collected at least 8 stars,
When bobi reach the door, the message "Collect at least 8 stars" will appear for 1 second. Disappearance will occur with the hideText function.
Apart from these functions, at this stage, in the update function, the events that will happen when the character touches the bombs and game failed. Detailed descriptions of the codes are in source code below:
<script type="text/javascript"> var config = { type: Phaser.AUTO, width: 1024, //Defining game scene width height: 768, //Defining game scene heght physics: { default: 'arcade', arcade: { debug: false } }, scene: { preload: preload, //Defining preloaded materials create: create, //Defining objects and animations update: update //Events in the flow of the game } }; var game = new Phaser.Game(config); //We create the phaser object whose settings are given in config above //We define variables that we will use throughout the game var cursors; var stars; var bombs; var door; var background; var bobi; var health=100; var score=0; var scoreTxt; var healthTxt; var infoTxt; function preload () { this.load.image('bg', 'images/bg.png'); //The images to be created must be preloaded in this way this.load.spritesheet('bobihorizontal', 'images/bobihorizontal.png', { frameWidth: 114, frameHeight: 300 }); //With this code, we load the sequence of horizontal character images of our character this.load.spritesheet('bobiup', 'images/bobiup.png', { frameWidth: 111, frameHeight: 312 }); //With this code, we load the sequence of up going character images of our character this.load.spritesheet('bobidown', 'images/bobidown.png', { frameWidth: 111, frameHeight: 312 }); //With this code, we load the sequence of down going character images of our character this.load.image('star', 'images/star.png'); this.load.image('bomb', 'images/bomb.png'); this.load.image('doorimg', 'images/door.png'); } function create () { background = this.add.image(512, 384, 'bg'); //We assign value to variable and add to scene bobi = this.physics.add.sprite(100, 450, 'bobihorizontal').setScale(0.3); //We assign preloaded image to variable and add to scene cursors = this.input.keyboard.createCursorKeys(); //We defined keys bombs = this.physics.add.staticGroup(); for (i = 0; i < 50; i++) { x = Phaser.Math.Between(0, 1024); y = Phaser.Math.Between(0, 768); bombs.create(x, y, 'bomb').refreshBody(); } stars = this.physics.add.staticGroup(); for (i = 0; i < 15; i++) { x = Phaser.Math.Between(0, 1024); y = Phaser.Math.Between(0, 768); stars.create(x, y, 'star').refreshBody(); } door = this.physics.add.sprite(x, y, 'doorimg').setScale(0.5); //We define the interaction of the main character of the game with other objects by overlap this.physics.add.overlap(bobi, stars, catchStar, null, this); this.physics.add.overlap(bobi, bombs, hitBomb, null, this); this.physics.add.overlap(bobi, door, newScene, null, this); //Creating characters move events this.anims.create({ key: 'up', frames: this.anims.generateFrameNumbers('bobiup', { start: 0, end: 3 }), frameRate: 10, repeat: -1 }); this.anims.create({ key: 'down', frames: this.anims.generateFrameNumbers('bobidown', { start: 0, end: 3 }), frameRate: 10, repeat: -1 }); this.anims.create({ key: 'left', frames: this.anims.generateFrameNumbers('bobihorizontal', { start: 0, end: 3 }), frameRate: 10, repeat: -1 }); this.anims.create({ key: 'turn', frames: [ { key: 'bobihorizontal', frame: 4 } ], frameRate: 20 }); this.anims.create({ key: 'right', frames: this.anims.generateFrameNumbers('bobihorizontal', { start: 5, end: 8 }), frameRate: 10, repeat: -1 }); //Creating texts scoreTxt = this.add.text(16, 16, 'Score: 0', { font: "bold 24px Verdana", fill: "#fff", boundsAlignH: "center", boundsAlignV: "middle" }); healthTxt = this.add.text(16, 46, 'Health: 100', {font: "bold 24px Verdana", fill: "#fff", boundsAlignH: "center", boundsAlignV: "middle"}); infoTxt = this.add.text(this.scene.centerX, this.scene.centerY, '', { font: "bold 64px Verdana", fill: "#fff", boundsAlignH: "center", boundsAlignV: "middle" }) } function update () { if (cursors.up.isDown) { bobi.setVelocityY(-160); bobi.anims.play('up', true); } else if (cursors.down.isDown) { bobi.setVelocityY(160); bobi.anims.play('down', true); } else { bobi.setVelocityY(0); } if (cursors.left.isDown) { bobi.setVelocityX(-160); bobi.anims.play('left', true); } else if (cursors.right.isDown) { bobi.setVelocityX(160); bobi.anims.play('right', true); } else { bobi.setVelocityX(0); } if (!(cursors.left.isDown||cursors.right.isDown||cursors.up.isDown||cursors.down.isDown)) { bobi.anims.play('turn'); } if (health < 10) { infoTxt = this.add.text(this.scene.centerX, this.scene.centerY, 'GAME OVER', { font: "bold 64px Verdana", fill: "#fff", boundsAlignH: "center", boundsAlignV: "middle" }) infoTxt.setTint(0xff00ff, 0xffff00, 0x0000ff, 0xff0000); Phaser.Display.Align.In.Center(infoTxt, this.add.zone(512, 354, 1024, 768)); bobi.destroy(); background.destroy(); healthTxt.destroy(); door.destroy(); Phaser.Actions.SetVisible(bombs.getChildren(), false); bombs.clear(); Phaser.Actions.SetVisible(stars.getChildren(), false); stars.clear(); return; } } //Functions that will work with the main characters interaction with other objects function hitBomb (bobi, bombs) { bombs.disableBody(true, true); health -= 10; healthTxt.setText('Health: ' + health); } function catchStar (bobi, stars) { stars.disableBody(true, true); score += 10; scoreTxt.setText('score: ' + score); } function newScene (bobi, door) { if (score>70){ infoTxt.setVisible(true); infoTxt.setText('CONGRATULATIONS!!'); infoTxt.setTint(0xff00ff, 0xffff00, 0x0000ff, 0xff0000); Phaser.Display.Align.In.Center(infoTxt, this.add.zone(512, 354, 1024, 768)); bobi.setX(512); bobi.setY(500); bobi.setScale(1); bobi.disableInteractive(); background.destroy(); door.destroy(); Phaser.Actions.SetVisible(bombs.getChildren(), false); bombs.clear(); Phaser.Actions.SetVisible(stars.getChildren(), false); stars.clear(); bobi.anims.play('turn'); } else { infoTxt.setVisible(true); infoTxt.setText('En az 8 yıldız toplayın'); infoTxt.setTint(0xff00ff, 0xffff00, 0x0000ff, 0xff0000); Phaser.Display.Align.In.Center(infoTxt, this.add.zone(512, 354, 1024, 768)); this.time.delayedCall(1000, infoTxthide, [], this); } } function infoTxthide () { infoTxt.setVisible(false); } </script>
To access this source code embedded in the website (also the final version of the game) CLICK HERE.
The sample game described in the construction steps here should be considered as an example of the use of basic Javascript-Phaser3. You can make use of the features in this game to develop your own original games and applications. We wish to see your comments and contributions about this event in the comments section below.
For downloading full game with all files CLICK HERE.