this is for a progress bar that displays users avatars like on tower of hell
i saw that people use
runService.RenderStepped
but it makes my game crash
local imageFrame = script:WaitForChild("Player")
local puttingFolder = script.Parent:WaitForChild("Players")
local runService = game:GetService("RunService")
local players = game:GetService("Players")
local checkpoints = #game.Workspace:WaitForChild("Checkpoints"):GetChildren()
local thumbnailType = Enum.ThumbnailType.HeadShot
local thumbnailSize = Enum.ThumbnailSize.Size150x150
runService.RenderStepped:Connect(function()
for _, image in pairs(puttingFolder:GetChildren()) do
image:Destroy()
end
for _, player in pairs(players:GetPlayers()) do
local playerStage = player.leaderstats.Stage
local imageClone = imageFrame:Clone()
local position = playerStage.Value*100/checkpoints
imageClone.Image = players:GetUserThumbnailAsync(player.UserId, thumbnailType, thumbnailSize)
imageClone.Position = UDim2.fromScale(position, .5)
imageClone.Parent = imageFrame
end
end)
RenderStepped does not run in parallel to Roblox’s rendering tasks and code connected to RenderStepped must be executed prior to the frame being rendered. This can lead to significant performance issues if RenderStepped is used inappropriately. To avoid this, only use RenderStepped for code that works with the camera or character. Otherwise, RunService.Heartbeat should be used.
Like what the Docs says, try switching to RunService.Heartbeat instead.
The biggest culprit here is :GetUserThumbnailAsync(), as you’re calling it within your RunService scope for each player. Functions with “Wait” or “Async” in their name mean that they yield the current thread, alongside extra code which overall is way too performance heavy causing too much stress on your script to be running EVERY frame.
I highly suggest instead of constantly deleting and recreating the GUI for your player’s thumbnail’s on your progress bar, create and remove the player’s thumbnail gui once via PlayerAdded/Removing events, store it in a folder, and have RunService update the position or the logic you intend to act on the existing guis.
Your current code has a race condition/memory leak.
cause players:GetUserThumbnailAsync(player.UserId) is like the api call suggests, asynchronous, that means the api will yield for an unreliable time. You are running the api call over and over again, without waiting for it to be complete, this causes a huge memory leak overtime and your game will end up crashing.
Fix
To fix this you need a bool variable which lets the connection know if the api calls are completed or not, here is the suggested code which should fix the bug encountered in your code:
local imageFrame = script:WaitForChild("Player")
local puttingFolder = script.Parent:WaitForChild("Players")
local runService = game:GetService("RunService")
local players = game:GetService("Players")
local checkpoints = #game.Workspace:WaitForChild("Checkpoints"):GetChildren()
local thumbnailType = Enum.ThumbnailType.HeadShot
local thumbnailSize = Enum.ThumbnailSize.Size150x150
locsl step_busy = false
runService.RenderStepped:Connect(function()
if step_busy then
return
end
step_busy = true
for _, image in pairs(puttingFolder:GetChildren()) do
image:Destroy()
end
for _, player in pairs(players:GetPlayers()) do
local playerStage = player.leaderstats.Stage
local imageClone = imageFrame:Clone()
local position = playerStage.Value*100/checkpoints
imageClone.Image = players:GetUserThumbnailAsync(player.UserId, thumbnailType, thumbnailSize)
imageClone.Position = UDim2.fromScale(position, .5)
imageClone.Parent = imageFrame
end
step_busy = false
end)
If this resolved your issue, feel free to let me know by marking this as the solution or by simply telling me. If there are any other issues or questions feel free to ask!