For a game jam I made a game which uses pathfinding AI, but I wasn’t able to solve it’s issues in time. I’ve reviewed the code now and I still can’t tell what the problems are, so I’m asking for help. I’m noticing:
it will get stuck on objects or walk off the map
sometimes putting the tool up will cause it to get stuck and animations to break
when it misses a shot, it’s not obvious
they shoot through walls sometimes
Here’s the code:
-- darkpixlz 2024
local PathfindingService = game:GetService("PathfindingService")
task.wait(2.5)
local Humanoid = script.Parent.Humanoid
Humanoid:EquipTool(script.Parent.Gun)
while task.wait(script.Parent:GetAttribute("TickTime")) do
local PartToTrack = workspace[script.Parent:GetAttribute("Target")]
--Humanoid:MoveTo(PartToTrack.Position)
local RootPart = script.Parent:FindFirstChild("HumanoidRootPart")
local RootPos = Vector3.new(0, 0, 0)
if RootPart ~= nil then
RootPos = RootPart.Position
end
local TrackPos = PartToTrack.Position
if math.abs((RootPos - TrackPos).Magnitude) <= 500 then
local path = PathfindingService:CreatePath()
path:ComputeAsync(RootPos, (TrackPos- Vector3.new(-10, 12, 0)))
local waypoints = path:GetWaypoints()
for i, waypoint in pairs(waypoints) do
script.Parent:FindFirstChildWhichIsA("Humanoid"):MoveTo(waypoint.Position)
end
end
if not script.Parent:FindFirstChild("HumanoidRootPart") then
print("NPC died, killing this script off...")
break
end
-- Check distance
local function IsWithinRange()
if RootPart ~= nil then
RootPos = RootPart.Position
end
if math.abs((RootPos - PartToTrack.Position).Magnitude) <= script.Parent:GetAttribute("Range") then
return true
else
return false
end
end
if IsWithinRange() == true then
-- Shoot
print("shooting")
local tool = script.Parent.Gun
local beam = Instance.new("Part", game.Workspace)
beam.Color = Color3.new(1,1,1)
beam.Material = Enum.Material.Neon
beam.Transparency = .3
beam.Anchored = true
beam.Locked = true
beam.CanCollide = false
local distance = (
tool.Dispenser.CFrame.p
-
PartToTrack.CFrame.p
).magnitude
beam.Size = Vector3.new(.3, .3, distance)
beam.CFrame = CFrame.new(tool.Dispenser.CFrame.p, PartToTrack.Position) * CFrame.new(0, 0, -distance / 2)
game:GetService("Debris"):AddItem(beam, 0.05)
-- chance to miss
if math.random(1, 5) == 3 then
print("Shot missed...")
beam.Position = Vector3.new(beam.Position.X + math.random(1,3), beam.Position.Y + math.random(1,3), beam.Position.Z + math.random(1,3))
continue
end
local HP = PartToTrack:GetAttribute("Health")
PartToTrack:SetAttribute("Health", HP - script.Parent:GetAttribute("Damage"))
end
end
while task.wait(script.Parent:GetAttribute("TickTime")) do
I highly recommend re-doing this part entirely. This is where most of your problems are coming from I am 99% sure. I think if you deconstruct your huge function and use something like rendered.stepped with different functions called into that you’d see a lot of fixes in your bugs. This also helps you later on, because you can pick and choose what functions to keep or test, thus making the hardest part of coding easy. Just simple deduction on what function is causing the problem, right now, you just got a big huge while do loop…
-- darkpixlz 2024
local PathfindingService = game:GetService("PathfindingService")
task.wait(2.5)
local Humanoid = script.Parent.Humanoid
Humanoid:EquipTool(script.Parent.Gun)
local PartToTrack = workspace[script.Parent:GetAttribute("Target")]
local RootPart = script.Parent:FindFirstChild("HumanoidRootPart")
local RootPos = Vector3.new(0, 0, 0)
local function FindDrone()
if RootPart ~= nil then
RootPos = RootPart.Position
end
local TrackPos = PartToTrack.Position
if math.abs((RootPos - TrackPos).Magnitude) <= 500 then
local path = PathfindingService:CreatePath()
path:ComputeAsync(RootPos, (TrackPos- Vector3.new(-10, 12, 0)))
local waypoints = path:GetWaypoints()
for i, waypoint in pairs(waypoints) do
script.Parent:FindFirstChildWhichIsA("Humanoid"):MoveTo(waypoint.Position)
end
end
end
local function Shoot()
local function IsWithinRange()
if RootPart ~= nil then
RootPos = RootPart.Position
end
if math.abs((RootPos - PartToTrack.Position).Magnitude) <= script.Parent:GetAttribute("Range") then
return true
else
return false
end
end
if IsWithinRange() == true then
-- Shoot
print("shooting")
local tool = script.Parent.Gun
local beam = Instance.new("Part", game.Workspace)
beam.Color = Color3.new(1,1,1)
beam.Material = Enum.Material.Neon
beam.Transparency = .3
beam.Anchored = true
beam.Locked = true
beam.CanCollide = false
local distance = (
tool.Dispenser.CFrame.p
-
PartToTrack.CFrame.p
).magnitude
beam.Size = Vector3.new(.3, .3, distance)
beam.CFrame = CFrame.new(tool.Dispenser.CFrame.p, PartToTrack.Position) * CFrame.new(0, 0, -distance / 2)
game:GetService("Debris"):AddItem(beam, 0.05)
local HP = PartToTrack:GetAttribute("Health")
PartToTrack:SetAttribute("Health", HP - script.Parent:GetAttribute("Damage"))
end
end
game:GetService("RunService").Heartbeat:Connect(function()
task.wait(script.Parent:GetAttribute("TickTime"))
FindDrone()
if math.random(1, 5) ~= 1 then
Shoot()
end
end)