二、游戏循环

游戏循环是每个游戏的重要组成部分。在这一章中,我们将通过创建一个可靠的工作流程和环境来为我们的游戏搭建舞台。我们会看到一些有用的库,并渲染我们的第一个游戏角色。这会很有趣的!

为我们的游戏搭建舞台

我们将使用最新的 JavaScript 标准和语言特性来构建游戏。这通常是我向您展示如何创建 JavaScript 构建的链的地方,但是我们将做一些不同的事情....

对于这本书,我们将在一个名为 CodePen 的托管服务中完成所有的编码工作。看起来像图 2-1 中的代码。

A435434_1_En_2_Fig1_HTML.jpg

图 2-1。

CodePen

这种方法有几个好处:

  1. 我们不需要讨论 JavaScript 构建链。它们是主观的、脆弱的、分散注意力的。
  2. 我们可以免费使用 SCSS(增强型样式表)。
  3. 您不需要设置任何东西就可以开始与源代码进行交互。

我们将使用一个 JavaScript 库,名为 PixiJS ( www.pixijs.com )。这是一个渲染库,可以消除浏览器的不一致性。它不是游戏引擎或物理引擎,所以我们仍然要自己学习和编写这些方面的代码。PixiJS 将允许我们更快地得到那些东西。

我们使用 PixiJS v4。当你读到这篇文章的时候,更新的版本是完全可能的。这些概念应该是通用的,尽管语法可能已经改变。

我们可以通过点击设置➤ JavaScript 将 PixiJS 添加到我们的 CodePens,并将以下 URL 添加到 PixiJS CDN 脚本: https://cdnjs.cloudflare.com/ajax/libs/pixi.js/4.0.0/pixi.min.js 。该过程如图 2-2 所示。

A435434_1_En_2_Fig2_HTML.jpg

图 2-2。

Adding PixiJS to CodePen

创建精灵

精灵是游戏中视觉对象的常见名称。我们可以在屏幕上移动它们(尽管通常它们负责移动自己)。我们可以和他们互动。

马里奥( https://en.wikipedia.org/wiki/Mario )是一个精灵,他走的平台是精灵,背景中的云是精灵。可以把精灵想象成设计文件的一部分,我们在抽象数据结构上绘制。这些抽象数据结构有一个位置,有时还有一个速度。这些抽象的数据结构是我们应用游戏规则的对象。他们是我们的力量和敌人。

那么我们如何制造它们呢?让我们首先创建一个小的 PNG 图像。我们正在使用 PNG,因为它允许我们使精灵纹理的一部分透明。如果你愿意,你也可以为你的精灵使用 JPEG 图片。

然后我们需要创建一个渲染器、一个舞台和一个精灵:

const renderer = new PIXI.autoDetectRenderer(
  window.innerWidth,
  window.innerHeight,
  {
    "antialias": true,
    "autoResize": true,
    "transparent": true,
    "resolution": 2,
  },
)

document.body.appendChild(renderer.view)

const sprite = new PIXI.Sprite.fromImage(
  "path/to/sprites/player-idle.png",
)

sprite.x = window.innerWidth / 2
sprite.y = window.innerHeight / 2

const stage = new PIXI.Container()
stage.addChild(sprite)

const animate = function() {
  requestAnimationFrame(animate)
  renderer.render(stage)
}

animate()

这是出自 http://codepen.io/assertchris/pen/qaobAz

好了,这里发生了很多事!让我们一步步来看这段代码:

  1. 我们创建一个渲染器。渲染器是转换像素抽象(精灵、纹理等)的东西。)转换成画布或 WebGL 图形。我们不需要与它们交互,但是我们总是需要一个渲染器来显示我们的 PixiJS 内容。我们告诉渲染器占据浏览器窗口的整个宽度和高度。我们还告诉它反走样我们的图形,并提高到视网膜分辨率。我们告诉它有一个透明的背景,并调整所有图形的大小以适应屏幕。
  2. 然后,我们使用之前创建的 PNG 图像创建一个新的PIXI.Sprite实例。默认情况下,它有一个位置x = 0y = 0。我们可以把它放在屏幕的中央。我们必须创建一个根 sprite 容器,通常称为 stage,并将 sprite 附加到 stage。它没有听起来那么复杂。想想 HTML 文档。它们有一个根html元素,我们将所有其他元素添加到其中。这是同类的东西。
  3. 最后,我们创建一个动画函数,并确保渲染器渲染我们的舞台和精灵。我们使用requestAnimationFrame函数作为一种不阻塞 JavaScript 线程的渲染方式。我们可以就此进行长时间的讨论。现在,重要的是知道requestAnimationFrame每秒钟发生多次。我们游戏的目标是每秒渲染 30 到 60 帧,同时在后台进行各种玩家和世界的计算。这是我们需要使用的函数,以便一切顺利进行。

游戏循环

游戏循环将控制我们游戏的流程。这是一个重复的过程,读取输入,计算状态变化,并将输出呈现到屏幕上。

到目前为止,我们已经建立了许多脚手架,我们所做的只是渲染一个静态图像。让我们把它移动一下!首先,我们将创建一个Player类,这样我们可以跟踪玩家的位置:

class Player {
  constructor(sprite, x, y) {
    this.sprite = sprite
    this.x = x
    this.y = y

    this.sprite.x = this.x
    this.sprite.y = this.y
  }

  animate(state) {
    this.x += 5

    if (this.x > window.innerWidth) {
      this.x = 0
    }

    this.sprite.x = this.x
    this.sprite.y = this.y
  }
}

这是出自 http://codepen.io/assertchris/pen/qaobAz

这就是 ES2015 及以后版本中 JavaScript 类的样子。Player类有一个构造函数,我们用它来存储对精灵的引用,以及初始的xy位置。

它还有一个animate方法,我们会在一秒钟内多次调用它。我们可以使用该方法来判断玩家是否需要改变位置或做其他事情。在这种情况下,我们将子画面x的位置增加一点。如果玩家/精灵离开了屏幕的右边,我们就把它移回到屏幕的左边。

我们还必须改变创建精灵的方式:

const player = new Player(
  sprite,
  window.innerWidth / 2,
  window.innerHeight / 2,
)

stage.addChild(sprite)

let state = {
  "renderer": renderer,
  "stage": stage,
}

const animate = function() {
  requestAnimationFrame(animate)

  player.animate(state)
  renderer.render(stage)
}

这是出自 http://codepen.io/assertchris/pen/qaobAz

现在我们开始看到我们游戏中的循环。正如你在图 2-3 中看到的,一秒钟内,我们多次告诉我们的玩家制作动画。播放器考虑了一些内部逻辑并调整了它的精灵。渲染器渲染输出,我们看到的是流畅的动画。

A435434_1_En_2_Fig3_HTML.jpg

图 2-3。

Moving sprites

我们这里唯一缺少的是输入,但我们很快就会做到这一点…

摘要

在这一章中,我们设法建立了一个游戏环境(使用 CodePen)。我们简要地了解了 PixiJS,并看到了如何在屏幕上渲染玩家的精灵。

我们还制作了玩家精灵的动画,并学习了如何使用requestAnimationFrame功能。

花点时间为你的游戏寻找精灵图形。分叉 CodePen,稍微定制一下。重要的是你要对创建精灵和操纵它们有一个感觉。这是你游戏的开始!