Your welcome! And yes, there is a website on Roblox Github that helped me a lot. Link: Roblox Lua Style guide.
As far as variables go, it’s sort of a standard. When you look at it, it’s pretty logical:
-- Services
local Players = game:GetService("Players")
local RunService = game:GetService("RunService") -- some write runService
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local UIS = game:GetService("UserInputService")
You need to require modules then, because if the script is long and there are a lot of variables, it’s useful for the person who is using/maintaining/etc. your code to see what modules are required if any.
local GameManager = require(-- path)
-- Relative path if module is stored near the script,
-- otherwise, it's a good practice to use absolute paths
-- and you also already have services defined.
Constants and user configurations (I really got used to capitals here):
local SPEED = 150
local DEBUG_IMPORT_FUNCTIONS = false
Variables:
here come all the variables, ordered by your preference. Some people order by type (paths, booleans, integers and floats…). Personally, I rather group variables partially by type and partially by use:
local NPC = script.Parent.Parent
--[[
this is a constant, but use of LOUD_SNAKE_CASE is somewhat
impractical here. It is more commonly used for important
configurations and constants we need to easily access and
perhaps change multiple times.
]]
local humanoidType = Enum.HumanoidRigType.R15
local healthDisplayDist = 30 -- we will rarely change this (example)
local other = 40
local isRunning = false
It’s true that variables can be used to shorten paths, or even functions and methods, for instance:
local random = math.random -- important: not math.random(); () takes arguments
print(random(1, 5))
Shortened paths are always useful, and when we have a fast running loop, such as:
local values = script.Parent
RunService.Heartbeat:Connect(function(deltaTime)
values.value_1.Value += 1
values.value_2.Value -= 8
-- bunch of values with the same path here
end)
-- Good, but can be better.
RunService.Heartbeat:Connect(function(dt)
script.Parent.value_1.Value += 1
script.Parent.value_2.Value -= 8
-- bunch of values with the same path here
end)
Variables are just on the right place, because we don’t very often need to find longs paths to access modules. If we do, we usually didn’t place it well. A module we require, if not external of course, should be either near the script we are accessing it from:
local SomeModule = require(script.SomeModule)
Or relatively close in ReplicatedStorage and ServerStorage:
-- Suppose ServerStorage is defined.
local AnotherModule = require(ServerStorage.Modules.AnotherModule)
-- If the path is still too long:
local modulesFolderPath = ServerStorage.Data.Modules.OtherModules.AnotherOtherModules
local AnotherModule = require(modulesFolderPath.AnotherModule)
This may sound boring and unimportant, but it’s good to keep only the truly needed variables. Otherwise, we can end up with a messy script. It’s also good practice to limit variable scope, so if a variable is only needed inside a certain block, don’t define it outside of it.
do
-- Imagine we need "n" in this loop.
local n = 0
for i = 1, #numbers do
-- continue
end
end
Lua garbage collector will clear this n variable from the memory as soon as the loop stops.
There is so much more to tell, and luckly, there are some good posts around the Dev Forum.
I hope this helps!