How should I approach making a flying enemy AI for my side-scroller PvE game

Hi! I’m trying to make a flying enemy AI that moves in a “circular” path around the target WITH some occasions of random directions, so that it doesn’t look like its going around in a perfect circle.

I’m not really good at explaining so here is a clip of what I want the AI to look like

Here’s where I’m at right now :
Video

Code

local Char = script.Parent

local Speed = 0.2
local Radius = 15
local Angle = 0

local Reverse = false

game:GetService("RunService").Heartbeat:Connect(function(dt)
	if Reverse then
		Angle -= dt * math.pi * Speed
	else
		Angle += dt * math.pi * Speed
	end
	
	local NewPos = Vector3.new(
		0,
		Radius * math.cos(Angle),
		Radius * math.sin(Angle)
	)
	
	NewPos += workspace.TestPart.Position
	
	Char.PrimaryPart.CFrame = CFrame.new(NewPos, workspace.TestPart.Position)
end)

while task.wait(math.random(1, 3)) do
	Reverse = not Reverse
end

It’s got the circular motion down but it is still not 100% of how I want it to behave. So I tweaked the script to make it so that it generates two points around the target (in this case its “TestPart”). And in between those two points, it will create a part and assigns a random offset to that part.

Something like this :
Image
image_2025-01-03_125820024

Code

local Char = script.Parent

local Speed = 0.2
local Radius = 15

local function Test(Angle) -- Creates part on the assigned angle
	Angle *= 3.14 -- Converts it to radians
	
	local NewPos = Vector3.new(
		0,
		Radius * math.cos(Angle),
		Radius * math.sin(Angle)
	)
	
	NewPos += workspace.TestPart.Position
	
	local Part = Instance.new("Part", workspace)
	Part.Anchored = true
	Part.Size = Vector3.new(1, 1, 1)
	Part.Material = Enum.Material.Neon
	Part.Position = NewPos
	
	return Part
end

local function Draw(A1, A2) -- Creates parts between two angles
	Test(A1)
	
	local Angle = A1 + 0.1
	
	for i = 2, A2 * 10 do
		local Part = Test(Angle)
		Part.Position += Vector3.new(0, math.random(-1, 1), math.random(-1, 1))
		
		Angle += 0.1 -- Increments every 0.1 radians
	end
	
	Test(A2)
end

Draw(0, 0.5)

The next step I was thinking of was iterating between each part and tweening the enemy character’s position to that part’s position, but there’s one issue. Since this script is handled on the server, it will look jittery (which i don’t want)

And so to prevent that, I thought of making the client be the one tweening it. Then, whenever a player attacks (hit detection is handled client sided), it will fire a remote event with the position of the enemy on the client as one of the arguments to the server which does sanity checks (like if the said argument is close to any of the points or not, and other basic sanity checks).

But then I’m not sure if this solution is the best way to approach this issue, as I’m afraid there are better ways on how to do it and I’m just overcomplicating it. So, I would like some feedbacks!

2 Likes