I’ve been trying to script a stupid pathfinding system for like 10 hours now, and I’m getting somewhat close.
Right now I’m using the script from the Character Pathfinding documentation, and I’m having problems making the NPC pathfinding go down from stuff
local char = script.Parent;
local root = char:WaitForChild("HumanoidRootPart");
local torso = char:WaitForChild("Torso");
local hum = char:WaitForChild("Humanoid");
local statusEffects = hum:WaitForChild("StatusEffects");
local health = hum:WaitForChild("PlayerHealth");
local armor = hum:WaitForChild("PlayerArmor");
local state = hum:WaitForChild("PlayerState");
---
local npcName = char.Name;
local startingPos = root.Position;
local jumpTick = tick();
local wanderTick = 0;
---
local pathfindingService = game:GetService("PathfindingService");
local runService = game:GetService("RunService");
local getSortedTargets = require(game.ReplicatedStorage.Functions.NPCs.Functions.GetSortedTargets);
local runAdjustors = require(game.ReplicatedStorage.Functions.Misc.RunAdjustors);
local getIgnores = require(game.ReplicatedStorage.Functions.Misc.GetRaycastIgnores);
-----
local loadout = {
alive = false;
stunned = false;
target = nil;
lastSeenTargetPosition = nil;
range = 0;
damage = 0;
walkspeed = 0;
jumppower = 0;
};
---
local charSize = char:GetExtentsSize();
local pathParams = {
WaypointSpacing = math.huge;
AgentRadius = (charSize.X+charSize.Z)/4;
AgentHeight = charSize.Y;
AgentCanJump = true;
Costs = {
Water = 10;
};
};
-----
function softWait(goal)
local i = 0;
local target = nil;
repeat
wait(0.1);
i += 0.1;
local targets = getSortedTargets.execute(char, loadout);
local target = targets[1];
until i >= goal or state.Value == "Aggrovated" or target;
end;
function stopExisting()
loadout.alive = false;
state.Value = "GameOver";
wait();
---
game.ReplicatedStorage.Events.SpawnRagdoll:Invoke(char);
---
char:Destroy();
end;
function healthChanged()
if (health.Value <= 0) then
stopExisting();
else
state.Value = "Aggrovated";
end;
end;
function armorChanged()
state.Value = "Aggrovated";
end;
function changeState()
local statename = state.Value;
local walkspeed = loadout.walkspeed;
local jumppower = loadout.jumppower;
local statset = runAdjustors.execute(char, {
["STAT_MovementHindered"] = false;
}, nil, "AdjustStats");
if (statename == "GameOver") then
walkspeed = 0;
jumppower = 0;
end;
if (statset["STAT_MovementHindered"]) then
walkspeed *= 0.5;
jumppower = 0;
end;
hum.WalkSpeed = walkspeed;
hum.JumpPower = jumppower;
end;
function loadNPC()
local npcset = game.ReplicatedStorage.NPCs:FindFirstChild(npcName);
if (npcset) then
npcset = require(npcset);
npcset = runAdjustors.execute(char, npcset, nil, "AdjustStats");
local npcstats = npcset.NpcStats;
health.Max.Value = npcstats["NPC_Health"];
health.Value = health.Max.Value;
armor.Max.Value = npcstats["NPC_Armor"];
armor.Value = armor.Max.Value;
---
loadout.viewdistance = npcstats["NPC_ViewDistance"];
loadout.attackrange = npcstats["NPC_AttackRange"];
loadout.damage = npcstats["NPC_Armor"];
loadout.walkspeed = npcstats["NPC_WalkSpeed"];
loadout.jumppower = npcstats["NPC_JumpPower"];
loadout.agentRadius = npcstats["AgentRadius"];
loadout.agentHeight = npcstats["AgentHeight"];
---
state.Value = "Idle";
---
loadout.alive = true;
end;
end;
function setNewTarget(target)
if (target) then
loadout.target = {
Character = target;
Humanoid = target:FindFirstChild("Humanoid");
Root = target:FindFirstChild("HumanoidRootPart");
};
else
loadout.target = nil;
end;
end;
---
local waypoints;
local nextWaypointIndex;
local reachedConnection;
local blockedConnection;
local path = pathfindingService:CreatePath(pathParams);
local ignore = getIgnores.execute("workspace", true, true, true, false, true);
local function followPath(destination)
local success, errorMessage = pcall(function()
path:ComputeAsync(root.Position, destination)
end)
if success and path.Status == Enum.PathStatus.Success then
local waypoints = path:GetWaypoints()
blockedConnection = path.Blocked:Connect(function(blockedWaypointIndex)
if blockedWaypointIndex >= nextWaypointIndex then
blockedConnection:Disconnect()
followPath(destination)
end
end)
-- Detect when movement to next waypoint is complete
if not reachedConnection then
reachedConnection = hum.MoveToFinished:Connect(function(reached)
if reached and nextWaypointIndex < #waypoints then
-- Increase waypoint index and move to next waypoint
nextWaypointIndex += 1
hum:MoveTo(waypoints[nextWaypointIndex].Position)
else
reachedConnection:Disconnect()
blockedConnection:Disconnect()
end
end)
end
nextWaypointIndex = 2
hum:MoveTo(waypoints[nextWaypointIndex].Position);
local obstacleRay = Ray.new(root.Position, root.CFrame.LookVector * (loadout.agentRadius+1));
local hit = game.Workspace:FindPartOnRayWithIgnoreList(obstacleRay, ignore);
if (hit) then
if ((tick()-jumpTick) > 1) then
hum.Jump = true;
jumpTick = tick();
end;
end;
hum.MoveToFinished:Wait();
else
hum:MoveTo(destination);
hum.MoveToFinished:Wait();
end
end;
loadNPC();
-----
health.Changed:Connect(healthChanged);
armor.Changed:Connect(armorChanged);
hum.Died:Connect(stopExisting);
---
changeState();
state.Changed:Connect(changeState);
statusEffects.ChildAdded:Connect(function()
changeState();
end);
statusEffects.ChildRemoved:Connect(function()
changeState();
end);
-----
local destination = nil;
local hInt = 0;
runService.Heartbeat:Connect(function()
hInt += 1;
if (not loadout.alive) then return end;
if (hInt < 10) then return end;
hInt = 0;
if (char and hum) then
local targets = getSortedTargets.execute(char, loadout);
local targetData = targets[1];
if (targetData) then
if (not loadout.target or loadout.target.Character ~= targetData.key) then
setNewTarget(targetData.key);
end;
loadout.lastSeenTargetPosition = loadout.target.Root.Position;
state.Value = "Aggrovated";
else
setNewTarget(nil);
state.Value = "Idle";
end;
---
if (loadout.target) then
destination = loadout.target.Root.Position;
elseif (loadout.lastSeenTargetPosition) then
if ((root.Position - loadout.lastSeenTargetPosition).Magnitude < 25) then
loadout.lastSeenTargetPosition = false;
else
destination = loadout.lastSeenTargetPosition;
end;
else
if ((tick()-wanderTick)>5) then
destination = startingPos + Vector3.new(math.random(-25,25), 0, math.random(-25,25));
wanderTick = tick();
end;
end;
if (destination) then
followPath(destination);
end;
end;
end);
I think I’ve looked through like 30 different threads on pathfinding shenanigans, but I can’t find anything on this issue.
Can anyone tell me what might be wrong, or point me to some direction?