さて、ここで私がやるだろう何のラフスケッチです:それは私が前に使用されてきたものだから
明らか
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
私は、getTicks
のために純粋にここにSDLを使用しています。現在の時刻を取得するために他の関数に置き換えても構いません。
runFrames
の最初の引数は、名前が示すとおり、ヘルツ単位のフレームレート、つまり1秒あたりのフレーム数です。 runFrames
関数は、最初に各フレームを描画するアクションに変換し、次にアクションを実行する前後の時間をチェックし、フレーム時間が経過するまでスリープします(addDelay
)。
私のコードは、一般的に、イベント用にSDLをポーリングし、バックグラウンド処理を行い、次の反復にデータを渡すなど、他の処理を行う複雑なループがあるため、これとは少し違って見えます。& c。しかし基本的な考え方は同じです。
明らかに、このアプローチの良い点は、かなり単純ですが、目標速度を明確に指定することで、可能な限り一貫したフレームレートを得ることです。
画面を消去すると、ちらつきが発生します。 haskellのためのアスキー・フラクタル・ゾーマーがあります。それを確認してください。 –