So I have this NPC, and it works, unless you walk behind it or around it. I get the error 'Workspace.NewNpc.Dummy.AI:94: attempt to index global 'prs' (a nil value)'.
The script's really long, sorry if this hurts your eyes.
``` local ts = game:GetService("TweenService")
local event = Instance.new("BindableEvent")
event.Name = ("StartAttacking")
event.Parent = script.Parent.Parent
wait(5)
script.Parent.AttackingPlayer.Value = ""
local range = 20
local function searchforplayer()
local ray = Ray.new(script.Parent.HumanoidRootPart.CFrame.Position, script.Parent.HumanoidRootPart.CFrame.LookVector * 500)
local hrp = script.Parent.HumanoidRootPart.Position
local num = 8
local part = game.Workspace:FindPartOnRay(ray)
local person = nil
if part then
if part.Parent:FindFirstChild("Humanoid") then
if game.Players:FindFirstChild(part.Parent.Name) then
print("Found player!")
print(part.Parent.Name)
person = part.Parent
end
end
end
if person == nil then
local region = Region3.new(Vector3.new(hrp.X - num, hrp.Y - num, hrp.Z - num), Vector3.new(hrp.X + num, hrp.Y + num, hrp.Z + num))
local parts = game.Workspace:FindPartsInRegion3(region)
for a, b in pairs(parts) do
if b.Name == ("HumanoidRootPart") then
print(b.Name)
person = b.Parent
end
end
else
return person()
end
if person ~= nil then
return person
end
end
while true do
if script.Parent.AttackingPlayer.Value == "" then
print("Searching...")
if searchforplayer() == nil then
while searchforplayer() == nil do
wait(0.1)
if searchforplayer() ~= nil then
script.Parent.AttackingPlayer.Value = searchforplayer().Name
script.Parent.Head["!Gui"].Frame.TextLabel.Visible = true
script.Parent.Humanoid.JumpPower = 48
script.Parent.Humanoid.Jump = true
wait(1)
script.Parent.Head["!Gui"].Frame.TextLabel.Visible = false
script.Parent.Humanoid.JumpPower = 0
break
end
end
end
end
local path = game:GetService("PathfindingService"):CreatePath()
if script.Parent.AttackingPlayer.Value ~= ("") then
local prs = game.Workspace:FindFirstChild(script.Parent.AttackingPlayer.Value)
end
if script.Parent.AttackingPlayer.Value ~= ("") then
event:Fire(script.Parent.AttackingPlayer.Value)
end
range = math.huge
path:ComputeAsync(script.Parent.HumanoidRootPart.Position, prs.HumanoidRootPart.Position)
local points = path:GetWaypoints()
local player = game.Workspace:FindFirstChild(script.Parent.AttackingPlayer.Value)
script.Parent.Parent.Points:ClearAllChildren()
for a, b in pairs(points) do
part = Instance.new("Part")
part.CanCollide = false
part.Size = Vector3.new(1,1,1)
part.Position = b.Position
part.Anchored = true
part.Transparency = 1
part.Parent = script.Parent.Parent.Points
end
if path.Status == Enum.PathStatus.Success then
for a, b in pairs(points) do
script.Parent.Humanoid:MoveTo(part.Position)
if b.Action == Enum.PathWaypointAction.Jump then
script.Parent.Humanoid.Jump = true
end
end
end
end ```
I get this error if I stand in front of the guy, or be around him. Any help?
Using :FindFirstChild() does not always return something. Before calculating a path, check to see if prs exists.
if prs then -- Code for pathfinding end
When you say that a variable is local
, it only exists in the scope you define it. In other words, because you define local prs
in the if
block, prs
does not exist outside of that if
block! prs
will never be a non-nil value.
To fix this, specify that prs
is local outside the if statement, in the same scope that you later use it:
lua
local prs
if script.Parent.AttackingPlayer.Value ~= ("") then
prs = game.Workspace:FindFirstChild(script.Parent.AttackingPlayer.Value)
end
SaltyIceberg is correct that you must also check to see if prs
is non-nil.
Some other problems with this script:
- return person()
will fail, since person
is not a function. Right after that, you have if person ~= nil then return person end
, which makes the return person()
redundant (in addition to being incorrect). Remove the else return person()
part.
- You have if searchforplayer() == nil then
followed by while searchforplayer() == nil then
, but you can just remove the if
staement (along with the corresponding end
) since while
will not run its code even once if the condition is false
- You should try to avoid running functions (especially ones that are complicated) more than necessary. You can save the result of calling searchforplayer()
to a variable so you can access the player's name:
lua
if script.Parent.AttackingPlayer.Value == "" then
print("Searching...")
local player
while true do
player = searchforplayer()
if player then break end
wait(0.1)
end
script.Parent.AttackingPlayer.Value = player.Name
script.Parent.Head["!Gui"].Frame.TextLabel.Visible = true
script.Parent.Humanoid.JumpPower = 48
script.Parent.Humanoid.Jump = true
wait(1)
script.Parent.Head["!Gui"].Frame.TextLabel.Visible = false
script.Parent.Humanoid.JumpPower = 0
end
- if script.Parent.AttackingPlayer.Value ~= ("") then
makes no sense because the code before it guarantees that AttackingPlayer will exist
- range = math.huge
could just be set once at the top of the script (where it currently says local range = 20
)
- You should assign AttackingPlayer
to a local variable instead of saying script.Parent.AttackingPlayer
every time
- prs.HumanoidRootPart might not exist if the player (for instance) fell off the edge of the map; you should use FindFirstChild
there
- No point in having both prs
and player
both point to the player's character model (rename prs
to player
and remove the repetition)
- When having the NPC follow the pathfinding result:
- You don't want to use pairs
, or else it'll attempt to follow the path out of order!
- You don't have the script wait until the NPC actually gets to the checkpoint, you just tell it to start moving towards each checkpoint. You need to either have a loop where you wait until the NPC stops moving and/or gets close to its target.
Aside from the last point, I fixed the above in the following: ```lua local ts = game:GetService("TweenService") local event = Instance.new("BindableEvent") event.Name = ("StartAttacking") event.Parent = script.Parent.Parent
wait(5)
local attackingPlayer = script.Parent.AttackingPlayer
attackingPlayer.Value = ""
local range = math.huge
local function searchforplayer() local ray = Ray.new(script.Parent.HumanoidRootPart.CFrame.Position, script.Parent.HumanoidRootPart.CFrame.LookVector * 500) local hrp = script.Parent.HumanoidRootPart.Position local num = 8 local part = game.Workspace:FindPartOnRay(ray) local person = nil if part then if part.Parent:FindFirstChild("Humanoid") then if game.Players:FindFirstChild(part.Parent.Name) then print("Found player!") print(part.Parent.Name) person = part.Parent end end end if person == nil then local region = Region3.new(Vector3.new(hrp.X - num, hrp.Y - num, hrp.Z - num), Vector3.new(hrp.X + num, hrp.Y + num, hrp.Z + num)) local parts = game.Workspace:FindPartsInRegion3(region) for a, b in pairs(parts) do if b.Name == ("HumanoidRootPart") then print(b.Name) person = b.Parent end end end if person then return person end end
while true do if attackingPlayer.Value == "" then print("Searching...") local player while true do player = searchforplayer() if player then break end wait(0.1) end attackingPlayer.Value = player.Name script.Parent.Head["!Gui"].Frame.TextLabel.Visible = true script.Parent.Humanoid.JumpPower = 48 script.Parent.Humanoid.Jump = true wait(1) script.Parent.Head["!Gui"].Frame.TextLabel.Visible = false script.Parent.Humanoid.JumpPower = 0 end local path = game:GetService("PathfindingService"):CreatePath() local player = game.Workspace:FindFirstChild(attackingPlayer.Value) event:Fire(attackingPlayer.Value) local playerHRP = prs:FindFirstChild("HumanoidRootPart") if playerHRP then path:ComputeAsync(script.Parent.HumanoidRootPart.Position, playerHRP.Position) local points = path:GetWaypoints() script.Parent.Parent.Points:ClearAllChildren() for a, b in pairs(points) do part = Instance.new("Part") part.CanCollide = false part.Size = Vector3.new(1,1,1) part.Position = b.Position part.Anchored = true part.Transparency = 1 part.Parent = script.Parent.Parent.Points end if path.Status == Enum.PathStatus.Success then for a, b in ipairs(points) do script.Parent.Humanoid:MoveTo(part.Position) if b.Action == Enum.PathWaypointAction.Jump then script.Parent.Humanoid.Jump = true end end end end end ```