Stop bullets when they hit walls

This commit is contained in:
2021-12-14 19:25:37 +00:00
parent 47391f3850
commit e3402bacf1
8 changed files with 64 additions and 21 deletions
+1 -1
View File
@@ -82,7 +82,7 @@ wallNormal wl = normalizeV . vNormal $ a -.- b
wallsOnLine :: Point2 -> Point2 -> IM.IntMap Wall -> [Wall] wallsOnLine :: Point2 -> Point2 -> IM.IntMap Wall -> [Wall]
wallsOnLine p1 p2 ws = hitWalls wallsOnLine p1 p2 ws = hitWalls
where where
hitPoint w = uncurry (intersectSegSeg p1 p2) (_wlLine w) hitPoint = uncurry (intersectSegSeg p1 p2) . _wlLine
hitWalls = filter (isJust . hitPoint) (IM.elems ws) hitWalls = filter (isJust . hitPoint) (IM.elems ws)
wallsOnLine3D :: Point3 -> Point3 -> IM.IntMap Wall -> [Wall] wallsOnLine3D :: Point3 -> Point3 -> IM.IntMap Wall -> [Wall]
+3 -3
View File
@@ -15,13 +15,13 @@ import Control.Lens
{- Update for a generic bullet. -} {- Update for a generic bullet. -}
mvBullet :: World -> Particle -> (World, Maybe Particle) mvBullet :: World -> Particle -> (World, Maybe Particle)
mvBullet w bt' mvBullet w bt'
| t <= 0 || magV (_btVel' bt) < 1 = wAnd Nothing | t <= 0 || magV (_btVel' bt) < 1 = (w,Nothing)
| otherwise = second (fmap dodrag) $ hiteff bt (thingsHitExceptCr mcr p (p +.+ vel) w) w | otherwise = second (fmap dodrag) $
hiteff bt (thingsHitExceptCr mcr p (p +.+ vel) w) w
where where
bt = foldr (\mg b -> _mgField mg mg b) bt' $ _magnets w bt = foldr (\mg b -> _mgField mg mg b) bt' $ _magnets w
dodrag = btVel' %~ (drag *.*) dodrag = btVel' %~ (drag *.*)
drag = _btDrag bt drag = _btDrag bt
wAnd = (w,)
mcr = _btPassThrough' bt mcr = _btPassThrough' bt
(p:_) = _btTrail' bt (p:_) = _btTrail' bt
vel = _btVel' bt vel = _btVel' bt
+1 -1
View File
@@ -36,8 +36,8 @@ putLasTurret rotSpeed = sps0 $ PutMachine blue (reverse $ square wdth) defaultMa
} }
lasTurret :: MachineType lasTurret :: MachineType
lasTurret = Turret lasTurret = Turret
--{ _tuWeapon = lasGun
{ _tuWeapon = lasGun { _tuWeapon = lasGun
--{ _tuWeapon = autoRifle
, _tuTurnSpeed = 0.1 , _tuTurnSpeed = 0.1
, _tuFireTime = 0 , _tuFireTime = 0
, _tuMCrID = Nothing , _tuMCrID = Nothing
+9
View File
@@ -51,9 +51,18 @@ mvPt pt = Just $ pt
destroyAt :: Point2 -> Particle -> Maybe Particle destroyAt :: Point2 -> Particle -> Maybe Particle
destroyAt hitp pt = Just $ pt destroyAt hitp pt = Just $ pt
& ptUpdate .~ killBulletUpdate
& btTrail' %~ (hitp :) & btTrail' %~ (hitp :)
& btTimer' %~ (\t -> min 3 (t-1)) & btTimer' %~ (\t -> min 3 (t-1))
killBulletUpdate :: World -> Particle -> (World,Maybe Particle)
killBulletUpdate w pt
| _btTimer' pt <= 0 = (w,Nothing)
| otherwise = (w
,Just $ pt & btTimer' -~ 1
& btTrail' %~ (\(x:xs) -> (x:x:xs))
)
penWalls penWalls
:: HitCreatureEffect :: HitCreatureEffect
-> HitWallEffect -> HitWallEffect
+3 -2
View File
@@ -31,12 +31,13 @@ thingsHit sp ep w
where where
hitCrs = IM.elems hitCrs = IM.elems
$ IM.filter (\cr -> circOnSeg sp ep (_crPos cr) (_crRad cr)) $ IM.filter (\cr -> circOnSeg sp ep (_crPos cr) (_crRad cr))
$ _creatures w -- $ _creatures w
-- $ creaturesAlongLine sp ep w $ creaturesAlongLine sp ep w
crPs = map (\cr -> ssaTriPoint ep (_crPos cr) sp (_crRad cr)) hitCrs crPs = map (\cr -> ssaTriPoint ep (_crPos cr) sp (_crRad cr)) hitCrs
crs = zip crPs (map Left hitCrs) crs = zip crPs (map Left hitCrs)
hitWls = wallsOnLine sp ep (IM.unions [f b $ f a $ _znObjects $ _wallsZone w | a<-[x-1,x,x+1] hitWls = wallsOnLine sp ep (IM.unions [f b $ f a $ _znObjects $ _wallsZone w | a<-[x-1,x,x+1]
, b<-[y-1,y,y+1]]) , b<-[y-1,y,y+1]])
--hitWls = wallsOnLine sp ep $ _walls w
(x,y) = zoneOfPoint (0.5 *.* (sp +.+ ep)) (x,y) = zoneOfPoint (0.5 *.* (sp +.+ ep))
f i m = case IM.lookup i m of f i m = case IM.lookup i m of
Just val -> val Just val -> val
+3 -8
View File
@@ -182,24 +182,19 @@ pHalf !a !b = 0.5 *.* (a +.+ b)
-- segment. -- segment.
circOnSegNoEndpoints :: Point2 -> Point2 -> Point2 -> Float -> Bool circOnSegNoEndpoints :: Point2 -> Point2 -> Point2 -> Float -> Bool
{-# INLINE circOnSegNoEndpoints #-} {-# INLINE circOnSegNoEndpoints #-}
circOnSegNoEndpoints !p1 !p2 !c !rad = isJustTrue (fmap (\p -> magV (p -.- c) < rad) y) circOnSegNoEndpoints !p1 !p2 !c !rad = intersectSegSegTest p1 p2 (c -.- thenormal) (c +.+ thenormal)
where where
y = intersectSegLine p1 p2 c (c +.+ vNormal (p1 -.- p2)) thenormal = rad *.* vNormal (normalizeV $ p1 -.- p2)
isJustTrue (Just True) = True
isJustTrue _ = False
-- | Test whether a circle is on a segment by intersecting a normal and testing -- | Test whether a circle is on a segment by intersecting a normal and testing
-- the distance to the endpoints of the segment. -- the distance to the endpoints of the segment.
circOnSeg :: Point2 -> Point2 -> Point2 -> Float -> Bool circOnSeg :: Point2 -> Point2 -> Point2 -> Float -> Bool
{-# INLINE circOnSeg #-} {-# INLINE circOnSeg #-}
circOnSeg !p1 !p2 !c !rad = magV (p1 -.- c) <= rad circOnSeg !p1 !p2 !c !rad = magV (p1 -.- c) <= rad
|| magV (p2 -.- c) <= rad || magV (p2 -.- c) <= rad
-- || isJustTrue (fmap (\p -> magV (p -.- c) < rad) y)
|| intersectSegSegTest p1 p2 (c -.- thenormal) (c +.+ thenormal) || intersectSegSegTest p1 p2 (c -.- thenormal) (c +.+ thenormal)
where where
thenormal = rad *.* vNormal (normalizeV $ p1 -.- p2) thenormal = rad *.* vNormal (normalizeV $ p1 -.- p2)
y = intersectSegLine p1 p2 c (c +.+ vNormal (p1 -.- p2))
isJustTrue (Just True) = True
isJustTrue _ = False
cylinderOnSeg :: Point3 -> Point3 -> Point3 -> Float -> Bool cylinderOnSeg :: Point3 -> Point3 -> Point3 -> Float -> Bool
{-# INLINE cylinderOnSeg #-} {-# INLINE cylinderOnSeg #-}
cylinderOnSeg = undefined cylinderOnSeg = undefined
+29 -4
View File
@@ -2,9 +2,9 @@
{- {-
Testing for and finding intersection points. Testing for and finding intersection points.
-} -}
module Geometry.Intersect module Geometry.Intersect where
where
import Geometry.Data import Geometry.Data
import Geometry.Vector
import Geometry.LHS import Geometry.LHS
import Control.Applicative import Control.Applicative
@@ -18,10 +18,21 @@ intersectLineLine' (V2 x1 y1) (V2 x2 y2) (V2 x3 y3) (V2 x4 y4)
where where
den = (x1-x2)*(y3-y4) - (y1-y2)*(x3-x4) den = (x1-x2)*(y3-y4) - (y1-y2)*(x3-x4)
t' = (x1-x3)*(y3-y4) - (y1-y3)*(x3-x4) t' = (x1-x3)*(y3-y4) - (y1-y3)*(x3-x4)
intersectSegSegErrorTest :: Point2 -> Point2 -> Point2 -> Point2 -> Maybe Point2
{-# INLINE intersectSegSegErrorTest #-}
intersectSegSegErrorTest a b c d = case intersectSegSeg a b c d of
Nothing | intersectSegSegFullTest a b c d ->
error $ "intersectSegSeg did not intersect"++show a ++ show b ++ show c++ show d
Just x | not $ intersectSegSegFullTest a b c d ->
error $ "intersectSegSeg did intersect"++show a ++ show b ++ show c++ show d
++ " at " ++ show x
m -> m
-- | If two segments intersect, return 'Just' that point. -- | If two segments intersect, return 'Just' that point.
intersectSegSeg :: Point2 -> Point2 -> Point2 -> Point2 -> Maybe Point2 intersectSegSeg :: Point2 -> Point2 -> Point2 -> Point2 -> Maybe Point2
{-# INLINE intersectSegSeg #-} {-# INLINE intersectSegSeg #-}
intersectSegSeg (V2 x1 y1) (V2 x2 y2) (V2 x3 y3) (V2 x4 y4) intersectSegSeg (V2 x1 y1) (V2 x2 y2) (V2 x3 y3) (V2 x4 y4)
| V2 x1 y1 == V2 x2 y2 || V2 x3 y3 == V2 x4 y4 = Nothing
| den == 0 = Nothing | den == 0 = Nothing
| den > 0 && (t' < 0 || u' < 0 || t' > den || u' > den) | den > 0 && (t' < 0 || u' < 0 || t' > den || u' > den)
= Nothing = Nothing
@@ -75,9 +86,23 @@ intersectSegLine (V2 x1 y1) (V2 x2 y2) (V2 x3 y3) (V2 x4 y4)
den = (x1-x2)*(y3-y4) - (y1-y2)*(x3-x4) den = (x1-x2)*(y3-y4) - (y1-y2)*(x3-x4)
t' = (x1-x3)*(y3-y4) - (y1-y3)*(x3-x4) t' = (x1-x3)*(y3-y4) - (y1-y3)*(x3-x4)
--u' = (y1-y2)*(x1-x3) - (x1-x2)*(y1-y3) --u' = (y1-y2)*(x1-x3) - (x1-x2)*(y1-y3)
-- | A test that should align with Just values from intersectSegSeg.
intersectSegSegFullTest
:: Point2
-> Point2
-> Point2
-> Point2
-> Bool
{-# INLINE intersectSegSegFullTest #-}
intersectSegSegFullTest x y z w
= f x y z w && f z w x y && x /= y && z /= w
&& normalizeV (x -.- y) /= normalizeV (z -.- w)
&& normalizeV (y -.- x) /= normalizeV (z -.- w)
where
f a b c d = ( not (isRHS a b c) && not (isLHS a b d) )
|| ( not (isLHS a b c) && not (isRHS a b d) )
-- | It is not always necessary to find a point of intersection, sometimes a -- | It is not always necessary to find a point of intersection, sometimes a
-- test may suffice. -- test may suffice.
-- IS THIS CORRECT? -- TODO tests
intersectSegSegTest intersectSegSegTest
:: Point2 :: Point2
-> Point2 -> Point2
@@ -86,7 +111,7 @@ intersectSegSegTest
-> Bool -> Bool
{-# INLINE intersectSegSegTest #-} {-# INLINE intersectSegSegTest #-}
intersectSegSegTest x y z w intersectSegSegTest x y z w
= f x y z w && f z w x y = f x y z w && f z w x y && x /= y && z /= w
where where
f a b c d = ( not (isRHS a b c) && not (isLHS a b d) ) f a b c d = ( not (isRHS a b c) && not (isLHS a b d) )
|| ( not (isLHS a b c) && not (isRHS a b d) ) || ( not (isLHS a b c) && not (isRHS a b d) )
+14 -1
View File
@@ -1,12 +1,13 @@
--import Test.HUnit --import Test.HUnit
import Test.Tasty import Test.Tasty
import Test.Tasty.QuickCheck import qualified Test.Tasty.QuickCheck as QC
import Test.Tasty.HUnit import Test.Tasty.HUnit
import Dodge.Room.CheckConsistency import Dodge.Room.CheckConsistency
import Geometry import Geometry
import Dodge.LevelGen.StaticWalls import Dodge.LevelGen.StaticWalls
import Geometry import Geometry
import Data.Maybe
main :: IO () main :: IO ()
main = defaultMain $ main = defaultMain $
@@ -14,6 +15,11 @@ main = defaultMain $
[testGroup "Geometry tests" geometryTests] [testGroup "Geometry tests" geometryTests]
geometryTests = geometryTests =
[ testGroup "(HUnit)" geometryUnitTests
, testGroup "(QuickCheck)" geometryQuickCheckTests
]
geometryUnitTests =
[ testCase "intersectSegSegTest cross intersect" $ [ testCase "intersectSegSegTest cross intersect" $
intersectSegSegTest (V2 1 0) (V2 1 2) (V2 0 1) (V2 2 1) intersectSegSegTest (V2 1 0) (V2 1 2) (V2 0 1) (V2 2 1)
@?= True @?= True
@@ -46,6 +52,13 @@ geometryTests =
@?= False @?= False
] ]
geometryQuickCheckTests =
[ QC.testProperty "intersectSegSeg--intersectSegSegTest" $
\(x1,y1,x2,y2,x3,y3,x4,y4) ->
isJust (intersectSegSeg (V2 x1 y1) (V2 x2 y2) (V2 x3 y3) (V2 x4 y4))
== intersectSegSegTest (V2 x1 y1) (V2 x2 y2) (V2 x3 y3) (V2 x4 y4)
]
--nextPair :: Eq a => (a,a) -> [(a,a)] -> [(a,a)] --nextPair :: Eq a => (a,a) -> [(a,a)] -> [(a,a)]
--nextPair (_,y) = filter (\(x,_) -> x == y) --nextPair (_,y) = filter (\(x,_) -> x == y)
-- --