第一的

在 Haskell 中实现 setTimeout 函数是否存在或需要多少大惊小怪?

的主要思想

setTimeout someFunction 1000 --someFunction will be called in 1000ms = 1s

我是 Haskell 的新手,可能不会使用它;我正在学习 Haskell。

第二

游戏的事件循环 通常需要您
  • 根据规则(通常是物理)修改你的内部游戏对象
  • 更新您的图形

  • 管理时间在这里很重要(因此 setTimeout)以确保恒定的 FPS。

    这样的模式在 Haskell 上看起来如何?

    最佳答案



    JavaScript 的 setTimeout 和其他类似的方法,如 Qt 的 QTimer 通常在单个线程的单个事件循环中工作(不包括 web workers 或 QThread )。使用 Haskell 对这种确切行为进行建模有点困难,尽管并非不可能,因为 GHC 已经提供了(内部) implementation

    如果您不关心实际的单线程行为(这也意味着具有几乎相同超时的两个函数可能同时执行),那么您可以简单地创建一个新线程并延迟其操作:

    doLater :: Int -> IO () -> IO ThreadId
    doLater ms io = forkIO $ threadDelay (ms * 1000) >> io
    

    对于任何进一步的想法,我们实际上需要更多地了解您的特定事件循环。



    非常, 非常 概括,你需要这样的东西:
    mkGame :: World
              -> (Input -> World -> World)
              -> (TimeDiff -> World -> World)
              -> (World -> GraphicalRepresentation)
              -> IO ()
    mkGame initialWorld handleInput handleProgression drawWorld = undefined
    

    请注意,您可能会在其中抛出其他参数,例如每秒世界更新的最大数量。

    我们现在如何对 setTimeout 建模?假设 World 类似于:
    data World = World {
         getWorldData    :: WorldData,
         getCurrentTime  :: TimePoint, -- would get updated by your loop
         getTimeouts     :: Queue TimePoint (World -> World)
    }
    

    其中 Queue 是任何工作优先级队列( pick one, 有很多,或者构建您自己的)。现在您可以简单地使用设置超时
    setTimeout world delay action = world { getTimeouts = timeouts' }
        where timeouts' = insert (getTimeouts world) t action
              t         = delay + getCurrentTime world
    
    -- insert :: Queue p v -> p -> v -> Queue p v
    

    如果您希望能够取消超时,您还需要 Queue 上的一个键,查看 GHC.Event.PSQ 以获得灵感。

    除此之外,您现在可以通过简单地遍历队列并应用所有函数来检查时间是否已经过去并在您的游戏循环中采取相应的行动。

    这基本上是一个非常简单和粗略的基础,您可以用来激发自己的工作。根据您实际想要做什么,您可能想看看 gloss ,它已经实现了一个非常相似的概念,虽然没有超时,但在这种情况下,您仍然可以将超时和总时差添加到您的世界并简单地使用拟合更新函数(TimeDiff -> World -> World 部分)。

    关于haskell - 如何在 Haskell 中编写游戏事件循环(例如 setTimeout)?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/23775046/

    10-11 22:35
    查看更多