Build a HTML5 game like “Color Jump” using Phaser 3 and Matter physics – adding coins and commenting the source code
Talking about Color Jump game, Game development, HTML5, Javascript and Phaser.
As promised, here we go with the second step of Color Jump prototype.
In the first step we saw the basic prototype of the game, and now it’s time to add collectible coins, just like we did in the fourth part of “Don’t Touch the Spikes” prototype.
Look at the game:
Tap to jump. Hit the walls matching the color of the ball, or it’s game over. If you fall down, it’s game over. If you fly off the top, it’s game over. Try to collect the coins.
Exactly like in Don’t Touch the Spikes, coins introduce a new kind of Matter body called sensor. Sensors trigger collision events, but do not react with colliding body physically, so the player won’t bounce on the coin, and it’s exactly what we need.
And now you have the full commented source code, line by line:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 | // the game itself let game; // global game options let gameOptions = { // world gravity gravity: 4, // ball horizontal speed ballSpeed: 4, // jump force jumpForce: 30, // amount of bars each wall is divided in bars: 4, // array with the colors to pick from barColors: [0x1abc9c, 0x2980b9, 0x9b59b6, 0xf1c40f, 0xc0392b, 0xecf0f1] } // constants used to pass "LEFT" and "RIGHT" as arguments rather than "0" and "1" const LEFT = 0; const RIGHT = 1; // function to be executed when the windows has loaded window.onload = function () { // object containing configuration options let gameConfig = { // render type: let the game decide if CANVAS of WEBGL type: Phaser.AUTO, // width of the game, in pixels width: 750, // height of the game, in pixels height: 1334, // background color (black) backgroundColor: 0x000000, // scene to play scene: playGame, // physics settings physics: { // we are using Matter JS default : "matter" , matter: { // gravity settings gravity: { x: 0, y: gameOptions.gravity } } } } // game creation game = new Phaser.Game(gameConfig); // giving focus to the frame (if any) where the game is running in window.focus(); // pure javascript to scale the canvas resize(); window.addEventListener( "resize" , resize, false ); } // playGame scene class playGame extends Phaser.Scene{ constructor(){ super ( "PlayGame" ); } // preloading assets preload(){ this .load.image( "wall" , "wall.png" ); this .load.image( "ball" , "ball.png" ); this .load.image( "coin" , "coin.png" ); } // method to be executed once, when the scene has been created create(){ // arrays where to store left and right walls this .leftWalls = []; this .rightWalls = []; // each wall is made by "gameOptions.bars" pieces, so we actually have "gameOptions.bars" walls each side for ( let i = 0; i < gameOptions.bars; i++){ // adding left and right walls this .leftWalls[i] = this .addWall(i, LEFT); this .rightWalls[i] = this .addWall(i, RIGHT); } // adding the ball this .ball = this .matter.add.image(game.config.width / 4, game.config.height / 2, "ball" ); // setting ball body as circular this .ball.setCircle() // adding the coin, no matter where, we'll set its position later this .coin = this .matter.add.image(0, 0, "coin" ); // setting coin body as circular this .coin.setCircle(); // setting coin body as static (not affected by gravity or collisions) this .coin.setStatic( true ); // setting coin body as sensor. Will fire collision events without actually collide this .coin.body.isSensor = true ; // giving the coin a label called "coin" this .coin.body.label = "coin" // this method will randomly place the coin this .placeCoin(); // setting ball velocity (horizontal, vertical) this .ball.setVelocity(gameOptions.ballSpeed, 0); // waiting for pointer down input to call "jump" method this .input.on( "pointerdown" , this .jump, this ); // waiting for a "collisionstart" event. "e" is the event, "b1" and "b2" the bodies this .matter.world.on( "collisionstart" , function (e, b1, b2) { // checking b1 and b2 labels to be "leftwall" if (b1.label == "leftwall" || b2.label == "leftwall" ){ // handling collisions on the LEFT side this .handleWallCollision(LEFT, b1, b2); } // checking b1 and b2 labels to be "rightwall" if (b1.label == "rightwall" || b2.label == "rightwall" ){ // handling collisions on the RIGHT side this .handleWallCollision(RIGHT, b1, b2); } // checking b1 and b2 labels to be "coin" if (b1.label == "coin" || b2.label == "coin" ){ // calling the method to move the coin elsewhere this .placeCoin(); } }, this ); } // method to add a wall, given its number (0 = top) and it side addWall(wallNumber, side){ // getting "wall" preloaded image let wallTexture = this .textures.get( "wall" ); // determining wall height according to game height and the number of bars let wallHeight = game.config.height / gameOptions.bars; // determining wall x position let wallX = side * game.config.width + wallTexture.source[0].width / 2 - wallTexture.source[0].width * side; // determining wall y position let wallY = wallHeight * wallNumber + wallHeight / 2; // adding the wall let wall = this .matter.add.image(wallX, wallY, "wall" ); // the wall is static wall.setStatic( true ); // giving the wall the proper label wall.body.label = (side == RIGHT) ? "rightwall" : "leftwall" // setting wall height wall.displayHeight = wallHeight; // returning the wall object return wall } // method to place the coin placeCoin(){ // just placing the coin in a random position between 20% and 80% of the game size this .coin.x = Phaser.Math.Between(game.config.width * 0.2, game.config.width * 0.8); this .coin.y = Phaser.Math.Between(game.config.height * 0.2, game.config.height * 0.8); } // method to handle ball Vs wall collision handleWallCollision(side, bodyA, bodyB){ // if the ball and the wall have different colors... if (bodyA.color != bodyB.color){ // restart the game this .scene.start( "PlayGame" ); } // calling a method to paint the walls this .paintWalls((side == LEFT) ? this .rightWalls : this .leftWalls); // updating ball velocity this .ball.setVelocity(gameOptions.ballSpeed, this .ball.body.velocity.y); } // method to paint the walls, in the argument the array of walls paintWalls(walls){ // looping through all walls walls.forEach( function (wall){ // picking a random color let color = Phaser.Math.RND.pick(gameOptions.barColors); // tinting the wall wall.setTint(color); // also assigning the wall body a custom "color" property wall.body.color = color; }); // picking a random wall let randomWall = Phaser.Math.RND.pick(walls); // painting the ball with the same color used by the random wall this .ball.setTint(randomWall.body.color); // also assigning the ball body a custom "color" property this .ball.body.color = randomWall.body.color; } // method to jump jump(){ // setting new ball velocity this .ball.setVelocity(( this .ball.body.velocity.x > 0) ? gameOptions.ballSpeed : -gameOptions.ballSpeed, -gameOptions.jumpForce); } // method to be called at each frame update(){ // updating ball velocity this .ball.setVelocity(( this .ball.body.velocity.x > 0) ? gameOptions.ballSpeed : -gameOptions.ballSpeed, this .ball.body.velocity.y); // if the ball flies off the screen... if ( this .ball.y < 0 || this .ball.y > game.config.height){ // restart the game this .scene.start( "PlayGame" ); } } }; // pure javascript to resize the canvas and scale the game function resize(){ let canvas = document.querySelector( "canvas" ); let windowWidth = window.innerWidth; let windowHeight = window.innerHeight; let windowRatio = windowWidth / windowHeight; let gameRatio = game.config.width / game.config.height; if (windowRatio < gameRatio){ canvas.style.width = windowWidth + "px" ; canvas.style.height = (windowWidth / gameRatio) + "px" ; } else { canvas.style.width = (windowHeight * gameRatio) + "px" ; canvas.style.height = windowHeight + "px" ; } } |
What about some particle effects next time? I will show you how to add eye-candy effects. Download the source code.
Never miss an update! Subscribe, and I will bother you by email only when a new game or full source code comes out.