Skip to content

Commit

Permalink
feat: Allow settings for FPS sampling refresh rate
Browse files Browse the repository at this point in the history
  • Loading branch information
Jean-René Lavoie committed Mar 21, 2024
1 parent fd7b943 commit d718b88
Show file tree
Hide file tree
Showing 4 changed files with 19 additions and 4 deletions.
2 changes: 1 addition & 1 deletion fxgl/src/main/kotlin/com/almasb/fxgl/app/Engine.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ internal class Engine(val settings: ReadOnlyGameSettings) {

private val log = Logger.get(javaClass)

private val loop = LoopRunner(settings.ticksPerSecond) { loop(it) }
private val loop = LoopRunner(settings.ticksPerSecond, settings.fpsRefreshRate) { loop(it) }

val tpf: Double
get() = loop.tpf
Expand Down
9 changes: 6 additions & 3 deletions fxgl/src/main/kotlin/com/almasb/fxgl/app/LoopRunner.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ package com.almasb.fxgl.app
import com.almasb.fxgl.logging.Logger
import javafx.animation.AnimationTimer
import javafx.application.Platform
import javafx.util.Duration
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
import kotlin.system.measureNanoTime
Expand All @@ -29,6 +30,8 @@ internal class LoopRunner(
*/
private val ticksPerSecond: Int = -1,

private val fpsRefreshRate: Duration = Duration.millis(500.0),

private val runnable: (Double) -> Unit) {

private val log = Logger.get<LoopRunner>()
Expand Down Expand Up @@ -94,7 +97,7 @@ internal class LoopRunner(
}

private fun frame(now: Long) {
val ticksPerSecond = if (ticksPerSecond < 0) 60 else ticksPerSecond // For JavaFX loops, cap at 60fps too
val ticksPerSecond = if (ticksPerSecond < 0) 60 else ticksPerSecond // When unknown, default to 60 fps

if (lastFrameNanos == 0L) {
lastFrameNanos = now - (1_000_000_000.0 / ticksPerSecond).toLong()
Expand All @@ -112,9 +115,9 @@ internal class LoopRunner(

fpsSamplingCount++

// Update the FPS value every 500 millis
// Update the FPS value based on provided refresh rate
val timeSinceLastFPSUpdateNanos = now - lastFPSUpdateNanos;
if (timeSinceLastFPSUpdateNanos >= 500_000_000) {
if (timeSinceLastFPSUpdateNanos >= fpsRefreshRate.toMillis() * 1_000_000) {
lastFPSUpdateNanos = now
fps = (fpsSamplingCount.toLong() * 1_000_000_000 / timeSinceLastFPSUpdateNanos).toInt()
fpsSamplingCount = 0
Expand Down
10 changes: 10 additions & 0 deletions fxgl/src/main/kotlin/com/almasb/fxgl/app/Settings.kt
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import javafx.beans.property.*
import javafx.scene.input.KeyCode
import javafx.scene.paint.Color
import javafx.stage.StageStyle
import javafx.util.Duration
import java.util.*
import java.util.Collections.unmodifiableList
import kotlin.math.roundToInt
Expand Down Expand Up @@ -269,6 +270,12 @@ class GameSettings(
*/
var ticksPerSecond: Int = -1,

/**
* Rate (time) between each FPS sampling update.
* Default value is 500 millis
*/
var fpsRefreshRate: Duration = Duration.millis(500.0),

/**
* How fast the 3D mouse movements are (example, rotating the camera).
*/
Expand Down Expand Up @@ -402,6 +409,7 @@ class GameSettings(
secondsIn24h,
randomSeed,
ticksPerSecond,
fpsRefreshRate,
userAppClass,
mouseSensitivity,
defaultLanguage,
Expand Down Expand Up @@ -583,6 +591,8 @@ class ReadOnlyGameSettings internal constructor(

val ticksPerSecond: Int,

val fpsRefreshRate: Duration,

val userAppClass: Class<*>,

/**
Expand Down
2 changes: 2 additions & 0 deletions fxgl/src/test/kotlin/com/almasb/fxgl/app/GameSettingsTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import com.almasb.fxgl.core.util.Platform
import com.almasb.fxgl.test.RunWithFX
import javafx.scene.input.KeyCode
import javafx.stage.Stage
import javafx.util.Duration
import org.hamcrest.CoreMatchers.`is`
import org.hamcrest.CoreMatchers.hasItems
import org.hamcrest.MatcherAssert.assertThat
Expand Down Expand Up @@ -87,6 +88,7 @@ class GameSettingsTest {
assertThat(settings.menuKey, `is`(KeyCode.ENTER))
assertThat(settings.credits, hasItems("TestCredit1", "TestCredit2"))
assertThat(settings.applicationMode, `is`(ApplicationMode.RELEASE))
assertThat(settings.fpsRefreshRate, `is`(Duration.millis(500.0)))

assertTrue(settings.isDesktop)
assertFalse(settings.isBrowser)
Expand Down

0 comments on commit d718b88

Please sign in to comment.