1

我正在尝试在 Haskell 中旋转图片,使用当前时间作为旋转函数的值。我有以下main功能:

main :: IO ()
main = do
    args <- getArgs
    time <- round <$> getPOSIXTime
    let initial'        = initial time
    let (w, h, display) = chooseDisplay args
    let background      = black
    let fps             = 60
    play display background fps initial' (draw w h) eventHandler timeHandler

三角形(=玩家)存储在“世界”数据类型中:模块模型其中

data World = World {
        -- all kinds of World properties --
        player           :: Picture
    }

然后我有一个initial初始化世界的函数,以及一个playerBody给定旋转值的函数,它返回一张图片player

initial :: Int -> World
initial _ = World{player = playerBody 0}

playerBody :: Float -> Picture
playerBody rot = Rotate rot $ color red $ Polygon[(-10, 100), (10, 100), (0, 125)]

绘制函数定义如下:

draw :: Float -> Float -> World -> Picture
draw _ _ world = player world

它目前只是返回player图片。

现在,在我的 timeHandler 模块中,我想使用时间(在main函数中给定 timeHandler)旋转player如下:

timeHandler :: Float -> World -> World
timeHandler time = (\world -> world {player = playerBody time} )

这行不通。我time用一个常量值替换(在 timeHandler 函数中),并且确实旋转了图片。所以似乎time没有更新..我做错了什么?

4

1 回答 1

3

自然它不起作用,timeHandler收到一个数字,实际上,该数字接近自上一帧以来的时间增量 -文档说:“一个让世界进行一次迭代的函数。它通过了一段时间(以秒为单位) ) 需要推进。” - 并且可能帧时间大约是恒定的,所以自然会期望输出大约是恒定的(并且一个非常接近于 0 的数字)。

您需要收集所有增量并将它们相加。getCurrentTime如果您只关心模拟开始以来的时间,那么您不需要main- 只需添加增量。这意味着您必须将时间存储在您的状态中。如果您确实需要处理实时,我建议您坚持使用UTCTime或其他抽象来明确您正在处理的数量:

import Graphics.Gloss 
import Graphics.Gloss.Interface.Pure.Game
import Data.Time.Clock

data World = World 
  { startTime 
  , time :: UTCTime 
  } 

-- make explicit what units are being used
seconds2DiffTime :: Float -> NominalDiffTime
seconds2DiffTime = realToFrac 
diffTime2seconds :: NominalDiffTime -> Float 
diffTime2seconds = realToFrac 

displayWorld World{time,startTime} = 
  Rotate rot $ color red $ Polygon[(-10, 100), (10, 100), (0, 125)]
    where rot = diffTime2seconds $ diffUTCTime time startTime 

updateWorld dt w = w {time = addUTCTime (seconds2DiffTime dt) $ time w}

main = do 
  t0 <- getCurrentTime
  let initialState = World { time = t0, startTime = t0 }
  play (InWindow "" (400,400) (400,400)) 
       white
       30 
       intialState 
       displayWorld 
       (const id) 
       updateWorld

这会为您提供自模拟开始以来经过的时间以及实际时钟时间。

请注意,您不应该在其中放置图片绘制代码timeHandler- 此函数的调用频率可能比重绘图片所需的频率高得多,从而导致大量额外工作。displayWorld而是按照上面的方法进行绘图。

于 2016-10-22T19:37:34.813 回答