What should I do to rework my AI?

Hello Developers.

I’m done finishing AI for a friendly AI who fights enemies for you for my The Battle Cat’s inspired game. (2D, Tower Defense game). The issue is that I want to revamp it, although I don’t know what to revamp and how to as well of a few bugs.

So I want to change on the AI is:

  1. Detecting whenever or not an humanoid is on it’s side or on the enemy team - The script constantly loops through all of the NPC’s inside of a folder called “ExistingEntities”. If it detects a NPC with the “EnemyTag” and is within range, it will attack it. I want to revamp it so that if it somehow manages to switch teams (Like an enemy switching to your side) it would switch tags and attack the other team instead.
  2. Using some other than .Touched(). Currently it uses .Touched() which I might turn away from since from what I heard, it would be too slow to activate and might cause the AI to not land a hit perfectly. I also want it so the AI can miss their attack, either by enemies jumping over or dodging the attack in general or just be within it’s blindspot.
  3. This isn’t much of a “change a bad practice thing to something better” thingy but there is an issue where friendly humanoids would die accidentally by damaging each other. I managed to pinpoint why and tried fixing it, although it only resulted on the friendly humanoids to not be able to damage enemies at all.
  4. Stop whenever the AI is attacking, whenever the AI is spawned manually by the player, it will automatically move via a handler script in ServerScriptService.
local Warlock = script.Parent
local Hitbox = Warlock:WaitForChild("Hammer").Hitbox
--Hum
local Humanoid = Warlock:WaitForChild("Humanoid")
Humanoid.BreakJointsOnDeath = false
local Animator = Humanoid:WaitForChild("Animator")
--//Functions
local function RaycastEffect(part)
	local RayParams = RaycastParams.new()
	RayParams.FilterDescendantsInstances = {workspace.Debris}
	RayParams.FilterType = Enum.RaycastFilterType.Exclude
	
	local Angle = 0
	
	for i=1, 30 do
		local Size = math.random(2,3)
		local Part = Instance.new("Part")
		Part.Size = Vector3.new(1, 1, 1)
		Part.Position = Hitbox.Position
		Part.Anchored = true
		Part.CanCollide = false
		Part.CFrame = Part.CFrame * CFrame.fromEulerAnglesXYZ(0,math.rad(Angle),0) * CFrame.new(5, 5, 0)
		
		game:GetService("Debris"):AddItem(Part,5)
		
		local Raycast = workspace:Raycast(Part.CFrame.Position, Part.CFrame.UpVector * -10, RayParams)
		if Raycast then
			Part.Position = Raycast.Position + Vector3.new(0, -5, 0)
			Part.Material = Raycast.Instance.Material
			Part.Color = Raycast.Instance.Color
			Part.Size = Vector3.new(Size, Size, Size)
			Part.Orientation = Vector3.new(math.random(-180, 180), math.random(-180, 180), math.random(-180, 180))
			Part.Parent = workspace.Debris
			
			local Tween = game:GetService("TweenService"):Create(Part, TweenInfo.new(.25, Enum.EasingStyle.Sine, Enum.EasingDirection.Out), {Position = Part.Position + Vector3.new(0, 5, 0)}):Play()
			delay(4, function()
				local Tween = game:GetService("TweenService"):Create(Part, TweenInfo.new(.25, Enum.EasingStyle.Sine, Enum.EasingDirection.Out), {Position = Part.Position + Vector3.new(0, -5, 0)}):Play()
			end)
			Angle += 25
		end
	end
end
--DEATH
local DeathFunc
DeathFunc = Humanoid.Died:Connect(function()
	for _, M6D in pairs(Warlock:GetDescendants()) do
		if M6D:IsA("Motor6D") then
			local socket = Instance.new("BallSocketConstraint")
			local a1 = Instance.new("Attachment")
			local a2 = Instance.new("Attachment")
			a1.Parent = M6D.Part0
			a2.Parent = M6D.Part1
			socket.Parent = M6D.Parent

			socket.Attachment0 = a1
			socket.Attachment1 = a2
			a1.CFrame = M6D.C0
			a2.CFrame = M6D.C1

			socket.LimitsEnabled = true
			socket.TwistLimitsEnabled = true
			M6D:Destroy()
		end
	end

	local DeathYell = Instance.new("Sound",Warlock.PrimaryPart)
	DeathYell.SoundId = "rbxassetid://1080610827"
	DeathYell:Play()

	DeathFunc:Disconnect()
	task.wait(5)
	Warlock:Destroy()
end)

--//ENRAGE
local ENRAGEMODE = false
Humanoid.HealthChanged:Connect(function(Health)
	if Health <= Humanoid.MaxHealth/2 and ENRAGEMODE ==false then
		ENRAGEMODE = true
		local EnrageAnim = Animator:LoadAnimation(script.Rage)
		EnrageAnim:Play()
		EnrageAnim:GetMarkerReachedSignal("RageMode"):Connect(function()
			local WarlocksHelmet = Warlock.SwordHelm
			game:GetService("Debris"):AddItem(WarlocksHelmet,3.8)

			WarlocksHelmet.Parent = workspace.Debris
			WarlocksHelmet.Handle.Decal.Transparency = 0
			WarlocksHelmet.Handle.Position = Warlock.Head.Position + Vector3.new(0, 1, 0)
			WarlocksHelmet.Handle.AssemblyLinearVelocity = Vector3.new(math.random(-20,20), 25, math.random(-20,20))
		end)
	end
end)
--//Getting nearby enemies
local DB = false
task.wait(0.8)
while task.wait() and Humanoid.Health >= 1 do
	
	for _, Enemy in pairs(workspace.ExistingEntities:GetChildren()) do
		if Enemy:IsA("Model") and Enemy:HasTag("EnemyTag") then
			
			local Magnitude = (Warlock.HumanoidRootPart.Position - Enemy.PrimaryPart.Position)
			if Magnitude.Magnitude <= 12 and not DB then
				DB = true
				Humanoid.WalkSpeed = 0
				task.wait(1.5)
				
				local ATKAnim = Humanoid:WaitForChild("Animator"):LoadAnimation(script.AttackAnim)
				ATKAnim:Play()
				ATKAnim:GetMarkerReachedSignal("Smash"):Connect(function()
					RaycastEffect(Hitbox)
					Hitbox.HitSound:Play()
					
					local Hits = {}
					local CanDamage = true
					Hitbox.Touched:Connect(function(OnHit)
						local model = OnHit:FindFirstAncestorWhichIsA("Model")
						local model_hum = model and model:FindFirstChildWhichIsA("Humanoid")
						if model_hum and CanDamage and not Hits[model] then

							Hits[model] = true
							model_hum:TakeDamage(150)
							task.wait(2)
							Hits[model] = false

						end
					end)
				end)
				
				task.wait(3)
				Humanoid.WalkSpeed = 1.8
				CanDamage = false
				DB = false
			end
			
		end
	end
end
1 Like