Created
November 13, 2013 22:18
-
-
Save amazari/7457521 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module GameSkeleton where | |
import Window | |
import Keyboard | |
import Random | |
{-- Part 1: Model the user input ---------------------------------------------- | |
What information do you need to represent all relevant user input? | |
Task: Redefine `UserInput` to include all of the information you need. | |
Redefine `userInput` to be a signal that correctly models the user | |
input as described by `UserInput`. | |
------------------------------------------------------------------------------} | |
type UserInput = (Int, Int) | |
data Input = Input Float (Int, Int) (Int, Int) | |
direction = foldp (\{x,y} -> \(prevX, prevY) -> let norm = sqrt <| x^2 + y^2 | |
in if norm == sqrt 1 | |
then (x,-y) | |
else (prevX,prevY)) (1,0) Keyboard.arrows | |
{-- Part 2: Model the game ---------------------------------------------------- | |
What information do you need to represent the entire game? | |
Tasks: Redefine `GameState` to represent your particular game. | |
Redefine `defaultGame` to represent your initial game state. | |
For example, if you want to represent many objects that just have a position, | |
your GameState might just be a list of coordinates and your default game might | |
be an empty list (no objects at the start): | |
type GameState = { objects : [(Float,Float)] } | |
defaultGame = { objects = [] } | |
------------------------------------------------------------------------------} | |
{--type SnakeSlice = (Int,Int) | |
type BoardSize = (Int,Int) --} | |
type GameState = {snakeSlices:[(Int,Int)], boardSize:(Int,Int), apple:(Int,Int)} | |
defaultGame : GameState | |
defaultGame = {snakeSlices = [(0, 0),(1, 0), (1, 1)], | |
boardSize = (8, 8), | |
apple = (4, 5) | |
} | |
{-- Part 3: Update the game --------------------------------------------------- | |
How does the game step from one state to another based on user input? | |
Task: redefine `stepGame` to use the UserInput and GameState | |
you defined in parts 1 and 2. Maybe use some helper functions | |
to break up the work, stepping smaller parts of the game. | |
------------------------------------------------------------------------------} | |
collidesWith (x1, y1) (x2, y2) = x1 == x2 && y1 == y2 | |
tileAhead (hX, hY) (dirX, dirY) (bW, bH) = ((hX + dirX) `mod` bW, (hY + dirY) `mod` bH) | |
randomAppleX = Random.range 0 7 direction | |
randomAppleY = Random.range 0 7 direction | |
randomApple = lift2 (\x -> \y -> (x, y)) randomAppleX randomAppleY | |
stepGame : Input -> GameState -> GameState | |
stepGame (Input delta dir randomApple) {snakeSlices,boardSize,apple} = | |
let | |
(hX ,hY) = head snakeSlices | |
newHead = tileAhead (hX, hY) dir boardSize | |
ateApple = newHead `collidesWith` apple | |
-- any (\(x, y) -> x ==)snakeSlices | |
fedHead = if ateApple then [tileAhead newHead dir boardSize] else [] | |
in | |
{snakeSlices = fedHead ++ newHead :: take ((length snakeSlices) - 1) snakeSlices | |
,boardSize = boardSize | |
,apple = if ateApple then randomApple else apple | |
} | |
{-- Part 4: Display the game -------------------------------------------------- | |
How should the GameState be displayed to the user? | |
Task: redefine `display` to use the GameState you defined in part 2. | |
------------------------------------------------------------------------------} | |
tileSize = 25 | |
translatedPos: (Int,Int) -> (Float, Float) -> (Float, Float) | |
translatedPos (tileX,tileY) (oX, oY) = (toFloat tileX * tileSize + oX, (toFloat -tileY) * tileSize + oY) | |
tile: Color -> (Int,Int) -> (Float, Float) -> Form | |
tile color tilePos origin = | |
square (toFloat tileSize) | |
|> filled color | |
|> (move <| translatedPos tilePos origin) | |
display : (Int,Int) -> GameState -> Element | |
display (w,h) {snakeSlices,boardSize,apple} = | |
let (bw,bh) = boardSize | |
(realW, realH) = (bw*tileSize, bh*tileSize) | |
origin = (-((toFloat realW) - tileSize) / 2, (((toFloat realH) - tileSize)) / 2) | |
snakeTiles = map (\t -> tile red t origin) snakeSlices | |
boardRep = rect (toFloat realW) (toFloat realH) |> filled green | |
appleTile = tile yellow apple origin | |
in container w h middle <| collage realW realH <| boardRep :: appleTile :: snakeTiles | |
{-- That's all folks! --------------------------------------------------------- | |
The following code puts it all together and shows it on screen. | |
------------------------------------------------------------------------------} | |
delta = fps 10 | |
input = sampleOn delta (lift3 Input delta direction randomApple) | |
gameState = foldp stepGame defaultGame input | |
main = lift2 display Window.dimensions gameState |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment