基于TILED的2D游戏绘制方法详解


1      Introduction

1.1    Purpose and Scope

游戏引擎作为游戏制作的基础是保证游戏质量的最重要部分,目前主要包括两方面:背景绘制和动画播放。

为了使新员工对目前开发的手机游戏能够有深入的了解,此文档详细描述了目前使用的背景绘制的原理和具体实现方法。

1.2    Abbreviation

GD               Game Design

BG               Background

1.3    Reference

[1]   Cao Heng, Gameloft, “Training Minutes For Game Tools”, V0.002.

2      Tiled Background

2.1    什么是Tiled Background

游戏场景中的背景要展现出一副巨大的图像,它是游戏设计者表现游戏环境和氛围的重要手段。无论对于PC游戏还是其他平台的游戏,巨大的背景都会带来容量问题,容量对于手机游戏更是十分宝贵的。

为了使用尽量少的图绘制出尽量多的背景,背景图像由无数的等大小的图形组成,这些图形通常使用正方形。而这些图形的种类是有限的,只是每一个都可能被使用了很多次。就好像墙上的瓷砖一样,可以通过有限的种类拼出无限的组合。那么组成背景的图形就被称为Tile,而使用Tile 拼成的背景就被称为 Tiled Background

 

最后,我们把拼接一副背景所用的所有 Tile 保存在一张图像中,就构成了我们在游戏中使用的图像资源,我们通常称之为 Tileset。并且,我们会把 Tileset 中的每一个 Tile 进行编号,顺序是从左到右,从上到下,如下所示。

0

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

通过编号,我们可以把组成巨大背景的每一个 Tile 用该 Tile Tileset中的索引值(Index)表示,如下所示。

4

5

7

18

8

4

5

7

18

8

4

5

7

18

8

9

0

1

11

13

9

0

1

11

13

9

0

1

11

13

10

6

17

2

12

10

6

17

2

12

10

6

17

2

12

3

16

15

19

14

3

16

15

19

14

3

16

15

19

14

4

5

7

18

8

4

5

7

18

8

4

5

7

18

8

9

0

1

11

13

9

0

1

11

13

9

0

1

11

13

10

6

17

2

12

10

6

17

2

12

10

6

17

2

12

3

16

15

19

14

3

16

15

19

14

3

16

15

19

14

4

5

7

18

8

4

5

7

18

8

4

5

7

18

8

9

0

1

11

13

9

0

1

11

13

9

0

1

11

13

我们将这些索引值以从左到右,从上到下的顺序保存起来,就得到了一个连续的索引值的数组。这样,我们只要拥有 Tileset 的图像和索引数组就可以得到一副完整的背景了。

2.2    Tiled Background的数据结构

通过上一节的介绍,我们可以知道,巨大的背景可通过一张很小的 Tileset 图和索引数组来绘制出来。

在手机功能允许的范围内,程序还可以对 Tile 进行水平翻转(X Flip)和垂直翻转(Y Flip),这样就可以在背景中使用经过翻转的 Tile ,用于丰富背景图的内容。

2.2.1     XML 数据格式

为了通用性和可读性,在编辑阶段我们将 Background 的索引数组和相关数据保存为 XML 格式,这样不仅可以在 IE 等软件中浏览,更可以在 Notepad, UltraEditor, HexEditor 等工具中进行编辑。

       下面是一个 XML 文件的例子,该格式为公司内部定义。

<Map width="160" height="176">

    file="X:/mac.png" tilew="16" tileh="16" tilew_t="10" tileh_t="11">

        16,16,16,16,-1,16,16,16,16,16,6,16,16,16,16,16,16,16,16,16,6,16,16,16,16,16,

16,16,16,16,6,16,16,16,17,1073741841,16,16,16,16,6,16,2,2,0,1073741824,2,2,2,2,6,16,7,7,5,1073741829,7,7,7,7,6,16,19,11,8,1,11,11,11,19,6,10,19,19,12,1073741836,15,15,19,19,13,14,536870930,536870930,536870930,536870930,536870930,536870930,536870930,536870930,9,18,18,18,18,18,18,18,18,18,4,4,1073741828,1073741828,4,4,1073741828,1073741828,4,4

   

        0,0,0,0,0,0,0,0,0,0,3,3,0,0,0,0,0,0,0,0,3,3,0,0,0,0,0,0,0,0,3,3,0,0,0,0,0,0,0,0,3,3, 0,0,1,1,0,0,0,0,3,3,0,0,1,1,0,0,0,0,3,3,4,0,1,1,0,0,0,4,3,3,4,4,1,1,0,0,4,4,3,3,2,2,2,2,2,2,2,2,3,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3

   

       在例子中,我们可以看到紫色的为背景图的大小(单位为象素),绿色依次为 Tileset 图像文件的路径,Tile 的宽度,Tile 的高度,背景上每行的 Tile 数量,背景上每列的 Tile 数量棕色即为索引数组。在索引数组中,每一个 Tile 的索引用一个4 Bytes的整数表示,如果索引值小于0(即二进制中的最高位为1),表示该 Tile 为空(即没有 Tile),为了便于记录,我们将二进制中的次高位和次次高位是否为1,分别用于表示每个 Tile 是否需要进行 X Flip Y Flip。如例子中的-1就表示该位置没有 Tile1073741828 (0x40000004)表示该 Tile 进行了 X Flip

2.2.2    物理层的用途

在上面的XML文件中,有两层背景,第一层用于游戏中绘制背景,可称为显示(Visual Layer),第二层不用于绘制背景,只以同样的形式记录每个 Tile 的物理属性,可称为物理层(Physical Layer)。

为了给背景上不同的区域划分物理属性,比如有些区域人物可以通过,有些区域不能通过。我们使用另外一套 Tileset 拼出与显示层同样大小的物理层,我们的目的只是得到物理层的索引数组,用这套索引数组表示每一个 Tile 对应位置的物理属性,而不是将物理层画到屏幕中。

2.2.3    背景编辑工具

目前我们所使用的背景编辑工具为 ezPlayfieldEditor.exe ,它是GameloftBeijing内部使用的开发工具,由Java语言编写,使用 J2SDK1.4.2编译完成,因此在J2SDK 1.4.2的环境下才可以正常运行。

它可以创建、读取、保存XML格式的背景数据,由于项目的不断创新,该工具还在不断的修改和完善中。

2.2.4    数据格式转换

XML文件并非游戏使用的最终资源,我们必须将XML文件转换为二进制文件,以便于程序使用和减少容量。所使用的工具为 Convert.exe ,与 ezPlayfieldEditor 一样,在公司内部开发和使用。

二进制文件的数据结构与XML文件基本相同,同样包括每张背景的宽、高和Tile 的宽、高等信息。而对使用的 Tileset 图像文件进行了统一的编号,在二进制文件中只记录背景所用 Tileset 的编号。

由于各个项目都会对所用的二进制资源进行容量上的优化,所以具体格式不尽相同,这里就不举例介绍了。大家可以集思广益,不断创新,以达到容量最小,使用最便利的目的。

2.3    Tiled Background显示算法

显示算法就是通过二进制文件和Tileset图在屏幕上的绘制背景的算法。对于手机游戏来说,显示算法的速度是最重要得。

2.3.1    逐块绘制法

当屏幕(红色框)要绘制背景上某一区域时,我们将涉及到的Tile黄色区域)逐块绘制到对应的位置,就是逐块绘制法。逐块绘制法是显示背景的最基本的方法。

0,0                       X

 

 

 

 

 

 

 

 

Y

当我们已知屏幕原点(左上角)在背景中的位置时,只要知道 Tile 的宽高,背景的宽高,就可知道每个涉及到的 Tile 相对屏幕的位置,用两层循环就可以绘制出来。

但是这种方法有一个致命的缺点,就是每帧都需要将所有涉及的 Tile 重新绘制到屏幕上,极大的影响了游戏的流畅度。为了提高速度,于是有了下面的缓冲绘制法。

2.3.2    缓冲绘制法

当屏幕在背景中移动时,实际上所涉及的 Tile 根本没有变化,或者只有一小部分发生了改变。所以我们可以创建一个背景图像缓冲(buffer),保存当前屏幕的背景图像,减少每帧得画图次数,可以大大提高速度。

当我们创建的图像缓冲和黄色区域大小相同时,如果背景涉及的Tile没有变化,我们只需将缓冲图像画到屏幕的适当位置上。如果背景涉及的 Tile 发生了变化,如变为绿色区域我们只需更新变化的部分Tile到背景缓冲,再将缓冲画到屏幕上即可。

0,0                       X

 

 

 

 

 

 

 

 

Y

为了保留缓冲图像中已有部分,我们采用滚动更新的方法。假设,当屏幕向右下移动时,缓冲中最上和最左的Tile已无用(IIIIII),我们便将新的最下的Tile 保存在最上(III区),将新的最右的Tile保存在最左(IIII区),得到新的缓冲图像。最后,我们将新的背景缓冲分4区,按照实际位置画到屏幕上即可,对应关系如图。

当然,按照屏幕在背景中的位置,我们的缓冲分区会出现四种情况。

l  1个区,刚好背景没有被缓冲切开

l  2个区,背景只在X轴方向被缓冲切开

l  2个区,背景只在Y轴方向被缓冲切开

l  4个区,背景在XY轴方向都被缓冲切开(如例子)

I                    II

 

 

 

 

III                 IV

 

 

 

                     IV                         III

 

 

 

 

 

                     II                            I

背景缓冲

实际背景

2.3.3    多层背景

背景和动画的图像是相同的,可以有透明效果。为了得到更加丰富的游戏背景,我们可以将两层甚至多层背景重叠,使背景的组合更多,更加复杂。

多层背景与单层背景的原理完全相同,也使用一个背景图像缓冲,区别在于更新缓冲时,需要更新多次缓冲,每一个Tile的位置会被多个Tile按顺序更新。

2.3.4    游戏背景知识扩展

l  背景缓冲的大小

背景缓冲图像的大小要大于屏幕最多可涉及的Tile的区域。

例如:

屏幕大小是128 X 128Tile 8 X 8,缓冲图像至少是

136 X 136  = (128 + 8) X (128 + 8)

屏幕大小是120 X 130Tile 8 X 8,缓冲图像至少是

128 X 144 =  (120 + 8) X ((130+7)/8*8 + 8)

屏幕大小是 screenW X screenHTile tileW X tileH,缓冲图像至少是

(screenW+(tileW-1))/tileW*tileW+tileW  X  (screenH+(tileH-1))/tileH*tileH+tileH

 

l  背景缓冲的内存消耗

背景缓冲虽然可以提高游戏的速度,但是它所占用的内存也是十分巨大的。

在一般手机中,一张图片的大小为 XX 2

如背景缓冲的大小为 136 X 136,那么它所占用的内存为 36992 Bytes

因为,我们可以认为使用背景缓冲是用内存换取速度的一种手段。

在游戏开发过程中,经常会利用内存换取速度,或者速度换取内存。

 

l  背景缓冲的滚动

当游戏的背景只用到了X轴滚动或者Y轴滚动时,我们的代码就可以进行优化,去掉不需要的滚动代码,可以减少一些容量的负担。

 

l  多层背景的限制

由于多层背景在更新缓冲时比单层背景要更多的绘图操作,因此更新缓冲的速度相对较慢。对于性能较差和背景滚动频繁的项目不宜使用这种方法。

另外,多层背景必然使用多个Tileset,而Tileset也会消耗大量内存,因此对于内存紧张的项目也不宜使用该方法。

你可能感兴趣的:(游戏开发,游戏,手机游戏,xml,数据结构,工具,图形)