Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
0

Wait() doesn't wait the same time for 60FPS than for higher framerates?

Asked by 3 years ago

Hi guys! I'm trying to make a music game similar to Friday Night Funkin'. Everything was right until I tried to chart the song. I personally play Roblox with 240 FPS. I tested the song at that frame rate and everything was right. The problem comes when I go to 60 FPS. The chart is VERY delayed to the song. It seems that those wait(0.15) and similar wait less time in higher framerates. Is there any solution to replace those awfully inconsistent wait() to other thing, more consistent to make the charting of the song? Thank you! The code of the charting.

game.ReplicatedStorage.SongBegin.OnServerEvent:Connect(function()
    local ts = game:GetService("TweenService")
    local SongInfo = {
        NotesSkins = {              
            NormalArrow = "rbxassetid://7382833833",
            ExtendArrow = "rbxassetid://7385411096"
        },
        songbpm = 0.6
        }
        local NotesColors = {
            Note1 = Color3.fromRGB(175,0,255),
            Note2 = Color3.fromRGB(0,255,255),
            Note3 = Color3.fromRGB(0,255,0),
            Note4 = Color3.fromRGB(255,50,50)
        }
        local ti = TweenInfo.new(
            SongInfo.songbpm,
            Enum.EasingStyle.Linear,
            Enum.EasingDirection.InOut,
            0,
            false,
            0
        )
        local go = {}
        go.Position = UDim2.new(0,0,1,0)
        local function chartnormalnote1()
            local nt1 = Instance.new("ImageLabel")
            nt1.Name = "Note"
            nt1.ZIndex = 2
            nt1.BackgroundTransparency = 1
            nt1.Image = SongInfo.NotesSkins.NormalArrow
            nt1.Position = UDim2.new(0,0,-0.137,0)
            nt1.Size = UDim2.new(1,0,0.137,0)
            nt1.ImageColor3 = NotesColors.Note1
            nt1.Parent = plr.PlayerGui:WaitForChild("Chart").Template.Chart.Arrow1
            nt1.Rotation = -90
            ts:Create(nt1,ti,go):Play()
        end
        local function chartlongnote1()
            local nt1 = Instance.new("ImageLabel")
            nt1.Name = "NoteExtension"
            nt1.ZIndex = 1
            nt1.BackgroundTransparency = 1
            nt1.Image = SongInfo.NotesSkins.ExtendArrow
            nt1.Position = UDim2.new(0,0,-0.137,0)
            nt1.Size = UDim2.new(1,0,0.137,0)
            nt1.ImageColor3 = NotesColors.Note1
            nt1.Parent = plr.PlayerGui:WaitForChild("Chart").Template.Chart.Arrow1
            nt1.Rotation = 0
            ts:Create(nt1,ti,go):Play()
        end
        local function chartnormalnote2()
            local nt1 = Instance.new("ImageLabel")
            nt1.Name = "Note"
            nt1.ZIndex = 2
            nt1.BackgroundTransparency = 1
            nt1.Image = SongInfo.NotesSkins.NormalArrow
            nt1.Position = UDim2.new(0,0,-0.137,0)
            nt1.Size = UDim2.new(1,0,0.137,0)
            nt1.ImageColor3 = NotesColors.Note2
            nt1.Parent = plr.PlayerGui:WaitForChild("Chart").Template.Chart.Arrow2
            nt1.Rotation = 180
            ts:Create(nt1,ti,go):Play()
        end
        local function chartlongnote2()
            local nt1 = Instance.new("ImageLabel")
            nt1.Name = "NoteExtension"
            nt1.ZIndex = 1
            nt1.BackgroundTransparency = 1
            nt1.Image = SongInfo.NotesSkins.ExtendArrow
            nt1.Position = UDim2.new(0,0,-0.137,0)
            nt1.Size = UDim2.new(1,0,0.137,0)
            nt1.ImageColor3 = NotesColors.Note2
            nt1.Parent = plr.PlayerGui:WaitForChild("Chart").Template.Chart.Arrow2
            nt1.Rotation = 0
            ts:Create(nt1,ti,go):Play()
        end
        local function chartnormalnote3()
            local nt1 = Instance.new("ImageLabel")
            nt1.Name = "Note"
            nt1.ZIndex = 2
            nt1.BackgroundTransparency = 1
            nt1.Image = SongInfo.NotesSkins.NormalArrow
            nt1.Position = UDim2.new(0,0,-0.137,0)
            nt1.Size = UDim2.new(1,0,0.137,0)
            nt1.ImageColor3 = NotesColors.Note3
            nt1.Parent = plr.PlayerGui:WaitForChild("Chart").Template.Chart.Arrow3
            nt1.Rotation = 0
            ts:Create(nt1,ti,go):Play()
        end
        local function chartlongnote3()
            local nt1 = Instance.new("ImageLabel")
            nt1.Name = "NoteExtension"
            nt1.ZIndex = 1
            nt1.BackgroundTransparency = 1
            nt1.Image = SongInfo.NotesSkins.ExtendArrow
            nt1.Position = UDim2.new(0,0,-0.137,0)
            nt1.Size = UDim2.new(1,0,0.137,0)
            nt1.ImageColor3 = NotesColors.Note3
            nt1.Parent = plr.PlayerGui:WaitForChild("Chart").Template.Chart.Arrow3
            nt1.Rotation = 0
            ts:Create(nt1,ti,go):Play()
        end
        local function chartnormalnote4()
            local nt1 = Instance.new("ImageLabel")
            nt1.Name = "Note"
            nt1.ZIndex = 2
            nt1.BackgroundTransparency = 1
            nt1.Image = SongInfo.NotesSkins.NormalArrow
            nt1.Position = UDim2.new(0,0,-0.137,0)
            nt1.Size = UDim2.new(1,0,0.137,0)
            nt1.ImageColor3 = NotesColors.Note4
            nt1.Parent = plr.PlayerGui:WaitForChild("Chart").Template.Chart.Arrow4
            nt1.Rotation = 90
            ts:Create(nt1,ti,go):Play()
        end
        local function chartlongnote4()
            local nt1 = Instance.new("ImageLabel")
            nt1.Name = "NoteExtension"
            nt1.ZIndex = 1
            nt1.BackgroundTransparency = 1
            nt1.Image = SongInfo.NotesSkins.ExtendArrow
            nt1.Position = UDim2.new(0,0,-0.137,0)
            nt1.Size = UDim2.new(1,0,0.137,0)
            nt1.ImageColor3 = NotesColors.Note4
            nt1.Parent = plr.PlayerGui:WaitForChild("Chart").Template.Chart.Arrow4
            nt1.Rotation = 0
            ts:Create(nt1,ti,go):Play()
        end
        plr.PlayerGui:WaitForChild("Chart").Start.Visible = false
        game.Workspace.Music:Play()
        wait(3.9)
        chartnormalnote1()
        wait(0.02)
        chartlongnote1()
        wait(0.055)
        chartlongnote1()
        wait(0.15)
        chartnormalnote2()
        wait(0.02)
        chartlongnote2()
        wait(0.055)
        chartlongnote2()    
        wait(0.15)
        chartnormalnote4()
        wait(0.15)
        chartnormalnote4()
        wait(0.1)
        chartnormalnote1()
        wait(0.15)
        chartnormalnote2()
        wait(0.15)
        chartnormalnote3()
        wait(0.15)
        chartnormalnote2()
        wait(0.15)
        chartnormalnote1()
        wait(0.2)
        chartnormalnote4()
        wait(0.2)
        chartnormalnote3()
        wait(0.02)
        chartlongnote3()
        wait(0.055)
        chartlongnote3()
        wait(0.2)
        chartnormalnote2()
end)
0
Sadly, that's the thing with waits, they wait longer than usual and having many of them can result in a laggy game. You can read this post on the developer forum which talks about waits waiting long than usual. https://devforum.roblox.com/t/avoiding-wait-and-why/244015 MarkedTomato 810 — 3y

1 answer

Log in to vote
0
Answered by
Rare_tendo 3000 Moderation Voter Community Moderator
3 years ago
Edited 3 years ago

wait(t) will always try to yield the current thread by t seconds, however, the accuracy is dependent on your fps: at a much higher fps, the actual time the thread has been yielded for will be much closer to the desired waiting time than at a lower fps. wait has a minimum wait time of 0.03 (~ 1/30th of a second) so wait really is only capped to a 30Hz pipeline, regardless of whether or not you're capped at 60 or using an fps unlocker to get a higher fps, however the frequency will drop if you do go below 30 fps, as in this case, the frequency of wait's pipeline will be correspondent to your current fps when it is less than 30. So, any waiting times less than 0.03 will have the thread wait for 0.03 seconds: an unintended wait time off by 10 milliseconds every time you wait 0.02 seconds in your code. The more of these you have, the more delayed the song will be.

Playing at 240 fps will have the accuracy of the actual time yielded compared to the desired time be ~4x as accurate as playing at 60 fps. wait spam can also further delay your game as often times, thread resumptions are deterred. However, a better solution would be to use task.wait(t) since it internalises the Heartbeat event which fires at the exact same frequency as your fps, since Heartbeat gets fired every frame. With this, you're no longer constrained to the 30Hz pipeline, which makes it so playing at 60 fps will have the accuracy be double the amount as if you're using wait

Ad

Answer this question