0

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?

Alex Goft
  • 1,114
  • 1
  • 11
  • 23
  • 3
    I seem to recall having made a comment about _repetitive code_... please factor out all that `translate` stuff so the code isn't bloated with needless, maintenance- and reading unfriendly repetition! – leftaroundabout Oct 29 '17 at 14:03
  • 2
    You do not 'combine' `play` and `animate` in any sense - you always use one or the other. You can recover the absolute time since starting the program from a sequence of time deltas by storing the absolute time in the game state (this is a typical solution to this problem.. I'm sure there's a duplicate somewhere). – user2407038 Oct 29 '17 at 18:57

1 Answers1

1

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.

ja.
  • 4,245
  • 20
  • 22