游戏开发(十) 之 lua 150行代码 实现A*寻路

因为游戏初步定为塔防类型,所以这里需要个简单的寻路算法,玩法对寻路效率要求并不高,所以就实现了个最简单的寻路算法

1.只能上下左右走

2.未做任何优化,可优化空间较大

3.初步测试, 15*15格子 什么都不摆 耗时 2 毫秒 (a*算法在没有障碍物的情况下基本上要遍历所有的路径,所以在这种情况下是最耗时的)

(蓝:start 绿:end 红:障碍 黄:路径)

代码如下,注释较多,有问题可以留言,代码文件可以直接拿到自己工程里使用

XXAStar = {}

local function removeChild(parent,child) --table 删除子
	local list = parent
	for k,v in pairs(list) do
		if v == child then
			table.remove(list,k)
			return list
		end
	end
end
local function getRoundPos(pos,closeList,openList) --寻找周围合法点,不在open 也不在close
	local px = pos.x
	local py = pos.y
	local list = {
		{x=px	,y=py+1}, 	--上
		{x=px-1	,y=py},		--左
		{x=px+1	,y=py},		--右
		{x=px	,y=py-1},	--下
	}
	local returnList = {}
	for _,v in pairs(list) do
		if v.x >= 1 and v.y >= 1 then --地图范围内
			if v.x <= XXAStar.size.width and v.y <= XXAStar.size.height then
				if closeList[v.x][v.y] == 0 then --排除closelist
					local isInOpen = nil
					for _,v1 in pairs(openList) do  --排除open列表
						if v1.x == v.x and v1.y == v.y then
							isInOpen = v1
						end
					end
					if isInOpen == nil then
						table.insert( returnList,v )
					else --如果在open中 需要更新查看F是否更小
						local newG = pos.g + (math.abs(pos.x - v.x) + math.abs(pos.y - v.y) )
						if newG < isInOpen.g then
							isInOpen.parent = pos
							isInOpen.g = newG
						end
					end
				end
			end
		end
	end
	return returnList
end
local function countFGH(startpos,endpos,list) --计算 FGH
	--  G = 从 起点   移动到 指定点
	--  H = 从 指定点 移动到 终点
	--  F = G + H
	local minF = nil
	for _,v in pairs(list) do
		if v.g == nil then
			v.g = math.abs(startpos.x - v.x) + math.abs(startpos.y - v.y)
			v.h = math.abs(v.x - endpos.x) + math.abs(v.y - endpos.y)
			v.f = v.g+v.h
		end
		if minF == nil then
			minF = v
		end
		
		if v.f < minF.f then
			minF = v
		end
	end
	return minF
end
function XXAStar:init()
	--寻路二维数组
	self.size = {width=0,height=0}	--尺寸
	self.pathList = {} 				--路径数据
	self.startPos = nil				--起始点
	self.endPos = nil				--终止点
	self.openList = {}				
	self.closeList = {}
end
function XXAStar:getPath(width,height,startpos,endpos,closeList)
	--初始化
	self:init()
	self.size.width = width
	self.size.height = height
	for j=1,width,1 do
		self.pathList[j] = {}
		self.closeList[j] = {}
		for i=1,height,1 do
			self.pathList[j][i] = { type = 0 }
			self.closeList[j][i] = 0
		end
	end
	self.startPos = startpos
	self.endPos = endpos
	
	--1.起始点加入到open列表中
	table.insert(self.openList,self.startPos)
	--2.将障碍物放到close列表
	for k,v in pairs(closeList) do
		self.pathList[v.x][v.y].type = 1
		self.closeList[v.x][v.y] = 1
	end
	--8.回溯路径
	local resultList = {}
	local lastPos = self:countPath(self.startPos)
	if lastPos == nil then 
		return {}
	end
	while(true)
	do
		if lastPos.parent == nil then
			break
		end
		if lastPos.parent.x == self.startPos.x and lastPos.parent.y == self.startPos.y then
			break
		end
		
		table.insert( resultList,{x=lastPos.parent.x,y=lastPos.parent.y} )
		lastPos = lastPos.parent
	end
	
	
	return resultList
end
function XXAStar:countPath( firstPos )
	--3.根据起点寻找周围相邻点,排除障碍物
	local roundlist = getRoundPos(firstPos,self.closeList,self.openList)
	--4.把起点从openlist中移除,加入到closelist
	self.openList = removeChild(self.openList,firstPos)
	self.closeList[firstPos.x][firstPos.y] = firstPos
	--5.找到的点加入到openlist
	for _,v in pairs(roundlist) do
		v.parent = firstPos
		table.insert(self.openList,v)
		--6 查看是否找到了终点
		if v.x == self.endPos.x and v.y == self.endPos.y then
			return v
		end
	end
	--7.计算 FGH 并得到f最小的值
	local minF = countFGH(self.startPos,self.endPos,self.openList)
	if minF == nil then
		--已经没有未遍历的点了
		return nil
	else
		return self:countPath(minF)
	end
end

使用示例:

--[[
function XXAStar:getPath(width,height,startpos,endpos,closeList)
--width,height    尺寸
--startpos        起始点
--endpos          终止点
--closeList       障碍物
]]--

local usePosList = XXAStar:getPath(15,15,{x=1,y=1},{x=15,y=15},closeList)
if table.getn(usePosList) == 0 then
	XXLog("没有找到路径")
else
    --TODO
    --usePosList 路径的坐标点集合
end

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值