packages feed

ActionKid-0.1.0.0: src/ActionKid/Internal.hs

module ActionKid.Internal where
import ActionKid.Types
import ActionKid.Utils
import Control.Applicative
import Control.Monad
import Data.List
import Data.Maybe
import Text.Printf
import Graphics.Gloss hiding (display)
import Data.Monoid ((<>), mconcat)
import Graphics.Gloss.Interface.IO.Game
import Data.Ord
import ActionKid.Globals
import Data.StateVar
import Control.Lens
import qualified Debug.Trace as D

-- bounding box for a series of points
pathBox points =
    let minx = minimum $ map fst points
        miny = minimum $ map snd points
        maxx = maximum $ map fst points
        maxy = maximum $ map snd points
    in ((minx, miny), (maxx, maxy))

catPoints :: (Point, Point) -> [Point]
catPoints (p1, p2) = [p1, p2]

-- | Code borrowed from https://hackage.haskell.org/package/gloss-game-0.3.0.0/docs/src/Graphics-Gloss-Game.html
-- Calculate bounding boxes for various `Picture` types.
type Rect = (Point, Point)     -- ^origin & extent, where the origin is at the centre
boundingBox :: Picture -> Rect
boundingBox Blank                    = ((0, 0), (0, 0))
boundingBox (Polygon path)           = pathBox path
boundingBox (Line path)              = pathBox path
boundingBox (Circle r)               = ((0, 0), (2 * r, 2 * r))
boundingBox (ThickCircle t r)        = ((0, 0), (2 * r + t, 2 * r + t))
boundingBox (Arc _ _ _)              = error "ActionKid.Core.boundingbox: Arc not implemented yet"
boundingBox (ThickArc _ _ _ _)       = error "ActionKid.Core.boundingbox: ThickArc not implemented yet"
boundingBox (Text _)                 = error "ActionKid.Core.boundingbox: Text not implemented yet"
boundingBox (Bitmap w h _ _)         = ((0, 0), (fromIntegral w, fromIntegral h))
boundingBox (Color _ p)              = boundingBox p
boundingBox (Translate dx dy p)      = ((x1 + dx, y1 + dy), (x2 + dx, y2 + dy))
    where ((x1, y1), (x2, y2)) = boundingBox p
boundingBox (Rotate _ang _p)         = error "Graphics.Gloss.Game.boundingbox: Rotate not implemented yet"

-- TODO fix scale, this implementation is incorrect (only works if scale
-- = 1). Commented out version is incorrect too
boundingBox (Scale xf yf p)          = boundingBox p
    -- let ((x1, y1), (x2, y2)) = boundingBox p
    --     w = x2 - x1
    --     h = y2 - y1
    --     scaledW = w * xf
    --     scaledH = h * yf
    -- in ((x1, x2), (x1 + scaledW, y1 + scaledH))
boundingBox (Pictures ps) = pathBox points
    where points = concatMap (catPoints . boundingBox) ps

-- | Check if one rect is touching another.
intersects :: Rect -> Rect -> Bool
intersects ((min_ax, min_ay), (max_ax, max_ay)) ((min_bx, min_by), (max_bx, max_by))
    | max_ax < min_bx = False
    | min_ax > max_bx = False
    | min_ay > max_by = False
    | max_ay < min_by = False
    | otherwise = True

-- | For future, if I want to inject something into the step function,
-- I'll do it here. Right now I just call the step function.
onEnterFrame :: MovieClip a => (Float -> a -> IO a) -> Float -> a -> IO a
onEnterFrame stepFunc num state = stepFunc num state

-- | Called to draw the game. Translates the coordinate system.
draw :: Renderable a => a -> IO Picture
draw gs = do
  w <- get boardWidth
  h <- get boardHeight
  return $ translate (-(fromIntegral $ w // 2)) (-(fromIntegral $ h // 2)) $
           display gs