2011-09-16 3 views
6

私は、Haskellを使用して生成されたいくつかのデータの非常に迅速で汚れたアニメーション表示を取得しようとしています。試してみると最も簡単なことはASCIIアートであると言えます。すなわち、Haskellからのasciiアニメーションを出力しますか?

type Frame = [[Char]]  -- each frame is given as an array of characters 

type Animation = [Frame] 

display :: Animation -> IO() 
display = ?? 

どのようにすればよいでしょうか?

フレーム間のポーズを最小限に抑える方法はわかりませんが、残りの部分はputStrLnとパッケージのclearScreenと一緒にthis answerで見つけられます。

+0

画面を消去すると、ちらつきが発生します。 haskellのためのアスキー・フラクタル・ゾーマーがあります。それを確認してください。 –

答えて

5

さて、ここで私がやるだろう何のラフスケッチです:それは私が前に使用されてきたものだから

明らか
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。しかし基本的な考え方は同じです。

明らかに、このアプローチの良い点は、かなり単純ですが、目標速度を明確に指定することで、可能な限り一貫したフレームレートを得ることです。

+0

ありがとう!最後に、私は本質的にこれを使用しましたが、追加パッケージをダウンロードする手間を避けるために、 'System.Time'の' getClockTime'で 'getTicks'を置き換えました。 (ハスケルは怠惰な言語ですよね?): – PLL

2

これは、うまく動作しますが、長期的には安定していないC. A McCannのanwerをベースにしています。特に、フレームレートがティックレートの整数分の1でない場合です。

import GHC.Word (Word32) 

-- import CAMcCann'sAnswer (Frame, Animation, displayFrame, getTicks, threadDelay) 

atTick :: IO() -> Word32 -> IO() 
act `atTick` t = do 
    t' <- getTicks 
    let delay = max (1000 * (t-t')) 0 
    threadDelay $ fromIntegral delay 
    act 

runFrames :: Integer -> Animation -> IO() 
runFrames fRate frs = do 
    t0 <- getTicks 
    mapM_ (\(t,f) -> displayFrame f `atTick` t) $ timecode fRate32 t0 frs 
    where timecode ν t0 = zip [ t0 + (1000 * i) `div` ν | i <- [0..] ] 
     fRate32 = fromIntegral fRate :: Word32 
+0

ああ、素敵!私の実際のコードの大部分では、時差に基づいてパラメトリックアニメーションが作成されていたため、正確なフレームレートについてあまり心配する必要はありませんでした。そのため、私はこのようなトップクラスの私の頭。しかし、間違いなく離散的なフレームのために行く方法。 –

関連する問題