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)
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:
Anchor the Players Character
Teleport them to a random spawn location
Unanchor them
This is what your spawn locations would be like (don’t forget, they’re not actually spawn locations).
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)
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.
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
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.
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.