Reputation: 3
I'm trying to code a turret, shooting enemies when it gets in the range of the turret, and the code sometimes breaks giving me the error Script:31: attempt to index nil with 'Humanoid'
This happens rarely and only does so when a zombie dies.
Not only that but it seems some of the bullets created seem to make way more damage than they really should.
head = script.Parent.PrimaryPart
local function triggershoot(part)
local beam = Instance.new("Part",script.Parent)
beam.Anchored = true
beam.CanCollide = false
beam.Shape = "Block"
beam.CFrame = head.CFrame
beam.Size = Vector3.new(0.5,0.5,0.5)
beam.Material = "Plastic"
beam.BrickColor = BrickColor.new("Dark taupe")
beam.CFrame = CFrame.lookAt(head.Position,part.Position)
for i = 0, 50, 1 do
wait()
beam.CFrame = beam.CFrame + beam.CFrame.LookVector
beam.Touched:Connect(function(plr)
if plr.Parent:HasTag("enemy") then
plr.Parent.Humanoid:TakeDamage(3)
beam:Destroy()
end
end)
end
end
while true do
wait()
local parts = workspace:GetPartsInPart(script.Parent.zone)
for _, part in pairs(parts) do
if part:HasTag("enemy") and part.Parent.Humanoid.Health > 0 then
local update = CFrame.lookAt(head.Position,part.Position)
head.CFrame = update
coroutine.wrap(triggershoot)(part)
wait(1)
end
end
end
Upvotes: 0
Views: 53
Reputation: 19
If i am correct you’re running into two main issues in your script:
This error occurs because part.Parent.Humanoid
is nil
when the turret tries to access it. This usually happens when a zombie dies, and its Humanoid object gets destroyed before the turret can check its health or apply damage.
Solution: Add a check to ensure Humanoid exists before trying to use it.
Modify this part:
if part:HasTag("enemy") and part.Parent.Humanoid.Health > 0 then
To this:
local humanoid = part.Parent:FindFirstChild("Humanoid")
if part:HasTag("enemy") and humanoid and humanoid.Health > 0 then
You’re connecting the beam.Touched event inside a loop, which means it gets repeatedly connected every frame. This can cause bullets to apply damage multiple times.
Solution: Move the .Touched event outside the loop so it only gets connected once.
Fixed Code:
head = script.Parent.PrimaryPart
local function triggershoot(part)
local beam = Instance.new("Part")
beam.Parent = script.Parent
beam.Anchored = true
beam.CanCollide = false
beam.Shape = Enum.PartType.Block
beam.CFrame = head.CFrame
beam.Size = Vector3.new(0.5, 0.5, 0.5)
beam.Material = Enum.Material.Plastic
beam.BrickColor = BrickColor.new("Dark taupe")
beam.CFrame = CFrame.lookAt(head.Position, part.Position)
local function onHit(plr)
if plr.Parent:HasTag("enemy") then
local humanoid = plr.Parent:FindFirstChild("Humanoid")
if humanoid then
humanoid:TakeDamage(3)
beam:Destroy()
end
end
end
beam.Touched:Connect(onHit)
for i = 1, 50 do
beam.CFrame = beam.CFrame + beam.CFrame.LookVector
wait()
end
beam:Destroy()
end
while true do
wait()
local parts = workspace:GetPartsInPart(script.Parent.zone)
for _, part in pairs(parts) do
local humanoid = part.Parent:FindFirstChild("Humanoid")
if part:HasTag("enemy") and humanoid and humanoid.Health > 0 then
head.CFrame = CFrame.lookAt(head.Position, part.Position)
coroutine.wrap(triggershoot)(part)
wait(1)
end
end
end
Summary of Fixes:
Humanoid
exists before accessing it (FindFirstChild("Humanoid"))
..Touched
event outside the loop so that it connects only once per bullet.I hope this fixes both of your issues! 🚀
Resources that may help:
Understanding FindFirstChild to Prevent Nil Errors
- Roblox Developer Hub -
FindFirstChild
Method 📖 FindFirstChild Documentation
- This method is essential to check if an object exists before accessing its properties (like
Humanoid.Health
).- It prevents errors like "attempt to index nil with 'Humanoid'".
Properly Handling Touched Events
- Roblox Developer Hub -
Touched
Event 📖 Touched Event Documentation
- The
.Touched
event can fire multiple times, so you need to connect it once per projectile.- Avoid putting
.Touched:Connect()
inside loops because it creates multiple event listeners, leading to unintended behavior.- DevForum - Why
Touched
Can Fire Multiple Times 📖 Thread on Touched Event Behavior
- Explains how the event works and common mistakes, like firing multiple damage events per bullet.
Using
CFrame.lookAt()
for Aiming
- Roblox Developer Hub - CFrame.lookAt Method 📖 CFrame.lookAt Documentation
- This function helps the turret rotate towards enemies automatically.
- You can see how it works with examples.
Coroutine Basics for Running Functions in Parallel
- Roblox Developer Hub -
coroutine.wrap
andcoroutine.resume
📖 Coroutine Documentation
- Used to make the turret shoot without pausing the main loop.
- Without
coroutine.wrap(triggershoot)(part)
, the turret would wait for each bullet to finish before checking other enemies.Proper Bullet Movement Techniques
- Roblox Developer Hub - TweenService for Smooth Bullet Movement 📖 TweenService Documentation
- Instead of using a loop (
for i = 1, 50
), TweenService can move bullets smoothly without affecting performance.
Upvotes: 0
Reputation: 359
try moving the touch event function outside the forloop
head = script.Parent.PrimaryPart
local function triggershoot(part)
local beam = Instance.new("Part",script.Parent)
beam.Anchored = true
beam.CanCollide = false
beam.Shape = "Block"
beam.CFrame = head.CFrame
beam.Size = Vector3.new(0.5,0.5,0.5)
beam.Material = "Plastic"
beam.BrickColor = BrickColor.new("Dark taupe")
beam.CFrame = CFrame.lookAt(head.Position,part.Position)
beam.Touched:Connect(function(plr)
local char=plr.Parent
local hum=char and char:FindFirstChildOfClass"Humanoid"
if char:HasTag("enemy") then
hum:TakeDamage(3)
beam:Destroy()
end
end)
for i = 0, 50, 1 do
wait()
beam.CFrame = beam.CFrame + beam.CFrame.LookVector
end
beam:Destroy()
end
while true do
wait()
local parts = workspace:GetPartsInPart(script.Parent.zone)
for _, part in ipairs(parts) do
local h=part.Parent;h=h and h:FindFirstChildOfClass"Humanoid"
if part:HasTag"enemy"and h and h.Health > 0 then
local update = CFrame.lookAt(head.Position,part.Position)
head.CFrame = update
coroutine.wrap(triggershoot)(part)
wait(1)
break
end
end
end
Upvotes: 0