Haskell 光泽度:时间变量保持不变
Haskell Gloss: time variable stays constant
我正在尝试旋转 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
三角形(=玩家)存储在 'World' 数据类型中:
模块型号
data World = World {
-- all kinds of World properties --
player :: Picture
}
然后我有一个初始化世界的函数initial
,以及一个函数playerBody
,给定一个旋转值,returns一张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
它目前只是returns player
图片。
现在,在我的 timeHandler 模块中,我想使用时间(在 main
函数中给定 timeHandler)来旋转 player
如下:
timeHandler :: Float -> World -> World
timeHandler time = (\world -> world {player = playerBody time} )
这行不通。我将 time
替换为一个常量值(在 timeHandler 函数中),这确实旋转了图片。所以好像 time
没有更新..我做错了什么?
自然它不起作用,timeHandler
收到一个数字,在实践中,该数字接近自上一帧以来的时间增量 - docs 说:"A function to step the world one iteration. It is passed the period of time (in seconds) needing to be advanced." -并且大概帧时间大约是恒定的,所以自然而然地人们会期望输出大约是恒定的(并且一个数字非常接近 0)。
您需要收集所有增量并将它们相加。如果您只关心自模拟开始以来的时间,那么您不需要 main
中的 getCurrentTime
- 只需添加增量即可。这意味着您必须 存储您所在州的时间。如果你确实需要处理实时,我建议你坚持使用 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
中画图。
我正在尝试旋转 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
三角形(=玩家)存储在 'World' 数据类型中: 模块型号
data World = World {
-- all kinds of World properties --
player :: Picture
}
然后我有一个初始化世界的函数initial
,以及一个函数playerBody
,给定一个旋转值,returns一张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
它目前只是returns player
图片。
现在,在我的 timeHandler 模块中,我想使用时间(在 main
函数中给定 timeHandler)来旋转 player
如下:
timeHandler :: Float -> World -> World
timeHandler time = (\world -> world {player = playerBody time} )
这行不通。我将 time
替换为一个常量值(在 timeHandler 函数中),这确实旋转了图片。所以好像 time
没有更新..我做错了什么?
自然它不起作用,timeHandler
收到一个数字,在实践中,该数字接近自上一帧以来的时间增量 - docs 说:"A function to step the world one iteration. It is passed the period of time (in seconds) needing to be advanced." -并且大概帧时间大约是恒定的,所以自然而然地人们会期望输出大约是恒定的(并且一个数字非常接近 0)。
您需要收集所有增量并将它们相加。如果您只关心自模拟开始以来的时间,那么您不需要 main
中的 getCurrentTime
- 只需添加增量即可。这意味着您必须 存储您所在州的时间。如果你确实需要处理实时,我建议你坚持使用 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
中画图。