I’m trying to make an enemy horde AI, but the zombies are all clumping up together. This is the script with the behaviour. The “GetNearyByEnemies” is useless as of now.
What I’ve tried is getting nearby enemies, and using their positions to add a force onto each zombie to push them away from eachother. All this does it fling a few of them into the void, and the rest are unphased.
I’ve also tried raycasting infront of each enemy to see if there is another enemy infront of them, and then lower their walkspeed to create distance. All this did was create a chain of zombies will exactly the same distance between eachother, which looks really weird.
I also tried a creating pathfinder modifier inside the enemy model, so that the paths don’t go through other zombies, but this didn’t work either.
The only thing that I believe would help is something like this post, but the author and reply didn’t give much information to work off of. Any help is appreciated.
--// Variables \\--
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local PathfindingService = game:GetService("PathfindingService")
local ScriptService = game:GetService("ServerScriptService")
local Collection = game:GetService("CollectionService")
local SimplePath = require(ScriptService.Modules.SimplePath)
local Remotes = ReplicatedStorage.Remotes
local Config = {
SearchLoop = 5,
PathfindingLoop = 0.25
}
--// Module \\--
local module = {}
module. AgentParams = {
AgentHeight = 6,
AgentRadius = 3,
AgentCanJump = true,
Costs = {
Enemy = 5
}
}
function module.Init(Enemy)
local EnemyCharacter = Enemy.Model
local EnemyRoot = EnemyCharacter.PrimaryPart
local TargetCharacter
local PathfindCoro
-- finding target loop
task.spawn(function()
while task.wait(Config.SearchLoop) do
local NewTargetCharacter = SimplePath.GetNearestCharacter(EnemyRoot.Position)
-- change the pathfinding target
if NewTargetCharacter ~= TargetCharacter then
TargetCharacter = NewTargetCharacter
EnemyCharacter.Humanoid:MoveTo(EnemyRoot.Position) -- stops the past movement
if PathfindCoro then coroutine.close(PathfindCoro) end
if TargetCharacter then
PathfindCoro = coroutine.create(module.Pathfinding)
coroutine.resume(PathfindCoro, TargetCharacter, EnemyCharacter)
else
-- no target, stopped moving, standing still rn
end
end
end
end)
end
function module.FindDistance(point1, point2)
if type(point1) ~= Vector3 then point1 = point1.Position end
if type(point2) ~= Vector3 then point2 = point2.Position end
return (point1 - point2).Magnitude
end
function module.GetNearbyEnemies(Enemy, Range)
local NearbyEnemies = {}
for _, OtherEnemy in pairs(Collection:GetTagged("Enemy")) do
if OtherEnemy ~= Enemy and module.FindDistance(Enemy.PrimaryPart, OtherEnemy.PrimaryPart) < Range then
table.insert(NearbyEnemies, OtherEnemy)
end
end
return NearbyEnemies
end
function module.Pathfinding(Target, Enemy)
local Goal = Target.PrimaryPart
local Path = SimplePath.new(Enemy, module.AgentParams)
while task.wait(Config.PathfindingLoop) do
if not Goal then return end
-- moving
Path:Run(Goal.Position + Goal.AssemblyLinearVelocity * 0.15)
end
end
return module