I have lots of experience with this.
I for example in my game Helsinki Vantaa i have a custom loading screen to ensure that no assets are missing.
So first you have a LocalScript in ReplicatedFirst which creates the GUI.
Then you wait for the local player to appear and then call
Players.LocalPlayer:WaitForChild("PlayerGui")
And then AND ONLY THEN you can remove the default Roblox loading screen with
ReplicatedFirst:RemoveDefaultLoadingScreen()
and parent your own GUI in to the Player Gui.
Now you cannot instantly just display the loading amount it has loaded because the ContentProvider service(the service which loads content) does not know the amount it has to load because it has not loaded that info either. So
You first must display “Loading game structure…”
Then you run this.
if not game:IsLoaded() then
game.Loaded:Wait()
end
What this ^ basically does is that it checks if the game structure has loaded.
Then you must check if the character has loaded.
Insert this \ / function in your script.
local function waitForCharacterLoaded()
if Players.CharacterAutoLoads then
local localPlayer = Players.LocalPlayer
if not localPlayer then
Players:GetPropertyChangedSignal("LocalPlayer"):wait()
localPlayer = Players.LocalPlayer
end
if not localPlayer.Character then
localPlayer.CharacterAdded:wait()
end
end
end
Then display this message “Loading characters …”
and call
waitForCharacterLoaded()
Now we have loaded all the necessary assets so you could add a “Skip” loading screen button.
Now you probably would still wan’t to make a loading screen for the unnecessary assets.
And here you can display the percentage loaded.
So you first store the max amount of assets being loaded via doing.
local MaxAssets = ContentProvider.RequestQueueSize
And then just start the loading process.
So first display the message “Loading assets …”
And then do \ /
repeat
local CurrentLoaded = ContentProvider.RequestQueueSize / MaxAssets
local PercentLoaded = math.round(CurrentLoaded * 100)
-- // Your other code
wait(1.4)
until ContentProvider.RequestQueueSize < 5
And there you go all assets have loaded.
If you wan’t to preload some assets you can do as @cxmeels suggested. But remember to wrap ContentProvider:PreloadAsync() in a pcall or xpcall.
You can additionally do stuff like failed asset detection but this was a kind of a bare bones guide to a good loading screen.