How to organise my code

This isn’t really about structuring you UI objects and script locations. I’m more stuck in the part where every time I script user interface the code looks extremely messy. Although it works and there’s no issue with it; it’s hard to read. I would appreciate any tips to organise it more.

A sample of ui code from my game:

local CONTENT_PROVIDER = game:GetService("ContentProvider")
local REPLICATED_FIRST = game:GetService("ReplicatedFirst")
local REPLICATED_STORAGE = game:GetService("ReplicatedStorage")
local TWEEN_SERVICE = game:GetService("TweenService")
local WORKSPACE = game:GetService("Workspace")
local PLAYERS = game:GetService("Players")
local RUN_SERVICE = game:GetService("RunService")
local GET_ASSETS = require(script.GetAssets)

local Player = PLAYERS.LocalPlayer
local Mouse = Player:GetMouse()
local Camera = WORKSPACE.CurrentCamera

local Cameras = WORKSPACE:WaitForChild("Cameras")
local Sounds = script:WaitForChild("Sound")
local BorderPosts = WORKSPACE:WaitForChild("BorderPosts")

-- replicating objects
local RepObjects = REPLICATED_STORAGE:WaitForChild("ReplicatedObjects")

for _, v in pairs(RepObjects:GetDescendants()) do
	local newObject = v:Clone()
	
	if v.Parent.Name == "Cameras" then
		newObject.Parent = Cameras
	elseif v.Parent.Name == "SpectateCameras" then
		newObject.Parent = BorderPosts[v.Name]
		newObject.Name = "SpectateCamera"
	elseif v.Parent.Name == "BorderTeleports" then
		newObject.Parent = BorderPosts[v.Name]
		newObject.Name = "TeleportPlayerPart"
	end
end

local MOVE_SPEED = 150

local MainMenuCam = Cameras:WaitForChild("MainMenuCamera")

function UpdateCamera()
	local Center = MainMenuCam.CFrame
	local MoveVector = Vector3.new((Mouse.X - Center.X)/MOVE_SPEED, (Mouse.Y - Center.Y)/MOVE_SPEED, 0)
	Camera.CFrame = MainMenuCam.CFrame * CFrame.Angles(math.rad(-(Mouse.Y - Center.Y)/MOVE_SPEED), math.rad(-(Mouse.X - Center.Y)/MOVE_SPEED), 0)
end

-- GUI
local PlayerGui = Player:WaitForChild("PlayerGui")
local MainMenu = PlayerGui:WaitForChild("MainMenu")
local LoadingScreen = MainMenu.LoadingScreen
local Menu = MainMenu.Menu
local BorderSelection = MainMenu.BorderSelection

REPLICATED_FIRST:RemoveDefaultLoadingScreen()

local Assets = GET_ASSETS.FetchAssets()

local Loading = true

for i = 1, #Assets do
	local Asset = Assets[i]

	CONTENT_PROVIDER:PreloadAsync({Asset})

	if i % 5 == 0 then
		task.wait()
	end

	TWEEN_SERVICE:Create(LoadingScreen.FillBackground.Fill, TweenInfo.new(0.5, Enum.EasingStyle.Sine), {Size = UDim2.new(i / #Assets, 0, 1, 0)}):Play()

	if i == #Assets then
		LoadingScreen.FillBackground.LoadingLabel.Text = "Complete"
		Loading = false
	end
end

local Connection = RUN_SERVICE.RenderStepped:Connect(UpdateCamera)
Player:RequestStreamAroundAsync(MainMenuCam.Position)

task.wait(1)
LoadingScreen.FillBackground:TweenPosition(UDim2.new(0.5, 0,1.5, 0), Enum.EasingDirection.InOut, Enum.EasingStyle.Sine, 0.5)
task.wait(1)
TWEEN_SERVICE:Create(LoadingScreen.Title, TweenInfo.new(2), {TextTransparency = 1}):Play()
task.wait(2.5)
TWEEN_SERVICE:Create(LoadingScreen, TweenInfo.new(0.5), {BackgroundTransparency = 1}):Play()
task.wait(0.6)
Menu:TweenPosition(UDim2.new(0.5, 0, 0.5, 0), Enum.EasingDirection.InOut, Enum.EasingStyle.Sine, 0.5)


function Transition(time)
	TWEEN_SERVICE:Create(LoadingScreen, TweenInfo.new(0.5), {BackgroundTransparency = 0}):Play()
	task.wait(time)
	TWEEN_SERVICE:Create(LoadingScreen, TweenInfo.new(0.5), {BackgroundTransparency = 1}):Play()
end


for _, object in pairs(Menu:GetChildren()) do
	if object:IsA("TextButton") then
		object.MouseEnter:Connect(function()
			TWEEN_SERVICE:Create(object, TweenInfo.new(0.1, Enum.EasingStyle.Sine), {BackgroundColor3 = Color3.fromRGB(54, 54, 54)}):Play()
			object:TweenSize(UDim2.new(0.352, 0,0.103, 0), Enum.EasingDirection.InOut, Enum.EasingStyle.Sine, 0.1)

			Sounds.Hover:Play()
		end)

		object.MouseLeave:Connect(function()
			TWEEN_SERVICE:Create(object, TweenInfo.new(0.1, Enum.EasingStyle.Sine), {BackgroundColor3 = Color3.fromRGB(62, 62, 62)}):Play()
			object:TweenSize(UDim2.new(0.345, 0,0.087, 0), Enum.EasingDirection.InOut, Enum.EasingStyle.Sine, 0.1)
		end)

		object.MouseButton1Click:Connect(function()
			Sounds.Click:Play()

			if object.Name == "PlayButton" then
				Menu:TweenPosition(UDim2.new(0.5, 0,1.5, 0), Enum.EasingDirection.InOut, Enum.EasingStyle.Sine, 0.5)
				task.wait(0.3)
				Transition(0.5)
				Connection:Disconnect()
				Camera.CameraType = Enum.CameraType.Scriptable
				Camera.CFrame = BorderPosts["1"].SpectateCamera.CFrame
				BorderSelection:TweenPosition(UDim2.new(0.5, 0,0.749, 0), Enum.EasingDirection.InOut, Enum.EasingStyle.Sine, 0.5)
			end
		end)
	end
end

local CurrentCameraIndex = 1


BorderSelection.SelectButton.MouseButton1Click:Connect(function()
	BorderSelection:TweenPosition(UDim2.new(0.5, 0,1.5, 0), Enum.EasingDirection.InOut, Enum.EasingStyle.Sine, 0.5)
	task.wait(0.5)
	Transition(1)
	Connection:Disconnect()
	Camera.CameraType = Enum.CameraType.Custom
	Player:RequestStreamAroundAsync(BorderPosts[tostring(CurrentCameraIndex)].TeleportPlayerPart.Position)
	Player.Character.HumanoidRootPart.CFrame = BorderPosts[tostring(CurrentCameraIndex)].TeleportPlayerPart.CFrame
	task.wait(1)
	CurrentCameraIndex = 1
end)

BorderSelection.SelectButton.MouseEnter:Connect(function()
	TWEEN_SERVICE:Create(BorderSelection.SelectButton, TweenInfo.new(0.1, Enum.EasingStyle.Sine), {BackgroundColor3 = Color3.fromRGB(61, 147, 43)}):Play()
	BorderSelection.SelectButton:TweenSize(UDim2.new(0.45, 0,0.207, 0), Enum.EasingDirection.InOut, Enum.EasingStyle.Sine, 0.1)

	Sounds.Hover:Play()
end)

BorderSelection.SelectButton.MouseLeave:Connect(function()
	TWEEN_SERVICE:Create(BorderSelection.SelectButton, TweenInfo.new(0.1, Enum.EasingStyle.Sine), {BackgroundColor3 = Color3.fromRGB(75, 186, 55)}):Play()
	BorderSelection.SelectButton:TweenSize(UDim2.new(0.426, 0,0.173, 0), Enum.EasingDirection.InOut, Enum.EasingStyle.Sine, 0.1)
end)




BorderSelection.ReturnButton.MouseButton1Click:Connect(function()
	CurrentCameraIndex = 1
	BorderSelection:TweenPosition(UDim2.new(0.5, 0,1.5, 0), Enum.EasingDirection.InOut, Enum.EasingStyle.Sine, 0.5)
	task.wait(0.5)
	Transition()
	Menu:TweenPosition(UDim2.new(0.5, 0,0.5, 0), Enum.EasingDirection.InOut, Enum.EasingStyle.Sine, 0.5)

	Connection = RUN_SERVICE.RenderStepped:Connect(UpdateCamera)
	Player:RequestStreamAroundAsync(MainMenuCam.Position)
end)

BorderSelection.ReturnButton.MouseEnter:Connect(function()
	TWEEN_SERVICE:Create(BorderSelection.ReturnButton, TweenInfo.new(0.1, Enum.EasingStyle.Sine), {BackgroundColor3 = Color3.fromRGB(147, 2, 4)}):Play()
	BorderSelection.ReturnButton:TweenSize(UDim2.new(0.35, 0,0.119, 0), Enum.EasingDirection.InOut, Enum.EasingStyle.Sine, 0.1)

	Sounds.Hover:Play()
end)

BorderSelection.ReturnButton.MouseLeave:Connect(function()
	TWEEN_SERVICE:Create(BorderSelection.ReturnButton, TweenInfo.new(0.1, Enum.EasingStyle.Sine), {BackgroundColor3 = Color3.fromRGB(186, 2, 5)}):Play()
	BorderSelection.ReturnButton:TweenSize(UDim2.new(0.343, 0,0.107, 0), Enum.EasingDirection.InOut, Enum.EasingStyle.Sine, 0.1)
end)
1 Like

Hey, what I would consider doing is adding comment blocks like

--[[ Variables 🫙 ]]--
local whatever = example

--[[ Button 👆 ]]--

--[[ ----------------------------------------------------------- ]]--

Or random stuff like that, to break the code up a bit better, also add some emojis for some fun.

However for tweens what I tend to do is:

-- This is your code, and I haven't copied the full tween at the bottom

TWEEN_SERVICE:Create(
     LoadingScreen,
     TweenInfo.new(0.5),
     {BackgroundTransparency = 1}
):Play()

task.wait(0.6)

Menu:TweenPosition(
     UDim2.new(0.5, 0, 0.5, 0),
     Enum.EasingDirection.InOut,
     Enum.EasingStyle.Sine, 0.5)

It can be a little bit easier to read; however, you have multiple tweens, so it probably unnecessarily lengthens the code out.

I hope this helps, I’ll come back if I think of any more ideas.

1 Like

Heya! This is something I’ve personally struggled with for quite a while, but mine is more so Script Structure, the only thing I change now is variable casing

It’s all about personal preference, whatever you like, you should do! It’s totally fine to look through others and makeup your own or follow another.

Keep in mind, coding UI, I’ve learned, will ALWAYS be long and somewhat messy, don’t stress yourself constantly rewriting everything either if you change some stuff in your style, you can leave the other scripts being a little bit different

This is a pretty good website for general things: Roblox Lua Style guide
I personally use it mixed with whatever I feel like doing/what I want to do

Currently I setup something like:

-- Services

-- Modules

-- Objects
--[[
    This one is abit random, but usually its the most important things to the least important
]]

-- Consts (variables that never change, e.g. local SPRINT_SPEED = 50)

-- Bools
-- Ints
-- Whatever other variables may be needed

-- Local Functions

-- Connections

-- Init

Rough example:

local content_provider = game:GetService("ContentProvider")
local replicated_first = game:GetService("ReplicatedFirst")
local replicated_storage = game:GetService("ReplicatedStorage")
local tween_service = game:GetService("TweenService")
local players = game:GetService("Players")
local run_service = game:GetService("RunService")

local get_assets = require(script.GetAssets)

local Player = players.LocalPlayer
local Mouse = Player:GetMouse()
local Camera = workspace.CurrentCamera

local PlayerGui = Player:WaitForChild("PlayerGui")
local MainMenu = PlayerGui:WaitForChild("MainMenu")
local LoadingScreen = MainMenu.LoadingScreen
local Menu = MainMenu.Menu
local BorderSelection = MainMenu.BorderSelection

local RepObjects = replicated_storage:WaitForChild("ReplicatedObjects")
local Assets = get_assets.FetchAssets()

local Cameras = workspace:WaitForChild("Cameras")
local Sounds = script:WaitForChild("Sound")
local BorderPosts = workspace:WaitForChild("BorderPosts")
local MainMenuCam = Cameras:WaitForChild("MainMenuCamera")

local MOVE_SPEED = 150

local Loading = true
local CurrentCameraIndex = 1
local camera_update_connection = nil :: RBXScriptConnection?

local function UpdateCamera() -- do local, they're proven to be better than global, and theres no need for a global function :)
	local Center = MainMenuCam.CFrame
	local MoveVector = Vector3.new((Mouse.X - Center.X)/MOVE_SPEED, (Mouse.Y - Center.Y)/MOVE_SPEED, 0)
	Camera.CFrame = MainMenuCam.CFrame * CFrame.Angles(math.rad(-(Mouse.Y - Center.Y)/MOVE_SPEED), math.rad(-(Mouse.X - Center.Y)/MOVE_SPEED), 0)
end

local function Transition(time)
	tween_service:Create(LoadingScreen, TweenInfo.new(0.5), {BackgroundTransparency = 0}):Play()
	task.wait(time)
	tween_service:Create(LoadingScreen, TweenInfo.new(0.5), {BackgroundTransparency = 1}):Play()
end

BorderSelection.SelectButton.MouseButton1Click:Connect(function()
	BorderSelection:TweenPosition(UDim2.new(0.5, 0,1.5, 0), Enum.EasingDirection.InOut, Enum.EasingStyle.Sine, 0.5)
	task.wait(0.5)
	Transition(1)
	camera_update_connection:Disconnect()
	Camera.CameraType = Enum.CameraType.Custom
	Player:RequestStreamAroundAsync(BorderPosts[tostring(CurrentCameraIndex)].TeleportPlayerPart.Position)
	Player.Character.HumanoidRootPart.CFrame = BorderPosts[tostring(CurrentCameraIndex)].TeleportPlayerPart.CFrame
	task.wait(1)
	CurrentCameraIndex = 1
end)

BorderSelection.SelectButton.MouseEnter:Connect(function()
	tween_service:Create(BorderSelection.SelectButton, TweenInfo.new(0.1, Enum.EasingStyle.Sine), {BackgroundColor3 = Color3.fromRGB(61, 147, 43)}):Play()
	BorderSelection.SelectButton:TweenSize(UDim2.new(0.45, 0,0.207, 0), Enum.EasingDirection.InOut, Enum.EasingStyle.Sine, 0.1)

	Sounds.Hover:Play()
end)

BorderSelection.SelectButton.MouseLeave:Connect(function()
	tween_service:Create(BorderSelection.SelectButton, TweenInfo.new(0.1, Enum.EasingStyle.Sine), {BackgroundColor3 = Color3.fromRGB(75, 186, 55)}):Play()
	BorderSelection.SelectButton:TweenSize(UDim2.new(0.426, 0,0.173, 0), Enum.EasingDirection.InOut, Enum.EasingStyle.Sine, 0.1)
end)

BorderSelection.ReturnButton.MouseButton1Click:Connect(function()
	CurrentCameraIndex = 1
	BorderSelection:TweenPosition(UDim2.new(0.5, 0,1.5, 0), Enum.EasingDirection.InOut, Enum.EasingStyle.Sine, 0.5)
	task.wait(0.5)
	Transition()
	Menu:TweenPosition(UDim2.new(0.5, 0,0.5, 0), Enum.EasingDirection.InOut, Enum.EasingStyle.Sine, 0.5)

	camera_update_connection = run_service.RenderStepped:Connect(UpdateCamera)
	Player:RequestStreamAroundAsync(MainMenuCam.Position)
end)

BorderSelection.ReturnButton.MouseEnter:Connect(function()
	tween_service:Create(BorderSelection.ReturnButton, TweenInfo.new(0.1, Enum.EasingStyle.Sine), {BackgroundColor3 = Color3.fromRGB(147, 2, 4)}):Play()
	BorderSelection.ReturnButton:TweenSize(UDim2.new(0.35, 0,0.119, 0), Enum.EasingDirection.InOut, Enum.EasingStyle.Sine, 0.1)

	Sounds.Hover:Play()
end)

BorderSelection.ReturnButton.MouseLeave:Connect(function()
	tween_service:Create(BorderSelection.ReturnButton, TweenInfo.new(0.1, Enum.EasingStyle.Sine), {BackgroundColor3 = Color3.fromRGB(186, 2, 5)}):Play()
	BorderSelection.ReturnButton:TweenSize(UDim2.new(0.343, 0,0.107, 0), Enum.EasingDirection.InOut, Enum.EasingStyle.Sine, 0.1)
end)

-- replicating objects
for _, v in pairs(RepObjects:GetDescendants()) do
	local newObject = v:Clone()

	if v.Parent.Name == "Cameras" then
		newObject.Parent = Cameras
	elseif v.Parent.Name == "SpectateCameras" then
		newObject.Parent = BorderPosts[v.Name]
		newObject.Name = "SpectateCamera"
	elseif v.Parent.Name == "BorderTeleports" then
		newObject.Parent = BorderPosts[v.Name]
		newObject.Name = "TeleportPlayerPart"
	end
end

-- GUI
replicated_first:RemoveDefaultLoadingScreen()

for i = 1, #Assets do
	local Asset = Assets[i]

	content_provider:PreloadAsync({Asset})

	if i % 5 == 0 then
		task.wait()
	end

	tween_service:Create(LoadingScreen.FillBackground.Fill, TweenInfo.new(0.5, Enum.EasingStyle.Sine), {Size = UDim2.new(i / #Assets, 0, 1, 0)}):Play()

	if i == #Assets then
		LoadingScreen.FillBackground.LoadingLabel.Text = "Complete"
		Loading = false
	end
end

camera_update_connection = run_service.RenderStepped:Connect(UpdateCamera)
Player:RequestStreamAroundAsync(MainMenuCam.Position)

task.wait(1)
LoadingScreen.FillBackground:TweenPosition(UDim2.new(0.5, 0,1.5, 0), Enum.EasingDirection.InOut, Enum.EasingStyle.Sine, 0.5)
task.wait(1)
tween_service:Create(LoadingScreen.Title, TweenInfo.new(2), {TextTransparency = 1}):Play()
task.wait(2.5)
tween_service:Create(LoadingScreen, TweenInfo.new(0.5), {BackgroundTransparency = 1}):Play()
task.wait(0.6)
Menu:TweenPosition(UDim2.new(0.5, 0, 0.5, 0), Enum.EasingDirection.InOut, Enum.EasingStyle.Sine, 0.5)

for _, object in pairs(Menu:GetChildren()) do
	if object:IsA("TextButton") then
		object.MouseEnter:Connect(function()
			tween_service:Create(object, TweenInfo.new(0.1, Enum.EasingStyle.Sine), {BackgroundColor3 = Color3.fromRGB(54, 54, 54)}):Play()
			object:TweenSize(UDim2.new(0.352, 0,0.103, 0), Enum.EasingDirection.InOut, Enum.EasingStyle.Sine, 0.1)

			Sounds.Hover:Play()
		end)

		object.MouseLeave:Connect(function()
			tween_service:Create(object, TweenInfo.new(0.1, Enum.EasingStyle.Sine), {BackgroundColor3 = Color3.fromRGB(62, 62, 62)}):Play()
			object:TweenSize(UDim2.new(0.345, 0,0.087, 0), Enum.EasingDirection.InOut, Enum.EasingStyle.Sine, 0.1)
		end)

		object.MouseButton1Click:Connect(function()
			Sounds.Click:Play()

			if object.Name == "PlayButton" then
				Menu:TweenPosition(UDim2.new(0.5, 0,1.5, 0), Enum.EasingDirection.InOut, Enum.EasingStyle.Sine, 0.5)
				task.wait(0.3)
				Transition(0.5)
				camera_update_connection:Disconnect()
				Camera.CameraType = Enum.CameraType.Scriptable
				Camera.CFrame = BorderPosts["1"].SpectateCamera.CFrame
				BorderSelection:TweenPosition(UDim2.new(0.5, 0,0.749, 0), Enum.EasingDirection.InOut, Enum.EasingStyle.Sine, 0.5)
			end
		end)
	end
end

I hope this helps atleast a bit :,D

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