HTML5 “Back to Square One” prototype made with Phaser – Adding enemies

Read all posts about "" game
If you enjoyed last week’s post HTML5 player movement like in popular iOS game “Back to Square One” made with Phaser, today there’s more for you as I am updating the prototype adding enemies. Enemies are moved with a tween with yoyo effect to make them patrol up and down, and we use ARCADE physics to check for collisions. The result works fine:
Click or touch the canvas to make the square roll. If you touch an enemy, the game will restart. I did not optimize some parts of the previous code, and even worse I do not have a pool to handle enemies, I am just creating and destroying them on the fly, but at least the code is well commented and I also highlighted the newly added lines:
// the game
var game;

// size of each square, in pixels
var squareSize = 40;

// square where the hero will start to walk
var startingSquare = 2;

// this is the time required to make a move, in milliseconds
var moveTime = 250;

// giving some color to ground squares
var squareColors = [0x888888, 0xaaaaaa];

// creation of the game, portrait mode 320x480
window.onload = function() {	
	game = new Phaser.Game(320, 480);
     game.state.add("PlayGame", playGame);
     game.state.start("PlayGame");
}


var playGame = function(game){}

playGame.prototype = {
     preload: function(){
          
          // preloading the assets
          game.load.image("square", "square.png");          
     },
     
     create: function(){ 
          // adding a group which will contain all terrain squares
          this.terrainGroup = game.add.group();
          
          // adding a group which will contain all enemies
          this.enemyGroup = game.add.group();
          
          // filling the field with squares to create the terrain
          for(var i = 0; i < game.width / squareSize + 2; i++){
               
               // adding a terrain square
               var square = game.add.sprite(i * squareSize, game.height / 3 * 2, "square");
               
               // settings its anchor on the center
               square.anchor.set(0.5);
               
               // giving the square a tint color
               square.tint = squareColors[i % 2];
               
               // finally adding the square to the group
               this.terrainGroup.add(square);
          }
          
          // adding the hero
          this.hero = game.add.sprite(startingSquare * squareSize, game.height / 3 * 2 - squareSize, "square");
          
          // setting the anchor on its center
          this.hero.anchor.set(0.5);
          
          // flag to see if the hero can move
          this.hero.canMove = true;
          
          // enabling arcade physics on hero
          game.physics.enable(this.hero, Phaser.Physics.ARCADE);
          
          // we will move the hero manually
          this.hero.body.moves = false;
          
          // input listener waiting for mouse or touch input, then calling moveSquare method
          game.input.onDown.add(this.moveSquare, this);
          
          // let's add an enemy
          this.addEnemy();                                                                                          
     },
     
     // this method will be called each time the player tries to move the square
     moveSquare: function(){
     
          // can the hero move?
          if(this.hero.canMove){
          
               // the hero is about to be moved so we aren't considering more inputs
               this.hero.canMove = false;
               
               // according to current square angle, we have to change its position and registration point
               // in order to make it rotate along the required pivot point
               // this part needs to be optimized but at the moment it works
               switch(this.hero.angle){
                    case 0:
                         this.hero.x += squareSize / 2;
                         this.hero.y += squareSize / 2;
                         this.hero.pivot.x = squareSize / 2;
                         this.hero.pivot.y = squareSize / 2;
                         break;
                    case 90:
                         this.hero.x += squareSize;
                         this.hero.pivot.x = squareSize / 2;
                         this.hero.pivot.y = -squareSize / 2;
                         break;
                    case -180:
                         this.hero.x += squareSize;
                         this.hero.pivot.x = -squareSize / 2;
                         this.hero.pivot.y = -squareSize / 2;
                         break;
                    case -90:
                         this.hero.x += squareSize;
                         this.hero.pivot.x = -squareSize / 2;
                         this.hero.pivot.y = squareSize / 2;                         
               }
               
               // tween to scroll the terrain to the left by squareSize pixels
               var scrollTween = game.add.tween(this.terrainGroup).to({
                    x: this.terrainGroup.x - squareSize 
               }, moveTime, Phaser.Easing.Linear.None, true);
               
               // tween to scroll the enemies to the left by squareSize pixels
               var enemyTween = game.add.tween(this.enemyGroup).to({
                    x: this.terrainGroup.x - squareSize 
               }, moveTime, Phaser.Easing.Linear.None, true);
               
               // tween to rotate and move the hero
               var moveTween = game.add.tween(this.hero).to({
                    angle: this.hero.angle + 90,
                    x: this.hero.x - squareSize 
               }, moveTime, Phaser.Easing.Linear.None, true);
               
               // once the tween has been completed...
               moveTween.onComplete.add(function(){
               
                    // the hero can move again
                    this.hero.canMove = true;
                    
                    // if hero's angle is zero, that is if we rotated by 360 degrees...
                    if(this.hero.angle == 0){
                    
                         // we restore hero original pivot point and position
                         this.hero.pivot.x = 0;
                         this.hero.pivot.y = 0;
                         this.hero.x += squareSize / 2;
                         this.hero.y -= squareSize / 2;
                    }
                    
                    // we order all terrain squares according to their x position
                    this.terrainGroup.sort("x", Phaser.Group.SORT_ASCENDING);
                    
                    // getting the leftmost enemy
                    this.enemyGroup.sort("x", Phaser.Group.SORT_ASCENDING);
                    
                    // if the leftmost enemy left the stage, just like the leftmost tile did...
                    if(this.enemyGroup.length &gt; 0 &amp;&amp; this.enemyGroup.getChildAt(0).x <= this.terrainGroup.getChildAt(0).x){
                    
                         // ... then destroy it
                         this.enemyGroup.getChildAt(0).destroy();     
                    }
                    
                    // we don't want to destroy assets to create new ones, we prefer to move the leftmost square
                    // which is not visible anymore to the right.
                    this.terrainGroup.getChildAt(0).x += this.terrainGroup.length * squareSize;
                    
                    // since this is a new tile, let's see if we should add an enemy
                    if(game.rnd.integerInRange(0, 9) &gt; 6){
                    
                         // let's add an enemy
                         this.addEnemy();
                    }              
               }, this);
          }
     },
     
     // function to add an enemy
     addEnemy: function(){
          
          // just a way to get the rightmost terrain tule
          this.terrainGroup.sort("x", Phaser.Group.SORT_DESCENDING);
          
          // adding the enemy over the rightmost tile
          var enemy = game.add.sprite(this.terrainGroup.getChildAt(0).x, 20, "square");
          enemy.anchor.set(0.5);
          enemy.tint = 0xff0000;
          
          // enabling arcade physics on enemy
          game.physics.enable(enemy, Phaser.Physics.ARCADE);

          // we will move the enemy manually
          enemy.body.moves = false;
          
          // giving the enemy a yoyo tween to move it at a random speed
          game.add.tween(enemy).to({
               y: game.height / 3 * 2 - squareSize,
          }, 1000 + game.rnd.integerInRange(0, 250), Phaser.Easing.Linear.None, true, 0, -1, true);
           
          this.enemyGroup.add(enemy);   
     },
     
     // function to be executed at each frame
     update: function(){
     
          // looking for collision between the hero and enemies
          game.physics.arcade.collide(this.hero, this.enemyGroup, function(){
          
               // restart the game
               game.state.start("PlayGame");   
          });
     }     
}
Next time, some optimization and some new tile types. Meanwhile, download the complete source code.

Get the most popular Phaser 3 book

Through 202 pages, 32 source code examples and an Android Studio project you will learn how to build cross platform HTML5 games and create a complete game along the way.

Get the book

214 GAME PROTOTYPES EXPLAINED WITH SOURCE CODE
// 1+2=3
// 100 rounds
// 10000000
// 2 Cars
// 2048
// A Blocky Christmas
// A Jumping Block
// A Life of Logic
// Angry Birds
// Angry Birds Space
// Artillery
// Astro-PANIC!
// Avoider
// Back to Square One
// Ball Game
// Ball vs Ball
// Ball: Revamped
// Balloon Invasion
// BallPusher
// Ballz
// Bar Balance
// Bejeweled
// Biggification
// Block it
// Blockage
// Bloons
// Boids
// Bombuzal
// Boom Dots
// Bouncing Ball
// Bouncing Ball 2
// Bouncy Light
// BoxHead
// Breakout
// Bricks
// Bubble Chaos
// Bubbles 2
// Card Game
// Castle Ramble
// Chronotron
// Circle Chain
// Circle Path
// Circle Race
// Circular endless runner
// Cirplosion
// CLOCKS - The Game
// Color Hit
// Color Jump
// ColorFill
// Columns
// Concentration
// Crossy Road
// Crush the Castle
// Cube Jump
// CubesOut
// Dash N Blast
// Dashy Panda
// Deflection
// Diamond Digger Saga
// Don't touch the spikes
// Dots
// Down The Mountain
// Drag and Match
// Draw Game
// Drop Wizard
// DROP'd
// Dudeski
// Dungeon Raid
// Educational Game
// Elasticity
// Endless Runner
// Erase Box
// Eskiv
// Farm Heroes Saga
// Filler
// Flappy Bird
// Fling
// Flipping Legend
// Floaty Light
// Fuse Ballz
// GearTaker
// Gem Sweeper
// Globe
// Goat Rider
// Gold Miner
// Grindstone
// GuessNext
// Helicopter
// Hero Emblems
// Hero Slide
// Hexagonal Tiles
// HookPod
// Hop Hop Hop Underwater
// Horizontal Endless Runner
// Hundreds
// Hungry Hero
// Hurry it's Christmas
// InkTd
// Iromeku
// Jet Set Willy
// Jigsaw Game
// Knife Hit
// Knightfall
// Legends of Runeterra
// Lep's World
// Line Rider
// Lumines
// Magick
// MagOrMin
// Mass Attack
// Math Game
// Maze
// Meeblings
// Memdot
// Metro Siberia Underground
// Mike Dangers
// Mikey Hooks
// Nano War
// Nodes
// o:anquan
// One Button Game
// One Tap RPG
// Ononmin
// Pacco
// Perfect Square!
// Perfectionism
// Phyballs
// Pixel Purge
// PixelField
// Planet Revenge
// Plants Vs Zombies
// Platform
// Platform game
// Plus+Plus
// Pocket Snap
// Poker
// Pool
// Pop the Lock
// Pop to Save
// Poux
// Pudi
// Pumpkin Story
// Puppet Bird
// Pyramids of Ra
// qomp
// Quick Switch
// Racing
// Radical
// Rebuild Chile
// Renju
// Rise Above
// Risky Road
// Roguelike
// Roly Poly
// Run Around
// Rush Hour
// SameGame
// SamePhysics
// Save the Totem
// Security
// Serious Scramblers
// Shrink it
// Sling
// Slingy
// Snowflakes
// Sokoban
// Space Checkers
// Space is Key
// Spellfall
// Spinny Gun
// Splitter
// Spring Ninja
// Sproing
// Stabilize!
// Stack
// Stick Hero
// String Avoider
// Stringy
// Sudoku
// Super Mario Bros
// Surfingers
// Survival Horror
// Talesworth Adventure
// Tetris
// The Impossible Line
// The Moops - Combos of Joy
// The Next Arrow
// Threes
// Tic Tac Toe
// Timberman
// Tiny Wings
// Tipsy Tower
// Toony
// Totem Destroyer
// Tower Defense
// Trick Shot
// Tunnelball
// Turn
// Turnellio
// TwinSpin
// vvvvvv
// Warp Shift
// Way of an Idea
// Whack a Creep
// Wheel of Fortune
// Where's my Water
// Wish Upon a Star
// Word Game
// Wordle
// Worms
// Yanga
// Yeah Bunny
// Zhed
// zNumbers