游戏邦在:
杂志专栏:
gamerboom.com订阅到鲜果订阅到抓虾google reader订阅到有道订阅到QQ邮箱订阅到帮看

如何创造一个出色的HTML5游戏引擎

发布时间:2014-03-25 10:47:43 Tags:,,,,

作者:Craig Robinson

去年,我们获得机会能够基于HTML5为Spil games创造一系列5款麻将连连看游戏。我们创造的第一款游戏是《Dream Pet Link》。考虑到我们所分配到的任务是基于以下同样的机制但却是不同的主题而创造4款额外的游戏,我们便假设是否能够反复使用同样的代码,即我们只需要编写第一款游戏然后为之后的游戏换入新图像和声音资产。

如果是这样的话一切就简单多了。

但这里存在一些问题可能让事情变得更复杂:

*想要在不具有同样机制的其它游戏中重新使用一些代码

*关于代码改变的不确定性必须适应图像和音频中的差异

*我们可以在之后的循环中发现功能和性能的完善

这些注意事项推动着我们去采取与预期不同的设计方法。在此我将与你们分享我在创造这些游戏的过程,以及在这些游戏和我们的其它HTML5游戏中创造代码库的过程。就像你们所看到的这样,这些过程都很顺利且非常有组织性。我也会描述为何JavaScript被当成是支持我们工作的最佳语言。

amazon farm (from develop-online)

amazon farm (from develop-online)

开启你的引擎

我们决定将功能整合到三个不同的框架里:

1.针对于特定游戏的代码和配置文件

2.所有带有这一机制的游戏将能够分享代码(我们将其称为LinkEnigine)

3.任何游戏都能够使用代码(我们将其称为绝对程序库)。

我们并不总是清楚该将特定的功能安置在哪个框架中。有时候我们将创造一个功能,并暂时运行它,然后意识到它其实可以变得更有效。之后我们将会把它推向下一个抽象阶段,即将其转移到一个不同的框架中。

在是时候创造第二款游戏前我们并不会开始从LinkEngine中分离出特定的游戏代码。等到那时候我们将会觉得自己能够处理绝对程序库中所需要的内容,但是从LinkEngine中分离出特定的游戏代码是一个需要付出额外努力的过程,即我们相信将比事先分离获得更好的结果。

为什么想要使用更大的字体?

我们并未输入第一款游戏的一件内容是图像资产的改变将如何影响屏幕内容的布局。有些图像经过了特别的设置,但其它却拥有固定/硬编码设置。在我们创造第二款游戏时这个计划失效了。每一款游戏的主题都是不同的,我们的美术师为每一款游戏的文本选择了不同的字体(基于不同的参数)。其它资产的大小也会随之发生改变,例如游戏的logo,按键,对话框,进程条等等。

为了适应这些不同的大小,我们也将一些资产的位置从固定改成相对值。在不适合的情况下,我们创造了一个特定的JSON布局文件,即为不同的资产提供坐标。我们将这一功能置于布局类中,即为了剩下的代码而将复杂性隐藏起来。

amazon(from develop-online)

amazon(from develop-online)

人们可能会认为我们应该预见需求事先去支持更灵活的布局,我们本来也能够通过事先计划不同规格的资产而节省一些不必要的付出。实际上,我们预见了这一问题,但我们选择不事先去处理它。游戏设计非常灵活,我们并不知道哪个功能和内容将保持在游戏中而哪个又会离开,不过我们知道可以在之后轻松地对其进行重构。

通过推迟工作去创造更加灵活的布局机制,我们最终获得了一个更棒的解决方法,因为我们能够收集更多有关各种场景所需的功能类型的信息。

听起来没错

每一款游戏都具有伴随着不同长度的独特音效,但我们能够不改变代码而使用这些音效。我们陷入了同样的结构中;同样的行动产生了同样的音效,我们拥有一些关于游戏的不同部分的不同音轨。JSON配置文件允许我们轻松地针对全新音频资产重置现有的行动。

关于在第一款游戏和第二款游戏之间,我们为自己的音频能理做出了较大的完善,所以我们想要将其应用于此。我们添加了能力去使用音频精灵,即运行我们将带有较低延迟的音效放置于设备中,而没有Web Audio API的支持。我们使用了一个Grunt(游戏邦注:JavaScript的自动化工具)任务从现有的音频资产中自动化音频精灵文件,

现在我们拥有一个音频程序库能够跨越平台利用高端能力去提供可伸缩的支持。

精益求精

在这一过程中我们引进了一些漏洞修补,优化,功能完善。尽管在程序库代码中的每个漏洞修补将有益于所有使用程序库的游戏,但是每个额外的功能和漏洞修补都要求在整个游戏中进行测试。

当我们完成第一款游戏时将改变带到程序库将是一个艰巨的过程—-就跟在开车时进行汽车维护一样,但我们却因为将JavaScript当成开发语言而大获其利。

为什么说JavaScript帮助了这一过程

JavaScript也具有其自身的问题,并且这些问题也体现在其它地方,但此外JavaScript也有它的优势:

属于松散类型语言

对象自变量表示法

普遍性和即时性

JSON

强硬类型的语言让编译器能够捕捉到错误并进行优化,这是在松散类型语言中所做不到的。松散类型语言因为这一点遭到了批评,但它却能够在类型转换和类别/对象定义中提供更多的灵活性。这些属性能够帮助我们进行原型设计与重整,甚至在之后的开发阶段中也能做到。

另外一个例子便是JavaScript的对象自变量表示法。在JavaScript中,你可以通过列举内容而创造一个对象。当与一些新功能进行试验或在不需要更加正式的对象/类别定义时这都非常有用。

JavaScript是一种解释型语言(或即时编译),运行于每一个现代网页浏览器中。这意味着代码/测试循环可以非常快。你能够马上看到改变的结果,这种即时性也能引起功能和结构的快速迭代。你仍然需要通过测试做到这点,但是基于快速反馈和功能检验,我知道没有比这更棒的环境了。

JSON是受到JavaScript的对象自变量表示法的启发,并且是源于JavaScript,这对于创造非开发者也能够轻松修改的配置文件来说是最理想的一种格式。我们使用JSON配置文件去进行关卡配置,声音设计,图像布局,动画等等内容的创造。

Douglas Crawford在《JavaScript: The Good Parts》这本书中彻底讨论了JavaScript的正面(和负面)属性。如果你真的对HTML5游戏开发感兴趣的话,我建议你可以去读这本书。

重构vs.前构

大多数资深的开发者都会避免预先优化代码,相反地,他们会先创造功能然后寻找瓶颈,并为了达到更棒的性能而进行优化。这并不意味着他们并不会事先考虑编写有效的代码,只是他们不愿意在知道需要做什么前花太多时间。

而我们的设计与开发方法与他们相类似。我们当然会事先考虑结构问题并创作出一些高水平的决定,但是在理解这么做的价值前我们并不会沉溺于创造功能。我们能够基于较低的成本快速使用设计理念并进行迭代。JavaScript支持着这一过程并创造出了灵活且有趣的开发体验。

我们最终创造出了5款出色的HTML5游戏,它们都带有较少游戏特定代码,一个面向所有连连看游戏的共用引擎,一个能够支持各种设备的音频回放程序库,一个你能够用于创造各种类型游戏的HTML5游戏引擎。

最重要的是,玩家玩了这些游戏数百万次,并且我们也看到她们对游戏具有非常高的忠诚度。玩家共玩了140万个小时的游戏,并且他们花费在游戏中的时间已经是过去几个月的2倍。毋庸置疑,我们将会在之后的游戏中继续使用这一方法论。

本文为游戏邦/gamerboom.com编译,拒绝任何不保留版权的转载,如需转载请联系:游戏邦

Growing an HTML5 game engine

By Craig Robinson

Last year we had the opportunity to create a series of five Mahjong-link games in HTML5 for Spil Games. The first game we built was Dream Pet Link. Given that we were tasked with building four additional games with the same mechanic but different themes, we assumed we’d be able to reuse much of the same code, that we could just write the first game and then swap in new art and sound assets for the subsequent titles.

Oh, only if things were so easy.

There were a few issues that made things more complicated:

* Desire to reuse some code in other games that didn’t have the same mechanic

* Uncertainty about code changes necessary to accommodate differences in the art and audio

* Features and performance improvements we knew we would discover later in the cycle

These considerations forced us to take a different design approach than we had initially anticipated. Here I will share with you the process we went through to build these games while creating code libraries for use in these and our other HTML5 games. As you will see, the process was fluid and organic. I will also describe why JavaScript proved to be an ideal language to support our work.

Start your engines

We decided that functionality would be organised into three distinct buckets;

1) Code and configuration files specific to a given game

2) Code that could be shared by all the games with this mechanic (we called this LinkEngine)

3) Code that could be used by any game (we called this the Absolute library).

It wasn’t always immediately clear into which bucket to place a particular functionality. Sometimes we would build a feature, and only after working with it for a while, realise that it could be made more generally useful. We would then promote it to the next level of abstraction and move it to a different bucket.

We didn’t start to split out game specific code from LinkEngine until it was time to build the second game. By that time we felt like we had a pretty good handle on what needed to be in the Absolute library, but splitting the game specific code from LinkEngine was a process that, as we describe below, required some additional effort that we believe provided a better result than if we had tried to make this separation in advance.

What do you mean you want to use a larger font?

One thing we didn’t address in the first game was how changes to the graphic assets would affect the layout of on screen items. Some of the graphics were positioned relatively, but others had fixed/hardcoded locations. This scheme broke down when we built the second game. The theme of each game was different and our artists chose a different font (with different metrics) for text in each game. Other asset sizes were changed as well such as the logo for the game, buttons, dialog box frames, progress bars, etc.

In order to accommodate these different sizes we changed some asset positioning from fixed to relative. In situations where that wasn’t appropriate, we created a game specific JSON layout file that provided coordinates for various assets. We wrapped this functionality in a Layout class that hides the complexities from the rest of the code.

One might argue that we should have foreseen the need to support more flexible layouts up-front and we could have saved ourselves some effort by planning for differently sized assets in advance. In fact, we did anticipate this issue, but we chose not to address it up-front. The game design was very fluid, we didn’t know which features and items would stay in the game and which would go, and we knew we could easily re-factor this later.

By putting off the work to build a more flexible layout mechanism we ended up with a more elegant solution, because we were able to collect more information about the type of features and functionality required across a number of scenarios.

Sounds about right

Each game had unique sound effects with different lengths, but we were able to use these without code changes. We stuck to the same structure; the same actions caused sound effects and we had a couple of different music tracks for different parts of the game. A JSON configuration file allowed us to easily re-map existing actions to new audio assets.

We made significant improvements to our audio capabilities in between the first and second games, so we wanted to work these in. We added the ability to work with audio sprites, which allowed us to place sound effects with lower latency on devices without Web Audio API support. We used a Grunt (JavaScript automation tool) task to automate the creation of audio sprite files from our existing audio assets.

We now have an audio library that provides scalable support across platforms by taking advantage of high-end capabilities where available, and falling back to less rich, but still acceptable functionality, where not.

Making it better

We introduced a number of bug fixes, optimisations and feature improvements throughout the process. While each bug fix in the library code benefitted all the games using the library, each feature addition and bug fix required testing across all games.

Introducing changes to the libraries once we had completed the first game could have been an arduous process — akin to performing maintenance on a car while driving — but we benefitted from having JavaScript as our development language.

Why JavaScript aided this process

JavaScript has its problems and these have been well documented elsewhere, but there are some great things about JavaScript as well, including:

* Loose typing

* Object literal notation

* Ubiquity & immediacy

* JSON

Strongly typed languages allow the compiler to catch errors and perform optimisations that can’t be performed in a loosely typed language. Loose typing has been criticised for these reason, however, it allows for much more flexibility in type conversion and class/object definition. These attributes help with prototyping and refactoring, even at later stages of development.

Another example is JavaScript’s object literal notation. In JavaScript you can create an object by just enumerating its contents. This is extremely useful when experimenting with new features or in cases where a more formal object/class definition is unnecessary.

JavaScript is an interpreted (or JIT compiled) language and runs in every modern web browser. That means that the code/test cycle can be very fast. You see the results of your changes right away and this immediacy allows for rapid iteration on features and architecture. You still need to do thorough testing, but in terms of quick feedback and feature validation, I know of no better environment.

JSON, which is inspired by JavaScript’s object literal notation and is native to JavaScript, is an ideal format for creating configuration files that non-developers can easily modify. We use JSON configuration files for level configuration, sound design, graphic layout, animation and many other things.

The good (and bad) attributes of JavaScript are thoroughly discussed in Douglas Crawford’s excellent book, “JavaScript: The Good Parts.” I highly recommend it if you are interested in doing HTML5 game development.

Refactoring vs. pre-factoring

Most experienced developers avoid pre-optimising code, rather, they build functionality and then look for bottlenecks, spot optimising where necessary to achieve desired performance. That doesn’t mean they don’t think about writing efficient code up-front, just that they don’t spend more time than warranted before they know they need to.

Our design and development approach was similar. We certainly thought about architectural issues up-front and made some high-level decisions, but we didn’t get hung up on making functionality abstract and re-usable until we understood the value of doing so. We were able to play with design concepts and iterate quickly, with very little cost. JavaScript supported this process and made the development experience flexible and fun.

We ended up with five great HTML5 games with very little game-specific code, a common engine for all the link games, a library to support audio playback across a variety of devices, and a general HTML5 game engine on which we can build any type of game.

Most important, the number of game plays is in the millions and we’re seeing great loyalty in the game. Players have logged in about 1.4 million hours of play and the time they spend in the games has doubled in the last couple of months. Needless to say, we will continue to use this methodology as we move on to our next titles.(source:develop-online)


上一篇:

下一篇: