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:
- 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.
- 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.
- 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.
- 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