【默默努力】h5-game-heroVSmonster

先放下作者大大的项目地址:https://github.com/yangyunhe369/h5-game-heroVSmonster
然后游戏的效果为
截动图的按键与游戏按键应该冲突,我就截几张图片了。



接下来我们来分析代码
页面入口文件,canvas绘制页面背景以及各个图片

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>英雄大战小怪兽v1.0</title>
  <link rel="stylesheet" href="css/common.css">
  <link rel="stylesheet" href="css/style.css">
</head>
<body>
<canvas id="canvas" width="1000" height="500"></canvas>
<div>
  空格键开始游戏<br>
  W、S、A、D键 和 上下左右方向键分别控制英雄、怪兽移动<br>
  K 键、小键盘数字 5 键分别控制英雄和怪兽攻击,P 键暂停游戏
</div>
<script src="js/common.js"></script>
<script src="js/scene.js"></script>
<script src="js/game.js"></script>
<script src="js/main.js"></script>
</body>
</html>

common.js中是公共的会用到的图片

//common.js
/* by:弦云孤赫——David Yang
** github - https://github.com/yangyunhe369
*/
// 封装打印日志方法
const log = console.log.bind(console)
// 生成图片对象方法
const imageFromPath = function (src) {
  let img = new Image()
  img.src = './images/' + src
  return img
}
// 图片素材路径
const allImg = {
  bg: 'gameBg.jpg',
  hero: {
    idle: [ // 站立不动
      'hero-Idle/hero_Idle_0.png',
      'hero-Idle/hero_Idle_1.png',
      'hero-Idle/hero_Idle_2.png',
      'hero-Idle/hero_Idle_3.png',
      'hero-Idle/hero_Idle_4.png',
      'hero-Idle/hero_Idle_5.png',
      'hero-Idle/hero_Idle_6.png',
      'hero-Idle/hero_Idle_7.png',
    ],
    run: [ // 移动
      'hero-Run/hero_Run_0.png',
      'hero-Run/hero_Run_1.png',
      'hero-Run/hero_Run_2.png',
      'hero-Run/hero_Run_3.png',
      'hero-Run/hero_Run_4.png',
      'hero-Run/hero_Run_5.png',
      'hero-Run/hero_Run_6.png',
      'hero-Run/hero_Run_7.png',
    ],
    attack: [ // 攻击
      'hero-Attack/hero_Attack_0.png',
      'hero-Attack/hero_Attack_1.png',
      'hero-Attack/hero_Attack_2.png',
      'hero-Attack/hero_Attack_3.png',
      'hero-Attack/hero_Attack_4.png',
      'hero-Attack/hero_Attack_5.png',
      'hero-Attack/hero_Attack_6.png',
      'hero-Attack/hero_Attack_7.png',
    ],
    hurt: [ // 受伤
      'hero-Hurt/hero_Hurt_0.png',
      'hero-Hurt/hero_Hurt_1.png',
      'hero-Hurt/hero_Hurt_2.png',
      'hero-Hurt/hero_Hurt_3.png',
      'hero-Hurt/hero_Hurt_4.png',
      'hero-Hurt/hero_Hurt_5.png',
      'hero-Hurt/hero_Hurt_6.png',
      'hero-Hurt/hero_Hurt_7.png',
    ],
    die: [ // 死亡
      'hero-Die/hero_Die_0.png',
      'hero-Die/hero_Die_1.png',
      'hero-Die/hero_Die_2.png',
      'hero-Die/hero_Die_3.png',
      'hero-Die/hero_Die_4.png',
      'hero-Die/hero_Die_5.png',
      'hero-Die/hero_Die_6.png',
      'hero-Die/hero_Die_7.png',
    ],
  },
  monster: {
    idle: [ // 站立不动
      'monster-Idle/monster_Idle_0.png',
      'monster-Idle/monster_Idle_1.png',
      'monster-Idle/monster_Idle_2.png',
      'monster-Idle/monster_Idle_3.png',
      'monster-Idle/monster_Idle_4.png',
      'monster-Idle/monster_Idle_5.png',
      'monster-Idle/monster_Idle_6.png',
      'monster-Idle/monster_Idle_7.png',
    ],
    run: [ // 移动
      'monster-Run/monster_Run_0.png',
      'monster-Run/monster_Run_1.png',
      'monster-Run/monster_Run_2.png',
      'monster-Run/monster_Run_3.png',
      'monster-Run/monster_Run_4.png',
      'monster-Run/monster_Run_5.png',
      'monster-Run/monster_Run_6.png',
      'monster-Run/monster_Run_7.png',

    ],
    attack: [ // 攻击
      'monster-Attack/monster_Attack_0.png',
      'monster-Attack/monster_Attack_1.png',
      'monster-Attack/monster_Attack_2.png',
      'monster-Attack/monster_Attack_3.png',
      'monster-Attack/monster_Attack_4.png',
      'monster-Attack/monster_Attack_5.png',
      'monster-Attack/monster_Attack_6.png',
      'monster-Attack/monster_Attack_7.png',
    ],
    hurt: [ // 攻击
      'monster-Hurt/monster_Hurt_0.png',
      'monster-Hurt/monster_Hurt_1.png',
      'monster-Hurt/monster_Hurt_2.png',
      'monster-Hurt/monster_Hurt_3.png',
      'monster-Hurt/monster_Hurt_4.png',
      'monster-Hurt/monster_Hurt_5.png',
      'monster-Hurt/monster_Hurt_6.png',
      'monster-Hurt/monster_Hurt_7.png',
    ],
    die: [ // 死亡
      'monster-Die/monster_Die_0.png',
      'monster-Die/monster_Die_1.png',
      'monster-Die/monster_Die_2.png',
      'monster-Die/monster_Die_3.png',
      'monster-Die/monster_Die_4.png',
      'monster-Die/monster_Die_5.png',
      'monster-Die/monster_Die_6.png',
      'monster-Die/monster_Die_7.png',
    ],
  }
}

scene.js中是定义的角色模型

//scene
/* by:弦云孤赫——David Yang
** github - https://github.com/yangyunhe369
*/
/**
 * 动画类
 */
class Animation{
  constructor (type, action, fps) {
    let a = {
      type: type,                                        // 角色类型,hero || monster
      action: action,                                    // 根据传入动作生成不同动画对象数组
      images: [],                                        // 当前引入角色图片对象数组
      img: null,                                         // 当前显示角色图片
      imgIdx: 0,                                         // 当前角色图片序列号
      count: 0,                                          // 计数器,控制动画运行
      fps: fps,                                          // 角色动画运行速度系数,值越小,速度越快
    }
    Object.assign(this, a)
  }
  /**
   * 为角色不同动作创造动画序列
   */
  create () {
    let self = this
    if (self.type === 'hero') {
      for(let item of allImg.hero[self.action]){
        self.images.push(imageFromPath(item))
      }
    } else if (self.type === 'monster') {
      for(let item of allImg.monster[self.action]){
        self.images.push(imageFromPath(item))
      }
    }
  }
}
/**
 * 角色模型类
 */
class Role{
  constructor (_main, obj) {
    let h = {
      _main: _main,                                        // 游戏主函数对象
      type: obj.type,                                      // 角色类型,hero || monster
      x: obj.x,                                            // x 轴坐标
      y: obj.y,                                            // y 轴坐标
      w: obj.w,                                            // 角色图片宽度
      h: obj.h,                                            // 角色图片高度
      speedX: 3,                                           // 角色x轴移动速度
      speedY: 3,                                           // 角色y轴移动速度
      life: 8,                                             // 角色血量

      // animation: {  
      //   idle: null,                                        // 站立动画对象
      //   run: null,                                         // 奔跑动画对象
      //   attack: null,                                      // 攻击动画对象
      //   hurt: null,                                        // 受伤动画对象
      //   die: null,                                         // 死亡动画对象
      // },

      idle: null,                                          // 站立动画对象
      run: null,                                           // 奔跑动画对象
      attack: null,                                        // 攻击动画对象
      hurt: null,                                          // 受伤动画对象
      die: null,                                           // 死亡动画对象
      canMove: true,                                       // 能否移动
      isFlipX: false,                                      // 是否翻转画布绘制图片,用于绘制人物朝右动画
      isAttacking: false,                                  // 是否处于攻击状态
      isDie: false,                                        // 是否死亡,血量降为 0 即死亡
      direction: null,                                     // 角色朝向
      state: 1,                                            // 保存当前状态值,默认为 0
      state_IDLE: 1,                                       // 站立状态
      state_RUN: 2,                                        // 奔跑状态
      state_ATTACK: 3,                                     // 攻击状态
      state_HURT: 4,                                       // 受伤状态
      state_DIE: 5,                                        // 死亡状态
    }
    Object.assign(this, h)
  }
  /**
   * 初始化方法
   * 对角色的站位方向、状态、不同姿势动画序列进行初始化
   */
  init (info) {
    let self = this
    // 角色初始站位方向,状态
    info.type === 'hero' ? self.direction = 'right' : self.direction = 'left'
    // 是否翻转绘制角色,根据角色朝向判断
    self.isFlipX = self.direction === 'left' ? false : true
    // 角色默认状态值为1,站立状态
    self.state = 1
    // 角色站立
    self.idle = new Animation(self.type, 'idle', 8)
    self.idle.create()
    // 角色奔跑
    self.run = new Animation(self.type, 'run', 4.5),
    self.run.create()
    // 角色攻击
    self.attack = new Animation(self.type, 'attack', 4)
    self.attack.create()
    // 角色受伤
    self.hurt = new Animation(self.type, 'hurt', 4)
    self.hurt.create()
    // 角色死亡
    self.die = new Animation(self.type, 'die', 4)
    self.die.create()
  }
  /**
   * 判断角色状态并返回对应动画对象名称方法
   */
  switchState (state) {
    let self = this
    switch (state) {
      case self.state_IDLE:
        return 'idle'
      case self.state_RUN:
        return 'run'
      case self.state_ATTACK:
        return 'attack'
      case self.state_HURT:
        return 'hurt'
      case self.state_DIE:
        return 'die'
    }
  }
  /**
   * 角色运行动画切换方法
   * game: 游戏对象
   */
  move (game) {
    let self = this,
        stateName = self.switchState(self.state)
    // 累加动画计数器
    self[stateName].count += 1
    // 设置角色动画运行速度
    self[stateName].imgIdx = Math.floor(self[stateName].count / self[stateName].fps)
    // 一整套动画完成后重置动画计数器
    self[stateName].imgIdx === 7 ? self[stateName].count = 0 : self[stateName].count = self[stateName].count
    // 设置当前帧动画对象
    if (game.state !== game.state_STOP) { // 运动时,逐帧显示图片
      if (stateName === 'hurt' && self[stateName].imgIdx === 7) { // 受伤时,执行完一套动画切换为站立状态后允许移动
        // 角色状态改为站立状态
        self.state = self.state_IDLE
        self.canMove = true
      } else if (stateName === 'die' && self[stateName].imgIdx === 7) {
        // 游戏状态改为结束状态
        game.state = game.state_GAMEOVER
        self[stateName].img = self[stateName].images[7]
      } else {
        self[stateName].img = self[stateName].images[self[stateName].imgIdx]
      }
    } else { // 静止时,默认显示第一张图片
      self[stateName].img = self[stateName].images[0]
    }
  }
  /**
   * 执行动画方法
   * game => 游戏引擎对象
   * action => 动作类型
   *  -idle: 站立
   *  -run: 移动
   *  -attack: 攻击
   *  -hurt: 受伤
   */
  animation (game, action) {
    let self = this,
        direction = self.direction,           // 获取角色朝向
        canvas = self._main.game.canvas       // 获取 canvas 对象
    if (game.state === game.state_RUNNING) {
      switch (action) {
        case 'idle':
          self.state = self.state_IDLE
          break
        case 'run':
          self.state = self.state_RUN

          // 上下左右键移动事件,并做边界判断
          if (direction === 'up') { // 上
            if (self.y > 25) { // 大于上边界 + 血条高度
              self.y -= self.speedY
            }
          } else if (direction === 'down') { // 下
            if (self.y < canvas.height - self.h + 15) { // 大于下边界 - 图片高度 + 图片下侧空白部分
              self.y += self.speedY
            }
          } else if (direction === 'left') { // 左
            if (self.x > -10) { // 大于左边界 - 图片左侧空白部分
              self.x -= self.speedX
            }
          } else if (direction === 'right') { // 右
            if (self.x < canvas.width - self.w) { // 大于右边界 - 图片宽度 - 图片右侧空白部分
              self.x += self.speedX
            }
          }
          break
        case 'attack':
          self.state = self.state_ATTACK
          break
        case 'hurt':
          self.state = self.state_HURT
          break
        case 'die':
          self.state = self.state_DIE
          break
      }
    }
  }
}

main.js中是定义的游戏的主函数,启动方法

//js\main.js
/* by:弦云孤赫——David Yang
** github - https://github.com/yangyunhe369
*/
/**
 * 游戏运行主函数
 */
let _main = {
  hero: null,                               // hero 实例对象
  hero_info: {                              // hero 初始化参数
    type: 'hero',                           // 角色类型
    x: 40,                                  // x 轴坐标
    y: 350,                                 // y 轴坐标
    w: 100,                                 // 图片宽度
    h: 109,                                 // 图片高度
  },
  monster: null,                            // monster 实例对象
  monster_info: {                           // monster 初始化参数
    type: 'monster',                        // 角色类型  
    x: 900,                                 // monster x 轴坐标
    y: 100,                                 // monster y 轴坐标
    w: 100,                                 // 图片宽度
    h: 113,                                 // 图片高度
  },
  game: null,                               // 游戏引擎对象
  fps: 60,                                  // 游戏运行每秒帧数
  rollPostion: function () {                // 随机角色坐标位置
    let self = this,
        canvas = document.getElementById('canvas'),
        hero = self.hero_info,
        monster = self.monster_info
    // 随机生成 hero 坐标,在左半区域随机
    hero.x = Math.random() * (canvas.width / 2 - hero.w) + 0
    hero.y = Math.random() * (canvas.height - hero.h) + 0
    // 随机生成 monster 坐标,在右半区域随机
    monster.x = Math.random() * (canvas.width / 2 - monster.w) + canvas.width / 2
    monster.y = Math.random() * (canvas.height - monster.h) + 0
  },
  start: function () {                      // 游戏主程序
    let self = this
    // 随机生成 hero,monster 坐标
    self.rollPostion()

    // 创建 hero 类
    self.hero = new Role(self, self.hero_info)
    // 创建 hero 动画序列
    self.hero.init(self.hero_info)

    // 创建 monster 类
    self.monster = new Role(self, self.monster_info)
    // 创建 monster 动画序列
    self.monster.init(self.monster_info)

    // 创建游戏引擎类
    self.game = new Game(self.fps)
    self.game.init(self)
  }
}
_main.start()

game.js中定义的是游戏说明以及得分点

//js\game.js

/* by:弦云孤赫——David Yang
** github - https://github.com/yangyunhe369
*/
/**
 * 游戏引擎函数
 */
class Game {
  constructor (fps = 60) {
    let g = {
      actions: {},                                                  // 按键事件方法集,并在按键事件触发时调用对应方法
      keydowns: {},                                                 // 按键事件生成对象集
      state: 1,                                                     // 游戏状态值,初始默认为 1
      state_START: 1,                                               // 游戏初始化
      state_RUNNING: 2,                                             // 游戏开始
      state_STOP: 3,                                                // 游戏暂停
      state_GAMEOVER: 4,                                            // 游戏结束
      canvas: document.getElementById("canvas"),                    // canvas 元素
      context: document.getElementById("canvas").getContext("2d"),  // canvas 画布
      timer: null,                                                  // 轮询定时器
      fps: fps,                                                     // 动画帧数,默认 60
    }
    Object.assign(this, g)
  }
  // 绘制所有游戏素材
  drawAll (hero, monster) {
    let g = this
    // 清除画布
    g.context.clearRect(0, 0, g.canvas.width, g.canvas.height)
    // 绘制背景
    g.drawBg()
    // 绘制角色及角色血条
    g.drawImage(hero)
    g.drawBlood(hero.x, hero.y, hero.life, hero.type)
    g.drawImage(monster)
    g.drawBlood(monster.x, monster.y, monster.life, monster.type)
  }
  // 绘制游戏背景
  drawBg () {
    let img = imageFromPath(allImg.bg)
    this.context.drawImage(img, 0, 0)
  }
  /**
   * 绘制角色血条
   * x:  x轴坐标
   * y:  y轴坐标
   * life:  血量
   * type: 角色类型 => hero || monster
   * height:  血条高度
   * fillColor:  填充颜色
   * borderWidth:  边框宽度
   * borderColor:  边框颜色
   */
  drawBlood (x, y, life, type, fillColor, borderColor, borderWidth = 1, height = 15) {
    let cxt = this.context,
        width = 6 * life // 血量单位宽度 * 总血量

    // 根据角色类型不同,绘制不同颜色血条
    if (type === 'hero') {
      fillColor = 'red'
      borderColor = 'red'
    } else {
      fillColor = '#cc3f30'
      borderColor = '#cc3f30'
    }
    // 开始绘制血条
    cxt.beginPath()
    cxt.rect(x + 26, y - 20, width, height)

    cxt.lineWidth = borderWidth
    cxt.strokeStyle = borderColor
    cxt.fillStyle = fillColor

    cxt.fill()
    cxt.stroke()
  }
  /**
   * 绘制图片
   * obj: 绘制对象
   */
  drawImage (obj) {
    let state = obj.state,                            // 当前角色状态值
        stateName = obj.switchState(obj.state)        // 判断并获取当前动画对象名称
    if (obj.isFlipX) { // 是否水平翻转图像并绘制,true 翻转且角色朝右,false 不翻转且角色朝左
      let x = obj.x + obj.w / 2
      // 把当前状态的一份拷贝压入到一个保存图像状态的栈中
      this.context.save()
      this.context.translate(x, 0)
      this.context.scale(-1, 1)
      this.context.translate(-x, 0)
      this.context.drawImage(obj[stateName].img, obj.x, obj.y)
      // 从栈中弹出存储的图形状态并恢复 CanvasRenderingContext2D 对象的属性、剪切路径和变换矩阵的值
      this.context.restore()
    } else {
      this.context.drawImage(obj[stateName].img, obj.x, obj.y)
    }
  }
  // 游戏结束执行方法
  drawGameOver (hero, monster) {
    let info = ''   // 游戏结束提示信息
    if (hero.isDie) {
      info = '恭喜怪兽获得胜利'
    }
    if (monster.isDie) {
      info = '恭喜英雄获得胜利'
    }
    // 清除定时器
    clearInterval(this.timer)
    // 清除画布
    this.context.clearRect(0, 0, this.canvas.width, this.canvas.height)
    // 绘制背景
    this.drawBg()
    this.context.fillStyle = 'red'
    this.context.font = '48px Microsoft YaHei'
    this.context.fillText(info, 308, 226)
  }
  // 注册事件
  registerAction (key, callback) {
    this.actions[key] = callback
  }
  // 设置逐帧动画
  setTimer (hero, monster) {
    let g = this
    // 事件集合
    let actions = Object.keys(g.actions)
    for (let i = 0; i < actions.length; i++) {
      let key = actions[i]
      if(g.keydowns[key]) {
        // 如果按键被按下,调用注册的action
        g.actions[key]()
      }
    }
    // 判断游戏状态并执行相应事件
    if (g.state === g.state_START){ // 游戏开始
      // 角色移动动画
      hero.move(g)
      monster.move(g)
      // 绘制所有游戏素材
      g.drawAll(hero, monster)

      // 绘制准备开始游戏标题
      g.context.fillStyle = 'red'
      g.context.font = '48px Microsoft YaHei'
      g.context.fillText('请按空格键开始游戏', 284, 226)
    } else if (g.state === g.state_RUNNING) { // 游戏运行
      // 角色移动动画
      hero.move(g)
      monster.move(g)
      // 绘制所有游戏素材 
      g.drawAll(hero, monster)
    } else if (g.state === g.state_STOP) { // 游戏暂停
      // 绘制所有游戏素材
      g.drawAll(hero, monster)

      // 绘制准备开始游戏标题
      g.context.fillStyle = 'red'
      g.context.font = '48px Microsoft YaHei'
      g.context.fillText('请按空格键开始游戏', 284, 226)
    } else if (g.state === g.state_GAMEOVER) { // 游戏结束
      // 绘制所有游戏素材
      g.drawAll(hero, monster)
      setTimeout(function () {
        // 绘制游戏结束标题
        g.drawGameOver(hero, monster)
      },500)
    }
  }
  /**
   * 注册按键移动事件
   * role: 注册角色对象
   * keyCode: 按键keyCode值
   * direction: 角色移动方向
   * [
   *  {role: hero, keyCode: '87', direction: 'up'},
   *  ...
   * ]
   */
  registerRoleMove (roleList) {
    let game = this
    for (let item of roleList) {
      game.registerAction(item.keyCode, function () {
        if (game.state === game.state_RUNNING && item.role.canMove) {
          // 设置当前角色朝向
          item.role.direction = item.direction
          // 判断是否需要翻转角色动画
          if (item.direction === 'left') {
            // 禁止翻转动画,同时角色朝左移动
            item.role.isFlipX = false
          } else if (item.direction === 'right') {
            // 翻转动画,同时角色朝右移动
            item.role.isFlipX = true
          }
          if (game.keydowns[item.keyCode] === 'down') {
            // 角色不处于受伤状态时才能移动
            if (item.role.state !== item.role.state_HURT) {
              // 执行奔跑动画
              item.role.animation(game, 'run')
            }
          } else if (game.keydowns[item.keyCode] === 'up') {
            // 取消奔跑动画
            game.keydowns[item.keyCode] = null
            item.role.animation(game, 'idle')
          }
        }
      })
    }
  }
  /**
   * 注册按键攻击事件
   * roList: [
   *   {
   *     role: 注册角色对象
   *     keyCode: 按键keyCode值
   *   }
   *   ...
   * ]
   */
  registerRoleAttack (roleList) {
    let game = this,                        // 当前游戏引擎类
        hero = roleList[0].role,            // hero 对象
        monster = roleList[1].role          // monster 对象
    for (let item of roleList) {
      let role = item.role.type  // 当前角色类型,hero || monster
      game.registerAction(item.keyCode, function () {
        if (game.state === game.state_RUNNING) {
          if (game.keydowns[item.keyCode] === 'down') {
            // 角色不处于受伤状态时才能攻击
            if (item.role.state !== item.role.state_HURT && item.role.state !== item.role.state_DIE) {  
              // 执行攻击动画
              item.role.animation(game, 'attack')
            }
            // 禁止左右移动
            item.role.canMove = false
          } else if (game.keydowns[item.keyCode] === 'up') {
            // 取消攻击动画
            if (item.role.attack.imgIdx === 7) { // 执行一次完整动画后停止
              // 将按键事件置为空
              game.keydowns[item.keyCode] = null
              item.role.animation(game, 'idle')
              // 检测 hero、monster 是否攻击成功
              if (role === 'hero') {
                game.checkAttack(role, hero, monster)
              } else {
                game.checkAttack(role, monster, hero)
              }
              // 允许左右移动
              item.role.canMove = true
            }
          }
        }
      })
    }
  }
  /**
   * 检测是否处于攻击范围
   * role1:当前执行攻击动作角色
   * role2:当前被攻击角色
   */
  collideAttack (role1, role2) {
    let r1 = role1,
        r2 = role2
    // 两个角色图片之间的中心点距离小与两站图片宽度之和的一半,即为可攻击
    if (Math.abs((role1.x + role1.w/2) - (role2.x + role2.w/2)) < (role1.w + role2.w - 80)/2 &&
      Math.abs((role1.y + role1.h/2) - (role2.y + role2.h/2)) < (role1.h + role2.h - 150)/2) {
      if (r1.isFlipX && r1.x < r2.x ||
          !r1.isFlipX && r1.x > r2.x) { // r1面向右侧,且r2在r1右侧时;r1面向左侧,且r2在r1左侧时
        return true
      }
    }
    return false
  }
  /**
   * 检测是否攻击成功
   * roleName:角色名称
   * role1:当前执行攻击动作角色
   * role2:当前被攻击角色
   */
  checkAttack (roleName, role1, role2) {
    let game = this
    // 处于角色攻击范围时,即可攻击
    if (game.collideAttack(role1, role2)) {
      if (role2.life === 1) { // 生命值为1时
        // 执行受伤动画
        role2.animation(game, 'die')
        // 禁止移动
        role2.canMove = false
        role2.life -= 1
        // 改变角色死亡状态
        role2.isDie = true
        setTimeout(function () {
          // 生命值为0时,游戏结束
          game.state = game.state_GAMEOVER
        }, 500)
      } else {
        // 执行受伤动画
        role2.animation(game, 'hurt')
        // 禁止移动
        role2.canMove = false
        role2.life -= 1
      }
    }
  }
  /**
   * 初始化函数
   * _main: 游戏入口函数对象
   */
  init (_main) {
    let g = this,
        hero = _main.hero,
        monster = _main.monster
    // 设置键盘按下及松开相关注册函数
    window.addEventListener('keydown', function (event) {
      g.keydowns[event.keyCode] = 'down'
    })
    window.addEventListener('keyup', function (event) {
      g.keydowns[event.keyCode] = 'up'
    })
    g.registerAction = function (key, callback) {
      g.actions[key] = callback
    }
    /**
     * 为 hero 和 monster 注册按键移动事件
     * hero 按键事件,对应 W、S、A、D
     * monster 按键事件,对应 up、down、left、right方向键
     */
    g.registerRoleMove([
      {role: hero, keyCode: '87', direction: 'up'},
      {role: hero, keyCode: '83', direction: 'down'},
      {role: hero, keyCode: '65', direction: 'left'},
      {role: hero, keyCode: '68', direction: 'right'},
      {role: monster, keyCode: '38', direction: 'up'},
      {role: monster, keyCode: '40', direction: 'down'},
      {role: monster, keyCode: '37', direction: 'left'},
      {role: monster, keyCode: '39', direction: 'right'},
    ])

    /**
     * 为 hero 和 monster 注册按键攻击事件
     */
    g.registerRoleAttack([
      {role: hero, keyCode: '75'},          // 注册 hero K 键攻击事件
      {role: monster, keyCode: '101'}       // 注册 monster 小键盘 5 键攻击事件
    ])

    // 设置轮询定时器
    g.timer = setInterval(function () {
      g.setTimer(hero, monster)
    }, 1000/g.fps)

    // 注册游戏全局按键控制事件
    window.addEventListener('keydown', function (event) {
      switch (event.keyCode) {
        // 注册空格键开始游戏事件
        case 32 :
          // 开始游戏
          g.state = g.state_RUNNING
          break
        // P 键暂停游戏事件
        case 80 :
          g.state = g.state_STOP
          break
      }
    })
  }
}

后记:我没有完全看懂代码啊~

猜你喜欢

转载自www.cnblogs.com/smart-girl/p/11447680.html
今日推荐