HTML5 2D 游戏开发: 设置舞台

[复制链接]
查看11 | 回复6 | 2007-1-24 12:56:49 | 显示全部楼层 |阅读模式
游戏开发的许多方面都和玩游戏没有关系。显示说明、暂停游戏、级别之间的过渡和滚动游戏分数,这些都是游戏开发人员必须在游戏本身以外实现的一些特性。
当游戏的灵感来临时,这些灵感中通常不包括显示高分数或级别之间的过渡的巧妙方式,开发人员会很自然地深入研究如何实现游戏机制,但对于游戏的基础架构却没有太多的想法。但在大多数项目中,如果想在开发后添加功能,所需的工作量比从一开始就添加功能要大得多。
在本系列的 上一期文章 中,我讨论了图形和动画,这些是 Snail Bait 游戏的基础内容。在本文中,我将临时转向去实现该游戏的一些基础架构。首先,我将 Snail Bait 的代码封装在一个 Game 对象中。最初实现该游戏时,我就是从这一步开始的,但在上一期 文章中,我不想在对象中实现它们而混淆了对图形和动画的讨论,所以我将对 Game 对象的介绍推迟到了现在。
我还将告诉您如何暂停和冻结 Snail Bait,以及随后如何利用动画倒计时解冻并重启游戏。在文章的结尾,我会回到游戏机制的主题,向您展示如何通过处理键盘事件来控制跑步小人的垂直位置。
在本文中,您将学习以下内容:
将游戏函数封装在一个对象中。
暂停和恢复游戏。
当窗口失去焦点时自动暂停游戏。
当窗口重新获得焦点时,利用动画的倒计时继续游戏。
暂时显示给用户的消息(被称为 toast)。
处理键盘输入。
在本文中,您将学习如何定义和实例化 JavaScript 对象,如何使用 CSS3 过渡,以及如何结合使用 setTimeout() 和这些过渡来实现分步动画。
回复

使用道具 举报

千问 | 2007-1-24 12:56:49 | 显示全部楼层
[size=0.76em]游戏对象[size=0.76em]在本系列文章中,到现在为止,我已经实现了所有 Snail Bait 函数,并将它们的几个变量定义为全局变量。当然,我们以后不会再这样做。如果您尚未了解全局变量的可恶之处,请参阅 参考资料,获得来自 Douglas Crockford 和 Nicholas Zakas 等 JavaScript 名人的支持论据。[size=0.76em]从现在开始,我不再使用全局变量,而是将所有 Snail Bait 函数和变量封装在一个对象中。该对象由两部分组成,如清单 1 和清单 2 所示。(本文的完整样例代码请参见 下载。)[size=0.76em]清单 1 是本游戏的构造函数,它定义了对象的属性:
清单 1. 本游戏的构造函数(部分清单)

var SnailBait = function (canvasId) { this.canvas= document.getElementById(canvasId); this.context = this.canvas.getContext('2d'); // HTML elementsthis.toast = document.getElementById('toast'), this.fpsElement = document.getElementById('fps'); // Constants this.LEFT = 1; this.RIGHT = 2; ... // Many more attributes are defined in the rest of this function};
回复

使用道具 举报

千问 | 2007-1-24 12:56:49 | 显示全部楼层
[size=0.76em]启动游戏SnailBait 的全局对象[size=0.76em][size=0.76em]如 清单 1 和 清单 3 所示,Snail Bait 只有两个全局对象:SnailBait 函数和 snailBait 对象。
[size=0.76em]清单 3 显示了启动游戏的 JavaScript。该清单的开头定义了三个SnailBait 方法的实现:animate()、start() 和initializeImages()。
清单 3. 启动

SnailBait.prototype = { ... // The 'this' variable in the animate() method is // the window object, so the method uses snailBait instead animate: function (now) { snailBait.fps = snailBait.calculateFps(now); snailBait.draw(now);requestNextAnimationFrame(snailBait.animate); }, start: function () {this.turnRight();
// Sets everything in motionthis.splashToast('Good Luck!', 2000); // "Good Luck" is displayed for 2 secondsrequestNextAnimationFrame(this.animate); }, initializeImages: function () {this.background.src = 'images/background_level_one_dark_red.png';this.runnerImage.src = 'images/runner.png'; this.background.onload = function (e) { // ...the 'this' variable is the window object, // so this function uses snailBait instead.
snailBait.start();}; },}; // End of SnailBait.prototype// Launch gamevar snailBait = new SnailBait(); // Note: By convention, the object
// reference starts with lowercase, but
// the function name starts with uppercasesnailBait.initializeImages();
回复

使用道具 举报

千问 | 2007-1-24 12:56:49 | 显示全部楼层
[size=0.76em]暂停游戏[size=0.76em]HTML5 游戏(尤其是视频游戏)必须能够暂停。在清单 4 中,我已经修改了 Snail Bait 的游戏循环,以便暂停和取消暂停游戏:
清单 4. 暂停和取消暂停

var SnailBait = function (canvasId) { ... this.paused = false, this.PAUSED_CHECK_INTERVAL = 200; // milliseconds ...};SnailBait.prototype = { animate: function (now) { if (snailBait.paused) { // Check again in snailBait.PAUSED_CHECK_INTERVAL milliseconds setTimeout( function () {
requestNextAnimationFrame(snailBait.animate); }, snailBait.PAUSED_CHECK_INTERVAL);}else { // The game loop from Listing 1 snailBait.fps = snailBait.calculateFps(now);
snailBait.draw(now); requestNextAnimationFrame(snailBait.animate);} }, togglePaused: function () {this.paused = !this.paused; },};
回复

使用道具 举报

千问 | 2007-1-24 12:56:49 | 显示全部楼层
[size=0.76em]冻结游戏[size=0.76em]暂停游戏所涉及的不仅仅是简单地中止动画。游戏应该恢复到离开它们时的确切位置。 清单 4 的出现满足了这一要求。毕竟,在游戏暂停后,什么也不会发生,就好像游戏已经恢复为和它暂停之前一样。但实际情况并非如此,因为所有动画(包括 Snail Bait 的动画)的主要参数是时间。[size=0.76em]如我在第二期文章中所讨论的(请参阅这篇文章的 requestAnimationFrame() 部分),requestAnimationFrame() 将时间传递给指定的回调函数。在使用 Snail Bait 的情况下,该回调函数是 animate() 方法,它随后会将时间传递给 draw() 方法。[size=0.76em]当游戏暂停时,即使动画没有运行,时间依然有增无减地继续前进。而且,由于 Snail Bait 的 draw() 方法根据从 animate() 接收的时间绘制下一个动画帧,所以 清单 4 中实现的 togglePaused() 会导致在恢复暂停游戏时,游戏的时间寸步难行。[size=0.76em]清单 6 显示了 Snail Bait 如何避免暂停的游戏在恢复时出现时间的变化:
清单 6. 冻结游戏

var SnailBait = function (canvasId) { ... this.paused = false, this.pauseStartTime = 0, this.totalTimePaused = 0, this.lastAnimationFrameTime = 0, ...};SnailBait.prototype = { ... calculateFps: function (now) {var fps = 1000 / (now - this.lastAnimationFrameTime);this.lastAnimationFrameTime = now; if (now - this.lastFpsUpdateTime > 1000) { this.lastFpsUpdateTime = now; this.fpsElement.innerHTML = fps.toFixed(0) + 'fps';}return fps;}, togglePaused: function () {var now = +new Date();this.paused = !this.paused; if (this.paused) { this.pauseStartTime = now;}else { this.lastAnimationFrameTime += (now - this.pauseStartTime);} },};
回复

使用道具 举报

千问 | 2007-1-24 12:56:49 | 显示全部楼层
[size=0.76em]当窗口获得焦点时解冻游戏[size=0.76em]当游戏恢复时,玩家会喜欢平稳地过渡到操作,为他们提供一些时间来重新获得控制。在这段时间里,在恢复游戏之前提供有关剩余时间量的反馈,这会是一个好主意。Snail Bait 通过在 toast 中显示倒计时来实现该反馈,所以我从 toast 的概述开始这个讨论。[size=0.76em]Toast[size=0.76em]toast 是游戏暂时向玩家显示的某些消息,像图 2 中的 Good Luck! toast:
图 2. toast

[size=0.76em]像 Snail Bait 本身,Snail Bait toast 是使用 HTML、CSS 和 JavaScript 的组合来实现的,如接下来的三个清单所示。[size=0.76em]清单 7 显示一个 toast 的 HTML 代码:
清单 7. toast:HTML

...
...
...

回复

使用道具 举报

千问 | 2007-1-24 12:56:49 | 显示全部楼层
2D?
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

主题

0

回帖

4882万

积分

论坛元老

Rank: 8Rank: 8

积分
48824836
热门排行