Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Holding down movement keys can cause multiple turns to execute simultaneously #8

Open
nanodeath opened this issue Mar 7, 2021 · 0 comments

Comments

@nanodeath
Copy link

By holding down the WASD keys, as one does to cruise around at _high speeds_💨, you might notice "ConcurrentModificationException" being generated into the stderr in the console. Turns out the reason for this is engine.executeTurn is actually asynchronous, and at least on my machine we might get keyboard events faster than we can actually process them.

I've tweaked the code as follows to ensure that we don't process a keyboard event if the previous turn is still executing.

(Context: just finished tutorial 8)

diff --git a/src/main/kotlin/com/example/cavesofzircon/view/PlayView.kt b/src/main/kotlin/com/example/cavesofzircon/view/PlayView.kt
index 0a08b60..fb9bda0 100644
--- a/src/main/kotlin/com/example/cavesofzircon/view/PlayView.kt
+++ b/src/main/kotlin/com/example/cavesofzircon/view/PlayView.kt
@@ -14,13 +14,11 @@ import org.hexworks.zircon.api.component.ColorTheme
 import org.hexworks.zircon.api.component.ComponentAlignment
 import org.hexworks.zircon.api.game.ProjectionMode
 import org.hexworks.zircon.api.grid.TileGrid
-import org.hexworks.zircon.api.uievent.KeyboardEvent
-import org.hexworks.zircon.api.uievent.KeyboardEventType
-import org.hexworks.zircon.api.uievent.Processed
-import org.hexworks.zircon.api.uievent.UIEventPhase
+import org.hexworks.zircon.api.uievent.*
 import org.hexworks.zircon.api.view.base.BaseView
 import org.hexworks.zircon.internal.Zircon
 import org.hexworks.zircon.internal.game.impl.GameAreaComponentRenderer
+import java.util.concurrent.atomic.AtomicBoolean
 import kotlin.random.Random

 class PlayView(
@@ -61,9 +59,14 @@ class PlayView(
             .build()
             .let { screen.addComponent(it) }

+        val currentlyUpdating = AtomicBoolean(false)
         screen.handleKeyboardEvents(KeyboardEventType.KEY_PRESSED) { event: KeyboardEvent, phase: UIEventPhase ->
-            game.world.update(screen, event, game)
-            Processed
+            if (currentlyUpdating.compareAndSet(false, true)) {
+                game.world.update(screen, event, game).invokeOnCompletion { currentlyUpdating.set(false) }
+                Processed
+            } else {
+                PreventDefault
+            }
         }
     }
 }
diff --git a/src/main/kotlin/com/example/cavesofzircon/world/World.kt b/src/main/kotlin/com/example/cavesofzircon/world/World.kt
index e578d5b..feefcd6 100644
--- a/src/main/kotlin/com/example/cavesofzircon/world/World.kt
+++ b/src/main/kotlin/com/example/cavesofzircon/world/World.kt
@@ -4,6 +4,7 @@ import com.example.cavesofzircon.blocks.GameBlock
 import com.example.cavesofzircon.extensions.AnyGameEntity
 import com.example.cavesofzircon.extensions.GameEntity
 import com.example.cavesofzircon.extensions.position
+import kotlinx.coroutines.Job
 import org.hexworks.amethyst.api.Engine
 import org.hexworks.amethyst.api.entity.Entity
 import org.hexworks.amethyst.api.entity.EntityType
@@ -69,8 +70,8 @@ class World(
             }
     }

-    fun update(screen: Screen, uiEvent: UIEvent, game: Game) {
-        engine.executeTurn(GameContext(
+    fun update(screen: Screen, uiEvent: UIEvent, game: Game): Job {
+        return engine.executeTurn(GameContext(
             world = this,
             screen = screen,
             uiEvent = uiEvent,
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant