ボールがうじゃうじゃ

ボールうじゃ

画面内をボールが動き回るだけの、よくあるプログラムです。

module Main where

import Graphics.HGL

-- スクリーン情報
width::Int
width  = 320
height::Int
height = 240
widthF::Float
widthF  = 320.0
heightF::Float
heightF = 240.0

-- ボールオブジェクト
data BallObj = BallObj {
    x, y   :: Float,
    dx, dy :: Float
}

-- ボールから座標を取得
toPos::BallObj -> Point
toPos ball = (round $ x ball, round $ y ball)

-- 色定義
color = RGB 255 255 0

-- 描画関数を返す
drawball:: Point -> Graphic
drawball (x,y) =
    do withRGB color $ ellipse (x-10, y-10) (x+10, y+10)

-- 描画
draw::[BallObj] -> Graphic
draw balls =
    do mapM_ drawball $ map toPos balls

-- 移動
moveBall:: BallObj -> BallObj
moveBall ball =
    BallObj {
        x  = (x ball) + (dx ball),
        y  = (y ball) + (dy ball),
        dx = (dx ball),
        dy = (dy ball) }

-- 状態の更新
updateState::[BallObj] -> [BallObj]
updateState balls = (map boundBall (map moveBall balls))

-- 初速
speed0 = 0.5
-- ボール達
balls= [
    BallObj{dx=  speed0*4, dy=  speed0,   x=0,      y=0},
    BallObj{dx= -speed0,   dy=  speed0*4, x=widthF, y=0},
    BallObj{dx= -speed0*2, dy= -speed0*3, x=widthF, y=heightF},
    BallObj{dx=  speed0*3, dy= -speed0*2, x=0,      y=heightF} ]

-- 跳ね返り
boundBall::BallObj -> BallObj
boundBall ball =
    let
        px = x ball
        py = y ball
        vx = if px < -3 || px > widthF+3
                then -(dx ball) -- 反転
                else dx ball
        vy = if py < -3 || py > heightF+3
                then -(dy ball) -- 反転
                else dy ball
    in
        BallObj {
            x  = px,
            y  = py,
            dx = vx,
            dy = vy }

-- ゲームループ
-- ウィドウ -> ボールオブジェクト
loopGame::Window -> [BallObj] -> IO()
loopGame w balls =
    do e <- maybeGetWindowEvent w
       -- イベント処理
       case e of
        Just(Char {char=c}) ->
            -- ESCキー
            if c == '\ESC'
                then closeWindow w
                else loopGame w balls
        Nothing -> do
            -- 描画処理
            setGraphic w $ do
                draw balls
            getWindowTick w
            loopGame w (updateState balls)
        _ -> loopGame w balls

-- エントリポイント
main::IO()
main = runGraphics $ do
    w <- openWindowEx "test" Nothing (width, height) DoubleBuffered (Just 33)
    -- ループ開始
    loopGame w balls