Hello, today i’ll share you my experience with writing redable code, you will learn few techniques of making your code more redable, also we will talk about positives & negatives of writing clean code
1. Positives & Negatives
Soo, first of all why we want to write redable code? See most of the time you will work with others, and those others must understand your code to make successful game, also you might make breaks from scripting and forget about what specific script does
Pros:
- Others can work with you
- You can take breaks and understand your code
- Fixing bugs is 100x easier
- You can analyze code and optimize it without problem
Cons:
- On client cheaters might understand your code well and make exploits faster
Still don’t worry about cheaters, you can annoy them in different ways than making their struggle to read your scripts :}
2. Example
Soo now the time for example, here we have script for giving player coins every time he touches part
local sp = script.Parent
local db = {}
sp.Touched:Connect(function(hit)
if hit.Parent:FindFirstChild("Humanoid") then
if game.Players:GetPlayerFromCharacter(hit.Parent) then
if not db[game.Players:GetPlayerFromCharacter(hit.Parent)] then
db[game.Players:GetPlayerFromCharacter(hit.Parent)] = 0
elseif tick() - db[game.Players:GetPlayerFromCharacter(hit.Parent)] >= 5 then
game.Players:GetPlayerFromCharacter(hit.Parent).Gold.Value = game.Players:GetPlayerFromCharacter(hit.Parent).Gold.Value + 5
end
end
end
end)
Script above is hard-coded and unredable and it’s only changing one value with debounce!!! imagine writing 10x longer script, it would be almost impossible!
To fix this, we can simply format our code, you can use formatting tool or use Tab to move code in every scope one step forward, our end result looks like this:
local sp = script.Parent
local db = {}
sp.Touched:Connect(function(hit)
if hit.Parent:FindFirstChild("Humanoid") then
if game.Players:GetPlayerFromCharacter(hit.Parent) then
if not db[game.Players:GetPlayerFromCharacter(hit.Parent)] then
db[game.Players:GetPlayerFromCharacter(hit.Parent)] = 0
elseif tick() - db[game.Players:GetPlayerFromCharacter(hit.Parent)] >= 5 then
game.Players:GetPlayerFromCharacter(hit.Parent).Gold.Value = game.Players:GetPlayerFromCharacter(hit.Parent).Gold.Value + 5
end
end
end
end)
As you can see, this code is at least redable, but imagine coming back from long break and seing it, it might take few minutes, soo to fix this we need to change it a little bit more
First of those changes would be soft-coding, we can’t change anything like cooldown or gold value, soo we will create settings for that, thanks to them we don’t need to read through main script to adjust it
local sp = script.Parent
local db = {}
local cd = 5
local gv = 10
sp.Touched:Connect(function(hit)
if hit.Parent:FindFirstChild("Humanoid") then
if game.Players:GetPlayerFromCharacter(hit.Parent) then
if not db[game.Players:GetPlayerFromCharacter(hit.Parent)] then
db[game.Players:GetPlayerFromCharacter(hit.Parent)] = 0
elseif tick() - db[game.Players:GetPlayerFromCharacter(hit.Parent)] >= cd then
game.Players:GetPlayerFromCharacter(hit.Parent).Gold.Value = game.Players:GetPlayerFromCharacter(hit.Parent).Gold.Value + gv
end
end
end
end)
But still, those settings might be not that redable, we can use types to fix that
local variable: type = value
Soo we applied types to our settings, and we have:
local sp = script.Parent
local db = {}
local cd: number = 5
local gv: number = 10
sp.Touched:Connect(function(hit)
if hit.Parent:FindFirstChild("Humanoid") then
if game.Players:GetPlayerFromCharacter(hit.Parent) then
if not db[game.Players:GetPlayerFromCharacter(hit.Parent)] then
db[game.Players:GetPlayerFromCharacter(hit.Parent)] = 0
elseif tick() - db[game.Players:GetPlayerFromCharacter(hit.Parent)] >= cd then
game.Players:GetPlayerFromCharacter(hit.Parent).Gold.Value = game.Players:GetPlayerFromCharacter(hit.Parent).Gold.Value + gv
end
end
end
end)
But wait, isn’t something missing? we know what kind of value we should write into settings, but can we really understand them?
Most beginners make one crucial mistake, they use shortcurts, see shortcurts are bad idea because we might not understand them, soo instead of writing two letters we should name our variables with clear names
local part = script.Parent
local debounce = {}
local cooldown: number = 5
local goldvalue: number = 10
part.Touched:Connect(function(hit)
if hit.Parent:FindFirstChild("Humanoid") then
if game.Players:GetPlayerFromCharacter(hit.Parent) then
if not debounce[game.Players:GetPlayerFromCharacter(hit.Parent)] then
debounce[game.Players:GetPlayerFromCharacter(hit.Parent)] = 0
elseif tick() - debounce[game.Players:GetPlayerFromCharacter(hit.Parent)] >= cooldown then
game.Players:GetPlayerFromCharacter(hit.Parent).Gold.Value = game.Players:GetPlayerFromCharacter(hit.Parent).Gold.Value + goldvalue
end
end
end
end)
Now we have pretty much understandable script, but there are few things we can do to optimize it a bit and make it look nicer
3. Polishing code
First of all, our variables look bad, we can use programming cases to make variable names look a lot better, here are 3 main cases: Programming - What are the different Case Style?
Today i’ll use PascalCase
local Part = script.Parent
local Debounce = {}
local Cooldown: number = 5
local GoldValue: number = 10
Part.Touched:Connect(function(hit)
if hit.Parent:FindFirstChild("Humanoid") then
if game.Players:GetPlayerFromCharacter(hit.Parent) then
if not Debounce[game.Players:GetPlayerFromCharacter(hit.Parent)] then
Debounce[game.Players:GetPlayerFromCharacter(hit.Parent)] = 0
elseif tick() - Debounce[game.Players:GetPlayerFromCharacter(hit.Parent)] >= Cooldown then
game.Players:GetPlayerFromCharacter(hit.Parent).Gold.Value = game.Players:GetPlayerFromCharacter(hit.Parent).Gold.Value + GoldValue
end
end
end
end)
Small change but if we have a lot of variables, it might be usefull
Another important thing we will use is how we will use variables, see you shouldn’t use them if something is repeated once or twice, but if something repeats a lot, it might help our redability
local Debounce = {}
local Cooldown: number = 5
local GoldValue: number = 10
script.Parent.Touched:Connect(function(hit)
if hit.Parent:FindFirstChild("Humanoid") then
local player: Player = game.Players:GetPlayerFromCharacter(hit.Parent)
if player then
if not Debounce[player] then
Debounce[player] = 0
elseif tick() - Debounce[player] >= Cooldown then
player.Gold.Value = player.Gold.Value + GoldValue
end
end
end
end)
If you are tired of my bad english, then you should know we will make ths code even better, by sorting if statements
local Debounce = {}
local Cooldown: number = 5
local GoldValue: number = 10
script.Parent.Touched:Connect(function(hit)
local player: Player = game.Players:GetPlayerFromCharacter(hit.Parent)
if player then
if not Debounce[player] then Debounce[player] = 0 end
if tick() - Debounce[player] >= Cooldown then
player.Gold.Value = player.Gold.Value + GoldValue
end
end
end)
See some if statements are logically unnecesary and we can remove them, for instance checking if hit’s parent have humanoid is useless if we have no moving NPC in our game
Another thing about if statements is that we can use one line if statement to detect if something is not OK and change it
Note: After sorting this we can see that this script had bug, we forget to add cooldown update, soo we can add it right now
Apart of this, we must think now, what is useless here? one lined if statement is useless, it causes memory leaks and it should be run only once, we will add new format to clean out stuff
local Debounce = {}
local Cooldown: number = 5
local GoldValue: number = 10
local function OnPartTouched(hit: BasePart)
local player: Player = game.Players:GetPlayerFromCharacter(hit.Parent)
if player then
if tick() - Debounce[player] >= Cooldown then
player.Gold.Value = player.Gold.Value + GoldValue
Debounce[player] = tick()
end
end
end
local function OnPlayerAdded(player: Player)
Debounce[player] = 0
end
local function OnPlayerRemoving(player: Player)
if Debounce[player] then
Debounce[player] = nil
end
end
script.Parent.Touched:Connect(OnPartTouched)
game:GetService("Players").PlayerAdded:Connect(OnPlayerAdded)
game:GetService("Players").PlayerRemoving:Connect(OnPlayerRemoving)
As you can see our code is a lot more redable and optimized rn, the last thing we can add is use roblox’s methoods and comments to shorten code
NOTE: You should always name functions that you connect events to like those event names
Example: OnPlayerAdded, OnPlayerRemoving, OnPartTouched
Let’s compare our two scripts:
Before sorting:
local sp = script.Parent
local db = {}
sp.Touched:Connect(function(hit)
if hit.Parent:FindFirstChild("Humanoid") then
if game.Players:GetPlayerFromCharacter(hit.Parent) then
if not db[game.Players:GetPlayerFromCharacter(hit.Parent)] then
db[game.Players:GetPlayerFromCharacter(hit.Parent)] = 0
elseif tick() - db[game.Players:GetPlayerFromCharacter(hit.Parent)] >= 5 then
game.Players:GetPlayerFromCharacter(hit.Parent).Gold.Value = game.Players:GetPlayerFromCharacter(hit.Parent).Gold.Value + 5
end
end
end
end)
After sorting:
local Debounce = {}
-- Settings
local Cooldown: number = 5
local GoldValue: number = 10
-- Gives set amount of gold to player that touched the part
local function OnPartTouched(hit: BasePart)
local player: Player = game.Players:GetPlayerFromCharacter(hit.Parent)
if player then
if tick() - Debounce[player] >= Cooldown then
player.Gold.Value += GoldValue
Debounce[player] = tick() --/ Update cooldown
end
end
end
-- Adds player to debounce list
local function OnPlayerAdded(player: Player)
Debounce[player] = 0
end
-- Removes player from debounce list
local function OnPlayerRemoving(player: Player)
if Debounce[player] then
Debounce[player] = nil --/ Prevent memory leaks
end
end
script.Parent.Touched:Connect(OnPartTouched)
game:GetService("Players").PlayerAdded:Connect(OnPlayerAdded)
game:GetService("Players").PlayerRemoving:Connect(OnPlayerRemoving)
Tip that i forget to add is that you should use space:
- Between yielding functions
- Between functions
- When you think it will look better
- Between important comments (you decide which)
I wish i helped and that you understood this tutorial, i should use those tips to improve my english xd, anyways have a nice day, goodbye!