So, I have created my own pathfinding system that uses Roblox’s pathfinding service. I have noticed that when the path is computed once the agent’s path is correct with respect to the agent’s radius; however, if the path is computed again a few seconds later, the agent has a tendency to run into walls. I am assuming that the geometry of the agent isn’t able to be compared the environment accurately when it is moving.
This is very obvious when the target is a player’s position. A snippet of my code is below to show the underlying logic.
function EasyPath:run(destination)
assert(typeof(destination) == "Vector3", "Destination must be a Vector3.")
-- Do not recompute the path if the destination is the same.
if destination ~= self._previousDestination then
local timeSinceComputed = DateTime.now().UnixTimestampMillis - self._lastComputed
-- Do not recompute the path if the path is currently being computed or it was recently computed.
if not self._isComputing and timeSinceComputed > EasyPath.COMPUTE_DELAY then
self._isComputing = true
local computationSuccess, errorMessage = pcall(function()
local characterPosition = self._character.PrimaryPart.Position
self._path:ComputeAsync(characterPosition, destination)
end)
local pathSuccess = self._path.Status == Enum.PathStatus.Success
if not computationSuccess or not pathSuccess then
self._nextWaypointIndex = -1
self._events.PathErrored:Fire()
else
if self._connections["BlockedConnection"] then
self._connections["BlockedConnection"]:Disconnect()
self._connections["BlockedConnection"] = nil
end
self._previousDestination = destination
self._connections["BlockedConnection"] = self._path.Blocked:Connect(function(blockedWaypointIndex)
-- Check if the obstacle is further down the path.
if blockedWaypointIndex >= self._nextWaypointIndex then
self._connections["BlockedConnection"]:Disconnect()
self._connections["BlockedConnection"] = nil
self._events.PathBlocked:Fire()
self._previousDestination = nil -- Allow for recomputations for this destination.
-- The destination may not have changed, but the path has been blocked so removing
-- the previous destination will allow for a path recomputation.
end
end)
local waypoints = self._path:GetWaypoints()
if waypoints and #waypoints > 2 then
self._waypoints = waypoints
self._nextWaypointIndex = 2
self._lastWaypointTimestamp = os.time()
if self._visualize then
for i = #self._visibleWaypoints, 1, -1 do
self._visibleWaypoints[i]:Destroy()
self._visibleWaypoints[i] = nil
end
for i = 2, #self._waypoints do
local visibleWaypoint = Instance.new("Part")
visibleWaypoint.Size = Vector3.one
visibleWaypoint.Position = self._waypoints[i].Position
visibleWaypoint.Anchored = true
visibleWaypoint.Material = Enum.Material.SmoothPlastic
visibleWaypoint.Shape = Enum.PartType.Ball
visibleWaypoint.BrickColor = BrickColor.White()
visibleWaypoint.CanCollide = false
visibleWaypoint.Parent = workspace
table.insert(self._visibleWaypoints, visibleWaypoint)
end
end
end
end
self._lastComputed = DateTime.now().UnixTimestampMillis
self._isComputing = false
end
end
local waypoint = self._waypoints[self._nextWaypointIndex]
if waypoint then
-- If the agent is not on the ground reset the waypoint timestamp.
-- The agent is most likely climbing and the next waypoint is far away.
if self._humanoid.FloorMaterial == Enum.Material.Air then
self._lastWaypointTimestamp = os.time()
end
local timeSinceLastWaypoint = os.time() - self._lastWaypointTimestamp
if timeSinceLastWaypoint > EasyPath.STUCK_TIME_LIMIT then
self._nextWaypointIndex = -1
self._events.AgentStuck:Fire()
else
self._humanoid:MoveTo(waypoint.Position)
end
end
end
If the destination is changed and an obstacle is in front of the AI, the AI bumps into the obstacle ignoring its preset radius. I was wondering if anyone else has run into this problem and has designed a solution.
I am aware that I can generate raycasts to ensure that the next waypoint isn’t hitting an obstacle within the agent’s radius, but that defeats the entire purpose of pathfinding.