{-# OPTIONS_HADDOCK hide #-}
{-# LANGUAGE NoImplicitPrelude #-}
module Imj.Graphics.Animation.Geo
( gravityFallGeo
, simpleExplosionGeo
, quantitativeExplosionGeo
, animatePolygonGeo
, laserAnimationGeo
) where
import Imj.Prelude
import Data.Char( intToDigit )
import Data.List( length )
import Imj.GameItem.Weapon.Laser.Types
import Imj.Geo.Continuous
import Imj.Geo.Discrete
import Imj.Graphics.Animation.Design.Types
import Imj.Iteration
laserAnimationGeo :: LaserRay Actual
-> Coords Pos
-> Frame
-> [AnimatedPoint]
laserAnimationGeo (LaserRay dir (Ray seg)) _ (Frame i) =
let (originalChar, replacementChar) =
if dir == LEFT || dir == RIGHT
then
('=','-')
else
('|','.')
char = if i >= 2
then
replacementChar
else
originalChar
points = if i >= 4
then
[]
else
bresenham seg
in map (\p -> AnimatedPoint DontInteract p (Just char)) points
gravityFallGeo :: Vec2 Vel
-> CanInteract
-> Coords Pos
-> Frame
-> [AnimatedPoint]
gravityFallGeo initialSpeed canInteract origin frame =
let o = pos2vec origin
points = [vec2pos $ parabola o initialSpeed frame]
in map (\p -> AnimatedPoint canInteract p Nothing) points
simpleExplosionGeo :: Int
-> CanInteract
-> Coords Pos
-> Frame
-> [AnimatedPoint]
simpleExplosionGeo resolution canInteract center (Frame iteration) =
let radius = fromIntegral iteration :: Float
c = pos2vec center
points = map vec2pos $ translatedFullCircleFromQuarterArc c radius 0 resolution
in map (\p -> AnimatedPoint canInteract p Nothing) points
quantitativeExplosionGeo :: Int
-> CanInteract
-> Coords Pos
-> Frame
-> [AnimatedPoint]
quantitativeExplosionGeo number canInteract center (Frame iteration) =
let numRand = 10 :: Int
rnd = 2 :: Int
radius = fromIntegral iteration :: Float
firstAngle = (fromIntegral rnd :: Float) * 2*pi / (fromIntegral numRand :: Float)
c = pos2vec center
points = map vec2pos $ translatedFullCircle c radius firstAngle number
in map (\p -> AnimatedPoint canInteract p Nothing) points
animatePolygonGeo :: Int
-> Coords Pos
-> Frame
-> [AnimatedPoint]
animatePolygonGeo n center (Frame i) =
let r = animateRadius (quot i 2) n
points = if r < 0
then
[]
else
case n of
1 -> let p = simpleExplosionGeo 8 DontInteract center $ Frame r
in map (\(AnimatedPoint _ p' _) -> p') p
_ -> polygon n r center
in map (\p -> AnimatedPoint DontInteract p (Just $ intToDigit n)) points
polygon :: Int -> Int -> Coords Pos -> [Coords Pos]
polygon nSides radius center =
let startAngle = if odd nSides then pi else pi/4.0
extrs = polyExtremities (pos2vec center) (fromIntegral radius) startAngle nSides
in connect $ map vec2pos extrs
animateRadius :: Int -> Int -> Int
animateRadius i nSides =
let limit
| nSides <= 4 = 5
| nSides <= 6 = 7
| otherwise = 10
in if i < limit
then
i
else
2 * limit - i
connect :: [Coords Pos] -> [Coords Pos]
connect [] = []
connect l@[_] = l
connect (a:rest@(b:_)) = connect2 a b ++ connect rest
connect2 :: Coords Pos -> Coords Pos -> [Coords Pos]
connect2 start end =
let numpoints = 80
in sampledBresenham numpoints start end
sampledBresenham :: Int -> Coords Pos -> Coords Pos -> [Coords Pos]
sampledBresenham nSamples start end =
let l = bresenhamLength start end
seg = mkSegment start end
bres = bresenham seg
in resampleWithExtremities bres (assert (l == length bres) l) nSamples