Flying Enemy keep a distance away from the player

I am trying to make a flying/hovering type enemy for my game, but when I have the NPC chase the player, the NPC rams the player. I want the NPC to keep a certain distance away from the player so that they can shoot projectiles (similar to the Wisps for Risk Of Rain 2)

I’ve tried to see if I can subtract a value from the target vector, but I can’t seem to figure it out.

-- check if attack possible , if not chase then
-- choose attack
-- repeat

local UpdateRate_PlayerDetector = 0.5
local NPC = script.Parent
local NPCRoot = NPC.Head
local Players = game.Players

local Settings = NPC.Settings
local PlayerDetectionSettings = Settings.PlayerDetection

local MinRange = 0
local MaxRange = 50

function findNearestPlayer() -- function to find nearest player
	local playerList = Players:GetPlayers()
	local nearestPlayer = nil
	for _, player in pairs(playerList) do
		character = player.Character
		if character then
			CurrentPlayerLocation = character:WaitForChild("HumanoidRootPart").Position
			DistanceTo = (NPCRoot.Position - CurrentPlayerLocation).Magnitude

			print(DistanceTo)
		end
	end
	return CurrentPlayerLocation, DistanceTo, character
end


while true do

	findNearestPlayer()
	if character then
		if DistanceTo < MaxRange and DistanceTo > MinRange then

			NPCRoot.Mover.Position = CurrentPlayerLocation

		else

			NPCRoot.Mover.Position = NPCRoot.Mover.Position

		end

	end

	wait(UpdateRate_PlayerDetector)
end

--chase player using the mover in HumanoidRootPart 

I’m relatively new to RScript (3 years on and off). If anyone has any ideas or documentation I haven’t seen, that would be greatly appreciated.

Try this code I have! The Target is the player’s humanoidrootpart, the HumanoidRootPart is the AI’s humanoidrootpart, and you can change RunDistance to whatever you want (mine is 6.75)! Just make it so if the player is too close to the AI, this code activates!

local function RunAway()
	if Target ~= nil then
		Humanoid.AutoRotate = false
		
		local PositionDifference = (Target.Position - HumanoidRootPart.Position) 
		local NormalizedDirection = PositionDifference.Unit
		
		Humanoid:MoveTo(HumanoidRootPart.Position + NormalizedDirection * -1 * RunDistance)
		
		for i = 0, 1, 0.01 do
			task.wait()
			HumanoidRootPart.CFrame = HumanoidRootPart.CFrame:Lerp(CFrame.lookAt(HumanoidRootPart.Position, Target.Position), i)
		end
	else
		return nil
	end
end

The NPC is bouncing back and forth; could I be implementing this wrong? vector3 math is difficult for me to visualize

local UpdateRate_PlayerDetector = 0.5
local NPC = script.Parent
local NPCRoot = NPC.Head
local Players = game.Players

local Settings = NPC.Settings
local PlayerDetectionSettings = Settings.PlayerDetection

local MinRange = 0
local MaxRange = 50
local KeepDist = 15

function findNearestPlayer() -- function to find nearest player
	local playerList = Players:GetPlayers()
	local nearestPlayer = nil
	for _, player in pairs(playerList) do
		character = player.Character
		if character then
			CurrentPlayerLocation = character:WaitForChild("HumanoidRootPart").Position
			DistanceTo = (NPCRoot.Position - CurrentPlayerLocation).Magnitude
			
			PositionDifference = (CurrentPlayerLocation - NPCRoot.Position) 
			NormalizedDirection = PositionDifference.Unit

			--print(DistanceTo)
		end
	end
	return CurrentPlayerLocation, DistanceTo, character, PositionDifference, NormalizedDirection
end



while true do

	findNearestPlayer()
	if character then
		if DistanceTo < MaxRange and DistanceTo > MinRange and DistanceTo > KeepDist then

			NPCRoot.Mover.Position = CurrentPlayerLocation
			
			else if DistanceTo < KeepDist then

				NPCRoot.Mover.Position = (NPCRoot.Position + NormalizedDirection * -1 * KeepDist)
				
			end

		end

	end

	wait(UpdateRate_PlayerDetector)
end