Help making a Player selection gui work as clean as possible

im trying to have a gui that has “classes” that you can choose to become, theres some small issues,

  1. The player technically dies when the button is clicked (I don’t want the player to die when they select a character)
    2 any script involving the camrea of the player does work properly (such as cutscenes, not idle camera)

i just want the script to act like it was starterplayer.startercharacter, without using startercharacter

i havent found any solutions that acts like how i want it to act.

heres the script i currently have, this script has the problems listed at the top

local Button = script.Parent
local Info = TweenInfo.new(1, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut)
local TweenService = game:GetService("TweenService")
game:GetService("ReplicatedStorage").KeyBindEvent.OnServerEvent:Connect(function(player, key)
    Button.MouseButton1Click:Connect(function()
        local Tween = TweenService:Create(Black, Info,{Transparency = 0})
        Tween:Play()
        wait(1)
        script.Parent.Parent.Visible = false
        local oldCharacter = player.Character
        local newChar = game.ServerStorage.NormalCharacters.Character.StarterCharacter:Clone()
        newChar.HumanoidRootPart.CFrame = oldCharacter.PrimaryPart.CFrame
        newChar.Name = oldCharacter.Name
        player.Character = newChar
        oldCharacter:Destroy()
        newChar.Parent = workspace
        local Scripts = game.ServerStorage.NormalCharacterScripts.Character1:Clone()
        Scripts.Parent = newChar
        wait(1)
        local Tween = TweenService:Create(Black, Info,{Transparency = 1})
        Tween:Play()
        wait(1)
        script.Parent.Parent.Parent.Enabled = false
    end)
end)

You could turn off CharacterAutoLoading and set up the characters yourself. Here is a simple example.

This is in ServerScriptService with a child which is just a copy of my charcter. You’ll likely have to rename it in the :WaitForChild to a clone of your character for testing.

game.Players.CharacterAutoLoads = false --Set this to false so that you can load character manually.  You honestly should just set this manually.

game.Players.PlayerAdded:Connect(function(plr)
	local CHAR = script:WaitForChild("tlr22") --Either name your character tlr22 or fix this line
	
	plr.CharacterAdded:Connect(function(char)
		print("CHARACTER ADDED", char:GetFullName())
	end)
	
	
	task.wait(3)
	print("Loading char for " .. plr.Name)
	
	--Load character
	local ch = CHAR:Clone()
	ch.Name = plr.Name
	plr.Character = ch
	ch.Parent = game.Workspace
	
	
	print(plr.Name .. " loaded")
end)

Doing this though means you will have to manage adding/removing characters yourself. They won’t autorespawn when they die, so you have to manage that.

turning off character auto loads will cause the character selection screen to not show up

Then don’t turn off autoload, but just set the character when you want it changed. The moment you do that it appears to automatically clean up the other character and moves all controls and cameras to the new character model. They won’t spawn as the correct character though, you will need to override it if they ever respawn and you want it to auto set them to their previous selected character. Just note that setting it like that would fire the characterAdded event a second time.

local newCharacter = model:Clone()
newCharcter.Name = player.Name
player.Character = newCharacter --this fires characterAdded despite the fact there was already a character
newCharacter.Parent = game.Workspace

Other than that there are really only 2 options I can think of. Write code that redecorates the character object into another one (this could potentially be a lot of work) Or just have them die like you currently have. Those are the 3.5 ways (the first two are very similar) I can think of to really do what you are trying to do.

Why is this the case?

The best option would be to have their character not autoload, then let them select a character, and then load their new character.