I’m a little new to Lua, and I’m not fairly sure how to write to the standard of Lua. But I wrote a pathfinding service in C# once, and I’ve nearly replicated the entire script. From creating the grid to creating my heap.
I’m hoping someone here today, can help me figure out why my main loop is repeating forever and never really breaking to find the end path. Here is the main find path function
function PathFinding:FindPath(StartPos, EndPos)
local waypoints = {}
local pathSuccess = false
local start_node = Grid:NodeFromWorldPosition(StartPos)
local target_node = Grid:NodeFromWorldPosition(EndPos)
start_node.parent = start_node
print("TargetNode walkable?: ", target_node.walkable, " StartNode walkable: ", start_node.walkable)
if(start_node.walkable and target_node.walkable) then
local openset = Heap.new()
local closedset = Heap:new()
openset:Add(start_node)
start_node = openset.Items[openset.currentcount - 1]
local count = 1
while (openset.currentcount > 1) do
print("before pop: ", openset.currentcount)
local currentNode = openset:RemoveFirst()
print("after pop: ", openset.currentcount)
closedset:Add(currentNode)
currentNode = openset.Items[closedset.currentcount -1]
if(currentNode:Equals(target_node)== true) then
pathSuccess = true
print("broke path. cause same node.")
break
end
for i,v in pairs(Grid:GetNeighbours(currentNode)) do
if(v.walkable == false or closedset:Contains(v) == true) then
else
local MovementCostToNeighbour = currentNode.gcost + GetDistance(currentNode, v) + v.movementPenalty
if(MovementCostToNeighbour < v.gcost or openset:Contains(v) == false) then
v.gcost = MovementCostToNeighbour
v.hcost = GetDistance(v, target_node)
v.fcost = v.gcost + v.hcost
v.parent = currentNode
if(openset:Contains(v) == false) then
openset:Add(v)
else
openset:SortUp(v)
end
count = count + 1;
end
end
end
end
end
if(pathSuccess == true) then
print("Retracing path.")
waypoints = RetracPath(start_node,target_node)
pathSuccess = (waypoints ~= nil and #waypoints > 1)
end
if(pathSuccess) then
print("Waypoints to create is :", #waypoints)
else
print("No path available.")
end
end
And here is my fairly useful heap class replication (module)
local Heap = {}
Heap.__index = Heap
function Heap.new()
local heap = {}
setmetatable(heap, Heap)
heap.Items = {}
heap.currentcount = 1
return heap
end
function Heap:RemoveFirst()
local first = self.Items[1]
self.currentcount = self.currentcount - 1
self.Items[1] = self.Items[self.currentcount]
self.Items[1].heapIndex = 1
self:SortDown(self.Items[1])
print(first)
return first
end
function Heap:Add(Node)
Node.heapIndex = self.currentcount
self.Items[Node.heapIndex] = Node
self.currentcount = self.currentcount + 1
self:SortUp(Node)
end
function Heap:SortUp(Node)
if(Node.heapIndex ~= 1) then
local parent = (Node.heapIndex) / 2
while (true) do
local parentItem = self.Items[parent]
if(parentItem == nil or Node:CompareTo(parentItem) > 0) then
self:Swap(Node, parentItem)
else
break;
end
parent = (Node.heapIndex) / 2
end
end
end
function Heap:SortDown(Node)
while (true) do
local childLeftIndex = Node.heapIndex * 2
local childRightIndex = Node.heapIndex * 2 + 1
local swapId = 0
if(childLeftIndex < self.currentcount) then
swapId = childLeftIndex
if(childRightIndex < self.currentcount) then
if(self.Items[childLeftIndex]:CompareTo(self.Items[childRightIndex]) < 0) then
swapId = childRightIndex
end
end
if (Node:CompareTo(self.Items[swapId]) < 0) then
self:Swap(Node, self.Items[swapId])
else
return
end
else
return
end
end
end
function Heap:Contains(Node)
for _,v in pairs (self.Items) do
if(v:Equals(Node)) then
return true
end
end
return false
end
function Heap:Swap(NodeA, NodeB)
if(NodeA == nil or NodeB == nil) then
return
end
self.Items[NodeA.heapIndex] = NodeB
self.Items[NodeB.heapIndex] = NodeA
local AIndex = NodeA.heapIndex
NodeA.heapIndex = NodeB.heapIndex
NodeB.heapIndex = AIndex
end
return Heap
Here is my Node:Equals()
function Node:Equals(Node)
if(self.gridX == Node.gridX and self.gridY == Node.gridY and self.fcost == Node.fcost and self.gcost == Node.gcost and self.hcost == Node.hcost) then
return true
end
return false
end