I am implementing a simple Simon game using Haskell with Gloss. I wish, at the moment, that, for example, for the first 4 seconds some rectangles will change their color (or simply in other words show some animation), and afterwards allow colors change using specific keyboard keys input.
This is the code, using animate
for an animation:
window :: Display
window = InWindow "Simon" (width, height) (offset, offset)
background :: Color
background = black
data SimonGame = Game {
rectangleGreen::Picture,
rectangleRed::Picture,
rectangleBlue::Picture,
rectangleYellow::Picture
} deriving Show
initialState :: SimonGame
initialState = Game
{ rectangleGreen = translate (-100) (0) $ color green $ rectangleSolid 60 60,
rectangleRed = translate (100) (0) $ color red $ rectangleSolid 60 60,
rectangleBlue = translate (0) (100) $ color blue $ rectangleSolid 60 60,
rectangleYellow = translate (0) (-100) $ color yellow $ rectangleSolid 60 60
}
render :: SimonGame -> Picture
render game = pictures
[ rectangleGreen game,
rectangleRed game,
rectangleBlue game,
rectangleYellow game
]
updateBoard :: Int-> SimonGame -> SimonGame
updateBoard seconds game
| sec_value == 1 = game {
rectangleGreen = translate (-100) (0) $ color white $ rectangleSolid 60 60,
rectangleRed = translate (100) (0) $ color red $ rectangleSolid 60 60,
rectangleBlue = translate (0) (100) $ color blue $ rectangleSolid 60 60,
rectangleYellow = translate (0) (-100) $ color yellow $ rectangleSolid 60 60
}
| sec_value == 2 = game {
rectangleGreen = translate (-100) (0) $ color green $ rectangleSolid 60 60,
rectangleRed = translate (100) (0) $ color white $ rectangleSolid 60 60,
rectangleBlue = translate (0) (100) $ color blue $ rectangleSolid 60 60,
rectangleYellow = translate (0) (-100) $ color yellow $ rectangleSolid 60 60
}
| sec_value == 3 = game {
rectangleGreen = translate (-100) (0) $ color green $ rectangleSolid 60 60,
rectangleRed = translate (100) (0) $ color red $ rectangleSolid 60 60,
rectangleBlue = translate (0) (100) $ color white $ rectangleSolid 60 60,
rectangleYellow = translate (0) (-100) $ color yellow $ rectangleSolid 60 60
}
| sec_value == 0 = game {
rectangleGreen = translate (-100) (0) $ color green $ rectangleSolid 60 60,
rectangleRed = translate (100) (0) $ color red $ rectangleSolid 60 60,
rectangleBlue = translate (0) (100) $ color blue $ rectangleSolid 60 60,
rectangleYellow = translate (0) (-100) $ color white $ rectangleSolid 60 60
}
| otherwise = game
where
sec_value = (seconds `mod` 4)
main :: IO ()
main = animate window background frame
where
frame :: Float -> Picture
frame seconds = render $ updateBoard (ceiling seconds) initialState
I know that using the function play
i can somehow implement a logic, that using the function i implemented handleKeys
, that takes users input and changes the game state.
handleKeys :: Event -> SimonGame -> SimonGame
handleKeys (EventKey (Char 'a') _ _ _) game = game { rectangleGreen = translate (-100) (0) $ color white $ rectangleSolid 60 60 }
handleKeys (EventKey (Char 's') _ _ _) game = game { rectangleRed = translate (100) (0) $ color white $ rectangleSolid 60 60 }
handleKeys (EventKey (Char 'd') _ _ _) game = game { rectangleBlue = translate (0) (100) $ color white $ rectangleSolid 60 60 }
handleKeys (EventKey (Char 'f') _ _ _) game = game { rectangleYellow = translate (0) (-100) $ color white $ rectangleSolid 60 60 }
handleKeys _ game = game
Is there a way to combine the function play
with the function animate
so my program will show a short animation and then wait for input and act accordingly?
Compare the types of animate
and play
(and also simulate
).
docs/Graphics-Gloss.
animate
is a simplified version of play
where you ignore any inputs, and ignore any previous state of the animation. So have your input handler check whether your're in the first 4 seconds or not, and have your step function do the same.