How can I make NPCs not ignore non collideable parts?

So I’ve got this pathfinding script right,

and basically, it works, as expected
but the problem is that the enemies will stack up into one place, which makes melee-fighting extremely difficult or impossible

they’ve got this detection part around them, but since it can’t collide nor query, they ignore it
my question is, how can i make them take that part into consideration so they also avoid that?

8 Likes

Hmm I think you can use collision groups and make it so the NPC can collide with it but nothing else can

5 Likes

collision groups? what are those

never heard never seen never used

5 Likes
5 Likes

uhhhh

where is the collision groups button on the beta UI :skull:

4 Likes

Maybe in group? I have no idea tbh lol

4 Likes

okay i think i’m doing something extremely stupid

image

image

CollisionGroupPart is the uh, anti stacking part that’s meant to block enemies from walking into each other

it can collide with itself, but it doesn’t prevent colliding anyway???

3 Likes

Honestly all this info is hurting my brain rn. Ill try and help more later lol

4 Likes

Instead of using physical parts to prevent enemies from stacking up, use code to prevent enemies from getting too close and stacking up. Otherwise, you’ll run into physics issues like the one you’re having right now.

1 Like

you know this is very much easier said than done

how can i even achieve something like this :sob: , is there a way to code in parts to pathfinding?? (if that makes sense)

2 Likes

you know this is very much easier said than done

What isn’t easier said than done? Hahaha

You’ll need to make your pathfinding algorithm treat the rest of the enemies like a wall (aka an obstacle to avoid).

1 Like

Okay so basically, CanQuery property lets you decide if you want the BasePart to be considered in spatial queries such as raycasts and region3 finds. (just wanted you to be clear on that since it doesn’t seem like it matters).

Now, if you’re facing problems in using collision groups, heres how they work:
Its simple, you create a collision group, and either use BasePart.CollisionGroup in script or manually set the collision group through properties.

You would have to create 2 groups, for example “NPCs” and “NPCsDontCollide”. And using a script, you’d have to set every single basepart in the npc to the collision group “NPCs”. And in the collision groups manager, in “NPCs can collide with”, you set “NPCsDontCollide” group checkbox to false.

Now, all you have to do is set the collision group of parts you dont want npcs to collide to “NPCsDontCollide”.

3 Likes

so what i’m getting from this

  • create a group called Enemies/NPCs
  • insert every bodypart of the enemy (including the collision part) into that group
  • make it collide with itself

isn’t that what i’m doing rn?
sorry if i’m stupid i’m just confused (and stupid)

2 Likes

Well, they wouldn’t stack up if you made it so they don’t collide with each other using CollisionGroups. But this might also make it look like they all disappear into 1 npc if they have the same walkto position. Is that what you want?

2 Likes

Yes so basically if you want to make them not collide with each other you set this checkbox to false:
image

and it would make it so every part that is of the CollisionGroup “Enemies” will not collide with each other, fixing the NPCs stacking up issue after you set every basepart inside the npc character models to the collision group “Enemies”.

2 Likes

wait wait, why does it have to be false?

it can’t collide, so shouldn’t it ignore those “collisions” and just stack again?

2 Likes

I thought what you meant by stacking up was going over one another. Now I know what you mean, well, to fix them all stacking up in one place, you’d have to make sure that every single npc has a unique moveto position, or atleast make sure that not all of them have the same moveto position.

1 Like

well, they are programmed to hunt down the player

they should walk around that grey part, so they don’t stack up in one place (which is very much seen in the video)

1 Like

Hmmm yeah, I see, let me think of what could be done, just to make sure, are you using pathfindingservice or just using Humanoid:MoveTo(playerHRPPosition) in a loop?

1 Like

pathfinding service

incase code is needed:

local pfService = game:GetService("PathfindingService")


local pathfinding = {}

function pathfinding.melee(Humanoid, targetPosition)
	if not Humanoid then return end		
	if not targetPosition then return end

	local pathParameters = {
		AgentRadius = 2,
		AgentHeight = 2,
		AgentCanJump = true,
		AgentCanClimb = false
	}

	local path = pfService:CreatePath(pathParameters)
	local humanoidRootPart = Humanoid.Parent:FindFirstChild("HumanoidRootPart")

	local startPosition = humanoidRootPart.Position


	local success, errorMessage = pcall(function()
		path:ComputeAsync(startPosition, targetPosition)
	end)

	if not success then
		warn("Pathfinding failed: " .. errorMessage)
		return
	end

	local waypoints = path:GetWaypoints()

	if path.Status == Enum.PathStatus.Success and #waypoints > 0 then
		for i = 2, #waypoints do
			local waypoint = waypoints[i]

			if waypoint.Action == Enum.PathWaypointAction.Jump then
				Humanoid.Jump = true
			end

			Humanoid:MoveTo(waypoint.Position)
			local moveFinished = Humanoid.MoveToFinished:Wait()
		end    
		return path
	end    
end

return pathfinding

server script

local pathfindingModule = require(game:GetService("ServerScriptService"):WaitForChild("Enemies").PathfindingModule)

local runService = game:GetService("RunService")
local enemiesFolder = workspace:WaitForChild("Enemies")

local heartbeatConnection

heartbeatConnection = runService.Heartbeat:Connect(function()
	if #enemiesFolder:GetChildren() > 0 then
		local enemies = enemiesFolder:GetChildren()

		for _, enemy in ipairs(enemies) do
			if enemy.EnemyType.Value == "MELEE" then
				local detectionBox = enemy:FindFirstChild("DetectionPart")
				local humanoid = enemy:FindFirstChildOfClass("Humanoid")


				local closestPlayer = nil
				local LOS = workspace:GetPartBoundsInBox(detectionBox.CFrame, detectionBox.Size)

				for _, v in pairs(LOS) do
					if v.Parent:FindFirstChild("Humanoid") then
						local targetPlayer = game.Players:GetPlayerFromCharacter(v.Parent)

						if targetPlayer then
							if closestPlayer == nil or (enemy.HumanoidRootPart.Position - targetPlayer.Character.HumanoidRootPart.Position).Magnitude < (enemy.HumanoidRootPart.Position - closestPlayer.Character.HumanoidRootPart.Position).Magnitude then
								closestPlayer = targetPlayer
							end
						end
					end
				end

				task.spawn(function()
					if closestPlayer then
						local targetPosition = closestPlayer.Character.Torso.PathfindPart.Position
						pathfindingModule.melee(humanoid, targetPosition)
					else
						humanoid:MoveTo(enemy.HumanoidRootPart.Position)
					end
				end)
			end
		end
	end
end)
1 Like