图形和动画是任何视频游戏最根本的方面,所以在本文中,我将从 Canvas2D API 的简要介绍开始,对 Snail Bait 的中央动画的实现进行讨论。在本文中,您将学习如何:
- 将图像和图形基元绘制到画布上
- 创建流畅的、无闪烁的动画
- 实现游戏循环
- 以帧数每秒为单位监视动画的速度
- 滚动游戏的背景
- 使用视差来模拟三维效果
- 实现基于时间的运动
本文中所讨论的代码的最终结果如图 1 所示:
图 1. 滚动背景并监视帧速率 背景和平台水平滚动。这些平台在前景中,所以它们的移动明显快于背景,这样会形成一个温和的视差效果。在游戏开始时,背景由右至左滚动。在结束某个级别时,背景和平台开始逆转方向。
在开发的这个阶段,跑步者不动。此外,游戏还没有经过碰撞检测,所以当跑步者的下面没有平台时,她会漂浮在半空中。
最后,游戏画布的上方和左侧的图标会显示剩余生命的数量(如 所示)。目前,该游戏会在这个位置上显示当前动画速度(以帧数每秒为单位)。
即时模式图形Canvas 是一个即时模式 图形系统,这意味着它会即时绘制您指定的内容,然后即时忘记。可伸缩矢量图形 (Scalable Vector Graphics, SVG) 等其他图形系统实现了保留模式 图形,这意味着它们会保存一个将要绘制的对象的列表。由于不会因保存显示列表而产生开销,所以 Canvas 的速度比 SVG 更快一些;但是,如果您想保存一个用户可以操作的对象列表,则必须自己在 Canvas 中实现该功能。
在继续后面的操作之前,您可能想尝试创建一个这类游戏,因为它就在 里;如果您创建了这样的游戏,就会更容易理解相关的代码。(请参阅 ,获得本期的 Snail Bait 实现。)
HTML5 Canvas 概述Canvas 2D 上下文提供了一个广泛的图形 API,让您可以在平台视频游戏中实现文本编辑器中的一切。在我撰写这篇文章的时候,该 API 包含了超过 30 个方法,但 Snail Bait 只使用了其中的极少数,如表 1 所示:
表 1. Snail Bait 使用的 Canvas 2D 上下文方法方法描述drawImage()您可以在画布的某个特定位置上绘制全部或部分图像,也可以绘制另一个画布或来自 video 元素的一个帧。save()在堆栈上保存上下文属性。restore()将上下文属性移出堆栈,并将它们应用于上下文。strokeRect()绘制一个未填充的矩形。fillRect()填充一个矩形。translate()平移坐标系。这是一个很强大的方法,在许多不同场景中都很有用。Snail Bait 中的所有滚动都是利用这一个方法调用来实现的。
基于路径的图形与 Apple 的 Cocoa 和 Adobe 的 Illustrator 类似,Canvas API 也是基于路径的,这意味着您可以先创建一条路径,然后描画或填充这条路径,在画布上绘制图形基元。strokeRect() 和 fillRect() 方法分别是描画或填充矩形的便捷方法。
除平台之外,Snail Bait 中的所有内容都是一个图像。背景、跑步者以及所有好人和坏人都是游戏使用 drawImage() 方法绘制的图像。
最终,Snail Bait 将使用 spritesheet(单个图像包含游戏的所有图形),但现在,我对背景和跑步者分别使用不同的图像。我使用 所示的函数绘制跑步者:
清单 1. 绘制跑步者1
2
3
4
5
| function drawRunner() {
context.drawImage(runnerImage, // image
STARTING_RUNNER_LEFT, // canvas left
calculatePlatformTop(runnerTrack) - RUNNER_HEIGHT); // canvas top
}
|
drawRunner() 函数将三个参数传递给了 drawImage():一个图像、左侧坐标和顶部坐标,将在画布的这个位置上绘制图像。左侧坐标是一个常数,而顶部坐标由跑步者所驻留的平台决定。
我以类似的方式绘制背景,如清单 2 所示:
清单 2. 绘制背景1
2
3
| function drawBackground() {
context.drawImage(background, 0, 0);
}
|
多用途的 方法您可以使用 Canvas 2D 上下文的 drawImage() 方法在画布内的任何地方绘制一个完整的图像,或图像内的任何矩形区域,有选择地沿着路线缩放图像。除了图像外,您还可以利用 drawImage() 绘制另一个画布或一个 video 元素当前帧的内容。这只是其中一个方法,但 drawImage() 还有助于便利地实现有趣的或者难以实现的应用程序(如视频编辑软件)。
中的 drawBackground() 函数在画布的 (0,0) 绘制背景图像。稍后,我会在本文中修改该函数,以便滚动背景。
绘制平台(它们不是图像)需要更广泛地使用 Canvas API,如清单 3 所示:
清单 3. 绘制平台1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
| var platformData = [
// Screen 1.......................................................
{
left: 10,
width: 230,
height: PLATFORM_HEIGHT,
fillStyle: 'rgb(150,190,255)',
opacity: 1.0,
track: 1,
pulsate: false,
},
...
],
...
function drawPlatforms() {
var data, top;
context.save(); // Save the current state of the context
context.translate(-platformOffset, 0); // Translate the coord system for all platforms
for (var i=0; i < platformData.length; ++i) {
data = platformData;
top = calculatePlatformTop(data.track);
context.lineWidth = PLATFORM_STROKE_WIDTH;
context.strokeStyle = PLATFORM_STROKE_STYLE;
context.fillStyle = data.fillStyle;
context.globalAlpha = data.opacity;
context.strokeRect(data.left, top, data.width, data.height);
context.fillRect (data.left, top, data.width, data.height);
}
context.restore(); // Restore context state saved above
}
|
中的 JavaScript 定义一个名称为 platformData 的数组。该数组中的每个对象代表着描述一个独立平台的元数据。
drawPlatforms() 函数使用 Canvas 上下文的 strokeRect() 和 fillRect() 方法来绘制平台矩形。这些矩形的特征存储在 platformData 数组内的对象中,用于设置上下文的填充风格和 globalAlpha 属性,该属性设置您之后在画布上绘制的任何图形的不透明度。
调用 context.translate() 将画布的坐标系(如图 2 所示)在水平方向平移指定数量的像素。该平移和属性设置是临时的,因为这些操作是在 context.save() 和 context.restore() 调用之间执行的。
图 2. 默认的 Canvas 坐标系 默认情况下,坐标系的原点位于画布的左上角。您可以使用 context.translate() 移动坐标系的原点。
我会在 中讨论如何使用 context.translate() 滚动背景。但现在,您几乎已经知道了实现 Snail Bait 需要了解的与 HTML5 Canvas 有关的一切内容。在本系列的其余部分中,我将侧重于 HTML5 游戏开发的其他方面,从动画开始。 |