How would I go about this?

I thought of this script which includes npc pathfinding and a function for chatting with other npcs. But would it be more optimal for it to be a central script (a script controlling said functions across multiple characters). Or if all the characters each had a copy of the script?

1 Like

It will barely matter in terms of how much processing and memory it uses. It would be easier to maintain it if it’s one script though since any changes will affect everyone immediately.

1 Like

How would i go about this? Like pathfinding like 10 characters?

The very simple way that is almost like using a single script is to just create a function that is basically a script you would run on each of them, then task.spawn or whatever passing in the NPC it controls to the function. Now this function controls everything but is scheduled to run like different scripts, but from the same script. The other approaches I can think of now boil down the same idea except they may split off something like pathfinding to run by itself or just divide the work slightly differently but fundamentally the same idea, spawn a function that manages the NPC per NPC. It’s fine if this function never returns until the NPC dies or unloads.

1 Like

Careful with network usage and replication. Moving 10 npc may not seem that great but as you’ll potentially want more, eventually replication will start taking a toll on network receiving.

Don’t do this, this is very unoptimized and causes a lot of lag.

Instead you should use events to handle pathfinding. All done within a single script of course.
I have developped the pathfinding like this the other day so here’s my code. I want you to look at how it disconnects once it reaches its destination, gets blocked, or changes

local WanderingNPCS = {
    --an array of rigs.
    workspace.Rig
}
local function Pathfind(npc:Model, pos)
	local VecObj:Vector3Value = npc:FindFirstChild("PathfindTo")
	VecObj.Value = pos
	
	local Humanoid = npc:FindFirstChildOfClass("Humanoid")
	
	local waypoints
	local nextWaypointIndex
	local reachedConnection
	local blockedConnection
	local TouchedConnection
	local touched = false
	
	local Path = PathfindingService:CreatePath({
		AgentRadius = 2,
		AgentHeight = 5,
		AgentCanJump = true,
		AgentCanClimb = true,
		Costs = Costs
	})
	
	local function FollowPath(destination)
		if Humanoid.Sit == true then
			Humanoid.Jump = true
		end
		
		local suc, err = pcall(function()
			return Path:ComputeAsync(npc.PrimaryPart.Position, destination)
		end)
		
		if suc and Path.Status == Enum.PathStatus.Success then
			waypoints = Path:GetWaypoints()

			blockedConnection = Path.Blocked:Connect(function(blockedWaypointIndex)
				if blockedWaypointIndex >= nextWaypointIndex then
					FollowPath(destination) --try again
					blockedConnection:Disconnect()
				end
			end)
			
			--TODO: Make it so that npcs don't bump into eachother.
			--Maybe make the npc move right for a bit when they touched another HumanoidRootPart?
			
			if not reachedConnection then
				reachedConnection = Humanoid.MoveToFinished:Connect(function(reached)
					if reached and nextWaypointIndex < #waypoints and pos == VecObj.Value then
						nextWaypointIndex += 1
						if npc.Humanoid.Sit == true or waypoints[nextWaypointIndex].Action == Enum.PathWaypointAction.Jump then
							npc.Humanoid.Jump = true
						end
						
						Humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
						
						task.wait(0.5)
						
						if npc.Humanoid.WalkToPoint.Y > npc.HumanoidRootPart.Position.Y then
							npc.Humanoid.Jump = true
						end
					else
						blockedConnection:Disconnect()
						reachedConnection:Disconnect()
					end
				end)
			end
			
			--print(waypoints)
			nextWaypointIndex = 2
			Humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
		else
			warn("Path not computed!", err, destination)
		end
	end
	
	FollowPath(pos)
end

local function Wander()
	for _, npc in WanderingNPCS do
		if npc.Humanoid.Sit == true then
			npc.Humanoid.Jump = true
		end
		
		Pathfind(npc, Locations[math.random(1, #Locations)].Position)
	end
end

while true do
	print("New location")
	Wander()
	task.wait(45)
end

I do not know how you would acheive the chatting feature but maybe edit the code and have that functionality?

While true you should handle the path itself with events, I meant this more in the sense of each NPC running it’s own code. So that loop where you are calling path on each NPC is handled internally by each NPC so they can chat independently.

So basically what you wrote except put the logic for each NPC at the same spot your wander function is but have it for each npc so it can pick what to do when it’s path is finished.

You can write your own dispatcher to handle this (like you are doing for your walking) but it won’t be that much more performant than just letting the Roblox code dispatcher schedule the NPC code to run.

Like this psuedocode

local handle PC(npc)
    while true do
        task.wait() --dont let worst case scenario crash the game
        local target = pickTalkPartner()
        walkTo(target) --handles pathfinding and pathwalk, returns when done
        chat(target)
    end
end

Then just task.spawn that for each NPC. Make sure it stops when the NPC dies though.

Could try and find 2 npcs and make them interact

I never thought of using events, I’ll look into it though