虚拟实验室引擎的开发和实现(九、地图和人物)
虚拟实验室引擎的需求之一就是人物漫游功能:即用户操纵人物在场景中移动。这就意味着在开发引擎的时候,要考虑到场景的某些地方,人物是无法移动到上面去的(例如河流,花坛)。我们还需要在场景上做一些“手脚”,来标记哪些区域允许移动,哪些区域不允许移动。例如,下图中,蓝色部分(用1表示)的区域是允许用户移动的区域,而红色(用0表示)则是不允许。
VGridPlace
扩展VPlace
我扩展了VPlace类,增添了一些变量和方法:
下表给出了这些属性或方法的定义及说明:
属性名 | 类型 | 说明 |
Value | Int32[] | 地图每一个网格的值,1表示可行,0表示不可通行 |
PlaceWidth | Int32 | 地图横向有几个格,PlaceWidth=Width/GridSize |
PlaceHeight | Int32 | 地图纵向有几个格,PlaceHeight=Height/GridSize |
GridSize | Int32 | 每一个格的大小,默认为20像素 |
Person | VPerson | 用户操作的人物 |
Persons | VPerson集合 | 所有人物,包括用户操作的人物(1个)和其他人物 |
AStar | AStar | 寻路算法辅助实现,详见寻路 |
方法名 | 说明 |
FindPath(Point from,Point to) | 是用A*寻路算法找到从点from到点to的最短路径 |
AddPerson (VPerson person) | 添加角色 |
RemovePerson (VPerson person) | 删除角色 |
扩展VPlace的属性文件
在VPlace属性文件基础上,添加一个Attribute:gridsize,和GridSize对应;添加一个Element:mapdata,和Value对应。扩展后的属性文件如下:
<gridplace name='中大商业街' width='1700' height='1200' centerx='0' centery='0' x='0' y='0' file='engine2/sysu/sysu.xml' gridsize='20'> <mapdata><!-- Map Data --></mapdata> </gridplace>
压缩mapdata
在地图中,网格的值只有两种情况(1-可行走,0-不可行走),如果在XML属性文件中用一个整型来表示这个地图中一个网格的值,在传输过程中会带来很大的数据开销(例如上面的属性文件,一共有1700/20*1200/20=5950个格,如果按照0,0,1,……1,1的形式来保存,则需要5950+5949=11899个字节)。我采用以下形式来压缩这些数据:用一个整数(32位)来表示相邻的32个格的值(例如相邻的32个格值分别为1,1,1,0,1,0,……,0,0,1,那么该整数的二进制为111010……001,最多需要10个字节,4294967295=11111……111,因此,按照上面的属性文件,最多只需要5950/32+1+5950/32=371个字节)。
解压缩算法如下:
//uint compress 为需要解压缩的32位整数 var mask = 0x80000000; for (int j = 0; j < 32; j++) { if ((compress & mask) == 0) { Value[j] = 0; } else { Value[j] = 1; } mask >>= 1; }
VPerson和UIPerson
VPerson继承自VItem,表示虚拟实验是中的人物角色;UIPerson继承自UIItem,是VPerson的表现形式。
当鼠标在地图上某点点击时,虚拟实验室引擎会将鼠标点击的位置转换成目标网格,然后计算出用户控制的人物所在的网格和目标网格之间的最短路径(调用VPlace的FindPath方法),如果该路径存在,则将人物移动到目标网格。
VPerson的ActionID
约定用以下ActionID来表示一个人物角色在引擎中的动做:
ActionID | 动作描述 |
faceright | 人物面向右侧站立 |
facerightdown | 人物面向右下站立 |
facedown | 人物面向下方站立 |
faceleftdown | 人物面向左下站立 |
faceleft | 人物面向左侧站立 |
faceleftup | 人物面向左上站立 |
faceup | 人物面向上方站立 |
facerightup | 人物面向右上站立 |
moveright | 人物面向右侧移动 |
moverightdown | 人物面向右下移动 |
movedown | 人物面向下方移动 |
moveleftdown | 人物面向左下移动 |
moveleft | 人物面向左侧移动 |
moveleftup | 人物面向左上移动 |
moveup | 人物面向上方移动 |
moverightup | 人物面向右上移动 |
寻路
在处理人物在移动时,采用了A*寻路算法来寻找最短路径,关于A*寻路算法,请参考:A* Pathfinding for Beginners