嗯,這裏是什麼,我會做一個草圖:
import Graphics.UI.SDL.Time (getTicks)
import Control.Concurrent (threadDelay)
type Frame = [[Char]]
type Animation = [Frame]
displayFrame :: Frame -> IO()
displayFrame = mapM_ putStrLn
timeAction :: IO() -> IO Integer
timeAction act = do t <- getTicks
act
t' <- getTicks
return (fromIntegral $ t' - t)
addDelay :: Integer -> IO() -> IO()
addDelay hz act = do dt <- timeAction act
let delay = calcDelay dt hz
threadDelay $ fromInteger delay
calcDelay dt hz = max (frame_usec - dt_usec) 0
where frame_usec = 1000000 `div` hz
dt_usec = dt * 1000
runFrames :: Integer -> Animation -> IO()
runFrames hz frs = mapM_ (addDelay hz . displayFrame) frs
很顯然,我使用SDL這裏純粹是爲了getTicks
,因爲這是我以前使用過。隨意將其替換爲任何其他功能以獲取當前時間。
runFrames
的第一個參數是 - 顧名思義 - 以赫茲爲單位的幀速率,即每秒幀數。 runFrames
函數首先將每個幀轉換爲一個動作,然後將其分配給addDelay
函數,該函數檢查運行動作之前和之後的時間,然後睡眠直至幀時間已過。
我自己的代碼看起來會有點不同,因爲我通常會有一個更復雜的循環來做其他的事情,比如輪詢SDL事件,做後臺處理,將數據傳遞給下一次迭代,& C。但基本的想法是一樣的。
很顯然,這種方法的好處在於,儘管仍然非常簡單,但在可能的情況下,您可以獲得一致的幀速率,並具有指定目標速度的明確方法。
如果你清除屏幕,它會閃爍。 haskell有一個ascii分形縮放,請檢查它。 –