77 lines
2.5 KiB
Haskell
77 lines
2.5 KiB
Haskell
-- | Deals with moving creature wall collisions.
|
|
module Dodge.WallCreatureCollisions (colCrsWalls) where
|
|
|
|
import Control.Lens
|
|
import Data.Foldable
|
|
import qualified Data.IntSet as IS
|
|
import Dodge.Base
|
|
import Dodge.Creature.Radius
|
|
import Dodge.Data.Universe
|
|
import Dodge.Zoning.Wall
|
|
import Geometry
|
|
import Linear
|
|
|
|
colCrsWalls :: Universe -> Universe
|
|
colCrsWalls uv = uv & uvWorld . cWorld . lWorld . creatures %~ fmap (noclipCheck (_uvConfig uv) (_uvWorld uv))
|
|
|
|
noclipCheck :: Config -> World -> Creature -> Creature
|
|
noclipCheck cfig w c
|
|
| debugOn Noclip cfig && _crID c == 0 = c -- for noclip
|
|
| otherwise = colCrWall w c
|
|
|
|
colCrWall :: World -> Creature -> Creature
|
|
colCrWall w c = cornpush . wallpush $ pushthrough c
|
|
where
|
|
cornpush = crPos . _xy %~ pushOutFromCorners r ls'
|
|
wallpush = pushCr wls
|
|
pushthrough = crPos . _xy %~ fst . flip (collidePoint p1) wls -- check push throughs
|
|
r = crRad (c ^. crType) + wallBuffer
|
|
p1 = c ^. crOldPos . _xy
|
|
p2 = c ^. crPos . _xy
|
|
ls = _wlLine <$> wls
|
|
ls' = filter (uncurry $ isLHS p1) ls
|
|
wls = filter notff $ wlsNearCirc p2 r w
|
|
notff x = x ^. wlMaterial /= ForceField
|
|
|
|
pushCr :: [Wall] -> Creature -> Creature
|
|
pushCr wls cr
|
|
| dist ep sp > r && dist ep ap > r =
|
|
ecr
|
|
& crDamage <>~ [Crushing 1000 0]
|
|
& crPos . _xy .~ ap
|
|
| otherwise = ecr
|
|
where
|
|
ep = ecr ^. crPos . _xy
|
|
ap = cr ^. crOldPos . _xy
|
|
sp = cr ^. crPos . _xy
|
|
ecr = foldl' f (cr & crWallTouch .~ mempty) wls
|
|
r = crRad (cr ^. crType)
|
|
f acr wl = case pushOutFromWall r (acr ^. crPos . _xy) (wl ^. wlLine) of
|
|
Just p -> acr & crPos . _xy .~ p & crWallTouch %~ IS.insert (wl ^. wlID)
|
|
Nothing -> acr
|
|
|
|
-- the amount to push creatures out from walls, extra to their radius
|
|
wallBuffer :: Float
|
|
wallBuffer = 0
|
|
|
|
-- assumes that the wall is orientated
|
|
-- assumes wall points are different
|
|
pushOutFromWall :: Float -> Point2 -> (Point2, Point2) -> Maybe Point2
|
|
pushOutFromWall rad cp2 (wp1, wp2)
|
|
| isOnWall = Just newP
|
|
| otherwise = Nothing
|
|
where
|
|
n = errorNormalizeV 61 $ vNormal (wp1 - wp2)
|
|
wp1' = wp1 + rad *^ n
|
|
wp2' = wp2 + rad *^ n
|
|
newP = errorClosestPointOnLine 5 wp1' wp2' cp2
|
|
isOnWall = circOnSegNoEndpoints wp1 wp2 cp2 rad
|
|
|
|
pushOutFromCorners :: Float -> [(Point2, Point2)] -> Point2 -> Point2
|
|
pushOutFromCorners r = flip $ foldr (squashIntersectCirclePoint r . fst)
|
|
|
|
squashIntersectCirclePoint :: Float -> Point2 -> Point2 -> Point2
|
|
squashIntersectCirclePoint rad p cCen
|
|
| dist cCen p > rad = cCen
|
|
| otherwise = p + (rad *^ squashNormalizeV (cCen - p))
|