エイリアン登場。まだ当り判定がありません。
一度作ったものの書き直しだからというのもあるのですが、思いのほか作業が早い。言語の違いにもっと手こずると思っていただけに、少し予想外でした。「わかりやすいコード」を意識したことで、より抽象的なレベルで考えようと心がけたからなのかも。手続き型言語と関数型言語では、ずいぶん違いがあるように感じたんですが、表現の違いほどには本質は違っていないんでしょうか。
一方で、言語固有の問題で頭を悩ましたり。うまく文字列が表示できない。ネットで情報を探すも見つからず。この部分は行き詰まりを見せている。困った。
以下、コード。
import Graphics.UI.GLUT import Control.Exception import System.Exit import Data.IORef import System.Random type Pos = (GLfloat, GLfloat) type Area = (GLfloat, GLfloat, GLfloat, GLfloat) data Direction = ToLeft | ToRight | ToUp | ToDown data Alien = Alien Pos GLfloat interval = 100 windowWidth = 320::GLsizei windowHeight = 240::GLsizei shapeShip = [(-10, 0), (0, -10), (10, 0), (10, 10), (-10, 10)] shapeAlien = [(-5, -5), (5, -5), (10, 0), (5, 5), (2, 2), (-2, 2), (-5, 5),(-10, 0)] shapeBullet = [(-3, -5), (0, -10), (3, -5), (0, 0)] colorShip = Color3 (0.0::Double) 0.0 1.0 colorAlien = Color3 (1.0::Double) 0.5 0.0 colorScore = Color3 (1.0::Double) 0.0 0.0 initialEnv :: (Area, Pos, [Pos], [Alien], [Pos], Integer, Integer) initialEnv = ( (0, 0, convf windowWidth, convf windowHeight), -- window size (convf $ div windowWidth 2, convf $ div windowHeight 2), -- ship's position [], -- bullets' position [], -- aliens' position [], -- alien's bullets' position 0, -- score 2 -- left ) initialAlien = Alien (0, 20) 5 convf :: (Integral a) => a -> GLfloat convf = fromInteger.toInteger convd :: (Integral a) => a -> GLdouble convd = fromInteger.toInteger includes (x1, y1, x2, y2) (x, y) = (x1 <= x) && (x <= x2) && (y1 <= y) && (y <= y2) display env = do draw env reshape (Size w h) = do viewport $= (Position 0 0, Size w h) loadIdentity ortho (-0.5) ((convd w) - 0.5) ((convd h) - 0.5) (-0.5) (-1.0) (1.0) keyboardMouse env key keystate modifiers position = do case key of SpecialKey KeyLeft -> do { modifyIORef env $ moveShip ToLeft; draw env } SpecialKey KeyRight -> do { modifyIORef env $ moveShip ToRight; draw env } SpecialKey KeyUp -> do { modifyIORef env $ moveShip ToUp; draw env } SpecialKey KeyDown -> do { modifyIORef env $ moveShip ToDown; draw env } Char ' ' -> do (_, _, sbs, _, _, _, _) <- readIORef env if length sbs == 0 then modifyIORef env (? (w, sp, _, as, abs, s, l) -> (w, sp, [sp], as, abs, s, l)) else return () Char 'q' -> throwIO $ ExitException ExitSuccess _ -> return () moveShip direction (win, ship, sbs, as, abs, score, left) = (win, (move direction ship), sbs, as, abs, score, left) where move ToLeft (x, y) = (x - 5.0, y) move ToRight (x, y) = (x + 5.0, y) move ToUp (x, y) = (x, y - 5.0) move ToDown (x, y) = (x, y + 5.0) timer env = do f <- randomRIO (0, 19) seed <- newStdGen fs <- return $ randomRs (0, 19) seed modifyIORef env $ updateEnv f fs draw env addTimerCallback interval $ timer env updateEnv f fs (win, ship, sbs, as, abs, score, left) = (win, ship, moveBullet sbs, addAlien $ updateAlien as, filter (includes win) $ addBullet (updateBullet abs) as fs, score, left) where moveBullet [] = [] moveBullet [pos@(x, y)] = if (includes win pos) then [(x, y - 10)] else [] updateAlien [] = [] updateAlien (a:as) = (updateAlienPos a):(updateAlien as) updateAlienPos (Alien (x, y) dx) = if (includes win (x + dx, y)) then Alien (x + dx, y) dx else Alien (x, y + 10) (-dx) addAlien as = if f == 0 then initialAlien:as else as updateBullet [] = [] updateBullet (b:bs) = (updateBulletPos b):(updateBullet bs) updateBulletPos (x, y) = (x, y + 10) addBullet bs [] _ = bs addBullet bs ((Alien pos _):as) (f:fs) = if f == 0 then pos:(addBullet bs as fs) else addBullet bs as fs draw env = do (_, ship, sbs, as, abs, score, left) <- readIORef env clear [ColorBuffer] drawShip ship mapM_ (drawBullet colorShip) sbs mapM_ drawAlien as mapM_ (drawBullet colorAlien) abs -- drawScore score left swapBuffers drawShip pos = do color colorShip render shapeShip pos drawBullet col pos = do color col render shapeBullet pos drawAlien (Alien pos _) = do color colorAlien render shapeAlien pos drawScore score left = do translate $ Vector3 (10::GLfloat) 10 0 scale (0.1::GLfloat) (-0.1) 0 color colorScore renderString Roman $ "SCORE : " ++ (setw 6 $ show score) ++ " / LEFT : " ++ show left where setw n s = (replicate (n - length s) '0') ++ s render shape (x, y) = renderPrimitive Polygon $ mapM_ vertex $ map makeVertex3 shape where makeVertex3 (dx, dy) = Vertex3 (x + dx) (y + dy) (0.0::GLfloat) main = do env <- newIORef initialEnv getArgsAndInitialize initialDisplayMode $= [RGBAMode, DoubleBuffered] initialWindowPosition $= Position 100 100 initialWindowSize $= Size windowWidth windowHeight createWindow "to write more comprehensible code" clearColor $= Color4 1.0 1.0 1.0 1.0 displayCallback $= display env reshapeCallback $= Just reshape keyboardMouseCallback $= Just (keyboardMouse env) addTimerCallback interval $ timer env mainLoop