Implement simple swarm mechanics

This commit is contained in:
2021-05-14 20:28:53 +02:00
parent 2b09bf2072
commit c5657fe855
8 changed files with 75 additions and 37 deletions
-29
View File
@@ -36,35 +36,6 @@ import System.Random
import Foreign.ForeignPtr import Foreign.ForeignPtr
lineOrth :: Point2 -> IM.IntMap Creature -> Point2 -> Point2
lineOrth ypos crs cpos = p
where ps = map _crPos $ IM.elems crs
cen = (1 / fromIntegral (length ps)) *.* foldr1 (+.+) ps
p | dist cen ypos < 20 = ypos
| otherwise = errorClosestPointOnLine 500 ypos (ypos +.+ vNormal (cen -.- ypos)) cpos
lineUp :: Point2 -> IM.IntMap Creature -> Point2 -> Point2
lineUp ypos crs cpos = p
where ps = map _crPos $ IM.elems crs
cen = (1 / fromIntegral (length ps)) *.* foldr1 (+.+) ps
p = (0.05 *.* ypos) +.+ (0.95 *.* errorClosestPointOnLine 500 cen ypos cpos)
holdForm :: Point2 -> IM.IntMap Creature -> Point2 -> Point2
holdForm ypos crs cpos = p
where ps = map _crPos $ IM.elems crs
cen = (1 / fromIntegral (length ps)) *.* foldr1 (+.+) ps
p | dist cen ypos < 20 = ypos
| otherwise = ypos +.+ cpos -.- cen
-- not nice, a kind of encircle
spreadOut :: Point2 -> IM.IntMap Creature -> Point2 -> Point2
spreadOut ypos crs cpos = p
where ps = map _crPos $ IM.elems crs
cen = (1 / fromIntegral (length ps)) *.* foldr1 (+.+) ps
p | dist cen ypos < 30 = ypos
| otherwise = ypos +.+ (spreadFactor *.* cpos -.- cen)
spreadFactor | dist ypos cpos > 200 = 1
| otherwise = 5
---- ----
---- -- generalised swarm ai, works out where you go from the position of your flock ---- -- generalised swarm ai, works out where you go from the position of your flock
---- swarmAI :: (Point -> IM.IntMap Creature -> Point -> Point) -> Int -> World -> World ---- swarmAI :: (Point -> IM.IntMap Creature -> Point -> Point) -> Int -> World -> World
+1
View File
@@ -278,6 +278,7 @@ startInventory = IM.fromList (zip [0..20]
,spawnGun lamp ,spawnGun lamp
,lasGun ,lasGun
,autoGun ,autoGun
,flamer
--,poisonSprayer --,poisonSprayer
,launcher ,launcher
--,lasGun --,lasGun
+64
View File
@@ -2,11 +2,58 @@ module Dodge.Creature.ImpulseRat
where where
import Dodge.Data import Dodge.Data
import Dodge.Creature.ChooseTarget import Dodge.Creature.ChooseTarget
import Dodge.Creature.State.Data
import Dodge.Creature.Rationality.Data import Dodge.Creature.Rationality.Data
import Geometry import Geometry
import qualified Data.IntMap as IM
import Control.Lens import Control.Lens
lineOrth :: Point2 -> IM.IntMap Creature -> Point2 -> Point2
lineOrth ypos crs cpos = p
where ps = map _crPos $ IM.elems crs
cen = (1 / fromIntegral (length ps)) *.* foldr1 (+.+) ps
p | dist cen ypos < 20 = ypos
| otherwise = errorClosestPointOnLine 500 ypos (ypos +.+ vNormal (cen -.- ypos)) cpos
lineUp :: Point2 -> IM.IntMap Creature -> Point2 -> Point2
lineUp ypos crs cpos = p
where ps = map _crPos $ IM.elems crs
cen = (1 / fromIntegral (length ps)) *.* foldr1 (+.+) ps
p = (0.05 *.* ypos) +.+ (0.95 *.* errorClosestPointOnLine 500 cen ypos cpos)
holdForm :: Point2 -> IM.IntMap Creature -> Point2 -> Point2
holdForm ypos crs cpos = p
where ps = map _crPos $ IM.elems crs
cen = (1 / fromIntegral (length ps)) *.* foldr1 (+.+) ps
p | dist cen ypos < 20 = ypos
| otherwise = ypos +.+ cpos -.- cen
-- not nice, a kind of encircle
spreadOut :: Point2 -> IM.IntMap Creature -> Point2 -> Point2
spreadOut ypos crs cpos = p
where ps = map _crPos $ IM.elems crs
cen = (1 / fromIntegral (length ps)) *.* foldr1 (+.+) ps
p | dist cen ypos < 30 = ypos
| otherwise = ypos +.+ (spreadFactor *.* cpos -.- cen)
spreadFactor | dist ypos cpos > 200 = 1
| otherwise = 5
chaseTarget'
:: (Point2 -> IM.IntMap Creature -> Point2 -> Point2)
-> (Creature -> World -> Maybe Creature) -- ^ Function for determining target
-> World
-> Creature
-> Creature
chaseTarget' f targFunc w cr = case targFunc cr w of
Nothing -> cr
Just crTarg -> cr & crActionPlan . crImpulse .~ chaseTarg' p cr crTarg
where
ypos = _crPos crTarg
cpos = _crPos cr
is = _swarm $ _crGroup cr
crs = IM.restrictKeys (_creatures w) is
p = f ypos crs cpos
chaseTarget chaseTarget
:: (Creature -> World -> Maybe Creature) -- ^ Function for determining target :: (Creature -> World -> Maybe Creature) -- ^ Function for determining target
-> World -> World
@@ -16,6 +63,23 @@ chaseTarget targFunc w cr = case targFunc cr w of
Nothing -> cr Nothing -> cr
Just crTarg -> cr & crActionPlan . crImpulse .~ chaseTarg cr crTarg Just crTarg -> cr & crActionPlan . crImpulse .~ chaseTarg cr crTarg
chaseTarg' :: Point2 -> Creature -> Creature -> [Impulse]
chaseTarg' p cr crT
| dist tpos cpos < combinedRad + 5
&& abs ((_crDir cr) - argV (tpos -.- cpos)) < pi/4
&& _crMeleeCooldown cr == Just 0
= [Melee (_crID crT)]
| dist tpos cpos < combinedRad + 5
&& abs ((_crDir cr) - argV (tpos -.- cpos)) < pi/4
= [ TurnToward tpos 0.05 ]
| abs ((_crDir cr) - argV (p -.- cpos)) < pi/4
= [MoveForward 2.5 , TurnToward p 0.2, RandomTurn 0.2 ]
| otherwise = [MoveForward 2.5 , TurnToward p 0.05, RandomTurn 0.2 ]
where
cpos = _crPos cr
tpos = _crPos crT
combinedRad = _crRad cr + _crRad crT
chaseTarg :: Creature -> Creature -> [Impulse] chaseTarg :: Creature -> Creature -> [Impulse]
chaseTarg cr crT chaseTarg cr crT
| dist tpos cpos < combinedRad + 5 | dist tpos cpos < combinedRad + 5
+2 -2
View File
@@ -9,7 +9,7 @@ import Dodge.Creature.Stance.Data
import Picture.Data import Picture.Data
import Control.Lens import Control.Lens
import qualified Data.Set as S import qualified Data.IntSet as IS
data CreatureState = CrSt data CreatureState = CrSt
{ _goals :: [[Impulse]] { _goals :: [[Impulse]]
@@ -42,7 +42,7 @@ data Faction
data CrGroup data CrGroup
= LoneWolf = LoneWolf
| Swarm { _swarm :: S.Set Int } | Swarm { _swarm :: IS.IntSet }
makeLenses ''CreatureState makeLenses ''CreatureState
makeLenses ''CrSpState makeLenses ''CrSpState
+2 -1
View File
@@ -29,11 +29,12 @@ import System.Random
swarmCrit :: Creature swarmCrit :: Creature
swarmCrit = defaultCreature swarmCrit = defaultCreature
{ _crUpdate = stateUpdate $ meleeCooldown $ impulsiveAI $ chaseTarget targetYouLOS { _crUpdate = stateUpdate $ meleeCooldown $ impulsiveAI $ chaseTarget' lineUp targetYouLOS
, _crHP = 1 , _crHP = 1
, _crRad = 4 , _crRad = 4
, _crPict = basicCrPict yellow , _crPict = basicCrPict yellow
, _crInv = IM.empty -- IM.fromList [(0,frontArmour)] , _crInv = IM.empty -- IM.fromList [(0,frontArmour)]
, _crCorpse = onLayer CorpseLayer $ color (greyN 0.5) $ circleSolid 4 , _crCorpse = onLayer CorpseLayer $ color (greyN 0.5) $ circleSolid 4
, _crFaction = ColorFaction yellow , _crFaction = ColorFaction yellow
, _crMeleeCooldown = Just 0
} }
+2 -1
View File
@@ -8,6 +8,7 @@ import Picture
import Dodge.Data import Dodge.Data
import Dodge.Room import Dodge.Room
import Dodge.Creature.State.Data import Dodge.Creature.State.Data
import Dodge.Creature.SwarmCrit
import Dodge.Room.Procedural import Dodge.Room.Procedural
import Dodge.Room.RoadBlock import Dodge.Room.RoadBlock
import Dodge.Room.Data import Dodge.Room.Data
@@ -51,7 +52,7 @@ roomTreex = do
[[StartRoom] [[StartRoom]
,[Corridor] ,[Corridor]
,[SpecificRoom . pure . pure . Right $ roomGlassOctogon 400 ,[SpecificRoom . pure . pure . Right $ roomGlassOctogon 400
& rmPS %~ ([swarmPS 0 (x,y) 0 smallChaseCrit | x <- [-20,-19.5.. 20] , y <- [200,200.5..202] ]++) & rmPS %~ ([swarmPS 0 (x,y) 0 swarmCrit | x <- [-20,-19.5.. 20] , y <- [200,200.5..202] ]++)
] ]
,[Corridor] ,[Corridor]
,[Corridor] ,[Corridor]
+2 -2
View File
@@ -6,7 +6,7 @@ import Dodge.Data
import Dodge.LevelGen.Data import Dodge.LevelGen.Data
import Dodge.Creature.State.Data import Dodge.Creature.State.Data
import qualified Data.Set as S import qualified Data.IntSet as IS
import Control.Lens import Control.Lens
swarmPS :: Int -> Point2 -> Float -> Creature -> Placement swarmPS :: Int -> Point2 -> Float -> Creature -> Placement
@@ -22,4 +22,4 @@ setSwarm psts (PutCrit cr) w
where where
cid = _crID cr cid = _crID cr
theSwarm = Swarm swarmSet theSwarm = Swarm swarmSet
swarmSet = S.fromList $ map (_crID . _unPutCrit) psts swarmSet = IS.fromList $ map (_crID . _unPutCrit) psts
+2 -2
View File
@@ -187,9 +187,9 @@ crCrSpring :: Creature -> Creature -> World -> World
crCrSpring c1 c2 w crCrSpring c1 c2 w
| id1 == id2 = w | id1 == id2 = w
| vec == (0,0) = w | vec == (0,0) = w
| diff < comRad = over (creatures . ix id1 . crPos) (+.+ overlap1) | diff >= comRad = w
| otherwise = over (creatures . ix id1 . crPos) (+.+ overlap1)
$ over (creatures . ix id2 . crPos) (-.- overlap2) w $ over (creatures . ix id2 . crPos) (-.- overlap2) w
| otherwise = w
where where
id1 = _crID c1 id1 = _crID c1
id2 = _crID c2 id2 = _crID c2