import Phaser from "phaser"; import bg from "./bg.jpg"; import tiles from "./tiles.png"; import sprites from "./tiles.json"; import title from "./title.png"; import instruction from "./instruction.png"; class PlayScene extends Phaser.Scene { constructor() { super({ key: "PlayScene", }); this.allowClick = true; this.gridBG; this.instructions; this.text1; this.text2; this.text3; this.currentColor = ""; this.emitters = {}; this.grid = []; this.matched = []; this.moves = 25; this.frames = [ "red.png", "bu.png", "grey.png", "ye.png", "pr.png", "gr.png", ]; } preload() { this.load.image("bg", bg); this.load.image("title", title); this.load.atlas("tiles", tiles, sprites); this.load.image("instruction", instruction); } create() { const bg = this.add.image(0, 0, "bg"); bg.setOrigin(0); bg.displayWidth = 1080; bg.displayHeight = 1080; this.createIcon(0, 0, 272); this.createIcon(1, 0, 272 + 252); this.createIcon(2, 0, 272 + 252 * 2); this.createIcon(3, 1080 - 184, 272); this.createIcon(4, 1080 - 184, 272 + 252); this.createIcon(5, 1080 - 184, 272 + 252 * 2); // The game is played in a 14x14 grid with 6 different colors this.grid = []; for (var x = 0; x < 14; x++) { this.grid[x] = []; for (var y = 0; y < 14; y++) { var sx = 204 + x * 48; var sy = 309 + y * 48; var color = Phaser.Math.Between(0, 5); var block = this.add.image(sx, -1032 + sy, "tiles", this.frames[color]); block.setOrigin(0); block.displayWidth = 48; block.displayHeight = 48; block.setData("oldColor", color); block.setData("color", color); block.setData("x", sx); block.setData("y", sy); this.grid[x][y] = block; } } // Do a few floods just to make it a little easier starting off this.helpFlood(); for (var i = 0; i < this.matched.length; i++) { var blockk = this.matched[i]; blockk.setFrame(this.frames[blockk.getData("color")]); } this.currentColor = this.grid[0][0].getData("color"); this.particles = this.add.particles("tiles"); for (var i = 0; i < this.frames.length; i++) { this.createEmitter(this.frames[i]); } const title = this.add.image(1080 / 2, 228, "title"); title.displayWidth = 222; title.displayHeight = 50; this.text1 = this.add .text(440, 160, "MOVES:", { fontSize: 40, color: "#fff", }) .setAlpha(0); this.text2 = this.add .text(590, 160, "00", { fontSize: 40, color: "#fff" }) .setAlpha(0); this.text3 = this.add.text(180, 200, "", 48).setAlpha(0); this.instructions = this.add.image(500, 600, "instruction").setAlpha(0); //初始化位置 this.revealGrid(); } update() {} helpFlood() { for (var i = 0; i < 8; i++) { var x = Phaser.Math.Between(0, 13); var y = Phaser.Math.Between(0, 13); var oldColor = this.grid[x][y].getData("color"); var newColor = oldColor + 1; if (newColor === 6) { newColor = 0; } this.floodFill(oldColor, newColor, x, y); } } createIcon(color, x, y) { const area = this.add.rectangle(x, y, 184, 758 / 3); area.setOrigin(0); area.setData("color", color); area.setInteractive(); } revealGrid() { this.tweens.add({ targets: this.gridBG, y: 300, ease: "Power3", }); var i = 500; for (var y = 13; y >= 0; y--) { for (var x = 0; x < 14; x++) { var block = this.grid[x][y]; this.tweens.add({ targets: block, y: block.getData("y"), ease: "Power3", duration: 500, delay: i, }); i += 20; } } i -= 1000; // Text this.tweens.add({ targets: [this.text1, this.text2], alpha: 1, ease: "Power3", delay: i, }); i += 500; var movesTween = this.tweens.addCounter({ from: 0, to: 25, ease: "Power1", onUpdate: function (tween, targets, text) { text.setText( Phaser.Utils.String.Pad(tween.getValue().toFixed(), 2, "0", 1) ); }, onUpdateParams: [this.text2], delay: i, }); i += 500; this.tweens.add({ targets: [this.instructions], alpha: 1, ease: "Power3", delay: i, }); this.time.delayedCall(i, this.startInputEvents, [], this); } startInputEvents() { this.input.on("gameobjectdown", this.onIconDown, this); // Cheat mode :) this.input.keyboard.on( "keydown_M", function () { this.moves++; this.text2.setText(Phaser.Utils.String.Pad(this.moves, 2, "0", 1)); }, this ); this.input.keyboard.on( "keydown_X", function () { this.moves--; this.text2.setText(Phaser.Utils.String.Pad(this.moves, 2, "0", 1)); }, this ); } stopInputEvents() { this.input.off("gameobjectdown", this.onIconDown); } onIconDown(pointer, gameObject) { if (!this.allowClick) { return; } var icon = gameObject; var newColor = icon.getData("color"); // Valid color? if (newColor === this.currentColor) { return; } var oldColor = this.grid[0][0].getData("color"); // console.log('starting flood from', oldColor, this.frames[oldColor], 'to', newColor, this.frames[newColor]); if (oldColor !== newColor) { this.currentColor = newColor; this.matched = []; this.instructions.setVisible(false); this.moves--; this.text2.setText(Phaser.Utils.String.Pad(this.moves, 2, "0", 1)); this.floodFill(oldColor, newColor, 0, 0); if (this.matched.length > 0) { this.startFlow(); } } } createEmitter(color) { this.emitters[color] = this.particles.createEmitter({ frame: color, lifespan: 1000, speed: { min: 300, max: 400 }, alpha: { start: 1, end: 0 }, scale: { start: 0.5, end: 0 }, rotate: { start: 0, end: 360, ease: "Power2" }, blendMode: "ADD", on: false, }); } startFlow() { this.matched.sort(function (a, b) { var aDistance = Phaser.Math.Distance.Between(a.x, a.y, 166, 66); var bDistance = Phaser.Math.Distance.Between(b.x, b.y, 166, 66); return aDistance - bDistance; }); // Swap the sprites var t = 0; var inc = this.matched.length > 98 ? 6 : 12; this.allowClick = false; for (var i = 0; i < this.matched.length; i++) { var block = this.matched[i]; var blockColor = this.frames[block.getData("color")]; var oldBlockColor = this.frames[block.getData("oldColor")]; var emitter = this.emitters[oldBlockColor]; this.time.delayedCall( t, function (block, blockColor) { block.setFrame(blockColor); emitter.explode(6, block.x, block.y); }, [block, blockColor, emitter] ); t += inc; } this.time.delayedCall( t, function () { this.allowClick = true; if (this.checkWon()) { this.gameWon(); } else if (this.moves === 0) { this.gameLost(); } }, [], this ); } checkWon() { var topLeft = this.grid[0][0].getData("color"); for (var x = 0; x < 14; x++) { for (var y = 0; y < 14; y++) { if (this.grid[x][y].getData("color") !== topLeft) { return false; } } } return true; } clearGrid() { // Hide everything :) var i = 500; for (var y = 13; y >= 0; y--) { for (var x = 0; x < 14; x++) { var block = this.grid[x][y]; this.tweens.add({ targets: block, scaleX: 0, scaleY: 0, ease: "Power3", duration: 800, delay: i, }); i += 10; } } return i; } gameLost() { this.stopInputEvents(); this.text1.setText("Lost!"); this.text2.setText(":("); var i = this.clearGrid(); this.text3.setAlpha(0); this.text3.setVisible(true); this.tweens.add({ targets: this.text3, alpha: 1, duration: 1000, delay: i, }); this.game.onLose && this.game.onLose(); this.input.once("pointerdown", this.resetGame, this); } resetGame() { this.text1.setText("Moves"); this.text2.setText("00"); this.text3.setVisible(false); // Show everything :) var i = 500; for (var y = 13; y >= 0; y--) { for (var x = 0; x < 14; x++) { var block = this.grid[x][y]; // Set a new color var color = Phaser.Math.Between(0, 5); block.setFrame(this.frames[color]); block.setData("oldColor", color); block.setData("color", color); this.tweens.add({ targets: block, scaleX: 1, scaleY: 1, ease: "Power3", duration: 800, delay: i, }); i += 10; } } // Do a few floods just to make it a little easier starting off this.helpFlood(); for (var i = 0; i < this.matched.length; i++) { var block = this.matched[i]; block.setFrame(this.frames[block.getData("color")]); } this.currentColor = this.grid[0][0].getData("color"); this.tweens.addCounter({ from: 0, to: 25, ease: "Power1", onUpdate: function (tween, targets, text) { text.setText( Phaser.Utils.String.Pad(tween.getValue().toFixed(), 2, "0", 1) ); }, onUpdateParams: [this.text2], delay: i, }); this.moves = 25; this.time.delayedCall(i, this.startInputEvents, [], this); } gameWon() { this.game.onWon && this.game.onWon(); this.stopInputEvents(); this.text1.setText("Won!!"); this.text2.setText(":)"); var i = this.clearGrid(); this.time.delayedCall(2000, this.boom, [], this); } boom() { var color = Phaser.Math.RND.pick(this.frames); this.emitters[color].explode( 8, Phaser.Math.Between(128, 672), Phaser.Math.Between(28, 572) ); color = Phaser.Math.RND.pick(this.frames); this.emitters[color].explode( 8, Phaser.Math.Between(128, 672), Phaser.Math.Between(28, 572) ); this.time.delayedCall(100, this.boom, [], this); } //调低难度中间放一些相同颜色的 floodFill(oldColor, newColor, x, y) { if ( oldColor === newColor || this.grid[x][y].getData("color") !== oldColor ) { return; } this.grid[x][y].setData("oldColor", oldColor); this.grid[x][y].setData("color", newColor); if (this.matched.indexOf(this.grid[x][y]) === -1) { this.matched.push(this.grid[x][y]); } if (x > 0) { this.floodFill(oldColor, newColor, x - 1, y); } if (x < 13) { this.floodFill(oldColor, newColor, x + 1, y); } if (y > 0) { this.floodFill(oldColor, newColor, x, y - 1); } if (y < 13) { this.floodFill(oldColor, newColor, x, y + 1); } } } export default PlayScene;