packages feed

fay-0.24.2.0: examples/CodeWorldMain.hs

-- By Chris Smith

{-# LANGUAGE NoImplicitPrelude #-}

module MyDrawing where

import Prelude
import FFI
import CodeWorld

main = playInCanvas initial step event draw

data World = World {
    stars     :: [(Double, Double, Double)],
    asts      :: [(Point, Vector)],
    ship      :: (Point, Vector),
    direction :: Double,
    left      :: Double,
    right     :: Double,
    thrust    :: Double,
    energy    :: Double,
    score     :: Double,
    lastScore :: Double,
    maxScore  :: Double,
    savedGen  :: StdGen
    }

initial g = initialWith 0 0 g

initialWith m l g0 =
  case splitR g0 of
    (genStars, g1) -> case splitR g1 of
      (genAsts,  g2) ->
        World {
            stars     = take 40 (makeStars genStars),
            asts      = take 20 (makeAsts  genAsts),
            ship      = ((0,0), (0,0)),
            direction = 0,
            left      = 0,
            right     = 0,
            thrust    = 0,
            energy    = 1,
            score     = 0,
            maxScore  = m,
            lastScore = l,
            savedGen  = g2
            }

makeStars g0 = case randomR (-250, 250) g0 of
  (x, g1) -> case randomR (-250, 250) g1 of
    (y, g2) -> case randomR (   1,   3) g2 of
      (r, g3) -> (x,y,r) : makeStars g3

makeAsts  g0 = case randomR (-250, 250) g0 of
  (x,  g1) -> case randomR (-250, 250) g1 of
    (y,  g2) -> case randomR ( -30,  30) g2 of
      (vx, g3) -> case randomR ( -30,  30) g3 of
        (vy, g4) -> ((x,y), (vx, vy)) : makeAsts g4

effective w x | energy w > 0 = x w
              | otherwise    = 0

lost w = any (collision (ship w)) (asts w)
    where collision ((x1,y1),_) ((x2,y2),_) = (((x2-x1)^2::Double) + ((y2-y1)^2::Double)) < 1764

step dt w = if lost w
    then initialWith (maxScore w) (if score w < 1 then lastScore w else score w) (savedGen w)
    else w {
        asts      = map (stepBody dt) (asts w),
        ship      = stepThrust dt (stepBody dt (ship w)) (effective w thrust) (direction w),
        direction = stepDir    dt (direction w) (left w) (right w),
        energy    = fence 0 1 (energy w + dt * (0.5 * (1 - thrust w) - 1.0 * thrust w)),
        score     = score w + dt,
        maxScore  = max (maxScore w) (score w)
        }

fence lo hi v = max 0 (min hi v)

stepThrust dt ((x,y), (sx,sy)) th dir = ((x,y), (sx', sy'))
    where sx' = sx + th * (-30) * sin (dir * pi / 180) * dt
          sy' = sy + th *   30  * cos (dir * pi / 180) * dt

stepDir dt dir l r = dir + l * 90 * dt - r * 90 * dt

stepBody dt ((x,y),(sx,sy)) = ((wrap (x + sx * dt), wrap (y + sy * dt)), (sx, sy))
  where wrap k | k <= (-300) = k + 600
               | k >=   300  = k - 600
               | otherwise   = k

draw w = pictures [
    rectangleSolid 500 500,
    drawStars (stars w),
    drawAsts (asts w),
    drawShip (ship w) (direction w) (effective w thrust),
    drawEnergyBar (energy w),
    drawScoreBar (score w) (lastScore w) (maxScore w)
    ]

drawStars ss = pictures [
    color (gray 0.5) (translate x y (circleSolid r ))
        | (x,y,r)   <- ss
    ]

drawAsts  as = pictures [
    color (light red) (translate x y (circleSolid 30))
        | ((x,y),_) <- as
    ]

drawShip ((x,y),_) dir th = translate x y (rotate dir (pictures [
    color (gray 0.2) (circle 12),
    color cyan   (polygon [(-9, -8), (9, -8), ( 0, 12) ]),
    if th > 0 then color orange (polygon [( -8, -8), (-10, -11), (10, -11), (8, -8)])
              else blank
    ]))

drawEnergyBar e = color yellow $ translate 0 (-230) $ rectangleSolid (400 * e) 15

drawScoreBar s l m = pictures [
  color blue $ translate 0 230 $ rectangleSolid 500 15,
  color white $ translate (-200) 225 $ scale 0.2 0.15 $ text $ "Score: " ++ fmtScore s,
  color white $ translate ( -25) 225 $ scale 0.2 0.15 $ text $ "Last: " ++ fmtScore l,
  color white $ translate ( 150) 225 $ scale 0.2 0.15 $ text $ "Max: " ++ fmtScore m
  ]

fmtScore :: Double -> String
fmtScore s = show (floor (10 * s))

event (KeyPressEvent   "Up")    w = w { thrust = 1 }
event (KeyReleaseEvent "Up")    w = w { thrust = 0 }
event (KeyPressEvent   "Left")  w = w { left   = 1 }
event (KeyReleaseEvent "Left")  w = w { left   = 0 }
event (KeyPressEvent   "Right") w = w { right  = 1 }
event (KeyReleaseEvent "Right") w = w { right  = 0 }
event _                         w = w