Preventing players from spawning on top of eachother

Essentially, when there is only one spawn location, players stack on top of each other when spawning at the same time.
I could disable players collisions, however that behavior seems to make the players still stack and then fall into each other.
This doesn’t work for my situation because I have two floors and the spawn on the first floor is directly under the second. So, even if I disable player collisions, if more than 3 players join and don’t move, one of them is going to end up on the second floor.

I don’t think I can just set the player’s CFrame because there are two spawns, and the player’s spawn is determined by which door they walk through in the start place using TeleportToPlaceWithSpawnAsync (i probably got the name wrong lol)

2 Likes

You could move them to a random offset off of the spawn point whenever their character loads.

I’m not a programmer but you could make it when the character spawns it turns off can collide.

That would make them fall through the floor.

You’ll want to use CollisionGroups to disable collision with others.

-- SERVICE
local Players = game:GetService("Players")
local PhysicsService = game:GetService("PhysicsService")

PhysicsService:CreateCollisionGroup("Players")
PhysicsService:CollisionGroupSetCollidable("Players", "Players", false)

Players.PlayerAdded:Connect(function(Player)
    Player.CharacterAdded:Connect(function(Character)
         for _, Object in pairs(Character:GetDescendants()) do
             if Object:IsA("BasePart") then
                 PhysicsService:SetPartCollisionGroup(Object, "Players")
             end
        end
    end
end)

Now for actually spawning the players!

There’s two different ways we could do this, they’re virtually the same.

A) You have a single spawn location (not an actual spawn location object, but a part named Spawn)
B) You have multiple spawn locations (not actual spawn location objects, but parts named Spawn)

B is best to go with as it means if 3 players spawn at once, there is a high chance they won’t spawn inside each other.

To start, you’ll want to have a single spawn location somewhere not accessible by anyone.

-- CLIENT
local Players = game:GetService("Players")

local Player = Players.LocalPlayer
local Character = Player.Character or Player.CharacterAdded:Wait()
local Root = Character:WaitForChild("HumanoidRootPart")

local RanNum = Random.new()
local Spawns = workspace.Spawns:GetChildren()

Root.Anchored = true
Root.CFrame = Spawns[RanNum:NextInteger(1, #Spawns).CFrame
Root.Anchored = false

The code above works like so:

  1. Anchor the Players Character
  2. Teleport them to a random spawn location
  3. Unanchor them

This is what your spawn locations would be like (don’t forget, they’re not actually spawn locations).

2 Likes

You could make it when player touches player can collide turns off for a split second

How would I implement a random spawn if I were using TeleportToSpawnByName?
(as in they teleport to a different game with a specific group of spawns picking a random one that’s free)

@twinqle use this video https://www.youtube.com/watch?v=hG7t3MTqjjY
I’m not sure if its out dated to the Roblox Code/Scripting,
but this should be your solution if it works

use Humanoid:MoveTo() instead of spawning them.

I’m confused on what you mean.

Do you mean that you’re teleporting to the same game and depending on the door you went through before teleporting determines the spawn location?

This may sound odd, but do you have a reason for not adding more spawns even if not visible ones? This would be a non-scripting solution to the problem, but would work for what you need.

Check if a humanoid is present on the spawn part, if so, make the player spawn neaby the spawn area (random locations near spawn).

I believe your best bet would be to CFrame the player to the “SpawnPoints” manually, @Kymaraaa explains this best but i’ll shorten it:

Connect a PlayerAdded event somewhere, preferably on the server of course, within that, include a CharacterAdded event. What these two will basically do is detect if a player joins the game, if they do, they make sure to connect a CharacterAdded event to that player. If the player respawns or is LoadCharacter()ed , the event fires. inside that CharacterAdded event, you want to CFrame the player to your spawn location, you don’t necessarily have to randomize it in your use case since you’re only saying you’re using one spawn location.

you can CFrame the HumanoidRootPart, MoveTo(), SetPrimaryPartCFrame(), etc. I usually just go for CFraming the HumanoidRootPart relative to the part’s CFrame and offsetting it so they “Spawn” above the spawn location like normal:

ThePlayerCharacterFromCharacterAdded:WaitForChild("HumanoidRootPart").CFrame = SpawnLocation.CFrame + Vector3.new(0, 2, 0) -- Probably might be wrong/inefficent the way im offsetting 

Then you can position your spawnlocation anywhere you need it to be like a normal spawn then play test to see if it works for you :+1:

Thank you! This worked. :smiley:

30postlimitskskkskskkssk

You don’t need to use CharacterAdded for this nor do you need to do this on the server.

Only do stuff that needs to be done on the server, on the server.

Having multiple fake spawn points means it’s highly unlikely players will spawn inside each other which is why I went with that instead of a single spawn point. You can still have a single spawn point using the code I provided.

2 Likes

Just had the same design issue with an elevator of mine. A second player spawning would be place above the model.

Players.PlayerAdded:Connect(function(Player)
    Player.CharacterAdded:Connect(function(Character)
         for _, Object in pairs(Character:GetDescendants()) do
             if Object:IsA("BasePart") then
                 PhysicsService:SetPartCollisionGroup(Object, "Players")
             end
        end
    end
end)

The above snippet is the go to from a logical stand point and is all I could find without a custom spawn as discussed above. It however didn’t work fast enough for studio tests, the event would fire and not all the parts would be given a collision group change.
(My assumption is that the event is called when the player is first attributed a model. Before all the parts are ready to be accessed)

Ergo:

Players.PlayerAdded:Connect(function(player)
	player.CharacterAdded:Connect(function(model)
		model.DescendantAdded:Connect(function(instant)
			if instant:IsA("BasePart") then
				PhysicsService:SetPartCollisionGroup(instant,"Players")
			end
		end)
		for i,part in pairs(model:GetDescendants()) do
			if part:IsA("BasePart") then
				PhysicsService:SetPartCollisionGroup(part,"Players")
			end
		end
	end)
end)

As soon as the model reference exists and the event fires, start listening for parts added and change collision group. Has worked beautifully for studio tests thus far.

Edit: Honestly, the for loop might be redundant but I don’t feel like testing/researching potential race conditions in live environments etc. :sleeping:

2 Likes