Flying npcs will already have a flight height variable in npc which moves the npc up, some distance up from ground. And a function to check the distance to ground to reduce or boost the flight force.
So think them as seperate.
What i do is calculate the path from the ground below. And if there is obstacle in front of npc, because that your npc is not on the ground, you can get the height of the part and move the npc up or down with increasing/lowering the force, whichever fits your case.
You can do that with only 1 raycast to front that can run on average every .5 second. No haul at all. You can also check up direction to limit the flight height but flight height function already handles that so the trick is just moving them based on ground below with some front obstacle checks.
well I can tell you why nodes when you debug them on the size 3 and why its the best option I could do. Is because 5 or 4 (maybe) will always not find a solution around walls. so I just use 3 and not 0-2. That was in my code.
The target part is too high and since the path is 3d the next waypoint is at the same z and x position but higher Y so that makes the npc never reach the node because the node is above
Hello! First of all, thank you for sharing this module!
May I ask why you used Manhattan distance for the heuristic instead of Euclidean? I found that changing it to Euclidean made it faster because it is 3D area rather than 2D and grid based. (Things can move diagonally)
local function Heuristic(a, b)
return (a - b).Magnitude
end
Also, as @AndiArbeitlol pointed out earlier, there seems to be timeouts occurring whenever I place the part in a specific area of the wall. You can replicate this by simply putting the part right about here:
EDIT: Nevermind, after further testing, the timeout problem persists. It just happens less often.
I think I fixed the timeout problem. I just changed the value of the radius of the check in the AStar function to 1:
local function AStar(start, goal)
start = roundToStep(start)
goal = roundToStep(goal)
local openSet = PriorityQueue.new()
openSet:Push(start, 0)
local cameFrom = {}
local gScore = {[start] = 0}
local fScore = {[start] = Heuristic(start, goal)}
local inPart = #workspace:getPartBoundsInRadius(goal, 1, oOverlapParams) > 0
--^ this one
if inPart then
return
end
while not openSet:IsEmpty() do
local current = openSet:Pop()
if current == goal then
local totalPath = {current}
while cameFrom[current] do
current = cameFrom[current]
table.insert(totalPath, 1, current)
end
return totalPath
end
for _, neighbor in pairs(GetNeighbors(current)) do
local tentative_gScore = gScore[current] + (neighbor - current).Magnitude
if not gScore[neighbor] or tentative_gScore < gScore[neighbor] then
cameFrom[neighbor] = current
gScore[neighbor] = tentative_gScore
fScore[neighbor] = gScore[neighbor] + Heuristic(neighbor, goal)
openSet:Push(neighbor, fScore[neighbor])
end
end
end
return {}
end
The only noticeable limitation so far is that the NPC sometimes doesnât move at all when the part is a bit too close to the wall.
The time out thing happens because the first and the last node should be checked if its InPart bounds. I forgot to put the goal and start node to be #workspace:getPartBoundsInRadius