haskanoid-0.1.2: src/Levels.hs
-- | Level definition
--
-- This module includes the definition of the levels.
--
-- Each level has:
--
-- - Logical properties (defined in 'blockPosS').
--
-- - Multimedia properties (a background and audio file).
--
-- Together they form 'levels'.
module Levels where
import Control.Arrow((***))
import Physics.TwoDimensions.Dimensions
import Constants
import Resources
-- * Levels
-- ** Level specification
data LevelSpec = LevelSpec
{ blockPoss :: [Pos2D] -- ^ Block positions
, levelBg :: ImageResource -- ^ Background image
, levelMusic :: MusicResource -- ^ Background music
}
-- * Concrete levels
levels :: [LevelSpec]
levels = [ -- Level 0
LevelSpec { blockPoss = blockPosS 0
, levelBg = Resource "data/level1.png"
, levelMusic = Resource "data/level0.mp3"
}
,
-- Level 1
LevelSpec { blockPoss = blockPosS 1
, levelBg = Resource "data/level1.png"
, levelMusic = Resource "data/level1.mp3"
}
,
-- Level 2
LevelSpec { blockPoss = blockPosS 2
, levelBg = Resource "data/level2.png"
, levelMusic = Resource "data/level2.mp3"
}
]
-- | Level block specification (positions)
-- Level 0
-- %%%%%%%%
-- % XXXXXXXX
-- % XXXXXXXX
-- % XXXXXXXX
-- % XXXXXXXX
blockPosS :: Int -> [Pos2D]
blockPosS 0 = map (adjustHPos *** adjustVPos) allBlocks
where allBlocks :: (Enum a, Num a) => [(a,a)]
allBlocks = [(x,y) | x <- [0..blockColumns-1], y <- [0..blockRows-1]]
adjustHPos :: Double -> Double
adjustHPos = (leftMargin +) . ((blockWidth + blockSeparation) *)
adjustVPos :: Double -> Double
adjustVPos = (topMargin +) . ((blockHeight + blockSeparation) *)
blockRows :: Num a => a
blockRows = 4
-- Fit as many as possible
blockColumns :: Num a => a
blockColumns =
1 + round' ((gameWidth - blockWidth - 2 * leftMargin) / (blockWidth + blockSeparation))
where round' = fromIntegral . floor
leftMargin :: Num a => a
leftMargin = 25
topMargin :: Num a => a
topMargin = 10
-- Level 1
-- %%%%%%%%
-- % XXXX
-- % XXXXX
-- % XXXXXX
-- % XXXXXX
-- % XXXXX
-- % XXXX
--
blockPosS 1 = map (adjustHPos *** adjustVPos) allBlocks
where
allBlocks :: (Enum a, Num a, Eq a, Ord a) => [(a,a)]
allBlocks = [ (x,y) | x <- [0..7], y <- [0..5]
, (x + y > 2) && (x + y < 10)
]
adjustHPos :: Double -> Double
adjustHPos = (leftMargin +) . ((blockWidth + blockSeparation) *)
adjustVPos :: Double -> Double
adjustVPos = ((blockHeight + blockSeparation) *)
leftMargin :: Num a => a
leftMargin = 20
-- Level 2
-- %%%%%%
-- % XXXXX
-- % X XXXX
-- % XX XXX
blockPosS 2 = map (adjustHPos *** adjustVPos) allBlocks
where
allBlocks :: (Enum a, Num a, Eq a) => [(a,a)]
allBlocks = [(x,y) | x <- [0..5], y <- [0..2], x /= y]
adjustHPos :: Double -> Double
adjustHPos = (blockWidth *)
adjustVPos :: Double -> Double
adjustVPos = (100 +) . (blockHeight *)
blockPosS _ = error "No more levels"
-- * Testing constants
--
-- These constans are used by the game, and can be mofidied on order to test
-- different levels.
--
-- TODO: should this be moved to the module Constants?
-- | Initial level. Change this in the code to start
-- from a different level.
initialLevel :: Int
initialLevel = 0
-- | Number of levels. Change this in the code to finish
-- in a different level.
numLevels :: Int
numLevels = length levels