← Blog Home

Common Mistakes

We've all made them at some point when we were learning to script. Whether it would be trying to change a property when using a table or when we would try to use LocalPlayer in a server script. This blog post will go through some of the most common mistakes I have seen on the site. This article may answer your problems or leave you further in confusion as to what your problem really is. We'll try to explain these issues and how you can fix and avoid them.



Table of Contents


LocalPlayers and Server Scripts

This is one of the most common issues seen on the site. A beginner may use LocalPlayer trying to find the desired player in the game when they come to find out that LocalPlayer is a nil value. At this point, we may conclude the script writer is using a Server Script. The difference between Server Scripts and Local Scripts is that Server scripts act on behalf of the server. The server is what is connecting all the players together. It's a physical server found at Roblox Headquarters that bring you the content of the game. Local Scripts will act on behalf of the Client, that being you and your computer, the intended target.

Think of it like your house and room. Your room is your room, you're the only person in your room. So for the Local Script, your Local Script is your Local Script, it works for you. However your house is your house, but everyone else is living in it. Your parents, siblings, and possibly other family members or pets. A Server Script would be acting for your house since it's acting for several people it can not keep track of that one intended person being LocalPlayer. To make things easy for the server LocalPlayer is nil to the server.

Fortunately, ROBLOX accounts for most of the events and instances you would need to get the Player in a Server Script. Some events would include PlayerAdded, Touched, or MouseClick. You would have to figure out your way of getting the player.

I'll be going over the example of how to get the player from a Touched event. The touched event returns the part that hit another part. It will not find the player on its own. For the touched event we would need to find out if the Part's parent is a character, and then use GetPlayerFromCharacter on the model.

Before your touched event script may have looked like this,

script.Parent.Touched:connect(function(Part)
    game.Players.LocalPlayer.leaderstats.Points.Value = game.Players.LocalPlayer.leaderstats.Points.Value + 1
end)

Since characters are models, you will need to be searching for the Humanoid in the model (the hitting part's parent).

script.Parent.Touched:connect(function(Part)
    if Part.Parent:FindFirstChild('Humanoid') then --Check if there is a humanoid. That makes it more likely it's a player.
        local Player = game.Players:GetPlayerFromCharacter(Part.Parent) --This will return the player or nil if the part's parent isn't actually a character.
        if Player ~= nil then --Check if Player exists.
            Player.leaderstats.Points.Value = Player.leaderstats.Points.Value + 1
        end
    end
end)

LocalScripts Not Running

Often times, beginning users will assume that LocalScripts can go anywhere. They would think that since it will allow them to use LocalPlayer, then why not just stick them in a brick in the workspace. Well, sad to say that it can not be done like this.

LocalScripts can only be used in PlayerGui, Backpack, PlayerScripts. ReplicatedFirst, or the Player's Character.

In addition to the locations of LocalScripts, many early script writers will assume that since a script works in Studio Mode it will work in Roblox Server mode.

In Roblox Studio Play Solo mode, which is what many people test with, the game does not tell the difference between server and client. They are both one in the Play Solo mode. That is why a LocalScript may have access to ServerScriptService or ServerStorage.

However, in Roblox Server mode you have to take into account the separation between the server and the client. A client will run LocalScripts which will allow the script access to LocalPlayer and CurrentCamera. If you have FilteringEnabled enabled then this separation becomes all the more apparent. You would need to use a LocalScript for modifying Guis that originate from StarterGui, and ServerScripts for modifying Workspace objects or other Player Damage.

You can check out evaera's Blog Article "It works in Studio, but not online!" for more information on this separation.

GetChildren Doesn't Change Everything

There've been times when beginners will try to go straight to editing the properties after using the function GetChildren. However, this can not be done as GetChildren will always return a table. Not to worry, this is a simple fix and all it requires is a loop.

Depending on what you're trying to do we can either use the numeric for loop or utilize one that uses in pairs(). The more common method is the in pairs() for loop. However, if you prefer the numeric one go for it. For this easy example, we'll just determine if the object is a part, then change the BrickColor.

for i,v in pairs(game.Workspace:GetChildren()) do --i and v are variables standing for index and value. In a table, everything has an index. GetChildren will provide a table with indexes from 1 to however many values are in the table.
    if v:IsA('BasePart') then --At this point, we're determining what we have is an actual part. If it is not a part and we try to change a BrickColor, then we'll experience an error.
        v.BrickColor = BrickColor.new('Bright blue') --Lua is case sensitive, so you need to use Bright blue, not BRIGHT BLUE or Bright Blue, just Bright blue.
    end
end

StarterGui and PlayerGui; Not the Same

Some beginners may find this to be a quick way to change a Gui for all players. Unfortunately, it's not that simple. StarterGui is basically what PlayerGui clones from when you respawn. That means, any changes you make to objects in StarterGui will not show until you respawn.

In order to fix this, and we will assume you're just going to go without FilteringEnabled for this example, you will want to use the :GetPlayers() function on the Players Service. GetPlayers will act as GetChildren, however only getting Player objects. You would then loop through all the players and go into the PlayerGui, ScreenGui, and then change that TextLabel.

for i,v in pairs(game.Players:GetPlayers()) do
    v.PlayerGui.ScreenGui.TextLabel.Text = "Hello!"
end

If you're using FilteringEnabled, you're probably experienced enough not to fall victim to this issue. You would just need to have a ServerScript fire a RemoteEvent and rely on the LocalScript in PlayerGui to pick up and modify the Text.


Infinite Loop Wall

--At the time of this Blog Article being posted. Hint and Message are deprecated. This is just an example.

local Hint = Instance.new("Hint",workspace) 
while wait(1) do
    Hint.Text = game.Players.NumPlayers
end

game.Players.PlayerAdded:connect(function(Player)
    local Message = Instance.new("Message",workspace)
    Message.Text = Player.Name .. " has just joined the server."
    wait(5)
    Message:Destroy()
end)

At first, one may assume there is nothing wrong with this script. However, that is not the case. What can be seen is a while loop. While loops continue on until the condition is met. This is actually the same for all loops, repeat until, for i=1,10 do, while true do. If these conditions are met, then the loop will continue.

Scripts read from top to bottom. It will remember to run code for functions when they are called, run code for events if one is fired, run loops when a loop is reached. Since the loop is reached before the event is caught, the script never makes it to the event. The loop is infinite, almost like a wall. You can not pass through that loop until you break that wall, or cause a condition to become false.

Though this script is inefficient, the simple solution would be to move all events before the loop.


Functions; Call Me Maybe?

Sometimes script writers may try to write an event to a function they're wanting to call, inside the function itself.

function Hello(Player)
    print("Hello " .. Player.Name .. "!")
    game.Players.PlayerAdded:connect(Hello)
end

You're not really calling the function. What the script is doing at this point, it's remembering the function's variable being "Hello". It's recognizing that it's a function and should run after it's been called. Unfortunately, the function is being called by an event which to the script does not exist. Reason being, it's in the function that is never ran.

I'll try to break it down. The script will remember to run "Hello" when it is called. It gets to the end of the script and Hello is not called anywhere outside of the function. Since Hello is not called outside of the function, it is never ran. Since the function hasn't been run, the script does not know to keep track of that event. Therefore, the script doesn't know it even needs to run the event which would call Hello.

The simple fix to this this is just moving the event outside of the function. Some users tend to forget to call the function in general which you would just call as Hello() and fill any arguments that are needed.


MouseButton1Click Event; Where's My Player?

Ever since Roblox introduced SurfaceGuis, this error has become more and more common. SurfaceGuis use Gui elements that have always been the same. Some people tend to think that since the SurfaceGuis can be placed in Workspace and Click Detectors will return the player value, you would be able to get the player value from MouseButton1Click. This, like many other of the mistakes mentioned above, is not the case.

MouseButton1Click has been the same since it was first created. It has always returned an X and Y mouse position value on the button object. In order to get the player value, you would need to place the SurfaceGui into PlayerGui. There are two ways to achieve getting the player, either through a server script going through all the parents until you get to the player, or use a LocalScript and use LocalPlayer. Whenever working with Guis meant for one player to see, it's always recommended to use a LocalScript.

Since you have the SurfaceGui in PlayerGui, you will need to set the Adornee property of the SurfaceGui to the part you want the Gui to show on.

If you're ever not sure what values an event provides. Always check the wiki and search for the event you're trying to use. It will list all of the values it will provide you.


A person who never made a mistake never tried anything new.

~Albert Einstein

This quote holds true if you've made one of these mistakes in the past. You can never have complete success without a little bit of failure along the way. If you've made any of these mistakes, or are making any of these mistakes, then hopefully you've learned from them and now know how to fix them. If you want to share your failure and success story to a simple mistake, let us know in the comments!

Have any suggestions for other Common Mistakes? Leave them in the comments below and we may just add them!

Posted in Scripting Tips

Commentary

Leave a Comment

User#11440 says: August 8, 2016
Maybe for the next article have one about using WaitForChild.
User#11440 says: October 9, 2016
and add 1 about scripts not being able to see things in PlayerGui if FE on.
M39a9am3R says: January 4, 2017
There is an error in the blog article I can no longer edit. In the Infinite Loop Wall portion, it states a while loop will continue until the condition is met. What was meant to be said was until the condition is no longer met. Sorry for the error.
User#19524 says: July 30, 2018
One on checking for enums. You can assign an enum by its name (e.g. "Neon") but in conditionals they check with strings when it should be checked with an enum.