flash游戏客户端设计2:地图实现

来源:互联网 发布:数据库触发器简单事例 编辑:程序博客网 时间:2024/04/30 00:39
 

地图分为四部分:wall也就是墙;frontLayer就是地图上人可以站其后面的物体,比如雕塑;miniMap小地图;tileLayer地图。

这些数据全配置在地图模板表中,每个场景为一行record。

一、wall

wall就是地图中的不可行走区域。

在美术画好不可行走区域后,由地图工具读入。因为美术的图每个像素还有颜色信息存储的位数会更多,按照每个像素是否可行走写入wall文件,这样每个像素只要一位。二维的数据实际是存为一维的。

同时因为游戏中对不可行走区域的精度不需要达到像素级。所以我们可以将粒度扩大,5452*4000的我们将其粒度设为10*10。这样原来需要100位的只要1位来存储。

二、frontLayer

frontLayer是地图上的遮盖物,比如雕塑等,人站在其后会看不见的。

一般来说有三种实现方法:

1.遮盖层在人物层之上,人物在遮盖层之后时,被遮盖完全不透明。

2.遮盖层在人物层之上,人物在遮盖物之后时,对应的遮盖物变为半透明。

3.人物层在遮盖层之上,人物在遮盖物之后时,人物变为半透明。

 

进入场景后生成所有代表遮罩物的对象,但是并不马上下载图片(类似没有bitmapdata的bitmap)。需要一个线程一直检查mask是否在屏幕中,检测到出现在屏幕中时再去下载并addchild,不在屏幕中时removechild。

三、miniMap

miniMap是当前地图的缩小版,在进入场景时马上下载,置于地图之下;也可以用于右上角的小地图。

需要把miniMap放大,将其高宽设为地图的实际高宽。因为地图要分块加载,miniMap显示在下面,避免出现地图未下载时黑块。

四、tileLayer

tileLayer是显示地图的。

 

1.需求

由于游戏地图太大,比如我们的大小为5452*4000。有3种解决方法。

1.flash最大支持 2880 x 2880大小的bitmap,可以通过BigAssCanvas 解决。

2.美术预先切好成小图,自己拼成大图,一次性加载全图。

3.从效率上考虑,只需要下载玩家可视范围内的地图。

所以我们将地图切块为500*300的大小。

2.资源组织

在资源文件夹下组织如下:

 

res

map

MAP_01_001 ...  各个文件夹代表各张地图:文件夹名如

0.1.2... 包含地图切分后的水平一行内的所有子图,文件夹名为行号。

0.1.2...   代表一个子图,文件名为列号。

item 文件夹,内含地图上的各个遮盖物,置于FrontLayer的mask层。

map.jpg 完整大的地图

mini.jpg 置于miniMap层的小地图

 

某地图文件下  0文件夹中0.jpg,就是左上角那块地图, 0文件夹中1.jpg就是0_0右边那一块。

 

3.实现

随着人物走动,地图也以人物为中心加载地图块。可以指定一个值PRE_LOAD_AREA设定加载的范围,比如人物所在块dx,dy,如果PRE_LOAD_AREA=1(本文假设都是这个值),则加载dx-1,dy-1 ;dx+1,dy+1  这个矩形框内的9块地图块。这个值由屏幕大小和地图块大小两者决定,只要加载区域能覆盖整个游戏显示区域;或者再考虑到网速,确保玩家走到一个新的区域时地图都已经加载完,在网速较慢时需要增大PRE_LOAD_AREA。

 

_tileTable缓存了当前地图的所有已加载或准备加载的地图块,key为坐标形如x_y的字符串,value为Bitmap。Bitmap不一定有data,是准备加载,或加载中的;有data的就是已经加载完毕的。

 

 

整个地图的移动由主容器stageContainer来移动,这里不详述移动,只考虑加载。

Class TileLayer:

 

 

function setCenterPix:

当用户走到地图上px py(非界面stage的x y)的位置时,调用setCenterPix(px,py)。会把像素坐标转为所在地图块的坐标x y。如果还在同一地图块中(记录了当前中心地图块位置),直接返回。如果移动到新的中心地图块,则继续调用setCenter( x, y ),获取显示矩形内的9个地图块。

 

function setCenter:

setCenter( x, y )需要考虑到边界时,所取的矩形就不再是x-1,y-1 ;x+1,y+1,而是靠边界的同样大小9格的矩形。比如人站在右上角 0,0时,取的矩形就是 0,0-2,2。边界时地图的移动也一样不再跟着移动了,人物还是在走动的,只是不居中了。

_tileFlag记录了上一个中心位置时所加载的9个地图块的坐标,key为x_y形式。赋给临时变量localtileFlag,然后设置_tileFlag为新的9个地图块坐标。同时调用loadTile( x, y ) 一一载入矩形内的9个地图块。在下载完数据的回调函数processData中通过ImageDecoder解码地图块。

之后再通过clearUnused()清除不在当前显示矩形内的地图块,如果设置了。

tip:localtileFlag此处似乎没用。

 

function loadTile:

loadTile( x, y )会载入x,y坐标的地图块。

它先调用getBitmap( x, y )获得地图块所在Bitmap。未生成Bitmap的地图块,将new 一个Bitmap,设置好相对于tileLayer的像素坐标,并缓存到_tileTable,返回无data的Bitmap。

如果获得的Bitmap没有data,则调用MapLoader下载地图块。

tip:此处_tileFlag[ x + "_" + y ] = true; 多此一举,直接在setCenter( x, y )中设置了就行了。



这里几个函数都是一个调用另一个,线性得调用下来。

个人趋向做成各个单独的功能性函数,放在一个总的函数中执行。1.pix坐标到块坐标的函数,2.从块X,Y 获得9个地图块矩形区域的函数。3.前后两次获取需要新加载的地图块,需要去掉的地图块。


 

 

Class MapLoader:

管理多个TileLoader下载地图块。

本来所有游戏内图片应该统一用一个管理器的,但是在切换地图后要清除原来异步还没下载完的任务。所以地图得单一使用一个管理器,每个任务也带了地图id。

frontLayer的遮盖物,也是和地图相关的。



        public static var MAX_LOADER : int = 9; //最多TileLoader数
        public var urlList:Vector.<Object>;//所有TileLoader都在下载地图块时,将新的任务放入此等待队列。当一个TileLoader下载完时会从此队列取任务。
        public var freeList:Vector.<TileLoader>;//空闲的TileLoader队列
        public var onData :Function;//下载完的回调函数

        public var mapId:int;//当前所在地图id
        private var _lastGetTime:Number;//上一次取TileLoader的时间,当过了很久没有空闲TileLoader就新建一个。

Class TileLoader:

通过UrlLoader下载地图。

Class ImageDecoder:

通过Loader解码图片。参考ActionScript显示大量外部jpg图片

原创粉丝点击