max_deep为最大遍历次数,当超过该次数时,以当前遍历到的路线为最终路线,这样就改变了目标点的位置
既然需要时间,那就等吧,别阻塞当前程序就行
并不好用
一张地图上有几个岛(岛与岛之间没有陆地连接),其余都是海,单位无法移动到海中,只能在陆地上移动,A岛的单位自然也无法移动到B岛
这种情况较好解决,只要在游戏初始化好前(包括制作地图时)标记好每个grid属于A岛、B岛还是海。当目标点为属于海或其他岛时,该点则不可达。
如果策划非要到这个点,
接上,一个岛上有好几个单位围成一个环,中间有几块空地没有单位,这些空地就是无法到达的地方,这个问题我还没实现过,只有思路
可以在一帧当中的恰当时机,遍历所有单位生成环,在起始点和目标点连一条线段,线段与环的交点情况:
如果一个环与线段有连续的交点,将这些交点视为一个交点
如果一个环与线段有连续的交点,该段交点的两个端点,如果它们附近不在线段上的点都在线段同一侧,则将该段交点视为零个交点,否则视为一个交点
可达
默认是grid map
这里需要用到一些游戏逻辑层的东西
坦克只能在陆地上行走,船只能在上面行走,直升机可以在任何地方行走,这几种单位所用的移动引擎各不相同
一张grid map 地形图当中可能由:山、丘陵、河流、海
那么,对于坦克的引擎的移动地图,就要从地形图当中映射
def geo_mapper(v):
# 9999 表示不可到达
table = {山:1, 丘陵:1, 河流: 9999, 海: 9999}
return table.get(v)
得出一张坦克引擎的移动地图,a*就是依据这张地图来进行计算的
依据上面的mapper,坦克可以移动岛丘陵上,但当该丘陵上有一个单位时,由于一个grid最多放一个单位,该坦克就无法移动到丘陵上
这时可以再加一个单位图层,用来标记单位的位置,可以规定:0表示没有单位,其他值表示有单位,添加引擎对单位地图的更新函数
def unit_mapper(v):
return 0 if v == 0 else 9999
当地形图更改、单位移动、单位创建和单位摧毁都会局部更新移动地图,这个步骤不怎么消耗性能
def refresh_move_map(loc):
move_map[loc[1], loc[0]] = geo_mapper(geo_map[loc[1], loc[0]])
unit_map_v = unit_map[loc[1], loc[0]]
if unit_map_v != 0:
move_map[loc[1], loc[0]] = unit_mapper(unit_map_v)
由于每个grid最多放一个单位,当一个单位想从A点移动到它的邻居B点时,必须先将B点占有
(同时也可以将原来占有的A点释放
)。
有时移动地图在不断变化,单位的移动路线也需要在恰当的时机(比如:a*寻路前提下占有
失败时)自动更新
center_loc = (average(x), average(y))
target_loc
target_loc
就行了,单位卡住一段时间后将视为到达目标,退出寻路,下面写的是不用流场而用a*+碰撞时(无法到达nextPoint)更新时的方案各单位与center_loc
的差值(offset = loc[0]-center_loc[0], loc[1]-center_loc[1]
)就是改单位目标点与target_loc
的差值
这样算出的目标点可能是不可移动的区域,方案二解决了这个问题
以target_loc
为起始点广度优先遍历出几个可移动(而且要可到达)的点,数量与单位的数量一致,先把它们称为候选目标点吧。离target_loc
最远的单位应该移动到候选目标点中离center_loc
最近的点上
如果在一帧中对组中所有单位进行寻路,会出现以下效果
![]() |
![]() |
![]() |
![]() |
所有引擎的移动地图的值全为1,不用管贴图
先看图1 图2
中间的蓝色坦克寻不到路,左边的两辆火箭车和上面的火箭车多走了一格
依据上面的单位移动相关内容,单位寻不到路时可以等一段时间再寻一次。这样就实现了基本的功能
目前我的优化方案效果并不明显:
离target_loc
越远的单位将等待更长的时间才开始寻路并移动,然后中间的坦克就跑到图3 中的左边去了,它打算绕个弯到达他的目标点
图4是其他单位都停止移动,左边蓝色坦克找不到路,乱窜
还是要用流场
构造流场时,会用广度优先将整张地图或整个岛遍历一遍得出一个矩阵(先这样称吧)群组中的所有单位都用这个流场来计算下一个移动点的位置。
当地图过大时(10000*10000),python创建一个numpy.ndarray就需要大概0.1s,pythonfor pass
一亿次大概要3s。一张10000*10000的numpy.ndarray占256MB。性能和内存都要优化
既然耗时,那就放到独立的线程中去吧,在计算出结果之前,单位就先卡在那里(或者用a*+max_deep算一条短点的路线给它走走)…似乎没有内存优化
class BlockedNdarray:
def __init__(self, ...):
self.mapSize = ... # 移动地图的大小
self.blockMapSize = ... # 块的数量
self.blockSize = ... # 块的大小
self.storage: Dict[Tuple[int, int], numpy.ndarray] = {} # 存放块
def __setitem__(self, key, value):
...
def __getitem__(self, item):
...
这个数据结构是用来省内存的
for u in group