From b74d49ffe3fa6182f70c3a3662d17eb4a2812418 Mon Sep 17 00:00:00 2001 From: Siyuan Chen Date: Thu, 7 Mar 2024 18:50:04 +0800 Subject: [PATCH] Fixed the issue where the game would freeze when the mouse moving over the window. Phenomenon: After executing spaceInvaders.exe, If you moving the mouse over the window, the game freezes! Root cause: When Yampa's sensing action takes window input, if the input is a `HGL.MouseMove` event, it calls `mmFilter` to consume all subsequent "redundant" `HGL.MouseMove` events. If there are several hundred `HGL.MouseMove` events, `mmFilter` will be recursively called several hundreds of times. The`mmFilter` further calls `gwi win` to take events, and `gwi win` calls `HGL.getWindowTick win` to yield the time slices to ensure that the thread acturally receiving WM events gets a chance to work. This leads to a problem: Since `HGL.getWindowTick win` is a blocking operation (i.e. waiting for a tickRate time), if there are 100 subsequent `HGL.MouseMove`, it will wait for "100 x tickRate time", which is unacceptable. Moreover, during this waiting period, there might be further mouse move events generated! This patch fixed the issue by placing `HGL.getWindowTick win` at the beginning of a frame, i.e. at the entry point of `getTimeInput`, rather than inside `gwi win`. Related issue: https://github.com/ivanperez-keera/SpaceInvaders/issues/44 --- src/Animate.hs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/Animate.hs b/src/Animate.hs index f08b04c..9f64691 100644 --- a/src/Animate.hs +++ b/src/Animate.hs @@ -120,6 +120,13 @@ mkInitAndGetTimeInput win = do -- Next delta time and input let getTimeInput _ = do + -- Seems as if we either have to yield or wait for a tick in order + -- to ensure that the thread receiving events gets a chance to + -- work. For some reason, yielding seems to result in window close + -- events getting through, wheras waiting often means they don't. + -- Maybe the process typically dies before the waiting time is up in + -- the latter case? + HGL.getWindowTick win -- Get time tp <- readIORef tpRef t <- getElapsedTime `repeatUntil` (/= tp) -- Wrap around possible! @@ -178,15 +185,7 @@ getWinInput win weBufRef = do Just (HGL.MouseMove {}) -> mmFilter mwe' Just _ -> writeIORef weBufRef mwe' >> return jmme - - -- Seems as if we either have to yield or wait for a tick in order - -- to ensure that the thread receiving events gets a chance to - -- work. For some reason, yielding seems to result in window close - -- events getting through, wheras waiting often means they don't. - -- Maybe the process typically dies before the waiting time is up in - -- the latter case? gwi win = do - HGL.getWindowTick win mwe <- HGL.maybeGetWindowEvent win return mwe