由于直接在game.js中写了很多逻辑,因此需要提取一些功能到Game对象中。
新建codetyphon/game.js
把之前在./game.js中的代码移过去
const context = canvas.getContext('2d')
const {
windowWidth,
windowHeight
} = wx.getSystemInfoSync()
类对象Game,具有一些属性。
export default class Game {
constructor(res_gameover) {
this.score = 0
this.life = 1
this.gameover = false
this.time = 0
this.on_times = []
this.on_update = () => {}
this.player = null
this.enemys = []
this.bullets = []
this.foods = []
this.res_gameover = res_gameover
}
}
如果重新开始游戏,需要重新初始化
restart() {
this.enemys = []
this.bullets = []
this.foods = []
this.score = 0
this.life = 1
this.gameover = false
this.time = 0
}
它得有update、render、start等方法
update(){
}
render(){
}
start(){
}
把step移过去
start() {
const step = (timestamp) => {
context.clearRect(0, 0, windowWidth, windowHeight)
if (!this.gameover) {
this.update()
}
this.render()
if (this.gameover) {
this.render_gameover()
}
window.requestAnimationFrame(step);
}
window.requestAnimationFrame(step);
}
设置添加不同种类的精灵
set_player(player) {
this.player = player
}
add_enemy(enemy) {
this.enemys.push(enemy)
}
add_bullet(bullet) {
this.bullets.push(bullet)
}
add_food(food) {
this.foods.push(food)
}
对时间间隔的处理:
this.on_times = []
添加一个间隔时间的函数
on_time(time = 100, fn = () => {}) {
this.on_times.push({
time: time,
fn: fn
})
}
在update中,处理时间间隔
this.time += 1
this.on_times.map(item => {
if (this.time % item.time == 0) {
item.fn()
}
})
全部代码如下:
export default class Game {
constructor(res_gameover) {
this.score = 0
this.life = 1
this.gameover = false
this.time = 0
this.on_times = []
this.on_update = () => {}
this.player = null
this.enemys = []
this.bullets = []
this.foods = []
this.res_gameover = res_gameover
}
restart() {
this.enemys = []
this.bullets = []
this.foods = []
this.score = 0
this.life = 1
this.gameover = false
this.time = 0
}
set_player(player) {
this.player = player
}
add_enemy(enemy) {
this.enemys.push(enemy)
}
// remove_enemy(enemy) {
// }
// remove_bullet(bullet) {
// }
// remove_food(food) {
// }
add_bullet(bullet) {
this.bullets.push(bullet)
}
add_food(food) {
this.foods.push(food)
}
on_time(time = 100, fn = () => {}) {
this.on_times.push({
time: time,
fn: fn
})
}
update() {
if (this.player) {
this.player.update()
}
this.enemys.map(item => item.update())
this.bullets.map(item => item.update())
this.foods.map(item => item.update())
}
render_life(x = 8, y = 30, fontSize = 20) {
context.font = `normal ${fontSize}px serif`
context.fillStyle = '#fff'
context.fillText(` x ${this.life}`, x, y)
}
render_score(x = 10, y = 60, fontSize = 20) {
context.font = `normal ${fontSize}px sans-serif`
context.fillStyle = '#fff'
context.fillText(`score: ${this.score}`, x, y)
}
render() {
if (this.player) {
this.player.draw(context)
}
this.enemys.map(item => item.draw(context))
this.bullets.map(item => item.draw(context))
this.foods.map(item => item.draw(context))
this.render_life()
this.render_score()
}
render_gameover() {
context.drawImage(this.res_gameover, windowWidth / 2 - this.res_gameover.width / 4, windowHeight / 2 - this.res_gameover.height / 4, this.res_gameover.width / 2, this.res_gameover.height / 2)
}
start() {
const step = (timestamp) => {
context.clearRect(0, 0, windowWidth, windowHeight)
if (!this.gameover) {
this.time += 1
this.on_times.map(item => {
if (this.time % item.time == 0) {
item.fn()
}
})
this.update()
this.on_update()
}
this.render()
if (this.gameover) {
this.render_gameover()
}
window.requestAnimationFrame(step);
}
window.requestAnimationFrame(step);
}
}
这样,./game.js 就变为:
import './libs/weapp-adapter'
import './libs/symbol'
import {
ResLoader,
Sprite,
Game
} from './codetyphon/index'
const {
windowWidth,
windowHeight
} = wx.getSystemInfoSync()
function rand(min, max) {
return Math.round(Math.random() * (max - min) + min);
}
let click = 0
const loader = new ResLoader()
loader.add('player', 'images/player.png')
loader.add('enemy', 'images/enemy.png')
loader.add('gameover', 'images/gameover.png')
loader.add('bullet', 'images/bullet.png')
loader.on_load_finish((res) => {
let game = new Game(res['gameover'])
game.life = 3
const player = new Sprite(0, 0, res['player'], 0.5)
player.setPosition(windowWidth / 2, windowHeight - player.height)
player.on_update = () => {
const arr = player.collision_with(game.enemys)
if (arr.length > 0) {
game.life -= 1
if (game.life <= 0) {
game.gameover = true
} else {
arr.map(item => {
item.remove_from(game.enemys)
game.score += 1
})
}
}
}
game.set_player(player)
game.on_time(200, () => {
//add food
})
game.on_time(80, () => {
const enemy = new Sprite(0, 0, res['enemy'], 0.5)
enemy.setPosition(rand(0, windowWidth - enemy.width), 0)
enemy.vy = rand(3, 10)
enemy.on_update = () => {
if (enemy.y > windowHeight) {
enemy.remove_from(game.enemys)
}
}
game.add_enemy(enemy)
})
game.on_update = () => {
}
game.start()
wx.onTouchMove(function (res) {
if (!game.gameover) {
const x = res.changedTouches[0].clientX
const y = res.changedTouches[0].clientY
player.setPosition(x, y)
}
})
wx.onTouchEnd((result) => {
if (!game.gameover) {
const bullet = new Sprite(0, 0, res['bullet'], 0.1)
bullet.setPosition(player.x, player.y)
bullet.vy = -5
bullet.on_update = () => {
if (bullet.y <= 0 - bullet.height) {
bullet.remove_from(game.bullets)
} else {
const collisioned = bullet.collision_with(game.enemys)
collisioned.map(item => {
game.score += 1
item.remove_from(game.enemys)
})
if (collisioned.length > 0) {
bullet.remove_from(game.bullets)
}
}
}
game.add_bullet(bullet)
}
if (game.gameover) {
click++
if (click >= 2) {
game.restart()
click = 0
}
}
})
})