diff --git a/phaser/match3/style.css b/font.css similarity index 100% rename from phaser/match3/style.css rename to font.css diff --git a/h5/flipper/font.ttf b/font.ttf similarity index 100% rename from h5/flipper/font.ttf rename to font.ttf diff --git a/h5/flipper/flipper.css b/h5/flipper/flipper.css index ca13b6c..3fd1217 100644 --- a/h5/flipper/flipper.css +++ b/h5/flipper/flipper.css @@ -1,7 +1,3 @@ -@font-face { - font-family: "flipper"; - src: url("font.ttf") format("truetype"); -} .flipper { position: relative; width: 100%; diff --git a/h5/flipper/game.js b/h5/flipper/game.js index 25f2b17..1853e88 100644 --- a/h5/flipper/game.js +++ b/h5/flipper/game.js @@ -1,3 +1,4 @@ +import "../../font.css"; import "./flipper.css"; function importAll(r) { let obj = {}; diff --git a/h5/snake/font.ttf b/h5/snake/font.ttf deleted file mode 100644 index 3729151..0000000 Binary files a/h5/snake/font.ttf and /dev/null differ diff --git a/h5/snake/snake.css b/h5/snake/snake.css index 898955a..5385ab8 100644 --- a/h5/snake/snake.css +++ b/h5/snake/snake.css @@ -1,7 +1,3 @@ -@font-face { - font-family: "game"; - src: url("font.ttf") format("truetype"); -} .snake { position: relative; width: 100%; diff --git a/h5/snake/snake.js b/h5/snake/snake.js index 38eb6f0..ffeee5a 100644 --- a/h5/snake/snake.js +++ b/h5/snake/snake.js @@ -1,3 +1,4 @@ +import "../../font.css"; import "./snake.css"; import SnakeModel from "./core/model"; diff --git a/h5/water/font.ttf b/h5/water/font.ttf deleted file mode 100644 index 3729151..0000000 Binary files a/h5/water/font.ttf and /dev/null differ diff --git a/h5/water/game.js b/h5/water/game.js index 6ffbefa..df76d05 100644 --- a/h5/water/game.js +++ b/h5/water/game.js @@ -1,4 +1,5 @@ import Waterful from "./waterful"; +import "../../font.css"; import "./water.css"; export default class Game { constructor({ containerId, onWon, onLose }) { @@ -28,9 +29,7 @@ export default class Game { right: [], }, callbacks: { - score(score) { - console.log("score: ", score, score.total); - }, + score(score) {}, end(score) { onWon(score.total); }, diff --git a/h5/water/water.css b/h5/water/water.css index 9876927..c551c25 100644 --- a/h5/water/water.css +++ b/h5/water/water.css @@ -6,10 +6,6 @@ background-image: url(./bg.jpg); background-size: cover; } -@font-face { - font-family: "game"; - src: url("./font.ttf") format("truetype"); -} .bg .watercanvas { position: absolute; diff --git a/phaser/index.js b/phaser/index.js index c675aef..c210c27 100644 --- a/phaser/index.js +++ b/phaser/index.js @@ -4,8 +4,11 @@ import game2048 from "./game2048/game"; import rect from "./game-rect/game"; import floodFill from "./game-flood-fill/game"; import match3 from "./match3/game"; -const attachMethods = (fn) => (...p) => - Object.assign(fn(...p), { +import slidingPuzzle from "./slidingPuzzle/index"; + +const attachMethods = (fn, isClass) => (...p) => { + const game = isClass ? new fn(...p) : fn(...p); + return Object.assign(game, { pause() { this.scene.scenes.forEach((scene) => { scene.scene.pause(); @@ -26,15 +29,20 @@ const attachMethods = (fn) => (...p) => this.destroy(false); }, }); -const games = Object.entries({ +}; +const functions = Object.entries({ ballMove, flappyBird, game2048, rect, floodFill, match3, -}) - .map(([name, fn]) => ({ [name]: attachMethods(fn) })) +}).map(([name, fn]) => ({ [name]: attachMethods(fn) })); +const classes = Object.entries({ + slidingPuzzle, +}).map(([name, fn]) => ({ [name]: attachMethods(fn, true) })); +const games = functions + .concat(classes) .reduce((acc, nxt) => Object.assign(acc, nxt), {}); export default games; diff --git a/phaser/match3/font.ttf b/phaser/match3/font.ttf deleted file mode 100644 index 3729151..0000000 Binary files a/phaser/match3/font.ttf and /dev/null differ diff --git a/phaser/match3/scene.js b/phaser/match3/scene.js index 7a66128..b5153c6 100644 --- a/phaser/match3/scene.js +++ b/phaser/match3/scene.js @@ -1,7 +1,7 @@ import gems from "./gems.png"; import Match3 from "./match3"; import bg from "./bg.jpg"; -import "./style.css"; +import "../../font.css"; const gameOptions = { gemSize: 260, frameSize: 238, diff --git a/phaser/slidingPuzzle/bg.jpg b/phaser/slidingPuzzle/bg.jpg new file mode 100644 index 0000000..d1b76ae Binary files /dev/null and b/phaser/slidingPuzzle/bg.jpg differ diff --git a/phaser/slidingPuzzle/countdown.png b/phaser/slidingPuzzle/countdown.png new file mode 100644 index 0000000..fe6437d Binary files /dev/null and b/phaser/slidingPuzzle/countdown.png differ diff --git a/phaser/slidingPuzzle/index.js b/phaser/slidingPuzzle/index.js new file mode 100644 index 0000000..d3a9a9f --- /dev/null +++ b/phaser/slidingPuzzle/index.js @@ -0,0 +1,236 @@ +import Phaser from "phaser"; +import bg from "./bg.jpg"; +import puzzle from "./puzzle.png"; +import countdown from "./countdown.png"; +import "../../font.css"; + +const PUZZLE_WH = 1640; +const PIECE_WH = 410; +const OFFSET_LEFT = 260 + PIECE_WH / 2; +const OFFSET_TOP = 390 + PIECE_WH / 2; + +const surroundingPieces = (z, w, h) => { + const x = z % w; + const y = Math.floor(z / h); + + const left = x === 0 ? null : z - 1; + const up = y === 0 ? null : z - w; + const right = x === w - 1 ? null : z + 1; + const down = y === h - 1 ? null : z + w; + + return [left, up, right, down].filter((i) => i !== null); +}; +const shuffle = (puzzle, moves, width, height) => { + let empty = puzzle[0]; + let lastPiece = empty; + + for (let i = 0; i < moves; i++) { + let pieces = surroundingPieces(empty, width, height); + pieces = pieces.filter((i) => i !== lastPiece); + + let pieceIndex = pieces[Math.floor(Math.random() * pieces.length)]; + + puzzle[empty] = puzzle[pieceIndex]; + lastPiece = empty; + + puzzle[pieceIndex] = 0; + empty = pieceIndex; + } + + return puzzle; +}; + +const createShuffledIndexArray = (piecesAmount) => { + const indexArray = new Array(piecesAmount).fill(0).map((_, i) => i); + return shuffle(indexArray, 25, 4, 4); +}; + +class Scene extends Phaser.Scene { + constructor() { + super("scene"); + } + preload() { + this.load.image("bg", bg); + this.load.image("countdown", countdown); + this.load.spritesheet("puzzle", puzzle, { + frameWidth: PIECE_WH, + frameHeight: PIECE_WH, + }); + } + create() { + this.won = false; + const bg = this.add.image( + this.game.config.width / 2, + this.game.config.height / 2, + "bg" + ); + bg.displayWidth = this.game.config.width; + bg.displayHeight = this.game.config.height; + const countdown = this.add.image(465, 474, "countdown"); + countdown.setDepth(1); + this.seconds = 300; + this.secText = this.add.text(520, 450, this.seconds, { + fontSize: 45, + fontFamily: "game", + color: "#429b47", + }); + this.secText.setDepth(2); + + const BOARD_COLS = Math.floor(PUZZLE_WH / PIECE_WH); + const BOARD_ROWS = Math.floor(PUZZLE_WH / PIECE_WH); + + let piecesAmount = BOARD_COLS * BOARD_ROWS; + this.time.addEvent({ + delay: 1000, + loop: true, + callback: () => { + if (this.seconds === 0) this.game.onLose && this.game.onLose(); + if (!this.won && this.seconds > 0) this.seconds--; + this.secText.setText(this.seconds); + }, + }); + const shuffledIndexArray = createShuffledIndexArray(piecesAmount); + let piecesIndex = 0; + let piecesGroup = this.add.group(); + + this.piecesGroup = piecesGroup; + for (let i = 0; i < BOARD_ROWS; i++) { + for (let j = 0; j < BOARD_COLS; j++) { + let piece; + if (shuffledIndexArray[piecesIndex]) { + piece = piecesGroup.create( + OFFSET_LEFT + j * PIECE_WH, + OFFSET_TOP + i * PIECE_WH, + "puzzle", + shuffledIndexArray[piecesIndex] + ); + } else { + //initial position of black piece + piece = piecesGroup.create( + OFFSET_LEFT + j * PIECE_WH, + OFFSET_TOP + i * PIECE_WH, + "puzzle", + shuffledIndexArray[piecesIndex], + false + ); + piece.black = true; + this.blackPiece = piece; + } + piece.name = "piece" + i.toString() + "x" + j.toString(); + piece.currentIndex = piecesIndex; + piece.destIndex = shuffledIndexArray[piecesIndex]; + piece.inputEnabled = true; + // piece.events.onInputDown.add(); + piece.posX = j; + piece.posY = i; + piece.setInteractive(); + piecesIndex++; + } + } + this.input.on( + "gameobjectdown", + (_, piece) => { + var blackPiece = this.canMove(piece); + if (blackPiece) { + this.movePiece(piece, blackPiece); + } + }, + this + ); + } + canMove(piece) { + let foundBlackElem = false; + + this.piecesGroup.getChildren().forEach(function (element) { + if ( + (element.posX === piece.posX - 1 && + element.posY === piece.posY && + element.black) || + (element.posX === piece.posX + 1 && + element.posY === piece.posY && + element.black) || + (element.posY === piece.posY - 1 && + element.posX === piece.posX && + element.black) || + (element.posY === piece.posY + 1 && + element.posX === piece.posX && + element.black) + ) { + foundBlackElem = element; + return; + } + }); + + return foundBlackElem; + } + movePiece(piece, blackPiece) { + var tmpPiece = { + posX: piece.posX, + posY: piece.posY, + currentIndex: piece.currentIndex, + }; + this.tweens.add({ + targets: piece, + x: OFFSET_LEFT + blackPiece.posX * PIECE_WH, + y: OFFSET_TOP + blackPiece.posY * PIECE_WH, + ease: "linear", + duration: 300, + }); + + piece.posX = blackPiece.posX; + piece.posY = blackPiece.posY; + piece.currentIndex = blackPiece.currentIndex; + piece.name = "piece" + piece.posX.toString() + "x" + piece.posY.toString(); + + blackPiece.posX = tmpPiece.posX; + blackPiece.posY = tmpPiece.posY; + blackPiece.currentIndex = tmpPiece.currentIndex; + blackPiece.name = + "piece" + blackPiece.posX.toString() + "x" + blackPiece.posY.toString(); + + this.checkIfFinished(); + } + checkIfFinished() { + let isFinished = true; + + this.piecesGroup.getChildren().forEach((element) => { + if (element.currentIndex !== element.destIndex) { + isFinished = false; + return; + } + }); + + if (isFinished) { + this.won = true; + this.blackPiece.visible = true; + this.game.onWon && this.game.onWon(); + } + } +} +export default class Game extends Phaser.Game { + constructor({ containerId, onLose, onWon }) { + const container = document.getElementById(containerId); + const containerWH = container.clientWidth; + super({ + type: Phaser.CANVAS, + width: containerWH, + height: containerWH, + parent: containerId, + scale: { + mode: Phaser.Scale.FIT, + autoCenter: Phaser.Scale.CENTER_BOTH, + parent: containerId, + width: 2160, + height: 2160, + }, + scene: Scene, + }); + Object.assign(this, { + onLose, + onWon, + restart() { + this.scene.scenes[0].scene.start("scene"); + }, + }); + } +} diff --git a/phaser/slidingPuzzle/puzzle.png b/phaser/slidingPuzzle/puzzle.png new file mode 100644 index 0000000..aa9f6ee Binary files /dev/null and b/phaser/slidingPuzzle/puzzle.png differ