{-# LANGUAGE NoImplicitPrelude #-} module Imj.Graphics.Animation ( -- * Animation functions -- | Animation functions are used by 'Animation's to update 'AnimatedPoint's. gravityFallGeo , simpleExplosionGeo , quantitativeExplosionGeo , animatePolygonGeo , laserAnimationGeo -- * Animation , Animation {- | An 'Animation' generates 'AnimatedPoint's: -} , AnimatedPoint(..) -- | 'AnimatedPoint's can interact with their environment: , CanInteract(..) -- | The result of an interaction between an 'AnimatedPoint' and its environment -- can trigger a /mutation/: , InteractionResult(..) {- | 'AnimatedPoint's live in a : -} , AnimatedPoints(..) -- ** Create , mkAnimation -- ** Predefined animations -- *** Explosive , simpleExplosion , quantitativeExplosionThenSimpleExplosion -- *** Free fall {- | 'freeFall' simulates the effect of gravity on an object that has an initial speed. 'freeFallThenExplode' adds an explosion when the falling object hits the environment (ie when the 'InteractionResult' of an interaction between the object and the environment is 'Mutation'). -} , freeFall , freeFallThenExplode -- *** Fragments {- | 'fragmentsFreeFall' gives the impression that the object disintegrated in multiple pieces before falling. 'fragmentsFreeFallThenExplode' adds an explosion when the falling object hits the environment (ie when the 'InteractionResult' of an interaction between the object and the environment is 'Mutation'). -} , fragmentsFreeFall , fragmentsFreeFallThenExplode -- *** Geometric , animatedPolygon , laserAnimation -- *** Nice chars {-| 'niceChar' presents a list of 'Char's that /look good/ when used in explosive and free fall animations. -} , niceChar -- ** Update , getDeadline , shouldUpdate , updateAnimation -- ** Render , renderAnim -- * Internal , module Imj.Graphics.Animation.Internal -- * Reexports , module Imj.Timing , module Imj.Iteration , Coords ) where import Imj.Prelude import Imj.GameItem.Weapon.Laser.Types import Imj.Geo.Continuous import Imj.Geo.Discrete import Imj.Graphics.Animation.Chars import Imj.Graphics.Animation.Design.Create import Imj.Graphics.Animation.Design.Color import Imj.Graphics.Animation.Design.Render import Imj.Graphics.Animation.Design.Timing import Imj.Graphics.Animation.Design.Types import Imj.Graphics.Animation.Design.Update import Imj.Graphics.Animation.Geo import Imj.Graphics.Animation.Internal import Imj.Iteration import Imj.Timing -- | A laser ray animation, with a fade-out effect. laserAnimation :: LaserRay Actual -- ^ The laser ray -> (Coords Pos -> InteractionResult) -- ^ Environment interaction function -> Either SystemTime KeyTime -- ^ 'Right' 'KeyTime' of the event's deadline -- that triggered this animation, or 'Left' 'SystemTime' -- of the current time if a player action triggered this animation -> Maybe Animation laserAnimation ray@(LaserRay _ (Ray seg)) interaction keyTime = let pos = fst $ extremities seg -- this needs to be collision-free in mkAnimation pos [laserAnimationGeo ray] (Speed 1) interaction keyTime Nothing -- | An animation chaining two circular explosions, the first explosion -- can be configured in number of points, the second has 4*8=32 points. quantitativeExplosionThenSimpleExplosion :: Int -- ^ Number of points in the first explosion -> Coords Pos -- ^ Center of the first explosion -> (Coords Pos -> InteractionResult) -- ^ Environment interaction function -> Speed -- ^ Animation speed -> Either SystemTime KeyTime -- ^ 'Right' 'KeyTime' of the event's deadline -- that triggered this animation, or 'Left' 'SystemTime' -- of the current time if a player action triggered this animation -> Char -- ^ Character used when drawing the animation. -> Maybe Animation quantitativeExplosionThenSimpleExplosion num pos interaction animSpeed keyTime char = let funcs = [ quantitativeExplosionGeo num Interact , simpleExplosionGeo 8 Interact ] in mkAnimation pos funcs animSpeed interaction keyTime (Just char) -- | An animation where a geometric figure (polygon or circle) expands then shrinks, -- and doesn't interact with the environment. animatedPolygon :: Int -- ^ If n==1, the geometric figure is a circle, else if n>1, a n-sided polygon -> Coords Pos -- ^ Center of the polygon (or circle) -> (Coords Pos -> InteractionResult) -- ^ Environment interaction function -> Speed -- ^ Animation speed -> Either SystemTime KeyTime -- ^ 'Right' 'KeyTime' of the event's deadline -- that triggered this animation, or 'Left' 'SystemTime' -- of the current time if a player action triggered this animation -> Char -- ^ Character used when drawing the animation. -> Maybe Animation animatedPolygon n pos interaction animSpeed keyTime char = mkAnimation pos [animatePolygonGeo n] animSpeed interaction keyTime (Just char) -- | A circular explosion configurable in number of points simpleExplosion :: Int -- ^ Number of points in the explosion -> Coords Pos -- ^ Center of the explosion -> (Coords Pos -> InteractionResult) -- ^ Environment interaction function -> Speed -- ^ Animation speed -> Either SystemTime KeyTime -- ^ 'Right' 'KeyTime' of the event's deadline -- that triggered this animation, or 'Left' 'SystemTime' -- of the current time if a player action triggered this animation -> Char -- ^ Character used when drawing the animation. -> Maybe Animation simpleExplosion resolution pos interaction animSpeed keyTime char = mkAnimation pos [simpleExplosionGeo resolution Interact] animSpeed interaction keyTime (Just char) -- | Animation representing an object with an initial velocity disintegrating in -- 4 different parts. fragmentsFreeFall :: Vec2 Vel -- ^ Initial speed -> Coords Pos -- ^ Initial position -> (Coords Pos -> InteractionResult) -- ^ Environment interaction function -> Speed -- ^ Animation speed -> Either SystemTime KeyTime -- ^ 'Right' 'KeyTime' of the event's deadline -- that triggered this animation, or 'Left' 'SystemTime' -- of the current time if a player action triggered this animation -> Char -- ^ Character used when drawing the animation. -> [Animation] fragmentsFreeFall speed pos interaction animSpeed keyTime char = mapMaybe (\sp -> freeFall sp pos interaction animSpeed keyTime char) $ variations speed -- | A gravity-based free-falling animation. freeFall :: Vec2 Vel -- ^ Initial speed -> Coords Pos -- ^ Initial position -> (Coords Pos -> InteractionResult) -- ^ Environment interaction function -> Speed -- ^ Animation speed -> Either SystemTime KeyTime -- ^ 'Right' 'KeyTime' of the event's deadline -- that triggered this animation, or 'Left' 'SystemTime' -- of the current time if a player action triggered this animation -> Char -- ^ Character used when drawing the animation. -> Maybe Animation freeFall speed pos interaction animSpeed keyTime char = mkAnimation pos [gravityFallGeo speed Interact] animSpeed interaction keyTime (Just char) -- | Animation representing an object with an initial velocity disintegrating in -- 4 different parts free-falling and then exploding. fragmentsFreeFallThenExplode :: Vec2 Vel -- ^ Initial speed -> Coords Pos -- ^ Initial position -> (Coords Pos -> InteractionResult) -- ^ Environment interaction function -> Speed -- ^ Animation speed -> Either SystemTime KeyTime -- ^ 'Right' 'KeyTime' of the event's deadline -- that triggered this animation, or 'Left' 'SystemTime' -- of the current time if a player action triggered this animation -> Char -- ^ Character used when drawing the animation. -> [Animation] fragmentsFreeFallThenExplode speed pos interaction k s c = mapMaybe (\sp -> freeFallThenExplode sp pos interaction k s c) $ variations speed -- | Given an input speed, computes four slightly different input speeds variations :: Vec2 Vel -> [Vec2 Vel] variations sp = map (sumVec2d sp) [ Vec2 0.12 (-0.16) , Vec2 (-0.22) (-0.116) , Vec2 (-0.04) 0.36 , Vec2 0.48 0.08] -- | An animation chaining a gravity-based free-fall and a circular explosion of 4*8 points. freeFallThenExplode :: Vec2 Vel -- ^ Initial speed -> Coords Pos -- ^ Initial position -> (Coords Pos -> InteractionResult) -- ^ Environment interaction function -> Speed -- ^ Animation speed -> Either SystemTime KeyTime -- ^ 'Right' 'KeyTime' of the event's deadline -- that triggered this animation, or 'Left' 'SystemTime' -- of the current time if a player action triggered this animation -> Char -- ^ Character used when drawing the animation. -> Maybe Animation freeFallThenExplode speed pos interaction animSpeed keyTime char = let funcs = [ gravityFallGeo speed Interact , simpleExplosionGeo 8 Interact] in mkAnimation pos funcs animSpeed interaction keyTime (Just char)