https://kotlinlang.org logo
Title
j

Jan

04/12/2022, 6:17 PM
Hey I'm creating a "game" or more like a simulation following the example of the Falling Balls Game on github. But my game is kinda "lagging" and it's also fps dependent. The example covers that (I think) but I don't think I'm implementing it right. Currently I have: (thread)
val x = (simX * SCALE) + windowWidth / 2
val y = (simY * SCALE) + windowHeight / 2
//this updates the x and y coordinates.
Here you can see the lag
This is the loop:
LaunchedEffect(Unit) {
        while (true) {
            withFrameNanos {
                if (sim.hasStarted && !sim.isPaused)
                    sim.update(it)
            }
        }
    }
But I'm currently ignoring "it" in the code above
l

Landry Norris

04/12/2022, 7:13 PM
Have you wrapped sim.update in measureTimeMillis to see if that's the bottleneck?
j

Jan

04/12/2022, 7:35 PM
thats giving me 0 or 1
l

Landry Norris

04/12/2022, 7:48 PM
It looks like the update function isn’t causing a bottleneck, then. Have you tried saving the last nanos value to get the exact fps it’s running at?
It looks like you’re trying to run it as fast as possible. Whenever I do something on loop, I usually set up a class that uses coroutines to set up an event loop. It would basically have a suspend function named run or something and would loop, checking if Clock.System.now() is greater than the last time plus a delay, delaying 1ms if it isn’t.
This will even out the fps more than running it as fast as possible.
j

Jan

04/12/2022, 7:52 PM
lemme try this
Like that?
val millis = System.currentTimeMillis()
        if(millis < previousTimeNanos + 1) {
            delay(1)
        }
        previousTimeNanos = millis
it still lags
used ur example but it somehow makes it worse
val nano = Clock.System.now()
        if(nano < previousTimeNano.plus(1.milliseconds)) {
            delay(1)
        }
        previousTimeNano = nano
l

Landry Norris

04/12/2022, 8:18 PM
The while loop should start with if(nano < previousTimeNano.plus(16.milliseconds)) continue, so you are comparing to the last actual frame time.
I generally use if(lastTime.periodUntil(now, TimeZone.UTC).nanoseconds < delay) { delay(1); continue }
After that, set lastTime to now and call your frameTick function
j

Jan

04/12/2022, 8:25 PM
Sorry for bothering you for so long, but like that?
while (true) {
            if(sim.previousTimeNano.periodUntil(Clock.System.now(), TimeZone.UTC).nanoseconds < 16.milliseconds.inWholeNanoseconds) { delay(1); continue }
            sim.previousTimeNano = Clock.System.now()
            if (sim.hasStarted)
                sim.update(scrollState)
        }
l

Landry Norris

04/12/2022, 9:00 PM
That looks fine. I personally would set now to a variable once so it will be the same in both places (affects how framerate works when your frame tick takes time).