5

我得到了一个与该threepenny-gui库一起工作的蛇版本,但我不喜欢我明确地手动调用newEventaddStateUpdate不是完全基于事件定义行为的事实,例如:

(updates, addUpdate) <- liftIO newEvent
managerB <- accumB initialManager updates

on UI.tick timer $ \_ -> addUpdate $ \manager -> manager'

相比:

managerB <- accumB initialManager $
  UI.tick timer $> \manager -> manager'

IIUC 第二个是更惯用的 FRP,因为它定义了实际事件的行为,而不是创建代理事件来代理更新。但是,当我进行此更改时,它会导致以下两个问题之一:

  1. 如果我managerB先定义(使用 RecursiveDo 访问timer,定义如下),则根本没有渲染
  2. 如果我移动managerB到最后(使用 RecursiveDomanagerB从 DOM 元素访问),第一次按下箭头键时的初始移动会滞后,并且帧以生涩的方式呈现。

难道我做错了什么?我应该以什么惯用方式构建这些事件/行为?

此处的代码差异:https ://github.com/brandonchinn178/snake/compare/inline-event-handlers

4

1 回答 1

0

我在您的存储库中的备用分支上测试过的一个不是特别好的解决方法是,可以说同时使用这两种方法:重新触发滴答事件并使用它而不是UI.tick timer定义managerB

  (timeE, fireTime) <- liftIO newEvent
  on UI.tick timer $ \_ -> liftIO (fireTime ())

  let managerUpdateE =
        fmap concatenate . unions $
          [ timeE $> getNextManagerState
          --  Instead of: UI.tick timer $> getNextManagerState
          --  etc.

问题似乎是UI.tick timer直接插入事件网络会以某种方式妨碍 Threepenny 及时发送更新 UI 所需的 JavaScript 调用。使用onwith的间接性fireTime(尤其应该意味着在timeE概念上发生在 之后UI.tick timer)似乎绕过了这个问题。一个不那么侵入性的解决方法是,而不是引入timeE,显式调用flushCallBuffer; 的处理程序UI.tick timer。然而,在我的测试中,这大大减少了抖动,但并没有完全消除它。(有关可能的相关背景信息,另请参见threepenny-gui issue #191。)

至于第一次击键的延迟,似乎可以通过将您的调用移动UI.start timer到 的末尾来消除gui,在managerB您的事件网络的其余部分设置完成之后。

(另外注意,遵循Graphics.UI.Threepenny.Timer文档的建议并-threadedghc-options编译可执行文件中设置可能是个好主意,即使这似乎对您在此处描述的问题没有影响。)

于 2021-10-12T17:58:16.247 回答