Is there a difference between placing LocalScripts in StarterCharacterScripts and StarterPlayerScripts?

Is there really a difference? Or can I place them interchangeably?

2 Likes

StarterCharacterScripts are placed in the Players Character, this could mean that the script resets on the players death because it copies the script over to the newly generated character (if that makes sense)

StarterPlayerScripts are placed in the Player, the same place where the PlayerGUI is stored. This means that it persists even when the player dies.

2 Likes

The main differences come down to this:

StarterChararacterScripts

  • These are cloned into the Player’s Character every time they respawn.

    • This means that once a Character respawns, a new version of that script will be cloned into the Character model and it’ll restart from the beginning of the code.

StarterPlayerScripts

  • These are cloned one time, when the player first joins the game, and are placed into the Player’s PlayerScripts folder.

    • Importantly, Server Scripts will not run when placed into the PlayerScripts folder. This means that if you place any scripts into the StarterPlayerScripts container, it should be a LocalScript.

    • Also, the server does not have access to viewing the contents of the PlayerScripts folder, so it cannot forcefully delete a LocalScript without communicating that request to the client via something like a RemoteEvent.



Main Takeaway / TL;DR

  • If you want to run code that specifically affects the Player’s Character, and are certain that it will continue working as expected even though the Script will restart from the very beginning every time the player’s Character respawns, then you can place it into the StarterChararacterScripts.

  • If you want to run client-sided code that isn’t solely related to the player’s Character, and / or if it doesn’t make much sense being placed into the Character or a ScreenGui, then you can place it into the StarterPlayerScripts. However, this is a generalization; you can still use LocalScripts to handle Character-related functions, even if that LocalScript is not placed in the Character model.



Examples / Situations for why you might use one over the other

  1. If you want the code within a LocalScript to continue running without interruptions, even when a player’s Character respawns, it would be better suited for StarterPlayerScripts.

    • For example, if you wanted to handle something such as player input (detecting when a player presses a specific button on their keyboard, controller, or a touch-screen action), it would make more sense for that to reside in the PlayerScripts folder so that it doesn’t have to restart what it’s doing every time the player’s Character respawns. Example:
-- Example: LocalScript placed into StarterPlayerScripts
local UserInputService = game:GetService("UserInputService")

UserInputService.InputBegan:Connect(function(inputObject)
	local userInputType = inputObject.UserInputType
	local keyCode = inputObject.KeyCode
	
	print("The player used: "..userInputType.Name)
	
	if keyCode ~= Enum.KeyCode.Unknown then
		warn("And the player pressed: "..keyCode.Name)
	end

    --[[ You could utilize this to perform some sort of action if the player
    presses a specific keybind. Even if that action is meant to affect
    the player's Character model in some way, it makes more sense to have this
    code running from here so that it doesn't suddenly stop running the moment
    the player's Character respawns
    --]]
end)

  • Although keep in mind that if you decide to reference the player’s Character via a LocalScript that was cloned into the PlayerScripts folder, you would need to make sure that you update any variables for the player’s Character and its descendants, or else it may continue referring to an older version of their Character and not the newest one that has respawned.

    Here’s an example LocalScript that you can place into the StarterPlayerScripts, start a playtest in Roblox Studio, and then view the Output to see what happens:

-- Example: LocalScript placed into StarterPlayerScripts
local Players = game:GetService("Players")
local player = Players.LocalPlayer

local currentNumber = 1

local Character = player.Character or player.CharacterAdded:Wait()
Character:SetAttribute("CharacterNumber", currentNumber)

print("Initial Character was assigned the value of: "..tostring(Character:GetAttribute("CharacterNumber") ) )


player.CharacterAdded:Connect(function(newCharacter)
    currentNumber += 1
    newCharacter:SetAttribute("CharacterNumber", currentNumber)

    print("A new Character has spawned!")
    warn("newCharacter was assigned the value of: "..tostring(newCharacter:GetAttribute("CharacterNumber") ) )

    print("Now, let's reference the original Character variable...")
    warn("The value assigned to the Character stored within the original variable is: "..tostring(Character:GetAttribute("CharacterNumber") ) )

    --[[ This second warning will ALWAYS print the initial number because the
    original Character variable was never updated to reflect the Character that
    had most recently respawned.

    However, if you added the following line of code into this function:

    Character = newCharacter

    Then what would happen is that the original "Character" variable
    will be updated to reference the Character that just spawned.
    --]]
end)

while true do
    task.wait(8)
    local currentCharacter = player.Character or player.CharacterAdded:Wait()
    local Humanoid = currentCharacter:WaitForChild("Humanoid", 5)

    if currentCharacter and Humanoid then
        Humanoid.Health = 0
    end
end



  1. If you want something to specifically affect the player’s Character model, such as handling health regeneration or animations, that would make more sense to be placed in the StarterChararacterScripts.

    Because a new version of the script is cloned into the Character model immediately upon respawn, the code will be able to instantly reference the newest Character model without needing to worry about listening for Player.CharacterAdded to fire, updating old variables that referred to the previous Character model, and so on. Here’s an example:

-- Example: LocalScript or Script placed into StarterCharacterScripts
local currentTime = os.date()
warn("This code has just started running at the following time: "..currentTime)

local Character = script.Parent
local Humanoid = Character:WaitForChild("Humanoid")

print("Activating superpowers!")

Humanoid.WalkSpeed = 50
Humanoid.JumpHeight = 20

task.wait(10)

Humanoid.Health = 0
print("The Character is about to respawn...")

Basically, cloning Scripts into the Character model upon respawn (which is being handled by the StarterCharacterScripts without needing to write any extra code to do that) simplifies the process of making sure that any code you’ve written that is meant to affect the player’s Character is actually referencing the current version of the player’s Character.

  • In fact, this is already how the default health regeneration functionality / animations are handled by Roblox. If you open up a brand new baseplate template in Roblox Studio, start a playtest, and then open the Character model within the explorer, you’ll see a “Health” Script and an “Animate” LocalScript.

    If you want to replace any of the default Scripts or LocalScripts within the Character, you can place a script into StarterChararacterScripts that has the exact name of “Health” or “Animate”, and it’ll use the one that you created instead of the default one.


I could probably explain a whole lot more about this, but I think this should be sufficient enough for now :smile:

If you have any further questions, feel free to ask and I’ll respond when I am next available (I haven’t gone to sleep yet and it is 7 AM; I just realized I have spent the past hour and a half writing this, but it was worth it!! More knowledge to go around :sunglasses: )

1 Like

It definitely was.

Thank you so much for the simple explanation! I highly appreciate it!

1 Like

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