2D游戏里的地图物件是用js数组存放对象好还是对象好

地图的数据以及区域的信息是场景的重要组成部分,这些数据同时存在客户端和服务器,而且都是由编辑器生成的。那么保存的文件数据结构是怎样的?一张3D的场景地图又是怎样处理这些数据的?同时告诉大家这里同样只是讲的理论与设计,理论和设计往往都很空洞,但是却很灵活,需要靠每个人怎么运用。
区域和格子
& 从上面的截图可以看出游戏场景其实是由格子来区分的,不管是矩形的格子还是其他形状的格子也好,一张地图不可能只有一个点(即多点组成一张地图)。在3D场景中似乎格子的位置总伴随着高度信息,所以让人感觉有些迷茫,其实我们可以将这些格子平铺成一张图。
& 如上面的最后一张图,是地形的剖面图,不过是横切面,如果我们看一下纵切面的话,就可以将3D的地图进行2D的转换。其实地图还是由一张平面图组成,只是多了Y轴的数据,也就是我们常说的地表高度。
&&由指定格式的数据组成,在服务器和客户端的主要作用是用来寻路(点击地图走路,以及自动寻路)。
&&一个场景一般情况下会有区域的划分,因为这些区域会有自己特殊的事件,如一个玩家加入该区域会产生某个事件,就像我们玩游戏的时候忽然触发了剧情一样,这都是区域的事件。
&&有了指定的数据结构后,文件才能被正常的读取,而地图的数据一般是由编辑器生成,所以也必须规定文件的数据结构。
& & 1.&文件数据
& & & 武侠世界/天龙八部的场景地图数据格式为:[文件头][单元数据][单元数据]&& 单元数据的数量为地图横长* 地图纵长。
& & & &code.
typedef struct map_header_struct {
int16_ //文件标记,用来区分是不是地图数据文件
int32_ //X方向大小 横长
int32_ //Y方向大小 纵长
} map_header_t; //文件头信息
typedef struct map_unit_struct {
int16_ //标识信息
||_ WalkDisable
-是否禁止地面上行走的OBJ穿越
1不可穿越]
|__ FlyDisable
-是否禁止空中飞行的OBJ穿越
1不可穿越]
int8_ //高度
int8_ //预留字段
} map_unit_t; //单元数据信息
& & 2.&对象数据
& & &整个对象也就是整张地图的数据,在武侠世界/天龙八部中采用的是左手坐标系,而在服务器其实用不着空间的坐标也就是Y轴的数据,将地图切割后就是一张平面的图,这张平面的图一般都是矩形。
& & &X坐标&左为0、右为最大(也可以说是地图横长)
& & &Y坐标 上为0、下为最大(也可以说是地图纵长)
& & &code.
/* 完整的地图示意图 */
___________
|_________|
& &&地图划分成一个个格子,而组成区域的也是格子,以下为一个区域的基本数据。
& & 1.&RECT(矩形格子)
& & &&left 左、top 高度、right 右、bottom 底部。
& & 2.&区域ID
& & 3.&脚本ID
算法(选择排序)
& 1、简单选择排序
& &&简单选择排序基本思想是将最小的数据移动到第一个位置并交换数据,比如有N个元素,一次将最小的元素移动到第一个位置并交换数据,那么剩下的就只剩下N-1个数据,将剩下的N-1的序列的数据最小的数据移动到该剩下序列的第一个位置,这样移动N次之后,序列便成了有序的序列。
#include &stdio.h&
#include &stdint.h&
#include &inttypes.h&
* 简单选择排序基本思想是将最小的数据移动到第一个位置并交换数据,比如有N个元素,
* 第一次将最小的元素移动到第一个位置并交换数据,那么剩下的就只剩下N-1个数据
* 再将剩下的N-1的序列的数据最小的数据移动到该剩下序列的第一个位置,这样移动N次
* 之后,序列便成了有序的序列。
//简单选择排序
void selectsort(int32_t array[], int32_t length);
//数组打印
void displayarray(int32_t array[], int32_t length);
int32_t main(int32_t argc, char *argv[]) {
int32_t array[] = {32, 1, 6, 9, 37, 88, 47, 35, 99};
int32_t length = sizeof(array) / sizeof(array[0]);
selectsort(array, length);
printf("sort result: ");
displayarray(array, length);
void selectsort(int32_t array[], int32_t length) {
int32_t i, j,
//将第i个元素与第i+1...length个元素比较,将最小的元素放在第i个位置
for (i = 0; i & length - 1; ++i) {
for (k = i + 1; k & ++k) { //最小元素的序号为j
if (array[k] & array[j])
if (j != i) { //如果序号i不等于j,则需要加序号i和序号j的元素交换
temp = array[i];
array[i] = array[j];
array[j] =
printf("the %d times sort result: ", i + 1);
displayarray(array, length);
void displayarray(int32_t array[], int32_t length) {
for (i = 0; i & ++i)
printf("%4d", array[i]);
printf("\n");
& & result.
& 2、堆排序
& &&堆排序算法实现比较复杂,它主要适用于大规模的数据排序,比如在10万个数据元素中找出前10个最小或是最大的元素,使用该算法效率最高。
#include &stdio.h&
#include &stdint.h&
#include &inttypes.h&
* 堆排序算法实现比较复杂,它主要适用于大规模的数据排序,比如在10万个数据元素
* 中找出前10个最小或是最大的元素,使用该算法效率最高。
//数组打印
void displayarray(int32_t array[], int32_t length);
//调整array[pos1...pos2],使其成为一个大顶堆
void adjustheap(int32_t array[], int32_t pos1, int32_t pos2);
//创建大顶堆
void createheap(int32_t array[], int32_t length);
//利用堆排序算法对数组进行排序
void heapsort(int32_t array[], int32_t length);
int32_t main(int32_t argc, char *argv[]) {
int32_t array[] = {32, 1, 6, 9, 37, 88, 47, 35, 99};
int32_t length = sizeof(array) / sizeof(array[0]);
printf("before sort: ");
displayarray(array, length);
heapsort(array, length);
printf("after sort: ");
displayarray(array, length);
void displayarray(int32_t array[], int32_t length) {
for (i = 0; i & ++i)
printf("%4d", array[i]);
printf("\n");
void adjustheap(int32_t array[], int32_t pos1, int32_t pos2) {
temp = array[pos1]; //临时存放根节点
for (i = 2 * pos1 + 1; i &= pos2; i *= 2 + 1) {
if (i & pos2 && array[i] & array[i + 1]) //从关键字较大的子节点向下筛选
++i; //i为关键字较大的节点的下标
if (temp & array[i]) break; //如果子节点的值小于根节点的值,则不进行交换
array[pos1] = array[i];
array[pos1] = //将根节点插入到正确的位置
void createheap(int32_t array[], int32_t length) {
for (i = length / 2 - 1; i &= 0; --i) //从序号length / 2 - 1开始建立大顶堆
adjustheap(array, i, length - 1);
void heapsort(int32_t array[], int32_t length) {
createheap(array, length); //创建堆
for (i = length - 1; i & 0; --i) { //将堆顶元素与最后一个元素交换,重新调整堆
temp = array[0];
array[0] = array[i];
array[i] =
printf("the %d sort times: ", length - i);
displayarray(array, length);
adjustheap(array, 0, i - 1); //将array[0...i-1]调整为大顶堆
& & result.
阅读(...) 评论()此页面上的内容需要较新版本的 Adobe Flash Player。
最新开发文章
最新信息推荐
上市公司专栏
实时股价每分更新
纳斯达克(美元)(市值:亿美元)
综指: 涨跌幅:
恒生指数(港币)(市值:亿港币)
综指: 涨跌幅:
综指: 涨跌幅:
浅谈2D游戏地图制作
11-24-2009
  浅谈2D游戏地图制作
  这些天公司程序在外包项目上和其他公司的策划有些交流,双方在地图问题上产生分歧,就我而言感觉对方对地图的理解有所偏差。就我个人感受说一说地图的编制。
  首先,我这里讲的地图只要是2D、俯视、45度正俯视、45度斜俯视这几类的地图。
  一般而言最简单的地图就相当于背景,比如血腥大地上,如果不设置障碍的话地图就是一个背景。如果,设置了障碍那么地图就多了一个属性--阻挡。也就是地图的两个最基本属性,显示和阻挡。
  实现阻挡的方法很多,一般两种,一种是定义不可通行地图切片快,那么构成地图只需要一层就够了。另外一种的话就是做两层,显示层和控制通行的层。有以上两个基础功能的地图基本上就像模像样了。
  在然后可以加入更复杂的功能---事件层。事件层类似阻挡层,不同的是事件层定义的块分类后用于实现不同的功能,基本上两种,开关和事件。
  一般而言,显示层通常不是单独的一层,为了表现出地图的纵深感、立体感显示层通常被分成2层,一层是基本的地图图层,一层是不规则装饰物层,然后将人物层置于基础层之上,不规则装饰物层之下,再加上阻挡的定义就可以实现,人在地图行走时的遮盖效果,表现出地图的景物层次。
  那么,地图需要实现那么多功能和作那么多事情,地图的活应该由谁来完成如何完成呢?
  显然,这大部分都是策划的活。只有策划知道要做什么样游戏,什么样的地图是最合适,这样的事情自然是策划自己来做,否则的话还要策划干啥?
  那么一个地图的制作过程是怎样的呢?
  一般而言地图制作分成几个步骤,切片制作、地图制作、脚本制作;
  切片制作就是制作地图切片的过程。首先,由策划提出图片需求,一般包括基本地形描述和元素描述,也就是地面和地面建筑及&装饰&的需求。然后美术制作效果图,第一步是确定色调和风格,然后再初步效果图的基础上制作精确的效果图,这里面要考虑很多东西,是考验美工水准的活。下一步则是根据精确的效果图来提炼地图切片,基本上地图切片出来,美工的活就结束了。
  切片制作完成,开始正式制作地图文件。这里要使用到地图编辑器,这样的工具网上很多,各个公司也有自己开发的工具,不过个人觉得地图编辑器至少要具有以下这些功能才够用:多张切片调用、支持不规则选取框、分层功能、层透明、设定切片阻挡、设定事件开关触发点、支持复制张贴。
  要开始制作地图,首先策划的前期准备应当十分充分,地图的制作过程实际上是剧情的进一步实质化。制作过程中要考虑的内容很繁杂,比如:地图转移关系、地图使用时机(使用几次、分别在游戏的什么阶段)、地图事件设置、地图开关设置&&没有好编辑器做起来很头痛的说&&
  基本上奥过制作阶段地图编制也基本大功告成,接下来要做的就是地图脚本制作,或者说运用类似脚本的思想来整理地图资源,比如文件名字定义、调用关系、配置怪物、配置NPC、配置动画等等&&
相关新闻:
相关专题:
<button style="border:2px solid #background-color:#margin-right:10" onclick='javascript:var _title=document.var _url=document.location.if( document.all ) {var _text=_title+" - "+ _clipboardData.setData("Text",_text);this.innerHTML="已经复制成功,请用 Ctrl+V 粘贴";}'>复制本文地址推荐给朋友
收藏这篇文章java:记事本保存游戏地图 - Java教程 - 编程入门网
java:记事本保存游戏地图
起初看到这个,你的想法是什么,这小子想干嘛呢???
这个方法是在一个多月前做多线程游戏的时候想到的,最初是中南的一位朋友提出来的。最近的博客老是在&炒剩饭&,一些新学的东西也总是来不及作总结,不过觉得这个想法确实不错,所以也才拿出来再与大家探讨一下,说不定还有更好的方法。
我们所玩的一些场景不动2D的游戏,往往需要构建一些地图,如泡泡堂,坦克大战等等。
而在地图构建的时候,我们往往采用的是用一个数组将所需的地图保存起来,但是做到后来,需要的地图多了,保存的效率往往也就偏低了,而且还会耗费大多的代码去填数组。
在一个记事本中把你想要做的地图保存起来,看上去也更加直观,简洁。使用IO流进行字节读取是出错率相对较低的,所以我们的地图中理论上可以存在256种元素(一个byte占8位)。当然,我们或许不需要这么多,a-z加上1到9就完全可以满足我们的日常需求了。
最开始的时候,有人问到,既然是OOP,为什么不用对象来保存我们的地图元素?原因很简单,我们操作byte数据的效率要高于操作对象本身。
好的,闲话不多说,方法如下:
首先,我们需要一个ArrayList来保存数据,有什么用呢?继续看你就知道了
//创建地图数组来保存数据
ArrayList&Byte& MapList=new ArrayList&Byte&();
* 将记事本中的数据读入到数组当中
* @param mapName 记事本的文件名
* @return 得到的字节数组
public int[][] createMap(String mapName){
File file=new File(mapName);
//创建地图数组
int map[][]=
if(file.exists()){
InputStream in=new FileInputStream(file);
//创建与文件相同大小的字节数组
byte content[]=new byte[in.available()];
//读取字节数组
in.read(content);
//将内容添加到队列当中
for(int i=0;i&content.i++){
MapList.add(content[i]);
//移除回车符
for(int i=0;i&MapList.size();i++){
if(MapList.get(i)==10){
MapList.remove(i);
//移除换行符
for(int i=0;i&MapList.size();i++){
if(MapList.get(i)==13){
MapList.remove(i);
//封装字节内容
String string=new String(content);
String arr[]=string.split(&\r\n&);
//存入数组当中
int index=0;
map=new int[arr.length][arr[0].length()];
for(int i=0;i&map.i++){
for(int j=0;j&map[i].j++{
map[i][j]=MapList.get(index)-48;
in.close();
}catch(Exception e){
e.printStackTrace();
System.out.println(&文件不存在&);
比较关键的步骤是移除回车换行字符,这两个字符是我们看不到的,只有在打印的时候才会发现他们,
莫名其妙的多出个10跟13,起初我也是觉得纳闷,任何方法当然都要测试一下,自己做个记事本地图试一下吧。您现在的位置: >>
>> 浏览文章
OPhone/Android 2D游戏的地图系统
作者:杨丰盛 日期:日 来源:互联网 
OPhone/Android 2D游戏的地图系统&
通过前面几篇文章的学习,我们也完成了引擎的大部分内容了,也可以来开发一些简单的游戏了,现在大家可以想象一下,我们现在需要做一个叫大型的RPG游戏,游戏中需要有多张不同的地图场景,如果我们将每一个场景都做成一张大的图片,可能就非常的浪费空间了,虽然现在的手机性能越来越好,但是过多的资源同样会影响游戏的效率,而且关于的地图的碰撞检测也就很麻烦了,那么解决这类问题的办法,通常就是使用瓦片地图。
瓦片地图 瓦片地图就是将一整张大的地图切成x*y个小的格子,每个格子中填入一个地图元素,这样来构成一张大的地图,对于这些地图的拼合通常都不需要程序来做,可以有策划通过地图编辑器来完成;关于地图编辑器,目前免费的也很多,比如:mapwin和Tiled等,基本可以实现地图的编辑功能了,如果实在觉得这些免费的地图编辑器不能满足需要(比如你要在地图中加入一些关卡脚本之类的),那么可以考虑自己编写一个地图编辑器。通常一个游戏都会有一个地图编辑器。关于地图编辑器的编写不是我们本文的内容,所以大家可以自己去查看一些资料,下面我们先简单的说一下地图的构成,首先需要一个地图元素的图片资源,如图7-1所示。
该图片是被拆成了2*4行小的地图元素,他们对应的索引如代码清单7-1所示。代码清单7-1:地图元素
1,2&3,4&5,6&7,8&&&&
当然也有的地图编辑器将第一个设置为0,依次类推,这样我们就可以使用上面这些索引来完成一个地图,我们就爱你过地图定义为一个二维数组,如代码清单7-2所示。代码清单7-2:地图数组
byte[][]&map&=&{&{1,1,1,1,1,1},&{2,4,7,8,3,2},&{4,5,2,4,5,6},&{4,5,6,8,1,4}&};&&&&
然后再绘制地图时就根据这个地图数组中的每一个元素所对应的地图元素资源中的图像即可。这样就大大的节省了资源所占用的空间,同时如果要进行碰撞检测也就可以直接根据地图数组中的元素是否是可行走区域来区分了,很方便的就能完成简单的碰撞检测,所以这也是我们在游戏开发中最常用的一种处理地图的方式,当然对于同时绘制这么多小的地图元素,同样存在效率问题,那么就可以考虑采用不同的地图优化技术,比如:卡马克算法等。
地图图片集(TileMapAtlas) 从图7-1我们可以看出这个地图资源图片实际上就是我们之前给他家介绍的图片集对象,这里有一点需要注意,该图片上的每一个地图元素都会对应一个唯一的地图索引,并且这个图片的宽度和高度尺寸都需要是我们的每一个单独的地图元素(title)的整数倍,这样我们在计算图片的行和列时才不会出错,该引擎中我们将具有这样一个功能的对象封装成一个类TileMapAtlas,该类被看成一个AtlasNode节点,继承自AtlasNode,具体实现入代码清单7-3所示。代码清单7-3:TileMapAtlas
该代码清单中使用了mPosToAtlasIndex来记录每一个地图元素的索引,mItemsToRender表示地图中需要渲染的所有地图元素,每一次更新地图之后都需要通过updateAtlasValues来更新图片集,其中通过了循环了整个地图的width 和height来达到对每一个元素的更新,具体内容大家可以根据注解去理解,这里需要特别说明的就是在setTile函数中,根据地图数据来取得索引值的计算,这里我们采用了pos.x && 32 | pos.y这中方式,这和我们的地图数据有关,因为我们默认采用的地图数据是一张TGA的图像,并不是前面说的一个数组。下面我们就结合一个TGA地图图像数据来分析一下TGA格式的瓦片地图的实现。
TGA瓦片地图数据(TGATileMapAtlas) 既然是用一张TGA图片来展示一个地图数据,很明显我们需要一张类似于代码清单7-1所示的代码一张的TGA图片,这里我们看一下cocos2d中的例子图片,如图7-2所示。
大家看到该图片是不是很茫然,该图像其实非常的小,图7-2是我们放大之后看到的效果,是不是怎么也看不到代码清单7-1的效果啊?如果将该图像中的每一个像素点当做代码清单7-1中的每一个元素数组,这样就能理解该地图数据了吧。在仔细一看,我们应该可以看到该地图的一个锥形,像一个超级玛丽的地图;那么我们的地图在构建出来之后也就会类似于这个效果,这也是使用TGA图像来作为地图数据的优点,能够看到地图的锥形(类似于代码清单7-1的数据,我们应该很难看到地图像什么样子),这里也就说明了我们在TileMapAtlas中的setTile函数中为什么要进行“pos.x && 32 | pos.y”操作了,原因是因为我们从TGA图像中取得了每一个像素的RGBA中的R值,然后对图片集的大小进行取商取余的操作,从而得到准确的地图元素所对应的索引,当然这也和我们在制作地图时的计算方式有关,比如:我们还可以使用RGBA分别来代表4个层次的地图,那么这个TGA地图数据就变得更加复杂,但是所能表示的数据就越多了。说了这么多,下面我们来分析一下具体的实现,如代码清单7-4所示。代码清单7-4:TGATileMapAtlas
public&class&TGATileMapAtlas&extends&TileMapAtlas&{&public&TGALoader.TGA&mTGAI&&&
TGA瓦片地图是在TileMapAtlas的基础上实现的,所以我们可以继承自TileMapAtlas来实现,这里我们使用了mTGAInfo来表示TGA图像数据,其中存储的就是我们准备好的TGA图像数据,因此我们首先需要装载这个TGA文件,并解析才能取得其数据,对于TGA文件的装载我们之前很早的文章中就介绍了,这里直接使用TGALoader.load来完成装载和解析即可。这里所实现的getHorizontalTileCount和getVerticalTileCount函数就分别取得的TGA图像的宽度和高度(像素),这里的二维数组的每个元素就对应于TGA文件的每个像素,最后在释放时(releaseMap中)记得释放TGA文件。
数组瓦片地图(ArrayTileMapAtlas) 对于复杂的地图我们推荐使用TGA瓦片地图,但是某些简单的游戏我们就没有必要使用TGA瓦片地图了,那么我们就可以使用一个数组来表示地图数据了,这样就比TGA图像更加简单了,现在回到代码清单7-1所示的地图数据中,我们就用这么一个数组来表示一张地图,下面我们看一下如何使用这个地图数据来表示一个地图,具体实现入代码清单7-5所示。代码清单7-5:ArrayTileMapAtlas
public&class&ArrayTileMapAtlas&extends&TileMapAtlas&{&&&
该代码中我们使用mTiles来代表一个地图数组,和TGA瓦片地图类似,不同的地方在于getHorizontalTileCount和getVerticalTileCount分别是指的地图数组的行数和列数了,当地图数组mTiles的某个元素的值为0,那么我们就认为该区域是空白的,不需要绘制,在通过tileValueAt来得到某个title时,就直接返回地图数组中对应的数值即可。
瓦片地图实例 前面讲了这么多,下面我们就用一个实例来告诉大家如何使用我们引擎所完成的瓦片地图,这里我们使用图7-2所示的TGA文件来表示一个地图数据,关于数组的瓦片地图就更简单,大家自己实现以下即可,先将TGA文件和地图元素资源文件(如图7-3所示)放置到res中对应的文件夹中。
然后构建一个图层Layer对象用来显示该地图对象,在该Layer中,包含一个瓦片地图对象,将该地图对象添加到Layer中即可,具体如代码清单7-6所示。代码清单7-6:TestTileMapAtlas
TileMapAtlas&mTileM&&&
其中“R.drawable.map”是我们的子图资源图片,”R.drawable.levelmap“则是具体的地图数据(TGA图像),16和16分别是每个title的宽度和高度,就这样简单的几句代码就能显示一个完整的地图了,呵呵,,很简单吧,要是不简单,那引擎就不起作用了。那么现在地图已经显示出来了,如何来控制地图呢,很简单,就和控制AtlasNode一样了,比如我们需要通过触摸来移动地图,就直接通过下面的代码即可在x和y上同时一个10个单位。
mTileMap.translate(10.f,&10.f);&& &&
该实例的运行效果如图7-4所示。
图7-4 瓦片地图实例(超级玛丽)
总结 本文主要介绍了游戏开发中的地图系统,这里我们主要分析和实现了瓦片地图,包括了两种常见的瓦片地图方式:数组和TGA地图,数组通常被用于一些简单的地图效果,比如我们可以用一个数组来做一个俄罗斯方块游戏的背景框架,TGA方式则适合于比较复杂的地图,地图比较大,比如我们实例中的超级玛丽的地图实现,当然你还可以根据你的需要使用不同的地图文件来存储地图,关键在于如何定义这些地图数据编辑、存储规范,读取和解析数据,当然大家也可以考虑来完成斜45度角的2.5D游戏地图设计。由于分享经验的心情急切,难免会出现一些疏忽或错误,还望不吝赐教!
杨丰盛:国内早期Android开发人员,实战经验极其丰富。精通Java、C、C++、Object-c等语言以及j2me、BREW、Android、OPhone、iPhone等开发平台,专注于移动通信软件开发,在机顶盒软件开发和MTK平台软件开发方面有非常深厚的积累。曾出版《Android应用开发揭秘》一书并入围51CTO 2009年度“最受读者喜爱的原创IT技术图书奖”,作者同时也入围51CTO 2009年度“最受读者喜爱的IT图书作、译者奖”。
【】【】【】【】【】
本站提供,,等服务,价格公道,针对性强。有意者请联系Email:。谢谢您的支持,愿本站提供的资料能给您带来帮助。
上一篇:下一篇:
相关文章列表

我要回帖

更多关于 php 数组存放对象 的文章

 

随机推荐