@ -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" |
|||
} |
|||
} |
|||