diff --git a/games/game-rect/assets/gridTile.png b/games/game-rect/assets/gridTile.png index 82f003a..fa25b41 100644 Binary files a/games/game-rect/assets/gridTile.png and b/games/game-rect/assets/gridTile.png differ diff --git a/games/game-rect/assets/tiles.png b/games/game-rect/assets/tiles.png index ea433fe..379d582 100644 Binary files a/games/game-rect/assets/tiles.png and b/games/game-rect/assets/tiles.png differ diff --git a/games/game-rect/scenes/Rect.js b/games/game-rect/scenes/Rect.js index d41925e..08794a1 100644 --- a/games/game-rect/scenes/Rect.js +++ b/games/game-rect/scenes/Rect.js @@ -1,23 +1,37 @@ import Phaser from "phaser"; -import tiles from "../assets/a.png"; +import tiles from "../assets/tiles.png"; import bg from "../assets/bg.jpg"; import gridTile from "../assets/gridTile.png"; -/** - *博客 - * https://www.emanueleferonato.com/2020/04/17/html5-prototype-of-bricks-hyper-casual-game-with-phaser-and-arcade-physics-step-2-adding-score/ - */ -const gameWidth = 927; + +const gameWidth = 924; const tileSpace = 3; const offsetLeft = (1080 - gameWidth) / 2; +const offsetTop = 200; +const columns = 9; +const rows = 20; +const getRandom = () => Math.floor(Math.random() * 5); +const getValues = () => + Phaser.Utils.Array.Shuffle([ + 0, + 1, + 2, + 3, + 4, + getRandom(), + getRandom(), + getRandom(), + getRandom(), + ]); +const tileSize = (gameWidth - tileSpace * (columns - 1)) / columns; export default class Rect extends Phaser.Scene { constructor() { super({ key: "Rect" }); this.gameOptions = { // number of columns - columns: 9, + columns, // number of rows, must be high enough to allow object pooling - rows: 20, + rows, // tile speed in pixels per second tileSpeed: 100, @@ -27,8 +41,8 @@ export default class Rect extends Phaser.Scene { this.load.image("bg", bg); this.load.image("gridTile", gridTile); this.load.spritesheet("tiles", tiles, { - frameWidth: 107, - frameHeight: 107, + frameWidth: 202, + frameHeight: 202, }); } create() { @@ -39,24 +53,37 @@ export default class Rect extends Phaser.Scene { ); this.bg.displayWidth = this.game.config.width; this.bg.displayHeight = this.game.config.height; + // physics group which manages all tiles in game this.tileGroup = this.physics.add.group(); - - // determining tile size according to game width and columns - this.tileSize = - (gameWidth - tileSpace * (this.gameOptions.columns - 1)) / - this.gameOptions.columns; - + const shape = this.add.graphics(); + shape.fillStyle = "#000"; + shape.beginPath(); + shape.moveTo(0, tileSize * 8 + tileSpace * 7 + offsetTop); + shape.lineTo(1080, tileSize * 8 + tileSpace * 7 + offsetTop); + shape.lineTo(1080, 1080); + shape.lineTo(0, 1080); + shape.lineTo(0, tileSize * 8 + tileSpace * 7 + offsetTop); + shape.fillPath(); + + const mask = shape.createGeometryMask(); + mask.setInvertAlpha(true); + for (let i = 0; i < this.gameOptions.columns; i++) { + for (let j = 0; j < 8; j++) { + const defaultTile = this.add.image( + offsetLeft + i * (tileSize + tileSpace), + offsetTop + j * (tileSize + tileSpace), + "gridTile" + ); + defaultTile.setOrigin(0); + defaultTile.displayWidth = tileSize; + defaultTile.displayHeight = tileSize; + } + } // time to add tiles to the game for (let i = 0; i < this.gameOptions.rows; i++) { // build an array with integers between 0 and this.gameOptions.columns - 1: [0, 1, 2, ..., this.gameOptions.columns - 1] - let values = Phaser.Utils.Array.NumberArray( - 0, - this.gameOptions.columns - 1 - ); - - // then we shuffle the array - Phaser.Utils.Array.Shuffle(values); + let values = getValues(); // save middle column color of first row if (i == 0) { @@ -67,34 +94,32 @@ export default class Rect extends Phaser.Scene { for (let j = 0; j < this.gameOptions.columns; j++) { // add a tile. Tile frame is set according to "values" shuffled array let tile = this.tileGroup.create( - offsetLeft + j * this.tileSize, - i * this.tileSize + (this.game.config.height / 4) * 3, + offsetLeft + j * (tileSize + tileSpace), + i * (tileSize + tileSpace) + (this.game.config.height / 4) * 3, "tiles", values[j] ); - + tile.setMask(mask); // call adjustTile method to adjust tile origin and display size this.adjustTile(tile); } } // let's build once again an array with integers between 0 and this.gameOptions.columns - 1 - let values = Phaser.Utils.Array.NumberArray( - 0, - this.gameOptions.columns - 1 - ); + let values = getValues(); // remove the item at "middlecolor" position because we don't want it to be randomly selected - values.splice(middleColor, 1); + values = values.filter((v) => middleColor != v); // add the player to the this.this.game. Player color is picked amoung "values" array items, which does not contain anymore "middlecolor" value this.player = this.tileGroup.create( - offsetLeft + this.tileSize * Math.floor(this.gameOptions.columns / 2), - (this.game.config.height / 4) * 3 - this.tileSize, + offsetLeft + + (tileSize + tileSpace) * Math.floor(this.gameOptions.columns / 2), + (this.game.config.height / 4) * 3 - (tileSize + tileSpace), "tiles", Phaser.Utils.Array.GetRandom(values) ); - + this.player.setMask(mask); // adjust player origin and display size this.adjustTile(this.player); @@ -104,12 +129,11 @@ export default class Rect extends Phaser.Scene { // add score text this.scoreText = this.add.text(0, 0, "0", { fontFamily: "Arial Black", - fontSize: this.tileSize / 3, + fontSize: tileSize / 2, color: "#ffffff", }); - // set a stroke to score text - this.scoreText.setStroke("#000000", this.tileSize / 6); + this.scoreText.setMask(mask); // method to adjust score position this.adjustScorePosition(); @@ -130,10 +154,9 @@ export default class Rect extends Phaser.Scene { // method to be executed at each frame update() { // if the player touches the top of the screen... - if (this.player.y < 200) { + if (this.player.y < offsetTop) { // gmae over man, restart the this.game - //this.scene.start("Rect"); - //this.scene.stop + this.game.onLose && this.game.onLose(); this.tileGroup.setVelocityY(0); this.input.off("pointerdown"); this.input.on( @@ -154,17 +177,17 @@ export default class Rect extends Phaser.Scene { sprite.setOrigin(0); // set display width and height to "tileSize" pixels - sprite.displayWidth = this.tileSize; - sprite.displayHeight = this.tileSize; + sprite.displayWidth = tileSize; + sprite.displayHeight = tileSize; } // method to adjust score position adjustScorePosition() { // adjust score position according to its bounding box and player position this.scoreText.x = - this.player.x + (this.tileSize - this.scoreText.getBounds().width) / 2; + this.player.x + (tileSize - this.scoreText.getBounds().width) / 2; this.scoreText.y = - this.player.y + (this.tileSize - this.scoreText.getBounds().height) / 2; + this.player.y + (tileSize - this.scoreText.getBounds().height) / 2; } // method to move player tile @@ -172,11 +195,13 @@ export default class Rect extends Phaser.Scene { // if we can move... if (this.canMove) { // determine column according to input coordinate and tile size - let column = Math.floor((pointer.x - offsetLeft) / this.tileSize); - + let column = Math.floor((pointer.x - offsetLeft) / tileSize); + if (column > 8) column = 8; + if (column < 0) column = 0; // get the ditance from current player tile and destination let distance = Math.floor( - Math.abs(column * this.tileSize - this.player.x) / this.tileSize + Math.abs(offsetLeft + column * (tileSize + tileSpace) - this.player.x) / + tileSize ); // did we actually move? @@ -187,7 +212,7 @@ export default class Rect extends Phaser.Scene { // tween the player to destination tile this.tweens.add({ targets: [this.player], - x: offsetLeft + column * this.tileSize, + x: offsetLeft + column * (tileSize + tileSpace), duration: distance * 30, callbackScope: this, onComplete: function () { @@ -203,8 +228,8 @@ export default class Rect extends Phaser.Scene { checkMatch() { // get tile below player tile let tileBelow = this.physics.overlapRect( - this.player.x + this.tileSize / 2, - this.player.y + this.tileSize * 1.5, + this.player.x + tileSize / 2, + this.player.y + tileSize * 1.5, 1, 1 ); @@ -217,7 +242,7 @@ export default class Rect extends Phaser.Scene { // check the whole row below player tile let rowBelow = this.physics.overlapRect( 0, - this.player.y + this.tileSize * 1.5, + this.player.y + tileSize * 1.5, gameWidth, 1 ); @@ -242,18 +267,13 @@ export default class Rect extends Phaser.Scene { this.scoreText.setText(this.score); // the good old array with all integers from zero to this.gameOptions.columns - 1 - let values = Phaser.Utils.Array.NumberArray( - 0, - this.gameOptions.columns - 1 - ); - - // let's shuffle the array - Phaser.Utils.Array.Shuffle(values); + let values = getValues(); // place all tiles below the lowest row for (let i = 0; i < this.gameOptions.columns; i++) { rowBelow[i].gameObject.setFrame(values[i]); - rowBelow[i].gameObject.y += this.tileSize * this.gameOptions.rows; + rowBelow[i].gameObject.y += + (tileSize + tileSpace) * this.gameOptions.rows; } // check for matches again, there could be a combo @@ -274,17 +294,14 @@ export default class Rect extends Phaser.Scene { // get the tile below the player let tileBelow = this.physics.overlapRect( - this.player.x + this.tileSize / 2, - this.player.y + this.tileSize * 1.5, + this.player.x + tileSize / 2, + this.player.y + tileSize * 1.5, 1, 1 ); // the good old array with all integers from zero to this.gameOptions.columns - 1 - let values = Phaser.Utils.Array.NumberArray( - 0, - this.gameOptions.columns - 1 - ); + let values = [0, 1, 2, 3, 4]; // remove the item at "frame" value of tile below the player pbecause we don't want it to be randomly selected values.splice(tileBelow[0].gameObject.frame.name, 1);