content: {-# LANGUAGE TemplateHaskell, NoMonomorphismRestriction #-}
  {-# OPTIONS_GHC -fno-full-laziness -fno-cse #-}
  import ActionKid
  import ActionKid.Utils
  import Control.Lens
  import Control.Monad.State
  
  -- This is an example of how to use ActionKid to make games with Haskell.
  -- ActionKid is inspired by Actionscript, so you will see some
  -- similarities.
  --
  -- Every video game has some objects on the screen that interact with each
  -- other. For example, in a game of Mario, you will have Mario himself,
  -- goombas, mushrooms, pipes etc. These objects are called "movie clip"s in
  -- ActionKid terminology. Any data type that is an instance of the
  -- MovieClip class can be used in your game.
  
  -- So first, make a data type for every object you will have in your game.
  -- In this demo game, we just have a player that will move around.
  --
  -- Every constructor must have `Attributes` as it's last field.
  data Player = Player { _pa :: Attributes }
  
  -- Ok, you have a Player type. Now before you can use it in your game,
  -- make it an instance of MovieClip. You can do this automatically with
  -- `deriveMC`:
  deriveMC ''Player
  
  -- Now that the player is a MovieClip, you can write code like this:
  --
  -- > player.x += 10
  --
  -- and the player will move 10 pixels to the right!
  -- More on this later.
  
  -- You also need a data type that will be the game state.
  data GameState = GameState {
                      _player :: Player,
                      _ga :: Attributes
  }
  
  -- Use this convenience function to make MovieClip instances
  -- for your data types automatically.
  deriveMC ''GameState
  
  -- Next, I suggest you make lenses for all of your data types.
  -- If you don't know how lenses work, check out the intro README here:
  -- https://github.com/ekmett/lens
  --
  -- and this tutorial:
  -- https://www.fpcomplete.com/school/to-infinity-and-beyond/pick-of-the-week/basic-lensing
  --
  -- Lenses are great for working with nested data structures, and writing
  -- functional code that looks imperative. Both are big plusses for game
  -- development.
  -- So this step is optional, but recommended.
  makeLenses ''Player
  makeLenses ''GameState
  
  -- Finally, you need to make both Player and GameState
  -- instances of Renderable. This defines how they will be shown on the
  -- screen.
  --
  -- The `render` function returns a Gloss Picture:
  --
  -- http://hackage.haskell.org/package/gloss-1.8.2.2/docs/Graphics-Gloss-Data-Picture.html
  
  instance Renderable Player where
      render p = color blue $ box 50 50
  
  -- Here we are just rendering the player as a blue box. With ActionKid,
  -- you can also use an image from your computer instead:
  --
  -- > render p = image "images/player.png"
  
  -- To render the game state, we just render the player.
  -- To do that, use the `display` function. `display` will render
  -- the player at the right x and y coordinates.
  instance Renderable GameState where
      render gs = display (_player gs)
  
  -- If the game state has multiple items, you can render them all by
  -- concatenating them:
  --
  -- > render gs = display (_player1 gs) <> display (_player2 gs)
  
  -- this is the default game state. The player starts at coordinates (0,0)
  -- (the bottom left of the screen).
  -- NOTE: For the `Attributes` field, you can just use `def`. This will set
  -- the correct default attributes for an object.
  --
  -- So this creates the game state with a player in it. Both have default
  -- attributes.
  gameState = (GameState (Player def) def)
  
  -- All of the core game logic takes place in this monad transformer stack.
  -- The State is the default game state we just made.
  type GameMonad a = StateT GameState IO a
  
  --------------------------------------------------------------------------
  --------------------------------------------------------------------------
  -- Ok, now we are done specifying all the data types and how they should
  -- look! Now it's time to implement the core game logic. There are two
  -- functions you need to define:
  --
  -- 1. An event handler (for key presses/mouse clicks)
  -- 2. A game loop.
  --
  -- The event handler listens for user input, and moves the player etc.
  -- The game loop is where the rest of the logic happens: firing bullets,
  -- hitting an enemy, animations etc etc.
  --------------------------------------------------------------------------
  --------------------------------------------------------------------------
  
  -- This is the event handler. Since we are using lenses, this logic is
  -- really easy to write.
  eventHandler :: Event -> GameMonad ()
  eventHandler (EventKey (SpecialKey KeyLeft) Down _ _) = player.x -= 10
  eventHandler (EventKey (SpecialKey KeyRight) Down _ _) = player.x += 10
  eventHandler (EventKey (SpecialKey KeyUp) Down _ _) = player.y += 10
  eventHandler (EventKey (SpecialKey KeyDown) Down _ _) = player.y -= 10
  eventHandler _ = return ()
  
  -- This is the main loop. It does nothing right now.
  mainLoop :: Float -> GameMonad ()
  mainLoop _ = return ()
  
  -- Now lets run the game! The run function takes:
  -- 1. the title for the window of the game
  -- 2. the size of the window
  -- 3. the initial game state
  -- 4. the eventHandler function
  -- 5. the main loop function
  main = run "demo game" (500, 500) gameState eventHandler mainLoop
  