Frame Limiting/Compensation

Started by Steve Elliott, November 14, 2017, 14:00:16

Previous topic - Next topic

Steve Elliott

What approach are people taking these days regards frame speed/compensation?
Win11 64Gb 12th Gen Intel i9 12900K 3.2Ghz Nvidia RTX 3070Ti 8Gb
Win11 16Gb 12th Gen Intel i5 12450H 2Ghz Nvidia RTX 2050 8Gb
Win11  Pro 8Gb Celeron Intel UHD Graphics 600
Win10/Linux Mint 16Gb 4th Gen Intel i5 4570 3.2GHz, Nvidia GeForce GTX 1050 2Gb
macOS 32Gb Apple M2Max
pi5 8Gb
Spectrum Next 2Mb

Derron

Movement Interpolation / Tweening
and traditional delta timing.

So for rendering you mix "last render position" with "now".

For physics ("update loop") you use delta timing ("how much time passed since last step in comparison to the time span each step has").


bye
Ron

BasicBoy

For my SB compo entry I'll be using delta time, obtained via Windows' QueryPerformanceCounter for high precision (although with deltas scaled to milliseconds which should be accurate enough for my purposes). If high precision timers aren't available (they usually will be with Windows PCs), then I can always fall back on timeGetTime or GetTickCount.









Qube

I use delta timing with averaging over X frames.
Mac Studio M1 Max ( 10 core CPU - 24 core GPU ), 32GB LPDDR5, 512GB SSD,
Beelink SER7 Mini Gaming PC, Ryzen 7 7840HS 8-Core 16-Thread 5.1GHz Processor, 32G DDR5 RAM 1T PCIe 4.0 SSD
MSI MEG 342C 34" QD-OLED Monitor

Until the next time.

therevills

#4
This page has a great write up of various framing routines:

http://www.koonsolo.com/news/dewitters-gameloop/

In Diddy2 I've coded a few ways and settled on fixed rate logic and tweening when needed:

https://github.com/therevills/diddy2/blob/master/deltatiming.monkey2
' converted from http://www.rightanglegames.com/top-down-shooter-tutorial-with-blitzmax.html
Class FixedRateLogicTimer
Field newTime:Double = Millisecs()
Field oldTime:Double = Millisecs()
Field delta:Float
Field dssOn:Int ' do we use delta spike suppression?
Field dssIndex:Int ' index into DSS_Array where next delta value is written
Field dssArray:Float[] ' this array contains the delta values to smooth
Field dssLenArray:Int ' how big is the array of delta values

Field logicFPS:Float
Field accumulator:Float
Field tween:Float

Field fpsAccumulator:Float
Field updateCount:Int
Field renderCount:Int
Field updatesPerSecond:Int
Field rendersPerSecond:Int
Field logicCyclesPerSecond:Float

Method New(logicCyclesPerSecond:Float, numSamples:Int = 0)
Self.logicCyclesPerSecond = logicCyclesPerSecond
logicFPS = 1.0 / logicCyclesPerSecond
If numSamples
dssOn = True
dssArray = New Float[numSamples]
dssLenArray = numSamples
End
End

Method ProcessTime:Float()
newTime = Millisecs()
delta = Float (newTime - oldTime) * 0.001
oldTime = newTime

If dssOn
dssArray[dssIndex] = delta

Local smoothDelta:Float = 0

For Local i:Int = 0 To dssLenArray - 1
smoothDelta += dssArray[i]
Next
delta = Float(smoothDelta / dssLenArray)

dssIndex += 1
If dssIndex > dssLenArray - 1 Then dssIndex = 0
End

accumulator += delta

fpsAccumulator += delta

If fpsAccumulator > 1.0
fpsAccumulator -= 1.0
updatesPerSecond = updateCount
updateCount = 0
rendersPerSecond = renderCount
renderCount = 0
End
Return delta
End

Method LogicUpdateRequired:Int()
If accumulator > logicFPS
updateCount += 1
accumulator -= logicFPS
Return True
End
Return False
End

Method CalcFrameTime:Float(ms:Float)
Local amount:Float = updatesPerSecond
If amount = 0
amount = logicCyclesPerSecond
End
' convert Hz to ms
Local msPerFrame:Float = 1000.0 / amount
' convert ms to frame time
Local rv:Float = ms / msPerFrame
Return rv
End

Method GetLogicFPS:Float()
Return logicFPS
End

Method GetTween:Float()
renderCount += 1
Return accumulator / logicFPS
End

Method ShowSpikeSuppression(x:Int, y:Int, canvas:Canvas)
Local ty:Int = y - (canvas.Font.Height * (3 + Self.dssLenArray))
canvas.DrawText("Delta Spike Suppressor:", x, ty)
ty += canvas.Font.Height
For Local i:Int = 0 To Self.dssLenArray - 1
canvas.DrawText(dssArray[i], x, ty)
ty += canvas.Font.Height
Next

ty += canvas.Font.Height
canvas.DrawText("Final Delta: " + delta, x, ty)
End

Method ShowFPS(x:Int, y:Int, canvas:Canvas, showUpdateFPS:Int = True, showRenderFPS:Int = True)
Local ty:Int = y - (canvas.Font.Height * 2)

If showUpdateFPS
canvas.DrawText("Logic FPS:  " + updatesPerSecond, x, ty)
ty += canvas.Font.Height
End
If showRenderFPS
canvas.DrawText("Render FPS: " + rendersPerSecond, x, ty)
End
End
End


And how to use it:

Global GameTime:FixedRateLogicTimer
Const UPDATE_FREQUENCY:Float = 100.0
Const SPIKE_SUPPRESSION:Int = 10
...
GameTime = New FixedRateLogicTimer(UPDATE_FREQUENCY, SPIKE_SUPPRESSION)
...

...
Local tween:Float
Local delta:Float = GameTime.ProcessTime()
While GameTime.LogicUpdateRequired()
GameLogic(GameTime.GetLogicFPS())
End
tween = GameTime.GetTween()
GameRender(tween)

Steve Elliott

Win11 64Gb 12th Gen Intel i9 12900K 3.2Ghz Nvidia RTX 3070Ti 8Gb
Win11 16Gb 12th Gen Intel i5 12450H 2Ghz Nvidia RTX 2050 8Gb
Win11  Pro 8Gb Celeron Intel UHD Graphics 600
Win10/Linux Mint 16Gb 4th Gen Intel i5 4570 3.2GHz, Nvidia GeForce GTX 1050 2Gb
macOS 32Gb Apple M2Max
pi5 8Gb
Spectrum Next 2Mb

Matty

My approach is non standard but works fine.

If your game, like mine, is non heavy on the CPU and the problem is more likely that the CPU is too fast rather than too slow I simply do this (blitz3d code)

main loop
{
stime = millisecs()
do everything
rendereverything
stime = millisecs() - stime
if stime < 15 then
        delay 15 - stime
endif
}

keeps everything moving nice and the same rate...I generally have simple games that don't exercise the CPU too hard.