@ -0,0 +1,2 @@ |
|||||
|
/node_modules |
||||
|
yarn.lock |
||||
@ -0,0 +1,65 @@ |
|||||
|
<template> |
||||
|
<div id="gameContainer" :style="containerStyle"></div> |
||||
|
</template> |
||||
|
<script> |
||||
|
import ballMove from "./games/game-ballmove/game"; |
||||
|
const games = { ballMove }; |
||||
|
const STATE_RUNNING = 0; |
||||
|
const STATE_LOSE = 1; |
||||
|
const STATE_WIN = 2; |
||||
|
const STATE_PAUSED = 3; |
||||
|
export default { |
||||
|
props: ["name", "containerStyle"], |
||||
|
data() { |
||||
|
return { |
||||
|
state: STATE_RUNNING, |
||||
|
gameInstance: null, |
||||
|
containerId: "gameContainer", |
||||
|
}; |
||||
|
}, |
||||
|
methods: { |
||||
|
pause() { |
||||
|
this.gameInstance.scene.scenes.forEach((scene) => { |
||||
|
scene.scene.pause(); |
||||
|
}); |
||||
|
this.state = STATE_PAUSED; |
||||
|
this.$emit("paused"); |
||||
|
}, |
||||
|
resume() { |
||||
|
if (this.state === STATE_PAUSED) { |
||||
|
this.gameInstance.scene.scenes.forEach((scene) => { |
||||
|
scene.scene.resume(); |
||||
|
}); |
||||
|
this.state = STATE_RUNNING; |
||||
|
this.$emit("resumed"); |
||||
|
} |
||||
|
}, |
||||
|
restart() { |
||||
|
this.gameInstance.restart(); |
||||
|
this.state = STATE_RUNNING; |
||||
|
}, |
||||
|
}, |
||||
|
async mounted() { |
||||
|
this.gameInstance = games[this.name]({ |
||||
|
containerId: this.containerId, |
||||
|
onLose: () => { |
||||
|
if (this.state !== STATE_LOSE) this.$emit("lost"); |
||||
|
this.state = STATE_LOSE; |
||||
|
}, |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
destroyed() { |
||||
|
for (const key in this.gameInstance.scene.keys) { |
||||
|
if (this.gameInstance.scene.keys.hasOwnProperty(key)) { |
||||
|
this.gameInstance.scene.stop(key); //停止渲染 |
||||
|
this.gameInstance.scene.keys[key] = undefined; |
||||
|
} |
||||
|
} |
||||
|
this.gameInstance.destroy(false); |
||||
|
}, |
||||
|
}; |
||||
|
</script> |
||||
|
|
||||
|
<style> |
||||
|
</style> |
||||
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 636 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 12 KiB |
@ -0,0 +1,10 @@ |
|||||
|
export const gameOptions = { |
||||
|
bounceHeight: 300, |
||||
|
ballGravity: 1200, |
||||
|
ballPosition: 0.2, |
||||
|
platformSpeed: 650, |
||||
|
platformDistanceRange: [250, 450], |
||||
|
platformHeightRange: [-50, 50], |
||||
|
platformLengthRange: [40, 120], |
||||
|
localStorageName: "bestballscore3" |
||||
|
}; |
||||
@ -0,0 +1,38 @@ |
|||||
|
import Phaser from "phaser"; |
||||
|
import PlayScene from "./scenes/PlayScene"; |
||||
|
|
||||
|
function launch({ containerId, onLose }) { |
||||
|
const container = document.getElementById(containerId); |
||||
|
const width = container.clientWidth; |
||||
|
const height = container.clientHeight; |
||||
|
const game = new Phaser.Game({ |
||||
|
type: Phaser.AUTO, |
||||
|
width, |
||||
|
height, |
||||
|
parent: containerId, |
||||
|
scale: { |
||||
|
mode: Phaser.Scale.FIT, |
||||
|
autoCenter: Phaser.Scale.CENTER_BOTH, |
||||
|
parent: containerId, |
||||
|
width: 600, |
||||
|
height: 600, |
||||
|
}, |
||||
|
physics: { |
||||
|
default: "arcade", |
||||
|
arcade: { |
||||
|
debug: false, |
||||
|
}, |
||||
|
}, |
||||
|
scene: PlayScene, |
||||
|
}); |
||||
|
Object.assign(game, { |
||||
|
onLose, |
||||
|
restart() { |
||||
|
this.scene.scenes[0].scene.start("PlayScene"); |
||||
|
}, |
||||
|
}); |
||||
|
return game; |
||||
|
} |
||||
|
|
||||
|
export default launch; |
||||
|
export { launch }; |
||||
@ -0,0 +1,191 @@ |
|||||
|
import Phaser from "phaser"; |
||||
|
import { gameOptions } from "../constant/index"; |
||||
|
function importAll(r) { |
||||
|
let obj = {}; |
||||
|
r.keys().forEach((key) => { |
||||
|
obj[key.replace("./", "").replace(".png", "")] = r(key); |
||||
|
}); |
||||
|
return obj; |
||||
|
} |
||||
|
|
||||
|
const images = importAll( |
||||
|
require.context("../assets/ballmove", false, /\.(png|jpe?g|svg)$/) |
||||
|
); |
||||
|
const blockNames = ["bu", "gr", "og", "pu", "red", "ye"]; |
||||
|
const blockWidth = (2 / 3) * 100; |
||||
|
const blockHeight = (blockWidth / 116) * 133; |
||||
|
class PlayScene extends Phaser.Scene { |
||||
|
constructor() { |
||||
|
super({ |
||||
|
key: "PlayScene", |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
preload() { |
||||
|
Object.entries(images).forEach(([k, v]) => { |
||||
|
this.load.image(k, v); |
||||
|
}); |
||||
|
} |
||||
|
newBlock(x, y, tex) { |
||||
|
return this.platformGroup.create(x, y, tex); |
||||
|
} |
||||
|
attachSidekick(platform, num) { |
||||
|
const { |
||||
|
x, |
||||
|
y, |
||||
|
texture: { key }, |
||||
|
} = platform; |
||||
|
switch (num) { |
||||
|
case 2: |
||||
|
platform.x -= blockWidth / 2; |
||||
|
{ |
||||
|
let platform = this.newBlock(x + blockWidth / 2, y, key); |
||||
|
platform.setImmovable(true); |
||||
|
platform.displayWidth = blockWidth; |
||||
|
platform.displayHeight = blockHeight; |
||||
|
} |
||||
|
break; |
||||
|
case 3: |
||||
|
platform.x += blockWidth; |
||||
|
{ |
||||
|
let platform = this.newBlock(x, y, key); |
||||
|
platform.setImmovable(true); |
||||
|
platform.displayWidth = blockWidth; |
||||
|
platform.displayHeight = blockHeight; |
||||
|
} |
||||
|
{ |
||||
|
let platform = this.newBlock(x - blockWidth, y, key); |
||||
|
platform.setImmovable(true); |
||||
|
platform.displayWidth = blockWidth; |
||||
|
platform.displayHeight = blockHeight; |
||||
|
} |
||||
|
break; |
||||
|
default: |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
newPlatForm(x) { |
||||
|
const y = |
||||
|
(this.game.config.height / 6) * 5 + |
||||
|
Phaser.Math.Between( |
||||
|
gameOptions.platformHeightRange[0], |
||||
|
gameOptions.platformHeightRange[1] |
||||
|
); |
||||
|
const tex = blockNames[Math.floor(Math.random() * blockNames.length)]; |
||||
|
let platform = this.newBlock(x, y, tex); |
||||
|
platform.setImmovable(true); |
||||
|
platform.displayWidth = blockWidth; |
||||
|
platform.displayHeight = blockHeight; |
||||
|
const number = Math.floor(Math.random() * 3 + 1); |
||||
|
platform.name = number; |
||||
|
this.attachSidekick(platform, number); |
||||
|
} |
||||
|
create() { |
||||
|
this.platformGroup = this.physics.add.group(); |
||||
|
this.bgGroup = this.physics.add.group(); |
||||
|
for (let i = 0; i < 2; i++) { |
||||
|
let bg = this.bgGroup.create( |
||||
|
this.game.config.width * (i + 1 / 2), |
||||
|
this.game.config.height / 2, |
||||
|
"bg" |
||||
|
); |
||||
|
bg.setImmovable(true); |
||||
|
bg.displayWidth = this.game.config.width; |
||||
|
bg.displayHeight = this.game.config.height; |
||||
|
} |
||||
|
this.ball = this.physics.add.sprite( |
||||
|
this.game.config.width * gameOptions.ballPosition, |
||||
|
(this.game.config.height / 4) * 3 - gameOptions.bounceHeight, |
||||
|
"ball" |
||||
|
); |
||||
|
this.ball.body.gravity.y = gameOptions.ballGravity; |
||||
|
this.ball.setBounce(1); |
||||
|
this.ball.body.checkCollision.down = true; |
||||
|
this.ball.body.checkCollision.up = false; |
||||
|
this.ball.body.checkCollision.left = false; |
||||
|
this.ball.body.checkCollision.right = false; |
||||
|
this.ball.displayWidth = 114; |
||||
|
this.ball.displayHeight = 120; |
||||
|
this.ball.setSize(114, 120, true); |
||||
|
let platformX = this.ball.x; |
||||
|
|
||||
|
for (let i = 0; i < 10; i++) { |
||||
|
this.newPlatForm(platformX); |
||||
|
platformX += Phaser.Math.Between( |
||||
|
gameOptions.platformDistanceRange[0], |
||||
|
gameOptions.platformDistanceRange[1] |
||||
|
); |
||||
|
} |
||||
|
this.input.on("pointerdown", this.movePlatforms, this); |
||||
|
this.input.on("pointerup", this.stopPlatforms, this); |
||||
|
this.score = 0; |
||||
|
this.topScore = |
||||
|
localStorage.getItem(gameOptions.localStorageName) == null |
||||
|
? 0 |
||||
|
: localStorage.getItem(gameOptions.localStorageName); |
||||
|
this.scoreText1 = this.add.text(20, 20, "", { |
||||
|
fontSize: 20, |
||||
|
}); |
||||
|
this.scoreText2 = this.add.text(20, 45, "", { |
||||
|
fontSize: 20, |
||||
|
}); |
||||
|
this.updateScore(this.score); |
||||
|
} |
||||
|
updateScore(inc) { |
||||
|
this.score += inc; |
||||
|
this.scoreText1.text = "Game Score: " + this.score; |
||||
|
this.scoreText2.text = "Best Score: " + this.topScore; |
||||
|
} |
||||
|
|
||||
|
movePlatforms() { |
||||
|
this.bgGroup.setVelocityX(-gameOptions.platformSpeed * 0.5); |
||||
|
this.platformGroup.setVelocityX(-gameOptions.platformSpeed); |
||||
|
} |
||||
|
stopPlatforms() { |
||||
|
this.bgGroup.setVelocityX(0); |
||||
|
this.platformGroup.setVelocityX(0); |
||||
|
} |
||||
|
getRightmostPlatform() { |
||||
|
let rightmostPlatform = 0; |
||||
|
this.platformGroup.getChildren().forEach((platform) => { |
||||
|
rightmostPlatform = Math.max(rightmostPlatform, platform.x); |
||||
|
}); |
||||
|
return rightmostPlatform; |
||||
|
} |
||||
|
update() { |
||||
|
this.physics.world.collide(this.platformGroup, this.ball); |
||||
|
const children = this.platformGroup.getChildren(); |
||||
|
children.forEach((platform) => { |
||||
|
if (platform.getBounds().right < 0) { |
||||
|
if (platform.name) { |
||||
|
this.updateScore(1); |
||||
|
setTimeout(() => { |
||||
|
this.newPlatForm( |
||||
|
this.getRightmostPlatform() - |
||||
|
Number(platform.name) * blockWidth + |
||||
|
Phaser.Math.Between( |
||||
|
gameOptions.platformDistanceRange[0], |
||||
|
gameOptions.platformDistanceRange[1] |
||||
|
) |
||||
|
); |
||||
|
}); |
||||
|
} |
||||
|
this.platformGroup.remove(platform, true, true); |
||||
|
} |
||||
|
}); |
||||
|
this.bgGroup.getChildren().forEach((bg) => { |
||||
|
if (bg.getBounds().right < 0) { |
||||
|
bg.x += this.game.config.width * 2; |
||||
|
} |
||||
|
}, this); |
||||
|
if (this.ball.y > this.game.config.height) { |
||||
|
localStorage.setItem( |
||||
|
gameOptions.localStorageName, |
||||
|
Math.max(this.score, this.topScore) |
||||
|
); |
||||
|
this.game.onLose && this.game.onLose(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export default PlayScene; |
||||
@ -0,0 +1,3 @@ |
|||||
|
import Vue from "vue"; |
||||
|
import Game from "./Game.vue"; |
||||
|
export default Game; |
||||
@ -0,0 +1,10 @@ |
|||||
|
{ |
||||
|
"name": "qmgame", |
||||
|
"version": "1.0.0", |
||||
|
"main": "index.js", |
||||
|
"license": "MIT", |
||||
|
"dependencies": { |
||||
|
"phaser": "^3.24.1", |
||||
|
"vue": "^2.6.12" |
||||
|
} |
||||
|
} |
||||