How can I make a Player Like Spawn But for NPCs

Your code works however you should use the PivotTo method and you should also keep in mind your code will tp the NPC into the ground. You can account for this by calculating the height of the npc legs + hrp height/2

2 Likes

Updated the Module and Server script, thanks for your input.

1 Like

[+] half of Spawnlocation height / 2 :smirk:

1 Like
local spawnCFrame = spawnLocation.CFrame + Vector3.new(0, spawnLocation.Size.Y * 2, 0)
1 Like

Your module works, but also (this is optional) can you make it where maybe idk if multiple NPCs are going to be spawned can you make it where all those NPCs will be stacked or randomly spawned. its kind of where that devform was about the upgraded the size of it and saying that allot of players can now be stacked up or something like that let me try to find it.

See where I’m going with @DangerRangerJJD ?

Do you want NPCs spawning on top of each other?

yes and also including yk the randomly spawned areas base on the spawn size if you can make that happen

1 Like

Change Logs:

  • Replaced requirement 'IsA(“SpawnLocation”) with '.Name == “SpawnLocation”
  • Added Raycast function to check for NPCs in the same location
  • Added random position within SpawnLocation size/region function
  • Added declarations that will move the NPC based on the new functions

Module

local NPCSpawner = {}

-- Function to perform a raycast to check for an NPC at the spawn location
local function getNPCAtLocation(spawnLocation)
	local rayOrigin = spawnLocation.Position + Vector3.new(0, spawnLocation.Size.Y * 2, 0)
	local rayDirection = Vector3.new(0, -spawnLocation.Size.Y * 2, 0)
	local ray = Ray.new(rayOrigin, rayDirection)
	local hitPart, hitPosition = workspace:FindPartOnRay(ray)

	if hitPart and hitPart.Parent and hitPart.Parent:IsA("Model") and hitPart.Parent.PrimaryPart then
		return hitPart.Parent
	end
	return nil
end

-- Function to spawn NPC at a specific location
local function spawnNPC(npc, targetCFrame)
	local newNPC = npc:Clone()

	-- Ensure npc has a PrimaryPart
	if not newNPC.PrimaryPart then
		newNPC.PrimaryPart = newNPC:FindFirstChild("HumanoidRootPart")
	end

	-- Set the position of the NPC using PivotTo
	newNPC.Parent = workspace
	newNPC:SetPrimaryPartCFrame(targetCFrame)
end

-- Function to generate a random position within the size of the spawnLocation
local function getRandomPositionInSpawnLocation(spawnLocation)
	local spawnPos = spawnLocation.Position
	local spawnSize = spawnLocation.Size

	-- Generate random offsets within the range of half the spawnLocation's size
	local offsetX = (math.random() - 0.5) * spawnSize.X / 2
	local offsetY = (math.random() - 0.5) * spawnSize.Y / 2 
	local offsetZ = (math.random() - 0.5) * spawnSize.Z / 2

	return spawnPos + Vector3.new(offsetX, offsetY, offsetZ)
end

-- Main function to spawn NPCs
function NPCSpawner.spawnNPCs(npcModel, spawnLocations)
	for _, spawnLocation in pairs(spawnLocations) do
		if spawnLocation.Name == "SpawnLocation" then
			local existingNPC = getNPCAtLocation(spawnLocation)

			local spawnCFrame
			if existingNPC then
				-- Spawn on top of existing NPC
				spawnCFrame = existingNPC.PrimaryPart.CFrame + Vector3.new(0, existingNPC.PrimaryPart.Size.Y * 2, 0)
			else
				-- Spawn at a random position within the size of the spawnLocation
				local randomPosition = getRandomPositionInSpawnLocation(spawnLocation)
				spawnCFrame = CFrame.new(randomPosition) + Vector3.new(0, spawnLocation.Size.Y * 2, 0)
			end

			spawnNPC(npcModel, spawnCFrame)
			break
		else
			warn("Detected object is not a SpawnLocation")
		end
	end
end

return NPCSpawner

Script

local NPCSpawner = require(game:GetService("ServerScriptService").NPCSpawnerModule)
local npcModel = game.ServerStorage.NPCModel -- Replace with your NPC model or change this to a for loop.

-- Find all SpawnLocation objects in workspace
local spawnLocations = {}

for _, descendant in pairs(workspace:GetDescendants()) do
	if descendant.Name == "SpawnLocation" then
		table.insert(spawnLocations, descendant)
	end
end

NPCSpawner.spawnNPCs(npcModel, spawnLocations)

I love it, but maybe some things so you know roblox used to have the spawnlocation size 6, 1, 6 and players used to stack can you also make it detect with that size so it stacks, but I like it. May you add that addition? Please. But I’m liking it so far.

You should make this a post in community resources.

It is off topic to post updates and such in this post.

I am confused. The NPCs do stack, but because the initial location is chosen randomly within the radius of the SpawnLocation, it’s less likely for them to spawn on top of each other. However, in some cases, they do.

nevermind. don’t need to change anything. Anyways thank you. But the final additions Forcefields from the spawnlocations duration and randomly selecting a random spawnlocation. Sorry for my confusion.

1 Like

To incorporate the desired additions, simply follow the documentation.

ForceField | Documentation - Roblox Creator Hub
Debris | Documentation - Roblox Creator Hub

  1. I recommend parenting local ForceField = Instance.new("ForceField") to the NPCs Humanoid.
  2. The forcefield can be added to the DebrisService as a new Debris and for the duration of your SpawnLocation property Duration or a custom number. DebrisService:AddItem(ForceField, SpawnLocation.Duration or Players.RespawnTime or 5)

NPCs spawn randomly based on the SpawnLocations you have as a descendant of Workspace.

1 Like

Well, you say that but when I tested it. It seems like they don’t. They just choose an option only one spawn location and not the others. Again, they just choose one spawn location, and I tried running it over and over and they perhaps just because it’s in a for loop.

1 Like

Fixed the issue.

Change the NPCSpawner.spawnNPCs function inside the Module to this:

function NPCSpawner.spawnNPCs(npcModel, spawnLocation)
	if spawnLocation.Name == "SpawnLocation" then
		local existingNPC = getNPCAtLocation(spawnLocation)

		local spawnCFrame
		if existingNPC then
			-- Spawn on top of existing NPC
			spawnCFrame = existingNPC.PrimaryPart.CFrame + Vector3.new(0, existingNPC.PrimaryPart.Size.Y * 2, 0)
		else
			-- Spawn at a random position within the size of the spawnLocation
			local randomPosition = getRandomPositionInSpawnLocation(spawnLocation)
			spawnCFrame = CFrame.new(randomPosition) + Vector3.new(0, spawnLocation.Size.Y * 2, 0)
		end

		spawnNPC(npcModel, spawnCFrame)
	else
		warn("Invalid name, expected SpawnLocation")
	end
end

Script

local NPCSpawner = require(game:GetService("ServerScriptService").NPCSpawnerModule)
local npcModel = game.ServerStorage.NPCModel -- Replace with your NPC model or change this to a for loop.

-- Find all SpawnLocation objects in workspace
local spawnLocations = {}

for _, descendant in pairs(workspace:GetDescendants()) do
	if descendant.Name == "SpawnLocation" then
		table.insert(spawnLocations, descendant)
	end
end

if #spawnLocations > 0 then
	NPCSpawner.spawnNPCs(npcModel, spawnLocations[math.random(1, #spawnLocations)])
end
1 Like

I have tried something for the forcefield, but it seems like it can’t destroy.

You can force destroy it by doing ForceField:Destroy().

I am going to try that also maybe a few things I want in it (ik i said final but I relized something) it has to basically deal with no spawns so if there is no spawns then that would mean the player would be in the air and also teamColor so basically the npc would basically go to a teamcolor if there isnt then basically it would go to any spawnlocation