(1)这些东西如何在场景中摆放:地面,围墙,小窝,人,未解锁区域等等。
(2)地图大小限制和地图最小单位的大小等因素。
(3)我们需要保存的数据有哪些。
当时的解决方法:
1)幻想的地图层,把地图分成好几块加载的。策划根据地图编辑器生成了对应的文件,底层加载地图的时候会加载这些地图。但是家园地图是一个全新的地图。而且不是地图编辑器编辑的。但是底层有不提供修改支持。因此原先那几块地图就用了空的文件进行修改。相当于进入这个场景的时候,是一个黑的世界。
2)地面,围墙,小窝,人,未解锁区域等,所有的家园场景的东西,我们通过不同的层加载到场景里。写了一个HomeMapDrawObject.lua下面是它的初始化函数。
下面是HomeMapPiece.lua
幻想的原先的地图的逻辑块大小是60*30代表一个格子。所有如果在原先基础上进行寻路和拾取就变成了60*120,120*240的地图。
当时美术那边提出说,要使用菱形的地板,从美术角度来说,看起来的效果会好一些。最后使用的方案是这样的:
图中的坐标系是服务器的坐标系,一个菱形面积等于二个坐标系格子面积。这样的摆放,通过观察会发现一些规律。
规律1:例如第一排的点A,B他们的坐标分表是(1,1),(3,1);第二排的点C,D他们的坐标分别是(2,2),(4,2);x,y满足奇偶性。
因为我们摆放的点不存在例如(2,3),(5,6)类似这样的点。
规律2:因为我们需要进行拾取判定,我们的点击可能落在任意坐标系格子内。但是可分成8种情况进行讨论(一个菱形区域中)。
下面讨论其中的1种情况。
1.例如图中E点,根据图中可以看出,当我们点击E点的时候,实际上我们要算出,当前我们点击的是(7,3)这个点的菱形区域。
E点的周围4个点分别是(min_x,min_y),(min_x,max_y),(max_x,min_y),(max_x,max_y)。(这些点都可以通过e点向上取整或者向下取整得出)
这4个点中的一个点就是当前我们想求出的菱形区域的中心点。
但是此时,连接的是(min_x,max_y),(max_x,min_y)这两个点,构成了菱形的一条边。
经过观察,我们知道
E点的min_x=6,max_y=3,和E点相类的点F,它的情况是min_x=7,max_y=4,可再根据几个点进行观察总结。
我们可以得出
当min_x,max_y不是同奇数或者同偶数的时候,连接的是(min_x,max_y),(max_x,min_y)这两个点,构成了菱形的一条边。
当min_x,max_y是同奇数或者同偶数的时候,连接的是(min_x,min_y),(max_x,max_y)这两个点,构成了菱形的一条边。
2.由于1.得出的判断,我们可以排除2个点(因为已经构成了菱形的一条边了),剩下2个点,我们要如何判断呢
使用线性规划,根据1.求出的这2个点,我们构建直线,判断E点是在这条线段上方还说下方。这样,我们就可以得出需要找到的那个点了。
剩下的几种情况类似,同理进行讨论。
通过这样,我们就可以进行对拾取和放置场景碎片(草地,小窝等)进行操作。
4)我们需要保存和维护的数据有哪些呢?
1self.pieceList={}--家园碎片对象(草地上的东西等)2self.map={}--家园地图3self.roadMap={}--可行走的区域维护4self.shadowMap={}--阴影区(人行走在这个区域会调整透明度)5self.tmpList={}--临时展示的区域6self.lockList={}--解锁格子信息
2.拾取问题。
如果通过模拟点击能判断到是具体哪一个地图最小元素。
下面代码是通过服务端逻辑坐标,计算出当前点击的是哪一个地图逻辑块的中心位置的坐标。
1functionHomeController:homePiecePick(location)2localpos=HandleRenderUnit:ViewToWorld(location)3pos=HandleRenderUnit:WorldToLogic(pos)--服务端的逻辑坐标4localscaleSize=HomeMapManager:getInstance():getScaleSize()--缩放比5localhomeLogicX,homeLogicY=self.handleTerrainHandler:ToHomeMapPos(pos.x,pos.y,scaleSize)67self:modelHander(homeLogicX,homeLogicY)8endViewCode
3.寻路问题。
(1)使用一个怎么样的寻路算法。迪杰斯特拉,或者A*,或者其他方式。
(2)如何维护一个动态地图。
首先要解决的是一个动态维护的过程。其实按照前面的铺垫,这个动态地图的维护并不难,等同于维护一个可行走区域。当加入一个逻辑快的时候,
我们会对这个数据进行分析,加入的是什么。是草地,还说小窝或者是其他什么东西。这里就可以需要添加一个判定函数,这个东西是行走有否。
然后分别对这个区域,和这个区域的相邻区域进行设置。这样加入和删除一个地图里的元素,我们都可以动态处理。
下面是动态删减的维护代码,其中SCENE_DIRECTION是当前地图最小格子,周围8个方向的table
原先使用的方案是迪杰斯特拉。刚刚说起,这个最小的地图是3600*3600,然后根据我们铺的菱形他的大小是120*60的。所以最小的行走地图是
30*60=1800个点。但是大多数情况下这个地图并不是稀疏的地图。极端情况可能存在路径是1800*8个方向=14400条路径。每一次行走,我们需要形成1800个点的最小生成树,这样消耗比较大。这仅仅是3600*3600的地图。后面扩展成7200*7200,会更明显。
A*算法。详细的这里不介绍了。详细请谷歌百度一下。
A*的实现
4.其他问题。
因为家园场景中对象太多,进入场景的时候,一次创建会卡帧。体验很不好。有一台比较老的安卓机子,等了好久才加载完这个场景。后面采取的方式是分帧加载。一帧创建几个对象。然后在x秒后能够完成创建完这个场景。这里的x需要各种尝试,应该多大,肯定不行,玩家进入场景的时候明显感觉到到周围是黑色的。如果过小也不行,代表一帧需要加载的数量太多,会卡帧。而且不同的手机性能不同,也会有不一样的效果。