21天徒手撸一个游戏引擎(7)整合一些变量到Game对象

codetyphon

由于直接在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
      }
    }
  })
})
阅读 589

17 声望
0 粉丝
0 条评论
17 声望
0 粉丝
文章目录
宣传栏