How would I tidy up this script

Hullo, I would like to make my code easier to edit and not have to make new variables every time I wanna make a new enemy for my game.

The code I wanna tidy up
local RunOnce = false
local FastZombieDB = false
local enemyHitbox
function EnemyAI.FastZombie(humrp,hum,Enemy)
	if FastZombieDB == false then
		FastZombieDB = true
		--local AnimId = 'rbxassetid://6932293833'
		local AnimId = 'rbxassetid://11188195611'
		local Damage = 15
		local delay = 1
		
		if RunOnce == false then
			print('Running once')
			RunOnce = true
			enemyHitbox = RaycastHitbox.new(Enemy.RightHand)
			enemyHitbox:SetPoints(Enemy.RightHand,{Vector3.new(0,0,0),Vector3.new(-1,1,2),Vector3.new(-3.5,1,2)})
		end
		if not Anims:FindFirstChild(AnimId) then
			local animationInstance = Instance.new('Animation')
			animationInstance.Parent = Anims
			animationInstance.AnimationId = AnimId
			animationInstance.Name = AnimId
		end
		local AttackAnim = hum:LoadAnimation(Anims[AnimId])

		AttackAnim:Play()
		enemyHitbox:HitStart()

		enemyHitbox.OnHit:Connect(function(hit,humanoid)
			if humanoid.Parent.Name ~= Enemy.Name then
				humanoid:TakeDamage(Damage)
			end
		end)
		coroutine.wrap(function()
			AttackAnim.Stopped:Wait()
			enemyHitbox:HitStop()
			task.wait(delay)
			FastZombieDB = false
		end)()
	end
end
Entire module
local Players = game:GetService('Players')
local RunService = game:GetService('RunService')
local PathfindingService = game:GetService('PathfindingService')
local ReplicatedStorage = game:GetService('ReplicatedStorage')
local RaycastHitbox = require(ReplicatedStorage.RaycastHitboxV4)
local maxDistance = math.huge
local Anims = script.Parent.Anims

local EnemyAI = {}
EnemyAI.__index = EnemyAI

function EnemyAI.new(Enemy,WalkAnim)
	local EnemyProperties = setmetatable({},EnemyAI)
	local hum = Enemy.Humanoid
	local humrp = Enemy.HumanoidRootPart
	local WalkAnim = hum:LoadAnimation(WalkAnim)

	EnemyProperties.Model = Enemy
	EnemyProperties.Humanoid = hum
	EnemyProperties.humrp = humrp
	--Pathfinding
	Enemy.PrimaryPart:SetNetworkOwner(nil)
	local CoreOfFactory = workspace.CentreOfFactory

	local function findTarget()
		local allies = workspace.Allies:GetChildren()
		local MaxDistance = 200
		local nearestTarget

		for _,ally in pairs(allies) do
			if ally then
				if ally.Humanoid.Health > 0 then
					local target = ally
					local distance = (humrp.Position - target.HumanoidRootPart.Position).Magnitude

					if distance < MaxDistance then
						nearestTarget = target
						MaxDistance = distance
					end
				end
			end
		end

		return nearestTarget
	end
	
	local function agro()
		repeat task.wait(0.05)
		local target = findTarget()
			if target and target.HumanoidRootPart then
		local distance = (humrp.Position - target.HumanoidRootPart.Position).Magnitude
--[[		local path = PathfindingService:CreatePath()
		local success, errorMessage = pcall(function()
			path:ComputeAsync(humrp.Position, target.HumanoidRootPart.Position + target.HumanoidRootPart.Velocity.Unit * 3)
		end)]]
--		if success and path.Status == Enum.PathStatus.Success then
--			local waypoints = path:GetWaypoints()
--			for _,waypoint in pairs(waypoints) do
				
--				if waypoint.Action == Enum.PathWaypointAction.Jump then
--					hum:ChangeState(Enum.HumanoidStateType.Jumping)
--				end
				
				if distance <= 5 then
					EnemyAI[string.gsub(Enemy.Name,' ','')](humrp,hum,Enemy)
				else
					local targetVel = target.PrimaryPart.Velocity
					local leadBy = 7
					local lead
					if targetVel.Magnitude < 0.1 then
						lead = Vector3.new(0, 0, 0)
					else
						lead = targetVel.Unit * leadBy
					end
					hum:MoveTo(target.PrimaryPart.Position + lead)
				end
--			end
				--			end
				end
		until target == nil or target.Humanoid.Health == 0 or (humrp.Position - target.HumanoidRootPart.Position).Magnitude > maxDistance
	end
	
	local function walkToCore()
		local path = PathfindingService:CreatePath()
		
		local success, errorMessage = pcall(function()
			path:ComputeAsync(humrp.Position, CoreOfFactory.Position)
		end)
		WalkAnim:Play()
		if success and path.Status == Enum.PathStatus.Success then
			local waypoints = path:GetWaypoints()
			for _,waypoint in pairs(waypoints) do
				
				if waypoint.Action == Enum.PathWaypointAction.Jump then
					hum:ChangeState(Enum.HumanoidStateType.Jumping)
				end
				
				if findTarget() and (humrp.Position - findTarget().HumanoidRootPart.Position).Magnitude < maxDistance then
					agro()
				end
				
				hum:MoveTo(waypoint.Position)
				hum.MoveToFinished:Wait()
			end
		end
		WalkAnim:Stop()
	end
	
	walkToCore()
end

local RunOnce = false
local FastZombieDB = false
local enemyHitbox
function EnemyAI.FastZombie(humrp,hum,Enemy)
	if FastZombieDB == false then
		FastZombieDB = true
		--local AnimId = 'rbxassetid://6932293833'
		local AnimId = 'rbxassetid://11188195611'
		local Damage = 15
		local delay = 1
		
		if RunOnce == false then
			print('Running once')
			RunOnce = true
			enemyHitbox = RaycastHitbox.new(Enemy.RightHand)
			enemyHitbox:SetPoints(Enemy.RightHand,{Vector3.new(0,0,0),Vector3.new(-1,1,2),Vector3.new(-3.5,1,2)})
		end
		if not Anims:FindFirstChild(AnimId) then
			local animationInstance = Instance.new('Animation')
			animationInstance.Parent = Anims
			animationInstance.AnimationId = AnimId
			animationInstance.Name = AnimId
		end
		local AttackAnim = hum:LoadAnimation(Anims[AnimId])

		AttackAnim:Play()
		enemyHitbox:HitStart()

		enemyHitbox.OnHit:Connect(function(hit,humanoid)
			if humanoid.Parent.Name ~= Enemy.Name then
				humanoid:TakeDamage(Damage)
			end
		end)
		coroutine.wrap(function()
			AttackAnim.Stopped:Wait()
			enemyHitbox:HitStop()
			task.wait(delay)
			FastZombieDB = false
		end)()
	end
end

return EnemyAI
  • The code makes a new enemy which does specific things when it attacks based on the ‘The code I wanna tidy up’ function.


    When I call this, it finds the entity ‘fast zombie’ and then I just input the animations, some values such as the damage and boom i’ve got a new enemy, i’m planning on putting the enemies in replicatedstorage later for cloning purposes.

  • I’ve considered making it oop but I couldn’t figure out how to do the : parameter when calling it, i’ve looked at this post and several others yet I couldn’t make them work.

  • I just want to make it easier to copy and paste so that I can make a lot of enemy attacks very fast

If anyone needs a place download, then I will happily provide.

It seems like this function can only spawn one zombie at a time, because of the FastZombieDB variable. If you want to use it for many enemies at the same time You should just remove the FastZombieDB variable, or declare it in the function.

Since this is a constructor/factory function producing a new object it must use . instead of :. : is only used on existing objects, they are just like any other function just implicitly defining the ‘self’ variable as whatever is on the left hand side of the :.

Don’t worry too much about object oriented programming, it is falling out of style for a number of reasons. It’s important to remember OOP was designed to make thinking about programs easier. It can however make it much harder to read your own code especially as bugs show up. If OOP doesn’t seem like a good fit it probably isn’t, because it’s far from a perfect programming pattern.

-- OOP module script --
local module= {}
module.__index = module
function module.new(name: string)
    local new_object = setmetatable({}, module)
    -- our 'new_object' and it's variables becomes 'self' in :functions
    new_object.name = name
    return new_object
end

function module:Say(words: string)
    -- new_object.name
    print(self.name, ": ", words)
end

-- using module script --
local factory = require(oopmodulescript)

local my_OOP_object = factory.new("zombie")

my_OOP_object:Say("Brainz!!")

This example shows a basic metatable usage that will make use of :functions. The more complicated object oriented part is inheritance, which I think you should only use if absolutely necessary.

Thanks for replying, yet I don’t think that I can get rid of the FastZombieDB or put it in the function as it gets called a lot of times per second, and I need the debounce to stop it from excessively running the stuff inside of the EnemyAI.FastZombie, as I am using a repeat until to check the distance and call the EnemyAI.FastZombie function. If I put the DB inside of the function, it would keep declaring it to be false I would presume (please correct me if I am wrong) making it completely useless, and the same goes for RunOnce and enemyHitbox, those variables only need to be called once.

I decided to go with OOP on this as I never did it before and I felt as if this would be a good thing to use it for, and i’ve been heavily encouraged to use it by a lot of people as apparently it would ‘make life easier for myself’, and the constructor is in

and it is called EnemyAI.new(), which creates the actual ai for the zombie.
EnemyAI.FastZombie just gives the EnemyAI.new function instructions for how to attack and what it should do to attack.