Hello, I am making an NPC handler for my new up and coming roblox MMORPG called Kingdom of Eldor. However I am encountering a bug, although it does not break anything, it is quite annoying and uses memory unneeded.
This happens because I destroy the NPC whenever I walk outside of the Region3 causing an error since the humanoid is not found.
Here is the script where the errors are found:
-- Services
local PathfindingService = game:GetService("PathfindingService")
-- Variables
local waypointsFolder = workspace:WaitForChild("Waypoints")
local npcsFolder = workspace:WaitForChild("NPCs")
local Behaviour = {}
-- Sees if you need to moveto or pathfind
local function NeedsMoveTo(npc: Model, target: Vector3): boolean
local humanoidRootPart = npc:FindFirstChild("HumanoidRootPart")
if not humanoidRootPart then
return false
end
local raycastParams = RaycastParams.new()
raycastParams.FilterType = Enum.RaycastFilterType.Exclude
raycastParams.FilterDescendantsInstances = {npc}
local raycast = workspace:Raycast(humanoidRootPart.Position, (target - humanoidRootPart.Position).unit * 500, raycastParams)
if raycast.Instance.Position == target then
return true
else
return false
end
end
-- Returns the closest waypoint set
local function FindClosestWaypointSet(npc: Model): Model?
local humanoidRootPart = npc:FindFirstChild("HumanoidRootPart")
if not humanoidRootPart then
return nil
end
local closestWaypointSet = nil
local closestDistance = math.huge
for _, waypointSet in pairs(waypointsFolder:GetChildren()) do
if waypointSet:IsA("Model") and #waypointSet:GetChildren() > 0 and waypointSet.PrimaryPart then
local waypointPosition = waypointSet.PrimaryPart.Position
local distance = (humanoidRootPart.Position - waypointPosition).magnitude
if distance < closestDistance then
closestDistance = distance
closestWaypointSet = waypointSet
end
end
end
return closestWaypointSet
end
-- Walks around waypoints
local function Waypoint(npc: Model)
local closestWaypointSet = FindClosestWaypointSet(npc)
if not closestWaypointSet then return end
local waypoints = closestWaypointSet:GetChildren()
if #waypoints == 0 then
warn("No waypoints in closest waypoint set")
return
end
local randomWaypoint = waypoints[math.random(1, #waypoints)]
if NeedsMoveTo(npc, randomWaypoint.Position) then
local humanoid = npc:FindFirstChildOfClass("Humanoid")
if humanoid then
humanoid:MoveTo(randomWaypoint.Position)
end
else
local path = PathfindingService:CreatePath({
AgentRadius = 2,
AgentHeight = 5,
AgentCanJump = true,
AgentJumpHeight = 10,
AgentMaxSlope = 45
})
path:ComputeAsync(npc.PrimaryPart.Position, randomWaypoint.Position)
for _, waypoint in pairs(path:GetWaypoints()) do
if npc then
if waypoint.Action == Enum.PathWaypointAction.Jump then
npc.Humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
end
npc:FindFirstChild("Humanoid"):MoveTo(waypoint.Position)
npc:FindFirstChild("Humanoid").MoveToFinished:Wait()
end
end
end
end
-- Locates the enemies
local function FindEnemy(npc: Model, enemies: {string}, attackDistance: number): Model?
local closestEnemy = nil
local closestDistance = attackDistance
for _, enemyName in ipairs(enemies) do
local enemy = npcsFolder:FindFirstChild(enemyName)
if not enemy then continue end
for _, enemyModel in pairs(enemy:GetChildren()) do
local humanoidRootPart = enemyModel:FindFirstChild("HumanoidRootPart")
if enemyModel:FindFirstChild("HumanoidRootPart") then
local distance = (npc.HumanoidRootPart.Position - humanoidRootPart.Position).Magnitude
if distance <= attackDistance and distance < closestDistance then
closestDistance = distance
closestEnemy = enemyModel
end
else
warn("No HumanoidRootPart found in enemy model: " .. enemyName)
end
end
end
return closestEnemy
end
-- For guards/enemies
local function AttackLoop(npc: Model, npcDictionary: {Enemies: {string}, AttackDistance: number})
while npc do
local enemy = FindEnemy(npc, npcDictionary.Enemies, npcDictionary.AttackDistance)
if enemy then
if NeedsMoveTo(npc, enemy.HumanoidRootPart.Position) then
-- Move to enemy
local humanoid = npc:FindFirstChild("Humanoid")
if humanoid and enemy:FindFirstChild("HumanoidRootPart") then
humanoid:MoveTo(enemy.HumanoidRootPart.Position)
task.wait(0.5)
else
break
end
else
-- Pathfinding to enemy
task.wait(0.5)
if npc:FindFirstChild("HumanoidRootPart") and enemy:FindFirstChild("HumanoidRootPart") then
local path = PathfindingService:CreatePath()
path:ComputeAsync(npc.HumanoidRootPart.Position, enemy.HumanoidRootPart.Position)
for _, waypoint in pairs(path:GetWaypoints()) do
if waypoint.Action == Enum.PathWaypointAction.Jump then
npc.Humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
end
npc:FindFirstChild("Humanoid"):MoveTo(waypoint.Position)
npc:FindFirstChild("Humanoid").MoveToFinished:Wait()
end
else
break
end
end
else
task.wait(0.5)
if npc then
Waypoint(npc)
else
break
end
end
end
end
-- For civilians
local function RunLoop(npc: Model)
-- Implement behavior for civilians
end
-- Creates a new behaviour instance
function Behaviour.New(npc: Model?, behaviourType: boolean?, npcDictionary: {Enemies: {string}, AttackDistance: number})
if not npc then
warn("No NPC provided")
return
end
if not behaviourType then
-- Attacks enemies
task.spawn(AttackLoop, npc, npcDictionary)
else
-- Runs from enemies
task.spawn(RunLoop, npc)
end
end
return Behaviour
The lines with the errors are:
npc:FindFirstChild("Humanoid"):MoveTo(waypoint.Position)
npc:FindFirstChild("Humanoid").MoveToFinished:Wait()
And
npc:FindFirstChild("Humanoid"):MoveTo(waypoint.Position)
npc:FindFirstChild("Humanoid").MoveToFinished:Wait()
Thankyou for all the help that I may recieve!