Weird Npc Movement Animations With PathFindingService

Hi, Im creating a game and using the “PathFindingService” to move npcs from 1 point to another but the
walk animations are weird.

Here is the code I use,

function CreatePath(Humanoid,Target)
	local Parms = 
		{
			AgentHeight = 3.5,
			AgentRadius = 2,
			AgentCanJump = true
		}
	local Path = PathFindingService:CreatePath(Parms)
	Path:ComputeAsync(Humanoid.Parent.PrimaryPart.Position,Target.Position)
	if Path.Status == Enum.PathStatus.Success then
		local WayPoints = Path:GetWaypoints()
		return Path,WayPoints
	end
end

script.Move.Event:Connect(function(Humanoid:Humanoid,Target,Action)
	if not Target then return end
	local Path,Waypoints = CreatePath(Humanoid,Target)
	if not Path or not Waypoints then return end
	
	for _, Point in ipairs(Waypoints) do
		if Point.Action == Enum.PathWaypointAction.Jump then
			Humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
		end	
		Humanoid:MoveTo(Point.Position)
		Humanoid.MoveToFinished:Wait(2)
	end
end)

Anyways to make the running animations smooth? Thanks :slight_smile:

2 Likes

this is probably not the solution, but in the MoveToFinished try using something smaller than 2, like just leave it was Wait()

1 Like

The reason that this is not smooth is because when you’re close to your NPCs the server will pass NetworkOwnership over to the nearby player. This is a problem because the server is waiting for the moveto to complete, but the client (player) is responsible for letting the server know. This means that anything the humanoid does is subject to network latency (hence the delay).

A really simple fix for this is to set the HumanoidRootPart or the Humanoid’s RootPart (whatever that may be)'s network ownership to to nil via Part:SetNetworkOwner(nil) See BasePart | Roblox Creator Documentation for more details.

The idea here is that if we force no network ownership of the Humanoid’s root part then the network ownership cannot change. This will ensure that your characters move to the next waypoint nearly instantly.

There are some optimizations with the game being able to be handed off to the various players so you may want to look into that down the road. But this should at least help you to understand the problem.

1 Like

You can use TweenService to interpolate the humanoid’s position between each waypoint in the path. This will make it have a smoother look.

Here’s an example of how you can use TweenService to do so:

-- Import TweenService
local TweenService = game:GetService("TweenService")

-- Define function to move the humanoid
function CreatePath(Humanoid, Target)
    local Parms = {
        AgentHeight = 3.5,
        AgentRadius = 2,
        AgentCanJump = true
    }
    local Path = PathFindingService:CreatePath(Parms)
    Path:ComputeAsync(Humanoid.Parent.PrimaryPart.Position, Target.Position)
    if Path.Status == Enum.PathStatus.Success then
        local WayPoints = Path:GetWaypoints()
        for i, Point in ipairs(WayPoints) do
            local MoveTween = TweenService:Create(Humanoid.Parent.PrimaryPart, TweenInfo.new(1), {
                CFrame = CFrame.new(Point.Position)
            })
            MoveTween:Play()
            if Point.Action == Enum.PathWaypointAction.Jump then
                Humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
            end
            MoveTween.Completed:Wait()
        end
    end
end

-- Connect the Move event
script.Move.Event:Connect(function(Humanoid, Target, Action)
    if not Target then
        return
    end
    CreatePath(Humanoid, Target)
end)
1 Like

Found The solution few hors ago, sorry forgot to update here.

If anyone is wondering, the solution is to only use waypoints that are turns. Here Is a function I used to solve this.
just pass the full waypoints list and it will filter them out.

function GetTunedPath(Path)
	
	if Path == nil then return {} end
	
	local WayPoints = Path:GetWaypoints()
	local CurrentDifference = Vector2.new(0,0)
	
	local ImportantWaypoints = {}
	
	for i, Waypoint in ipairs(WayPoints) do
		if i == #WayPoints then table.insert(ImportantWaypoints,Waypoint) continue end
		if i == 1 then table.insert(ImportantWaypoints,Waypoint) continue end
		
		local CurrentPos = Waypoint.Position
		local NextPos = WayPoints[i+1].Position
		
		local Difference = (Vector2.new(CurrentPos.X,CurrentPos.Z) - Vector2.new(NextPos.X,NextPos.Z))
		
		if (CurrentDifference - Difference).Magnitude > 0.2 then
			table.insert(ImportantWaypoints,Waypoint)
		end
		CurrentDifference = Difference
	end
	return ImportantWaypoints
end
3 Likes

Haven’t tested this but you might be right

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.