Search code examples
haskellgloss

Gloss function `animate` doesnt seem to be doing anything


I am tying to create a simple animation using haskell gloss. I want that at the first 4 seconds, every rectangle will change its color to a darker one. The problem is that after a relatively long time of linking, nothing really happens -

enter image description here

All rectangles appear and they don't change color

This is the following code i used -

window :: Display
window = InWindow "Simon" (width, height) (offset, offset)

background :: Color
background = black

data SimonGame = Game {
    rectangleGreen::Picture, 
    rectangleRed::Picture,
    rectangleBlue::Picture,
    rectanglYellow::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,
    rectanglYellow = translate (0) (-100)  $  color yellow $ rectangleSolid 60 60
  }

render :: SimonGame -> Picture 
render game = pictures
              [ rectangleGreen game,
                rectangleRed game,
                rectangleBlue game,
                rectanglYellow game
              ]

updateBoard :: Float-> SimonGame -> SimonGame 
updateBoard 1.0 game = game { 
                              rectangleGreen = translate (-100) (0) $ color (dark green)  $ rectangleSolid 60 60,
                              rectangleRed = translate (100) (0) $ color red $ rectangleSolid 60 60,
                              rectangleBlue = translate (0) (100)  $  color blue $ rectangleSolid 60 60,
                              rectanglYellow = translate (0) (-100)  $  color yellow $ rectangleSolid 60 60
                            }
updateBoard 2.0 game = game { 
                              rectangleGreen = translate (-100) (0) $ color green $ rectangleSolid 60 60,
                              rectangleRed = translate (100) (0) $ color (dark red) $ rectangleSolid 60 60,
                              rectangleBlue = translate (0) (100)  $  color blue $rectangleSolid 60 60,
                              rectanglYellow = translate (0) (-100)  $  color yellow $rectangleSolid 60 60
                            }                         
updateBoard 3.0 game = game {
                              rectangleGreen = translate (-100) (0) $ color green $ rectangleSolid 60 60,
                              rectangleRed = translate (100) (0) $ color red $ rectangleSolid 60 60,
                              rectangleBlue = translate (0) (100)  $  color (dark blue) $rectangleSolid 60 60,
                              rectanglYellow = translate (0) (-100)  $  color yellow $rectangleSolid 60 60
                            }
updateBoard 4.0 game = 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,
                              rectanglYellow = translate (0) (-100)  $  color (dark yellow) $rectangleSolid 60 60
                            }
updateBoard _ game = game

main :: IO ()
main = animate window background frame
  where
    frame :: Float -> Picture
    frame seconds = render $ updateBoard seconds initialState

Solution

  • Never equality-check on floating point numbers. (Or, if you do, always assume the result may be False even if the numbers are conceptually equal.)

    In your case, that's not even conceptually the case, because animate is called on some finite points in time; why would these include any exact integral number of seconds?

    One simple way to get around this is to look up the rounded-to-whole-seconds time.

    updateBoard :: Int -> SimonGame -> SimonGame 
    updateBoard 1 game = game { ... }
    updateBoard 2 game = game { ... }
    ...
    
    main = animate window background frame
      where
        frame :: Float -> Picture
        frame seconds = render $ updateBoard (floor seconds) initialState