Hi. Im making a battle game and there is two teams, blue and red. Sometimes i spawn more soldiers and enemies, they stacking onto other npcs heads. Here is the video: Video
Btw im using pathfinding.
Hi. Im making a battle game and there is two teams, blue and red. Sometimes i spawn more soldiers and enemies, they stacking onto other npcs heads. Here is the video: Video
Btw im using pathfinding.
is there a way to stop this? because its really annoying and sometimes npcs standing on enemies head and cant kill
Also i disabled npc’s jump so npcs cant jump but they are still stacking onto other npcs heads
Without code snippet I can’t 100% tell you but it looks to me as if you are pathfinding directly to the enemies HumanoidRootPart(the npc wants to go directly to the center position of the enemy). If you want the NPC to stay distant from the enemy you could calculate the magnitude between the path waypoints position and the enemy before you do the :MoveTo() and only move the npc if it isn’t too close and else not.
You can do this with magnitude,
if (npcHumanoidRootPart.Position - target.HumanoidRootPart.Position).Magnitude > 5 then
--move to function, wont fire function if the target is within 5 studs
end
here is my code
local soldier = script.Parent
local basePart = soldier.Torso
local humanoid = soldier.Humanoid
local damageDelay = 0.5
local pathfindingservice = game:GetService("PathfindingService")
local runservice = game:GetService("RunService")
soldier.PrimaryPart:SetNetworkOwner(nil)
local function createPath(destination)
local pathfindingservice = game:GetService("PathfindingService")
local pathParameters = {
AgentHeight = 5.162,
AgentRadius = 2,
AgentCanJump = false
}
local path = pathfindingservice:CreatePath(pathParameters)
path:ComputeAsync(basePart.Position, destination.Torso.Position)
for i, w in pairs(workspace.waypoints:GetChildren()) do
w:Destroy()
end
local waypoints = path:GetWaypoints()
for i, w in pairs(waypoints) do
local waypoint = Instance.new("Part")
waypoint.Name = tostring(table.find(waypoints,w))
waypoint.Position = w.Position
waypoint.CanCollide = false
waypoint.Parent = workspace.waypoints
waypoint.Shape = "Ball"
waypoint.Size = Vector3.new(1, 1, 1)
waypoint.Anchored = true
end
return path
end
local blockedTargets = {}
local target
local function findTarget(blockedTargets)
local targets = workspace.RedTeamSoldiers:GetChildren()
if #targets ~= 0 then
local maxDistance = math.huge
local nearestTarget
if targets then
for i, t in pairs(targets) do
if t.Humanoid.Health > 0 then
if not table.find(blockedTargets,t) then
if t.Torso then
local distance = (basePart.Position - t.Torso.Position).Magnitude
if distance < maxDistance then
nearestTarget = t
maxDistance = distance
end
end
else
local pathfindingservice = game:GetService("PathfindingService")
local pathParameters = {
AgentHeight = 5.162,
AgentRadius = 2,
AgentCanJump = false
}
local path = pathfindingservice:CreatePath(pathParameters)
path:ComputeAsync(basePart.Position, t.Torso.Position)
if path.Status == Enum.PathStatus.Success then
table.remove(blockedTargets,table.find(blockedTargets,t))
end
end
else
t.Parent = workspace.DiedSoldiers
end
end
else
nearestTarget = nil
end
return nearestTarget
end
end
local result = {}
local damaged = Instance.new("BoolValue")
damaged.Value = false
damaged:GetPropertyChangedSignal("Value"):Connect(function()
if damaged.Value == true then
wait(damageDelay)
damaged.Value = false
end
end)
function rotateTowards(target, this)
local targetPosition = target.Position
local thisPosition = this.Position
local rotationTowards = CFrame.new(thisPosition, targetPosition)
this.CFrame = this.CFrame:Lerp(rotationTowards, 0.5)
end
local function walkTo(destination)
local path = nil
local waypoints = nil
while true do
target = findTarget(blockedTargets)
if destination ~= target then
break
end
local distance = (basePart.Position - destination.Torso.Position).Magnitude
if destination.Humanoid.Health > 0 then
path = createPath(destination)
waypoints = path:GetWaypoints()
if waypoints[2] and distance > 4 then
humanoid:MoveTo(waypoints[2].Position)
end
if distance < 4 and damaged.Value == false then
rotateTowards(destination.Torso,basePart)
local anim = humanoid:LoadAnimation(script.SwordAnim)
anim:Play()
end
soldier.SwordHandle.Touched:Connect(function(hit)
if hit.Parent == destination and damaged.Value == false then
destination.Humanoid.Health -= 10
damaged.Value = true
end
end)
else
break
end
if path.Status == Enum.PathStatus.NoPath then
table.insert(blockedTargets,destination)
return blockedTargets
else
for i, t in pairs(blockedTargets) do
if t == destination then
table.remove(blockedTargets,table.find(blockedTargets,t))
if path.Status == Enum.PathStatus.NoPath then
break
end
end
end
end
end
return blockedTargets
end
local function patrol()
local targetList = workspace.RedTeamSoldiers:GetChildren()
if #targetList > 0 then
target = findTarget(result)
if target then
result = walkTo(target)
end
else
end
wait(0.00001)
end
while true do
patrol()
end
oh by the way, im using torso to move enemies. Because before i use humanoidrootpart i got many errors (like “humanoidrootpart is not valid member of enemy”) so i decided to use torso.
im already using this to calculate distance
Why dont you just use Humanoid:MoveTo()? Is this a local script? (you should use :WaitForChild() so it doesnt say “HumanoidRootPart” is not a valid member of enemy
im using it, look at the walkto function, i used this. its local script.
but if i change torso to humanoidrootpart does this fix it?
I don’t understand this, why are you directly indexing one waypoint and not doing it with a for loop?
Because when i use loop, it doesnt update path everytime. I created a post before about that and 5uphi said follow next waypoint. Here is post: movetofinished is delaying
It sucks to say this about others people code, (since my code is also a bit rusty at some times),
but you should maybe rewrite it.
You can use this module to rewrite your pathfinding. It is more reliable than robloxs’ default pathfinding service (as it is easy to use and wont mess with your code, and i saw the post you mentioned, it updates with the characters position as well).
Ok I understand, if you recompute it it makes sense. The distance > 4 you are using is the distance before the NPC was moved but you need to calculate the distance the NPC would have if it went to the waypoint because else it would be too late.
Basically if the position between the NPC and enemy was 6 Studs but the waypoint is 1 stud away from the enemy it would move the NPC to the waypoint but afterwards there’s only 1 Stud between NPC and enemy.
if waypoints[2] then
local waypoint = waypoints[2]
local waypointDistance = (waypoint.Position - destination.Torso.Position).Magnitude
if waypointDistance < 4 then
humanoid:MoveTo(waypoint.Position)
end
end
Something like this, also I recommend you try avoid nesting (many If’s/Indentions in each other) then your code looks much cleaner and is easy to undertand. Basically you want to do the opposite first like
if #targets == 0 then return end
local maxDistance = math.huge
-- etc
if not targets then
nearestTarget = nil
return
end
-- rest which would be in the if targets
Well… just so you know, you should be using server scripts for NPCs, and local scripts for players. (There is an exception if you need to use remote events, but im pretty sure local scripts are made just for client, or the player, not server, or NPCs because a NPC is not an actual player)
I changed distance to waypoint distance but it still not working they are stacking onto other npcs heads
here is my updated code
local soldier = script.Parent
local basePart = soldier.Torso
local humanoid = soldier.Humanoid
local damageDelay = 0.5
local pathfindingservice = game:GetService("PathfindingService")
local runservice = game:GetService("RunService")
soldier.PrimaryPart:SetNetworkOwner(nil)
local function createPath(destination)
local pathfindingservice = game:GetService("PathfindingService")
local pathParameters = {
AgentHeight = 5.162,
AgentRadius = 2,
AgentCanJump = false
}
local path = pathfindingservice:CreatePath(pathParameters)
path:ComputeAsync(basePart.Position, destination.Torso.Position)
for i, w in pairs(workspace.waypoints:GetChildren()) do
w:Destroy()
end
local waypoints = path:GetWaypoints()
for i, w in pairs(waypoints) do
local waypoint = Instance.new("Part")
waypoint.Name = tostring(table.find(waypoints,w))
waypoint.Position = w.Position
waypoint.CanCollide = false
waypoint.Parent = workspace.waypoints
waypoint.Shape = "Ball"
waypoint.Size = Vector3.new(1, 1, 1)
waypoint.Anchored = true
end
return path
end
local blockedTargets = {}
local target
local function findTarget(blockedTargets)
local targets = workspace.RedTeamSoldiers:GetChildren()
if #targets ~= 0 then
local maxDistance = math.huge
local nearestTarget
if targets then
for i, t in pairs(targets) do
if t.Humanoid.Health > 0 then
if not table.find(blockedTargets,t) then
if t.Torso then
local distance = (basePart.Position - t.Torso.Position).Magnitude
if distance < maxDistance then
nearestTarget = t
maxDistance = distance
end
end
else
local pathfindingservice = game:GetService("PathfindingService")
local pathParameters = {
AgentHeight = 5.162,
AgentRadius = 2,
AgentCanJump = false
}
local path = pathfindingservice:CreatePath(pathParameters)
path:ComputeAsync(basePart.Position, t.Torso.Position)
if path.Status == Enum.PathStatus.Success then
table.remove(blockedTargets,table.find(blockedTargets,t))
end
end
else
t.Parent = workspace.DiedSoldiers
end
end
else
nearestTarget = nil
end
return nearestTarget
end
end
local result = {}
local damaged = Instance.new("BoolValue")
damaged.Value = false
damaged:GetPropertyChangedSignal("Value"):Connect(function()
if damaged.Value == true then
wait(damageDelay)
damaged.Value = false
end
end)
function rotateTowards(target, this)
local targetPosition = target.Position
local thisPosition = this.Position
local rotationTowards = CFrame.new(thisPosition, targetPosition)
this.CFrame = this.CFrame:Lerp(rotationTowards, 0.5)
end
local function walkTo(destination)
local path = nil
local waypoints = nil
while true do
target = findTarget(blockedTargets)
if destination ~= target then
break
end
local distance
if waypoints then
distance = (waypoints[2].Position - destination.Torso.Position).Magnitude
end
if destination.Humanoid.Health > 0 then
path = createPath(destination)
waypoints = path:GetWaypoints()
if distance then
if waypoints[2] and distance > 4 then
humanoid:MoveTo(waypoints[2].Position)
end
if distance < 4 and damaged.Value == false then
rotateTowards(destination.Torso,basePart)
local anim = humanoid:LoadAnimation(script.SwordAnim)
anim:Play()
end
end
soldier.SwordHandle.Touched:Connect(function(hit)
if hit.Parent == destination and damaged.Value == false then
destination.Humanoid.Health -= 10
damaged.Value = true
end
end)
else
break
end
if path.Status == Enum.PathStatus.NoPath then
table.insert(blockedTargets,destination)
return blockedTargets
else
for i, t in pairs(blockedTargets) do
if t == destination then
table.remove(blockedTargets,table.find(blockedTargets,t))
if path.Status == Enum.PathStatus.NoPath then
break
end
end
end
end
end
return blockedTargets
end
local function patrol()
local targetList = workspace.RedTeamSoldiers:GetChildren()
if #targetList > 0 then
target = findTarget(result)
if target then
result = walkTo(target)
end
else
end
wait(0.00001)
end
while true do
patrol()
end
Mind If I ask is this totally accurate battle simulator in roblox?
yes, im making totally accurate battle simulator
You are calculating the distance from the old waypoints[2] to the enemy, calculate the distance after you’ve created the new path.