As a Roblox developer, it is impossible to have more than one StarterCharacter.
My use case is simple. I have a game that needs a different StarterCharacter depending on the in-game role of the character. For example, a knight would require a StarterCharacter that looks like a knight, and a wizard would require a StarterCharacter that looks like a wizard.
If Roblox is able to address your issue, how would it improve your game and/or your development experience.
With this feature, it would be very easy to create games with multiple StarterCharacters that have different appearances.
Here is a sample implementation:
Players.PlayerAdded:Connect(function(player)
local playerRole = GetPlayerRole(player)
if playerRole == "Knight" then
player.StarterCharacter = KnightStarterCharacter
else
player.StarterCharacter = WizardStarterCharacter
end
end)
Currently, I am forced to do one of two workarounds, neither of which is ideal.
1. Set player.Character to a custom model.
But this does not load the default character scripts (Animate, Health, Animate), nor does it load any scripts in the CharacterScripts folder. It also does not automatically spawn characters at SpawnLocations.
2. Use a single StarterCharacter, and morph it into another.
The morph basically swaps out all the body parts, and then uses BuildRigFromAttachments. But this method is prone to the occasional character death during the process.
I want to bring up this underrated feature request once again. As mentioned, a big problem is that there can only be one StarterCharacter at a time. But to make things worse, the Player:LoadCharacter() method is also a yielding method.
The problem with LoadCharacter() being a yielding method is that two players could now technically be loading at the same time. There is no guarantee that calling LoadCharacter() on player A before player B will also make player A spawn before player B. Maybe player B loads faster. So if you swap in the StarterCharacter for a player, load them, and then swap out the StarterCharacter, there is no guarantee that some other character loaded as that StarterCharacter in the meantime.
With multiple StarterCharacters, one assigned to each player, this would no longer be a problem.
To work around the loading problem, I have to implement a loading system where characters are being added to a queue so that I can load their character one by one and guarantee that they load in the right order, so that I can swap in and out StarterCharacter models at the right moment. However, I also need to be careful because a player could technically leave the game while they are loading because, again, LoadCharacter() is a yielding method and there is no guarantee that the player’s character is always loaded before PlayerRemoving is called.
The result looks something like this:
local SpawnQueue = {}
function spawnPlayer(Plr: Player)
table.insert(SpawnQueue, Plr) -- SpawnQueue is an ordered array with Player instances
task.spawn(
function()
-- wait until it's time to spawn the player or the player is no longer in the game
while SpawnQueue[1] ~= Plr and Plr ~= nil and Plr:IsDescendantOf(game.Players) do -- edge-case in case players leave
game:GetService("RunService").Heartbeat:Wait() -- ideally you would find a way to eliminate any additional waits, but this is 'simpler' to program
end
-- destroy old starter character and create a new one
if game.StarterPlayer:FindFirstChild("StarterCharacter")~= nil then
game.StarterPlayer.StarterCharacter:Destroy()
end
local NewCharacter = createStarterCharacter(Plr)
NewCharacter.Parent = game.StarterPlayer
-- if the player is still in the game, finally load them and remove them from the queue
if Plr ~= nil and Plr:IsDescendantOf(game.Players) then
Plr:LoadCharacter()
-- check again if the player is in the game because LoadCharacter yields
if SpawnQueue[1] == Plr then
table.remove(SpawnQueue, 1)
end
end
end
)
end
game.Players.PlayerRemoving:Connect(
function(Plr: Player)
-- if a player leaves, remove them from the spawn queue to prevent a soft-lock
for i = 1, #SpawnQueue do
if SpawnQueue[i] == Plr then
table.remove(SpawnQueue, i)
break
end
end
end
)
This is a ton of code for a task that should be super simple to do. With multiple StarterCharacters I can remove all of this code and simply use the code from the original post. I know which one I prefer.
This! Currently, Gem Galaxies uses a method of setting the Player.Character directly to a new character’s rig from a ServerStorage location. I have a solid enough workaround to mitigate this, however for other games in the future I’d like to avoid using workarounds and instead something more official that let’s me set a character per player.
Another unrelated/on another note feature I’d like to see too is not having a character loaded by default, I know there’s also work arounds for that, but being able to have the player not loaded in automatically so that I don’t have to shove the players into a random spawn cube (and any workaround advice would be appreciated, too).
HumanoidDescription is an object that stores a description a Humanoid for R6 and R15 rigs.
This does not help if you are using a custom character made out of skinned MeshParts. It also does not work if your rig is a custom rig for an animal for example. It also does not work if you want to add more fidelity to your character by splitting limbs into multiple parts. I think you get the idea.
What about a SpawnParams object that was passed through Player/LoadCharacter? That way, the functionality is extendable (Model, CFrame, HumanoidDescription, etc.) on a case-by-case basis without sacrificing forwards-compatibility.
Yes, this has been on my Feature-Request TODO list. No, I cannot create a thread for it because I’m stuck as a member.