[ SOLVED ] Random mob spawner

I’m currently working on a horror game inspired by apple pie, but I’ve ran into a issue. I’m not sure how to have the monster spawn at either certain parts, to simulate it having a 360 range around the player that it can spawn from. Or have it spawn randomly around the player using math.random of some sort.

I’m not sure what would be the better practice, or how to do either. So how would I go about doing either one? Either way, Thank you to anyone who helps.

As in this picture, you have points, [ spawn 1, spawn 2, spawn 3, spawn 4 ], I’m trying to make a monster randomly spawn on one of those 4 points.
image

In the picture below, you have a circle of which the monster can spawn anywhere along it.
image

2 Likes

A video showing the monster spawn system.

Create a Part named CampCenter in Workspace
Move the monster to ReplicatedStorage and name it Monster

Create a Script in ServerScriptService containing this code:

local Workspace = game:GetService("Workspace")
local CollectionService = game:GetService("CollectionService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local campCenter = Workspace.CampCenter
local monster = ReplicatedStorage.Monster

local AMOUNT_OF_SPAWNS = 16
local AMOUNT_OF_MONSTERS = 4
local RADIUS = 32

local random = Random.new()

local function createSpawnParts(amount, radius)
	for i = 1, amount do
		local spawnPart = Instance.new("Part")
		spawnPart.Anchored = true
		spawnPart.CanCollide = false
		spawnPart.Size = Vector3.new(1, 1, 1)
		local angle = math.rad((360 / amount) * i)
		local x = radius * math.cos(angle)
		local y = radius * math.sin(angle)

		spawnPart.CFrame = CFrame.new(campCenter.Position + Vector3.new(x, 0, y))
		spawnPart.Transparency = 1
		spawnPart.Name = "MonsterSpawnPart"
		spawnPart.Parent = Workspace
		spawnPart:AddTag("MonsterSpawnPart")
		spawnPart:SetAttribute("MonsterUsingSpawn", false)
	end
end

local function spawnMonsters(amount)
    local monsterSpawnPoints = CollectionService:GetTagged("MonsterSpawnPart")

	for _ = 1, amount do
		local attempts = 0
		while attempts < (#monsterSpawnPoints) * 2 do
			local randomIndex = random:NextInteger(1, #monsterSpawnPoints)
			local randomSpawn = monsterSpawnPoints[randomIndex]

			local isMonsterUsingSpawn = randomSpawn:GetAttribute("MonsterUsingSpawn")
			if not isMonsterUsingSpawn then
				local monsterClone = monster:Clone()
				randomSpawn:SetAttribute("MonsterUsingSpawn", true)
				monsterClone:PivotTo(randomSpawn.CFrame)
				monsterClone.Parent = Workspace
				monsterClone.HumanoidRootPart.Anchored = false
				break
			else
				attempts = attempts + 1
			end
		end

		if #monsterSpawnPoints == 0 then
			break
		end
	end
end

monster.HumanoidRootPart.Anchored = true
createSpawnParts(AMOUNT_OF_SPAWNS, RADIUS)
spawnMonsters(AMOUNT_OF_MONSTERS)
2 Likes

I just want to say I’m truly sorry for such the late response. But thank you, from the bottom of my heart for helping me, it means a lot.

Side note, for whatever reason, the code can’t find the CampCenter. So I tried using WaitForChild, and now I got this. I’m not sure how to fix it.
image

You must’ve copied my script wrong because I never used anything called TimerService
Can you show what you pasted in the Script

Possible reasons why the script can’t find CampCenter

  • CampCenter is supposed to be a Part If it’s not a part, it won’t work.
  • CampCenter is supposed to have .Anchored set to true and .CanCollide set to false
  • CampCenter might have been spelled incorrectly like campCenter, camp center, Camp Center. It is supposed to be CampCenter with no spaces in between the words.
  • CampCenter must be a child of the Workspace service. Even if it’s a descendant but not a child, the script won’t work. So it must be a direct child of the Workspace service

If you could provide the Script, Explorer Window (showing CampCenter), Properties Window (Highlighting CampCenter), I will be able to help more.

1 Like

Thank you so much for being so helpful, and hopefully this is correct, I had to remove some spaces/empty lines so the whole script could fit.

Ah yes I see the problem.
Line 4
That’s not how you use :WaitForChild()
Moreover, you don’t even need :WaitForChild() in this case as this script is running with Server RunContext

So all you want to do is change that line
Before:

local campCenter = game:WaitForChild(Workspace.CampCenter)

After:

local campCenter = Workspace.CampCenter

If you do want to use :WaitForChild() to learn how it works (which you should because it does have important uses)

:WaitForChild() basically has a name paramater and should be used like this
Parent:WaitForChild(name)
So in this case you could do:

local campCenter = Workspace:WaitForChild("CampCenter")

The name parameter should be a string, strings should be surrounded by quotation marks.
To learn more about this topic check these resources:

Thank you so much, sadly, I once again get an error. Using both

local campCenter = Workspace.CampCenter

and

local campCenter = Workspace:WaitForChild("CampCenter")

image

Change the code to this as I was using a deprecated feature, sorry.

local Workspace = game:GetService("Workspace")
local CollectionService = game:GetService("CollectionService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local campCenter = Workspace.CampCenter
local monster = ReplicatedStorage.Monster

local AMOUNT_OF_SPAWNS = 16
local AMOUNT_OF_MONSTERS = 4
local RADIUS = 32

local random = Random.new()

local function createSpawnParts(amount, radius)
	for i = 1, amount do
		local spawnPart = Instance.new("Part")
		spawnPart.Anchored = true
		spawnPart.CanCollide = false
		spawnPart.Size = Vector3.new(1, 1, 1)
		local angle = math.rad((360 / amount) * i)
		local x = radius * math.cos(angle)
		local y = radius * math.sin(angle)

		spawnPart.CFrame = CFrame.new(campCenter.Position + Vector3.new(x, 0, y))
		spawnPart.Transparency = 1
		spawnPart.Name = "MonsterSpawnPart"
		spawnPart.Parent = Workspace
		spawnPart:AddTag("MonsterSpawnPart")
		spawnPart:SetAttribute("MonsterUsingSpawn", false)
	end
end

local function spawnMonsters(amount)
    local monsterSpawnPoints = CollectionService:GetTagged("MonsterSpawnPart")

	for _ = 1, amount do
		local attempts = 0
		while attempts < (#monsterSpawnPoints) * 2 do
			local randomIndex = random:NextInteger(1, #monsterSpawnPoints)
			local randomSpawn = monsterSpawnPoints[randomIndex]

			local isMonsterUsingSpawn = randomSpawn:GetAttribute("MonsterUsingSpawn")
			if not isMonsterUsingSpawn then
				local monsterClone = monster:Clone()
				randomSpawn:SetAttribute("MonsterUsingSpawn", true)
				monsterClone:PivotTo(randomSpawn.CFrame)
				monsterClone.Parent = Workspace
				monsterClone.HumanoidRootPart.Anchored = false
				break
			else
				attempts = attempts + 1
			end
		end

		if #monsterSpawnPoints == 0 then
			break
		end
	end
end

monster.HumanoidRootPart.Anchored = true
createSpawnParts(AMOUNT_OF_SPAWNS, RADIUS)
spawnMonsters(AMOUNT_OF_MONSTERS)
1 Like

IT WORKS, THANK YOU SO MUCH. But no need for the sorry, you really helped me out, thank you again.

side note, if it’s okay to ask, what did you change in the code to get it to work?

Great that it works now. I would appreciate if you could mark my original post as the solution.

The problem with the original code was that I was using :SetPrimaryPartCFrame() which is deprecated and also doesn’t work if Model.PrimaryPart is set to nil. I changed it to :PivotTo() which uses the pivot tools and works for parts, models, and other PVInstances. Even if the model’s PrimaryPart is set to nil, :PivotTo() still works.

Further Reading:

2 Likes

Done! Thank you again, it means a lot. I’ll give the documentations a look to hopefully understand it better!

Side note, you did a great job explaining by the way, and amazing job helping me. By far one of the most wonderful users I’ve seen on devforum, not only kind, but helpful. I appreciate it a lot, and I hope you have a wonderful day.

Also, I’m going to try and add somethings to the script, would it be okay if I ask for some help regrading the script in dms if I can’t figure it out?

1 Like

Yes that’s completely fine. You can DM me for further help. I might not be able to respond today and will respond when I can.

1 Like

Thank you so much again. and no worries, please take all the time you need with responding. Have a wonderful day!

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.