packages feed

gloss-game-0.3.0.0: examples/bouncy-slime/Main.hs

-- Very simple example of bouncing and jumping character.

import Data.Maybe
import Graphics.Gloss.Game


-- Constants
-- ---------

width, height :: Float
width  = 600
height = 400

slimeSprite :: Picture
slimeSprite = bmp "Slime.bmp"

slimeBounceSprites :: [Picture]
slimeBounceSprites 
  = [ scale 0.5 0.5 $ bmp "Slime2.bmp"
    , scale 0.5 0.5 $ bmp "Slime3.bmp"
    , scale 0.5 0.5 $ bmp "Slime4.bmp"
    , scale 0.5 0.5 $ bmp "Slime2.bmp"
    ]

platformSprite :: Picture
platformSprite = bmp "Platform.bmp"

gravitationalConstant :: Float
gravitationalConstant = -0.5

slimeWidth, slimeHeight :: Float
(_, (slimeWidth, slimeHeight)) = boundingBox (scale 0.5 0.5 slimeSprite)

platformPos :: Point
platformPos = (-200, -150)

platformWidth, platformHeight :: Float
(_, (platformWidth, platformHeight)) = boundingBox (scale 0.5 0.5 platformSprite)


-- Game world state
-- ----------------

data World 
  = World
    { pressedKeys   :: [Char]
    , slimePos      :: Point
    , slimeVelocity :: Float
    , slimeAnim     :: Animation
    }

initialWorld :: World
initialWorld 
  = World 
    { pressedKeys   = []
    , slimePos      = (-200, 0)
    , slimeVelocity = 0
    , slimeAnim     = noAnimation
    }


-- Game play
-- ---------

main
  = playInScene (InWindow "Bouncy Slime" (round width, round height) (50, 50)) white 30 initialWorld level handle
    [applyMovement, applyVelocity, applyGravity]
  where
    handle _now (EventKey (Char c) Down _ _)              world = world {pressedKeys = c : pressedKeys world}
    handle _now (EventKey (Char c) Up   _ _)              world = world {pressedKeys = filter (/= c) (pressedKeys world)}
    handle _now (EventKey (SpecialKey KeySpace) Down _ _) world = world {slimeVelocity = 10}
    handle _now _event                         world            = world

    applyMovement _ _ world | 'a' `elem` pressedKeys world = world {slimePos = moveX (slimePos world) (-10)}
                            | 'd' `elem` pressedKeys world = world {slimePos = moveX (slimePos world) 10}
                            | otherwise                    = world                
    
    applyVelocity _ _ world
      = world {slimePos = moveY (slimePos world) (slimeVelocity world)}
    
    applyGravity now _ world
      | onTheFloor world
        || onThePlatform world = world { slimeVelocity = slimeVelocity world * (-0.5)
                                       , slimeAnim     = if slimeVelocity world < -5
                                                         then animation slimeBounceSprites 0.15 now
                                                         else noAnimation}
      | otherwise              = world {slimeVelocity = slimeVelocity world + gravitationalConstant}
    
    onTheFloor world = snd (slimePos world) <= (-height / 2) + slimeHeight / 2
    
    onThePlatform world = snd (slimePos world) <= snd platformPos + slimeHeight / 2 + platformHeight / 2
                          && fst (slimePos world) + slimeWidth / 2 > fst platformPos - platformWidth / 2
                          && fst (slimePos world) - slimeWidth / 2 < fst platformPos + platformWidth / 2
    
moveX :: Point -> Float -> Point
moveX (x, y) offset 
  | x + offset > width / 2 - slimeWidth / 2    = (width / 2 - slimeWidth / 2, y)
  | x + offset < (-width / 2) + slimeWidth / 2 = ((-width / 2) + slimeWidth / 2, y)
  | otherwise                                  = (x + offset, y)

moveY :: Point -> Float -> Point
moveY (x, y) offset 
  | y + offset > height / 2 - slimeHeight / 2 
  = (x, height / 2 - slimeHeight / 2)
  | y + offset < (-height / 2) + slimeHeight / 2 
  = (x, (-height / 2) + slimeHeight / 2)
  | y + offset < snd platformPos + slimeHeight / 2 + platformHeight / 2 
    && x + slimeWidth / 2 > fst platformPos - platformWidth / 2
    && x - slimeWidth / 2 < fst platformPos + platformWidth / 2
  = (x, snd platformPos + slimeHeight / 2 + platformHeight / 2)
  | otherwise
  = (x, y + offset)


-- Level design
-- ------------

level :: Scene World
level = scenes
        [ translating slimePos $ animating slimeAnim (scale 0.5 0.5 slimeSprite)
        , picture              $ (translate (fst platformPos) (snd platformPos) (scale 0.5 0.5 platformSprite))
        ]