I’m trying to get this zombie module to work with pathfinding
For some reason it won’t work. It attacks when I get close to it half the time, and whenever it does, it walks towards me for like half a second and stops, and nothing errors.
All the print statements I made (!!, ?, pathToTarget, LostTarget) All get printed in the output, so that’s just some info if u need it I guess
Here’s the TagHuman function in Tags module:
--Setting up Utility
local tagsUtility = {}
function tagsUtility.tagHuman(instance: Instance)
local success, err = pcall(function()
local human = instance:FindFirstChildWhichIsA("Humanoid")
if human then
human:AddTag("Human")
end
end)
end
return tagsUtility
Here’s the Zombie OOP module (Maybe check if the threadSpawn function is right):
Zombie Module
--Services
local CollectionService = game:GetService("CollectionService")
local PathfindingService = game:GetService("PathfindingService")
--Main module
local zombie = {}
zombie.__index = zombie
--Setting up zombie
function zombie.new(char: Model, health: number, damage: number, attackRange: number, detectRange: number, smoothness: number,position: CFrame)
--Setting up Metatable
setmetatable({}, zombie)
--Setting up values and variables
zombie.char = char
zombie.root = char:FindFirstChild("HumanoidRootPart")
zombie.humanoid = char:FindFirstChild("Humanoid") :: Humanoid
zombie.head = char:FindFirstChild("Head")
zombie.torso = char:FindFirstChild("Torso")
zombie.animator = zombie.humanoid:FindFirstChild("Animator")
zombie.grabAnim = zombie.animator:LoadAnimation(zombie.char:FindFirstChild("Grab"))
zombie.target = nil
--Properties
zombie.health = health
zombie.humanoid.MaxHealth = health
zombie.humanoid.Health = health
zombie.damage = damage
zombie.attackRange = attackRange
zombie.detectRange = detectRange
zombie.smoothness = smoothness
--Thread variables
zombie.threads = {}
zombie.__type = "Zombie"
--Run code
zombie.humanoid:AddTag("Zombie")
zombie:position(position)
return zombie
end
------------------------------------------------------------
--METAMETHODS
------------------------------------------------------------
--INITIALIZE ZOMBIE
function zombie:INITIALIZE()
if self.__type ~= "Zombie" then return end
--Initializing zombie
self.threadSpawn(self, function()
while task.wait(1) do
if self then
self:updateTarget()
else
return
end
end
end)
--Attack checking
self.threadSpawn(self, function()
self:attackChecking()
end)
self:initializePathfinding()
return self
end
--------------------------------------------------
--MOVEMENT FUNCTIONS
--Move zombie to position instantly
function zombie:position(position: CFrame)
if self.__type ~= "Zombie" then return end
self.root:PivotTo(position)
return self
end
--------------------------------------------
--PATHFINDING FUNCTIONS
--Check distance(NORMAL FUNCTION)
function zombie.checkDist(part1: Part | Vector3, part2: Part | Vector3): number
if typeof(part1) ~= Vector3 then part1 = part1.Position end
if typeof(part2) ~= Vector3 then part2 = part2.Position end
return (part1 - part2).Magnitude
end
--Update target
function zombie:updateTarget()
if self.__type ~= "Zombie" then return end
--Variables
local humans = CollectionService:GetTagged("Human")
--Setting up zombie
self.target = nil
for _, human in pairs(humans) do
local root = human.RootPart
if (root) and (human.Health > 0) and (self.checkDist(root, self.root) < self.detectRange) and (not table.find(human:GetTags(), "Zombie")) then
self.detectRange = self.checkDist(root, self.root)
self.target = root
end
end
return self
end
--Path to Target
function zombie:pathToTarget()
if self.__type ~= "Zombie" then return end
print("pathToTarget")
--Creating path
local path = PathfindingService:CreatePath()
path:ComputeAsync(self.root.Position, self.target.Position)
--Variables
local waypoints = path:GetWaypoints()
local currentTarget = self.target
--Setting up pathfinding
for i, waypoint in pairs(waypoints) do
-----------------
local part = Instance.new("Part")
part.CanCollide = false
part.Anchored = true
part.Material = "Neon"
part.BrickColor = BrickColor.new("Royal purple")
part.Position = waypoint.Position
part.Size = Vector3.new(1,1,1)
-----------------
--Creating waypoints and moving zombie there
if waypoint.Action == Enum.PathWaypointAction.Jump then
self.humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
else
self.humanoid:MoveTo(waypoint.Position)
self.threadSpawn(self, function()
task.wait(0.5)
if self.humanoid.WalkToPoint.Y > self.root.Position.Y then
self.humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
end
end)
end
--Makes sure zombie walking is correct
self.humanoid.MoveToFinished:Wait()
print("!!")
--Making sure tracking works
if not self.target then
print("Lost target")
break
elseif (self.checkDist(currentTarget, waypoints[#waypoints]) > self.smoothness) or currentTarget ~= self.target then
print("?")
self:pathToTarget()
break
end
end
return self
end
--Movement handler
function zombie:moveHandler()
if self.__type ~= "Zombie" then return end
--Setting up zombie movement
while task.wait(1) do
--Makes sure zombie is moving only if zombie is alive
if self.humanoid.Health <= 0 then
break
end
--Makes sure the zombie has a target
if zombie.target then
self:pathToTarget()
end
end
return self
end
--moveToEntrance
--[[
function zombie:moveToEntrance()
end
]]
--------------------------------------------
--Loops
--Initialize zombie attacks
function zombie:attackChecking()
while task.wait(0.5) do
if self then
--Checking if zombie should attack
if self.target then
if self.checkDist(self.target, self.root) < self.attackRange then
self:attack(self.damage)
end
end
else
return
end
end
return self
end
--------------------------------------------
--UTILITY FUNCTIONS
--Remove zombie
function zombie:removeZombie()
if self.__type ~= "Zombie" then return end
task.wait(5)
--Close all threads
for _, thread in pairs(self.threads) do
coroutine.close(thread)
thread = nil
end
self.char:Destroy()
self = nil
return self
end
--Attack
function zombie:attack()
if self.__type ~= "Zombie" then return end
--Attack code
local human = self.target.Parent.Humanoid :: Humanoid
human:TakeDamage(self.damage)
--Attack Animation
self.grabAnim:Play()
return self
end
--Initialize pathfinding
function zombie:initializePathfinding()
if self.__type ~= "Zombie" then return end
--When a zombie is eliminated
self.humanoid.Died:Connect(function()
self:removeZombie()
end)
--Making sure server has full control of zombie
for i, v in pairs(zombie.char:GetDescendants()) do
if v:IsA("BasePart") and v:CanSetNetworkOwnership() then
v:SetNetworkOwner(nil)
end
end
--Handle zombie movement
self.threadSpawn(self, function()
self:moveHandler()
end)
return self
end
--Spawn thread
function zombie.threadSpawn(zombieObject, functionObject, ...)
if zombieObject.__type ~= "Zombie" then return end
local co = coroutine.wrap(functionObject)
table.insert(zombieObject.threads, co)
co(...)
end
------------------------------------------------------------
return zombie