Chrome 小恐龙游戏源码探究完 -- 游戏结束和其他要素

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

内容简介:文章首发于我的上一篇文章:《这个游戏结束时的

文章首发于我的 个人博客

前言

上一篇文章:《 Chrome 小恐龙游戏源码探究九 -- 游戏碰撞检测 》实现了游戏的碰撞检测,这一篇文章中将利用碰撞检测的结果,实现游戏的结束。

绘制 Game Over 面板

这个游戏结束时的 Game Over 面板是通过 GameOverPanel 类绘制的。

定义 GameOverPanel 类:

/**
 * 游戏结束面板类
 * @param {!HTMLCanvasElement} 画布元素
 * @param {Object} textImgPos 文字 "Game Over" 在雪碧图中的位置
 * @param {Object} restartImgPos 重置按钮在雪碧图中的位置
 * @param {!Object} dimensions 游戏画布的尺寸
 */
function GameOverPanel(canvas, textImgPos, restartImgPos, dimensions) {
  this.canvas = canvas;
  this.ctx = canvas.getContext('2d');
  this.canvasDimensions = dimensions;
  this.textImgPos = textImgPos;
  this.restartImgPos = restartImgPos;

  this.draw();
};

相关的配置参数,以及原型链上的方法:

// 配置参数
GameOverPanel.dimensions = {
  TEXT_X: 0,          // 文字 "Game Over" 的 x 坐标
  TEXT_Y: 13,
  TEXT_WIDTH: 191,    // 文字 "Game Over" 的宽度
  TEXT_HEIGHT: 11,
  RESTART_WIDTH: 36,  // 重置按钮的宽度
  RESTART_HEIGHT: 32,
};

GameOverPanel.prototype = {
  draw: function() {
    var dimensions = GameOverPanel.dimensions;
    var centerX = this.canvasDimensions.WIDTH / 2;

    // 文字 "Game Over"
    var textSourceX = dimensions.TEXT_X;
    var textSourceY = dimensions.TEXT_Y;
    var textSourceWidth = dimensions.TEXT_WIDTH;
    var textSourceHeight = dimensions.TEXT_HEIGHT;

    var textTargetX = Math.round(centerX - (dimensions.TEXT_WIDTH / 2));
    var textTargetY = Math.round((this.canvasDimensions.HEIGHT - 25) / 3);
    var textTargetWidth = dimensions.TEXT_WIDTH;
    var textTargetHeight = dimensions.TEXT_HEIGHT;

    // 重置按钮
    var restartSourceWidth = dimensions.RESTART_WIDTH;
    var restartSourceHeight = dimensions.RESTART_HEIGHT;
    var restartTargetX = centerX - (dimensions.RESTART_WIDTH / 2);
    var restartTargetY = this.canvasDimensions.HEIGHT / 2;

    textSourceX += this.textImgPos.x;
    textSourceY += this.textImgPos.y;

    // 文字 "Game over"
    this.ctx.drawImage(Runner.imageSprite,
      textSourceX, textSourceY, textSourceWidth, textSourceHeight,
      textTargetX, textTargetY, textTargetWidth, textTargetHeight);

    // 重置按钮
    this.ctx.drawImage(Runner.imageSprite,
      this.restartImgPos.x, this.restartImgPos.y,
      restartSourceWidth, restartSourceHeight,
      restartTargetX, restartTargetY, dimensions.RESTART_WIDTH,
      dimensions.RESTART_HEIGHT);
  }
};

然后需要在游戏结束时,调用 GameOverPanel 类。

gameOver 方法中调用 GameOverPanel 类,并更新小恐龙的状态和一些标志位:

Runner.prototype = {
  // 游戏结束
  gameOver: function () {
    this.stop();
+   this.crashed = true;                    // 小恐龙撞到了障碍物
+   this.distanceMeter.achievement = false; // 结束分数闪动特效

+   // 更新小恐龙为碰撞状态
+   this.tRex.update(100, Trex.status.CRASHED);

+   // 绘制游戏结束面板
+   if (!this.gameOverPanel) {
+     this.gameOverPanel = new GameOverPanel(this.canvas,
+       this.spriteDef.TEXT_SPRITE, this.spriteDef.RESTART,
+       this.dimensions);
+   } else {
+     this.gameOverPanel.draw();
+   }

    if (this.distanceRan > this.highestScore) {
      this.highestScore = Math.ceil(this.distanceRan);
      this.distanceMeter.setHighScore(this.highestScore); // 保存最高分
    }

    // 重置时间
    this.time = getTimeStamp();
  },
};

补充数据:

Runner.spriteDefinition = {
  LDPI: {
    // ...

+   RESTART: {x: 2, y: 2}, // 重置游戏按钮
  },
};

前面的文章中,为了演示效果,我们把 gameOver 方法的调用临时放在了判断页面是否失焦的 onVisibilityChange 方法中。现在我们就不需要这个临时调用了,删除即可。 gameOver 实际的调用如下:

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

    if (this.playing) {
      // ...

      // 碰撞检测
      var collision = hasObstacles &&
-       checkForCollision(this.horizon.obstacles[0], this.tRex, this.ctx);
+       checkForCollision(this.horizon.obstacles[0], this.tRex);

+     if (!collision) {
        this.distanceRan += this.currentSpeed * deltaTime / this.msPerFrame;

        if (this.currentSpeed < this.config.MAX_SPEED) {
          this.currentSpeed += this.config.ACCELERATION;
        }
+     } else {
+       this.gameOver();
+     }

      var playAchievementSound = this.distanceMeter.update(deltaTime,
        Math.ceil(this.distanceRan));

      // ...
    }

    // ...
  },
};

这样就实现了结束游戏后, Game Over 面板的绘制,效果如下:

Chrome 小恐龙游戏源码探究完 -- 游戏结束和其他要素

查看添加和修改的代码, 戳这里

重新开始游戏

想要重新开始游戏,无非就是把保存的数据清零以及把标志位给重置:

Runner.prototype = {
  // 重新开始游戏
  restart: function() {
    if (!this.raqId) {
      this.runningTime = 0;                  // 重置游戏运行时间
      this.setPlayStatus(true);              // 游戏重置为进行状态
      this.paused = false;                   // 游戏没有暂停
      this.crashed = false;                  // 小恐龙没有撞到障碍物
      this.distanceRan = 0;                  // 重置游戏移动距离(分数)
      this.currentSpeed = this.config.SPEED; // 重置游戏当前的速度
      this.time = getTimeStamp();            // 重置计时器
      this.clearCanvas();                    // 清空画布
      this.distanceMeter.reset();            // 重置分数类
      this.horizon.reset();                  // 重置背景类
      this.tRex.reset();                     // 重置小恐龙类
      this.invert(true);                     // 重置页面为没有进行颜色反转
      this.update();                         // 重置后更新游戏
    }
  },
};

其中 Trex 类上的 reset 方法已经定义过了。 DistanceMeterHorizon 类上的 reset 方法定义如下:

DistanceMeter.prototype = {
  // 重置当前分数为 '00000'
  reset: function() {
    this.update(0);           // 更新分数
    this.achievement = false; // 分数不进行闪动特效
  }
};

Horizon.prototype = {
  // 重置背景类
  reset: function() {
    this.obstacles = [];      // 清空障碍物
    this.horizonLine.reset(); // 重置地面
    this.nightMode.reset();   // 重置夜晚模式
  },
};

同样的, HorizonLineNightMode 类上的 reset 方法定义如下:

HorizonLine.prototype = {
  reset: function() {
    // 重置两段地面的坐标
    this.xPos[0] = 0;
    this.xPos[1] = HorizonLine.dimensions.WIDTH;
  },
};

NightMode.prototype = {
  reset: function() {
    this.currentPhase = 0; // 重置月期
    this.opacity = 0;      // 重置夜晚模式中的物体透明度
    this.update(false);    // 重置夜晚模式位未激活状态
  },
};

最后,调用 restart 方法:

Runner.prototype = {
  onKeyUp: function(e) {
    var keyCode = String(e.keyCode);
    var isjumpKey = Runner.keyCodes.JUMP[keyCode];

    if (this.isRunning() && isjumpKey) {        // 跳跃
      this.tRex.endJump();
    } else if (Runner.keyCodes.DUCK[keyCode]) { // 躲避状态
      this.tRex.speedDrop = false;
      this.tRex.setDuck(false);
+   } else if (this.crashed) {
+     var deltaTime = getTimeStamp() - this.time;
+
+     // 按下回车键或者等待 750 毫秒后,按下空格键,重新开始游戏
+     if (Runner.keyCodes.RESTART[keyCode] ||
+         (deltaTime >= this.config.GAMEOVER_CLEAR_TIME &&
+         Runner.keyCodes.JUMP[keyCode])) {
+       this.restart();
+     }
+   }
  },
};

效果如下:

Chrome 小恐龙游戏源码探究完 -- 游戏结束和其他要素

查看添加和修改的代码, 戳这里

加载游戏音效

TODO

Demo 体验地址:[]() TODO

游戏的其他要素

到这里,我们已经把游戏的必要功能都实现了。原游戏中,还实现了移动端适配,高分屏的适配,是否需要进入街机模式的处理,游戏画布对浏览器窗口大小的自适应。

这些功能我们就不再实现,感兴趣的可以自行尝试。

结语

利用十多天的业余时间探究了小恐龙游戏的源码,收获很多,也为自己以后开发 H5 游戏提供了一定的思路。

由于水平有限,如果文章存在有歧义或错误的地方,欢迎评论指出。

(完)

上一篇 下一篇 Chrome 小恐龙游戏源码探究九 -- 游戏碰撞检测

以上所述就是小编给大家介绍的《Chrome 小恐龙游戏源码探究完 -- 游戏结束和其他要素》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

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

DOM Scripting

DOM Scripting

Jeremy Keith / friendsofED / 2010-12 / GBP 27.50

There are three main technologies married together to create usable, standards-compliant web designs: XHTML for data structure, Cascading Style Sheets for styling your data, and JavaScript for adding ......一起来看看 《DOM Scripting》 这本书的介绍吧!

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具