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

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

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

前言

上一篇文章:《 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 小恐龙游戏源码探究三 -- 进入街机模式

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

查看所有标签

猜你喜欢:

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

Beginning Apache Struts

Beginning Apache Struts

Arnold Doray / Apress / 2006-02-20 / USD 44.99

Beginning Apache Struts will provide you a working knowledge of Apache Struts 1.2. This book is ideal for you Java programmers who have some JSP familiarity, but little or no prior experience with Ser......一起来看看 《Beginning Apache Struts》 这本书的介绍吧!

URL 编码/解码
URL 编码/解码

URL 编码/解码

html转js在线工具
html转js在线工具

html转js在线工具