layers-game-0.3: src/GameData/Animation.hs
module GameData.Animation where
import qualified Data.List as L
import Gamgine.Math.Vect as V
data Animation = Animation {
currentPosition :: V.Vect,
currentVelocity :: V.Vect,
velocity :: Double,
path :: [V.Vect],
bidirectional :: Bool,
movingToPathIdx :: Int,
finished :: Bool
} deriving Show
newAnimation :: Double -> [V.Vect] -> Bool -> Animation
newAnimation velocity path@(currPos : nextPos : _) bidirectional =
Animation currPos currVelo velocity path bidirectional 1 False
where
currVelo = (V.normalize $ nextPos - currPos) * V.v3 velocity velocity velocity
basePosition :: Animation -> V.Vect
basePosition = L.head . path
setBasePosition :: Animation -> V.Vect -> Animation
setBasePosition ani newBase =
let (basePt : otherPts) = path ani
diffPath = L.map ((-) basePt) otherPts
otherPts' = L.map (newBase `plus`) diffPath
in newAnimation (velocity ani) (newBase : otherPts') (bidirectional ani)
where
plus = (+)
update :: Animation -> Animation
update ani@Animation {finished = True} = ani
update ani@Animation {currentPosition = currPos, currentVelocity = currVelo, velocity = velo, path = path, movingToPathIdx = idx} =
let nextPos | idx >= L.length path = currPos
| otherwise = path !! idx
currPos' = currPos + currVelo
nextPosReached = V.len (currPos' - nextPos) < 0.1
in if nextPosReached
then incrementIdx ani {currentPosition = nextPos}
else ani {currentPosition = currPos'}
where
incrementIdx ani@Animation {currentPosition = currPos, movingToPathIdx = idx, path = path, bidirectional = bidir} =
let nextIdx = idx + 1
atEnd = nextIdx >= L.length path
in if atEnd
then if bidir then newAnimation velo (L.reverse path) bidir else ani {finished = True}
else ani {movingToPathIdx = nextIdx,
currentVelocity = (V.normalize $ (path !! nextIdx) - currPos) * V.v3 velo velo velo}