Chrome 小恐龙游戏源码探究二 -- 让地面动起来

栏目: 后端 · 发布时间: 5年前

内容简介:上一篇文章:《要实现地面的移动就要不断更新地面的其中

前言

上一篇文章:《 Chrome 小恐龙游戏源码探究一 -- 绘制静态地面 》 中定义了游戏的主体类 Runner,并实现了静态地面的绘制。这一篇文章中,将实现效果:1、地面无限滚动。2、刚开始地面不动,按下空格后地面滚动。

地面无限滚动

要实现地面的移动就要不断更新地面的 x 坐标。定义方法:

HorizonLine.prototype = {
  /**
   * 更新地面的 x 坐标
   * @param {Number} pos 地面的位置
   * @param {Number} incre 移动距离
   */
  updateXPos: function (pos, incre) {
    var line1 = pos;
    var line2 = pos === 0 ? 1 : 0;

    // 第一段地面向左移动,第二段地面随之
    this.xPos[line1] -= incre;
    this.xPos[line2] = this.xPos[line1] + this.dimensions.WIDTH;

    // 第一段地面移出了 canvas
    if (this.xPos[line1] <= -this.dimensions.WIDTH) {
      // 将第一段地面放到 canvas 右侧
      this.xPos[line1] += this.dimensions.WIDTH * 2;
      // 此时第二段地面的 x 坐标刚好和 canvas 的 x 坐标对齐
      this.xPos[line2] = this.xPos[line1] - this.dimensions.WIDTH;
      // 给放到 canvas 后面的地面随机地形
      this.sourceXPos[line1] = this.getRandomType() + this.spritePos.x;
    }
  },
  /**
   * 获取随机的地形
   */
  getRandomType: function () {
    return Math.random() > this.bumpThreshold ? this.dimensions.WIDTH : 0;
  },
};

其中 updateXPos 实现了地面 x 坐标的更新。当第一段地面移出 canvas 时,会将第一段地面 x 坐标乘 2 放到 canvas 后面,然后为其随机地形。这时,原来的第二段地面就变成了第一段地面继续向前移动,以此类推。这样就实现了地面的不断移动和更新。

上面的函数只是实现了地面移动相关的逻辑,真正让地面动起来还需要调用这个函数。添加方法:

HorizonLine.prototype = {
  /**
   * 更新地面
   * @param {Number} deltaTime 间隔时间
   * @param {Number} speed 速度
   */
  update: function (deltaTime, speed) {
    // 计算地面每次移动的距离(距离 = 速度 x 时间)时间由帧率和间隔时间共同决定
    var incre = Math.floor(speed * (FPS / 1000) * deltaTime);

    if (this.xPos[0] <= 0) {
      this.updateXPos(0, incre);
    } else {
      this.updateXPos(1, incre);
    }
    this.draw();
  },
};

然后需要通过 Horizon 上的 update 方法来调用 HorizonLine 上的 update 方法。

在 Horizon 的原型链上添加方法:

Horizon.prototype = {
  update: function (deltaTime, currentSpeed) {
    this.horizonLine.update(deltaTime, currentSpeed);
  },
};

同理,按照上面的逻辑,现在应该在 Runner 上定义 update 方法来调用 Horizon 上的 update 方法。

在 Runner 上添加方法:

Runner.prototype = {
  /**
   * 更新游戏帧并进行下一次更新
   */
  update: function () {
    this.updatePending = false; // 等待更新

    var now = getTimeStamp();
    var deltaTime = now - (this.time || now);

    this.time = now;

    this.clearCanvas();
    this.horizon.update(deltaTime, this.currentSpeed);

    // 进行下一次更新
    this.scheduleNextUpdate();
  },
  clearCanvas: function () {
    this.ctx.clearRect(0, 0, this.dimensions.WIDTH,
      this.dimensions.HEIGHT);
  },
  scheduleNextUpdate: function () {
    if (!this.updatePending) {
      this.updatePending = true;
      this.raqId = requestAnimationFrame(this.update.bind(this));
    }
  },
};

// 获取时间戳
function getTimeStamp() {
  return performance.now();
}

最后在 Runner 的 init 方法中调用它的 update 方法:

Runner.prototype = {
  init: function () {
    // ...

    // 更新 canvas
+   this.update();
  },
};

现在地面就可以进行无限滚动了,效果如下:

Chrome 小恐龙游戏源码探究二 -- 让地面动起来

查看添加的代码: 戳这里

响应空格键

下面要实现的效果是:刚开始地面不动,按下空格后地面滚动。

修改 Runner 原型链中的 update 方法:

Runner.prototype = {
  /**
   * 更新游戏帧并进行下一次更新
   */
  update: function () {
    var now = getTimeStamp();
    var deltaTime = now - (this.time || now);

    this.time = now;

+   if (this.playing) {
      this.clearCanvas();
      this.horizon.update(deltaTime, this.currentSpeed);
+   }

+   if (this.playing) {
      // 进行下一次更新
      this.scheduleNextUpdate();
+   }
  },
};

监听键盘事件:

Runner.prototype = {
  startListening: function () {
    document.addEventListener(Runner.events.KEYDOWN, this);
    document.addEventListener(Runner.events.KEYUP, this);
  },
  stopListening: function () {
    document.removeEventListener(Runner.events.KEYDOWN, this);
    document.removeEventListener(Runner.events.KEYUP, this);
  },
};

添加数据:

Runner.events = {
  // ...

+ KEYDOWN: 'keydown',
+ KEYUP: 'keyup',
};

在 Runner 的 init 方法中调用上面定义的 startListening 方法:

Runner.prototype = {
  init: function () {
    // ...
    
    // 开始监听用户动作
+   this.startListening();
  },
};

当浏览器监听到用户按下键盘时,会执行 handleEvent 方法来处理键盘事件:

Runner.prototype = {
  // 用来处理 EventTarget(这里就是 Runner 类) 上发生的事件
  // 当事件被发送到 EventListener 时,浏览器就会自动调用这个方法
  handleEvent: function (e) {
    return (function (eType, events) {
      switch (eType) {
        case events.KEYDOWN:
          this.onKeyDown(e);
          break;
        default:
          break;
      }
    }.bind(this))(e.type, Runner.events);
  },
};

上面用到的 onKeyDown 方法定义如下:

Runner.prototype = {
  onKeyDown: function (e) {
    if (!this.crashed && !this.paused) {
      if (Runner.keyCodes.JUMP[e.keyCode]) {
        e.preventDefault();

        if (!this.playing) {
          this.setPlayStatus(true);
          this.update();
        }
      }
    }      
  },
  setPlayStatus: function (isPlaying) {
    this.playing = isPlaying;
  },
};

这里需要说一下,当按下空格键后, 为什么浏览器会执行handleEvent 事件 :当使用 addEventListener 监听某个对象上的事件时,只要被监听的事件触发了,就会执行该对象上的名为 handleEvent 的方法(如果有)。

到此,就实现了预期的效果:

Chrome 小恐龙游戏源码探究二 -- 让地面动起来

查看添加的代码, 戳这里

Demo 体验地址: https://liuyib.github.io/pages/demo/games/google-dino/horizonline-move/

上一篇 下一篇 Chrome 小恐龙游戏源码探究一 -- 绘制静态地面 Chrome 小恐龙游戏源码探究三 -- 进入街机模式

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

JavaScript权威指南(第6版)

JavaScript权威指南(第6版)

David Flanagan / 淘宝前端团队 / 机械工业出版社 / 2012-4-1 / 139.00元

本书是程序员学习核心JavaScript语言和由Web浏览器定义的JavaScript API的指南和综合参考手册。 第6版涵盖HTML 5和ECMAScript 5。很多章节完全重写,以便与时俱进,紧跟当今的最佳Web开发实践。本书新增章节描述了jQuery和服务器端JavaScript。 本书适合那些希望学习Web编程语言的初、中级程序员和希望精通JavaScript的JavaSc......一起来看看 《JavaScript权威指南(第6版)》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具