I'm not that great of a programmer, and I'd followed a tutorial and made my own edits to make an AI. It worked perfectly until I starting cloning it for minigames where it would fail to target the player when they got in range or touched the "detector". Attached the entire script below.

local Goblin = script.Parent:WaitForChild("Humanoid")
local Root = script.Parent:WaitForChild("HumanoidRootPart")
local Head = script.Parent:WaitForChild("Head")
local lowerTorso = script.Parent:WaitForChild("LowerTorso")
local runservice = game:GetService("RunService")

local AttackAnim = script:WaitForChild("SlashAnim")
local Attack = Goblin:LoadAnimation(AttackAnim)
local BlockAnim = script:WaitForChild("BlockAnim")
local Block = Goblin:LoadAnimation(BlockAnim)
Attack.Priority = Enum.AnimationPriority.Action
local Blocking = script.Parent.Blocking

local AttackSound = script:WaitForChild("Slash")
local RoarSound = script:WaitForChild("Roar")

local clone = script.Parent:Clone()

function walkRandomly()
	local xRand = math.random(-50,50)
	local zRand = math.random(-50,50)
	local goal = Root.Position + Vector3.new(xRand,0,zRand)
	
		local path = game:GetService("PathfindingService"):CreatePath()
		path:ComputeAsync(Root.Position, goal)
		local waypoints = path:GetWaypoints()
	
		if path.Status == Enum.PathStatus.Success then
			for _, waypoint in ipairs(waypoints) do
				if waypoint.Action == Enum.PathWaypointAction.Jump then
					Goblin.Jump = true
				end
				Goblin:MoveTo(waypoint.Position)
				local timeOut = Goblin.MoveToFinished:Wait(1)
				if not timeOut then
					Goblin.Jump = true
					walkRandomly()
				end
					end
		else
			wait(1)
			walkRandomly()
	end
end

function findPath(target)
	runservice.Heartbeat:Connect(function()
	local path = game:GetService("PathfindingService"):CreatePath()
	path:ComputeAsync(Root.Position, target.Position)
	local waypoints = path:GetWaypoints()
	
	if path.Status == Enum.PathStatus.Success then
		for _, waypoint in ipairs(waypoints) do
			if waypoint.Action == Enum.PathWaypointAction.Jump then
				Goblin.Jump = true
			end
			Goblin:MoveTo(waypoint.Position)
			local timeOut = Goblin.MoveToFinished:Wait(1)
			if not timeOut then
				Goblin.Jump = true
				findPath(target)
				break
			end
			if checkSight(target) then
				repeat
					Goblin:MoveTo(target.Position)
					attack(target)
					wait(0.1)
					if target == nil then
						break
					elseif target.Parent == nil then
						break
					end
				until checkSight(target) == false or Goblin.Health < 1 or target.Parent.Humanoid.Health < 1
				break
			end
			if (Root.Position - waypoints[1].Position).Magnitude > 20 then
				findPath(target)
				break
			end
		end
		end
	end)
end

function checkSight(target)
	local ray = Ray.new(Root.Position, (target.Position - Root.Position).Unit * 40)
	local hit,position = workspace:FindPartOnRayWithIgnoreList(ray, {script.Parent})
	if hit then
		runservice.Heartbeat:Connect(function()
		if hit:IsDescendantOf(target.Parent) and math.abs(hit.Position.Y - Root.Position.Y) < 3 then
			return true
			end
		end)
	end
	return false
end

function findTarget()
	local dist = 50
	local target = nil
	local potentialTargets = {}
	local seeTargets = {}
	for i,v in ipairs(workspace:GetChildren()) do
		runservice.Heartbeat:Connect(function()
			local human = v:FindFirstChild("Humanoid")
			local torso = v:FindFirstChild("Torso") or v:FindFirstChild("HumanoidRootPart")
			if human and torso and v.Name ~= script.Parent.Name then
				if (Root.Position - torso.Position).Magnitude < dist and human.Health > 0 then
					table.insert(potentialTargets,torso)
				end
			end
		end)
	end
	if #potentialTargets > 0 then
		for i,v in ipairs(potentialTargets) do
			if checkSight(v) then
				table.insert(seeTargets, v)
			elseif #seeTargets == 0 and (Root.Position - v.Position).Magnitude < dist then
				target = v
				dist = (Root.Position - v.Position).Magnitude
			end
		end
	end
	if #seeTargets > 0 then
		dist = 200
		for i,v in ipairs(seeTargets) do
			if (Root.Position - v.Position).Magnitude < dist then
				target = v
				dist = (Root.Position - v.Position).Magnitude
			end
		end
	end
		if target then
			if math.random(20) == 3 then
				RoarSound:play()
			end
		end
		return target
end

function attack(target)
	if (Root.Position - target.Position).Magnitude < 7 then
		Attack:Play()
		wait(0.3)
		AttackSound:Play()
		if target.Parent ~= nil then 
			if math.random(5) == 3 then
				Blocking.Value = true
				Block:Play()
				wait(2)
				Block:Stop()
				Blocking.Value = false
			else
				if target.Parent.Blocking.Value == false then
					target.Parent.Humanoid:TakeDamage(15)
				elseif target.Parent.Blocking.Value == true then
					script.Clang:Play()
				end
			end
		end
		wait(1)
	end
end

function died()
	wait(5)
	script.Parent:Destroy()
end

Goblin.Died:Connect(died)

function main()
	local target = findTarget()
	if target then
		Goblin.WalkSpeed = 16
		findPath(target)
	else
		Goblin.WalkSpeed = 12
		walkRandomly()
		end
end

while wait(0.1) do
	if Goblin.Health < 1 then
		break
	end
	main()
end

script.Parent.Detector.Touched:Connect(function(hit)
	if hit.Parent:FindFirstChild("Humanoid") and hit.Parent.Name ~= "Goblin" then
		local target = findTarget()
			checkSight(target)
	end
end)

4 comments

0

You could probably put a lot of goblins in a model in ReplicatedStorage and put that model in the Workspace when the minigame starts.

0

What I am doing is putting the amount I want in every wave in folders in the ReplicatedStorage, then cloning each wave's folder which contains the goblins and it still breaks.

0

Dude, I've never written a script that long before and your calling yourself "not a great programmer"?, Btw I've also been working on an AI recently without using pathfinding which I can explain the whole process of it if you want the script.

0

Well I followed a tutorial for practically all of it, but I need the pathfinding because the AI needs to be able to chase the player and attack them.