Files
loop/src/Dodge/Creature/Impulse/Movement.hs
T
2025-10-17 22:32:40 +01:00

100 lines
3.1 KiB
Haskell

module Dodge.Creature.Impulse.Movement (
creatureTurnToward,
creatureTurnTowardDir,
crMvAbsolute,
crMvBy,
crMvByNoStride,
crMvForward,
creatureTurnTo,
) where
import Linear
import Control.Lens
import Dodge.Base
import Dodge.Creature.Statistics
import Dodge.Data.World
import Geometry
{- | Creature attempts to moves under its own steam.
The idea is that this may or may not work, depending on the status of the creature.
For now, though, this cannot fail.
-}
crMvBy ::
-- | Movement translation vector, will be made relative to creature direction
Point2 ->
LWorld ->
Creature ->
Creature
crMvBy p lw cr = crMvAbsolute lw (rotateV (_crDir cr) p) cr
crMvByNoStride ::
-- | Movement translation vector, will be made relative to creature direction
Point2 ->
LWorld ->
Creature ->
Creature
crMvByNoStride p lw cr = crMvAbsoluteNoStride lw (rotateV (_crDir cr) p) cr
crMvAbsolute :: LWorld -> Point2 -> Creature -> Creature
crMvAbsolute lw p' cr =
advanceStepCounter (magV p) cr
& crPos . _xy +~ p
& crMvDir .~ argV p
where
p = strengthFactor (getCrMoveSpeed lw cr) *.* p'
crMvAbsoluteNoStride :: LWorld -> Point2 -> Creature -> Creature
crMvAbsoluteNoStride lw p' cr = cr & crPos . _xy +~ p
where
p = strengthFactor (getCrMoveSpeed lw cr) *.* p'
strengthFactor :: Int -> Float
strengthFactor i
| i > 50 = 1
| i < 1 = 0
| otherwise = 0.02 * fromIntegral i
crMvForward :: Float -> LWorld -> Creature -> Creature
crMvForward speed = crMvBy (V2 speed 0)
advanceStepCounter :: Float -> Creature -> Creature
advanceStepCounter speed cr = cr & crStance . carriage %~ f
where
f car = case car of
Standing -> f (Walking 0 RightForward)
Walking i ff -> Walking (min (cr ^. crStance . strideLength) (i + speed)) ff
_ -> car
creatureTurnTo :: Point2 -> Creature -> Creature
creatureTurnTo p cr
| vToTarg == V2 0 0 = cr -- this should deal with the angleVV error
| otherwise = cr & crDir .~ dirToTarget
where
vToTarg = p -.- cr ^. crPos . _xy
dirToTarget = argV vToTarg
-- the following is perhaps not ideal because it mixes normalizeAngle with
-- angleVV, but it seems to work
creatureTurnTowardDir :: Float -> Float -> Creature -> Creature
creatureTurnTowardDir a turnSpeed cr
| abs (normalizeAnglePi (a - cdir)) <= turnSpeed = cr & crDir .~ dirToTarget
| otherwise = cr & crDir %~ addOrSub turnSpeed
where
addOrSub
| isLeftOfA dirToTarget cdir = (+)
| otherwise = subtract
cdir = _crDir cr
dirToTarget = argV $ rotateV a (V2 1 0)
creatureTurnToward :: Point2 -> Float -> Creature -> Creature
creatureTurnToward p turnSpeed cr
| vToTarg == V2 0 0 = cr -- this should deal with the angleVV error
-- | errorAngleVV 3 vToTarg (unitVectorAtAngle (_crDir cr)) <= turnSpeed =
| angleVV vToTarg (unitVectorAtAngle (_crDir cr)) <= turnSpeed =
cr & crDir .~ dirToTarget
| isLeftOfA (normalizeAngle dirToTarget) (normalizeAngle $ _crDir cr) = cr & crDir +~ turnSpeed
| otherwise = cr & crDir -~ turnSpeed
where
vToTarg = p -.- cr ^. crPos . _xy
dirToTarget = argV vToTarg