So, I want to find the best way to make a hostile npc, and I was wondering if using PathFindingService’s way is the best way, or should I just do the simple Humanoid:MoveTo() instead of the whole complex algorithm.
Edit: The reason why I asked this is because I want the NPC to jump if needed, so the players don’t just cheese it.
Pathfinding and MoveTo are two completely different things , If you wanted ‘complex’ player like movements, you’d use Pathfinding the calculate a path which you can use MoveTo() to each way point. You can always just let it follow in the players position, but then if the player runs behind a obstacle, the NPC will become useless
Yeah, I know, which is why I want to try and do the Pathfind. I don’t want them to lure it to a hill where you need to jump and then jump over it while the NPC’s stuck there.
Well, the problem is it’s an RPG. I can ask the main guy to probably split it. Should I do the Path:Create() from PathFinding Service so that it can jump or is there an easier way?
Pathfinding doesn’t provide any jumping mechanism, It takes a parameter AgentCanJump which defaults to true, which I assume just calculates the path while keeping in consideration it can jump to certain areas. You’ll need to create your jumping system which should be very easy
local HasJumped = false;
game:GetService("RunService").RenderStepped:Connect(function()
local JumpRay = Ray.new(NPCHumanRP.CFrame.p, NPCHumanRP.CFrame.LookVector.Unit * 5);
local hit = workspace:FindPartOnRayWithIgnoreList(JumpRay, {NPC}) --<This is deprecated I think, but I never used RaycastParams so I'll use this for now
if(hit)then
if not (HasJumped) then
HasJumped = true;
NPCHuman.Jumping = true;wait(3);HasJumped=false;
end;
end;
end)
the PathfindingService can help you here and has everything you need to make a smart hostile npc. first, lets create a path using the PathfindingService
local pathfinding_service = game:GetService('PathfindingService');
local human = workspace.Weeabus;
local enemy = workspace.Zombie;
local path_arguments = {
AgentCanJump = true; -- this tells ::CreatePath that our npc can jump
};
local path_to_human = pathfinding_service:CreatePath(path_arguments);
now, we must use the method ::ComputeAsync to find the waypoints of the path. each waypoint is a position that the npc needs to walk to in order to reach its destination.
path_to_human:ComputeAsync(enemy.HumanoidRootPart.Position, human.HumanoidRootPart.Position);
local waypoints = path_to_human:GetWaypoints();
just a reminder that ::ComputeAsync yields the current thread until the path is calculated
in order for the npc to walk along the path we just computed, we have to iterate through our waypoints and have the npc walk to each
for _, waypoint in next, waypoints do
-- detect for jumps
if waypoint.Action == Enum.PathWaypointAction.Jump then
enemy.Humanoid:ChangeState(Enum.HumanoidStateType.Jumping);
end;
-- move npc to the next waypoint
enemy.Humanoid:MoveTo(waypoint.Position);
-- we're using .MoveToFinished::Wait here, which yields the thread until the humanoid is finished walking
enemy.Humanoid.MoveToFinished:Wait();
end;
The event that fires when a property changes DOESN’T fire when the engine changes it itself. This means the npc would only re-calculate the path if the HumanoidRootPart’s position was set by a LocalScript. That could be fixed by creating a function that runs every heartbeat checking if the position has changed.
local initialPosition = targetObject.HumanoidRootPart.Position
FollowEvent = RunService.Heartbeat:Connect(function()
if targetObject.HumanoidRootPart.Position ~= initialPosition then
FollowTarget(targetObject)
end
end)
However, even if that got fixed, you still have to consider that computing a path takes a few milliseconds, which means the character would either stop until the new path is calculated (player moved while npc reached waypoint), or go back to the initial position of the new path (the path was calculated with the character being a few steps behind in mind).
This can be solved by calculating the new path the character is moving to with the current waypoint, while the character is moving to it, and waiting until the character has has reached that waypoint to follow that path.