From e85dc20a4869c91faa3869695d2d19bfe07f9abc Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Tue, 9 Mar 2010 22:36:22 +0100 Subject: Nice tank-border collision detection --- src/CPUPlayer.hs | 2 +- src/Collision.hs | 41 +++++++++++++++++++++++++++++++++++++++++ src/Simulation.hs | 33 ++++++++++++++++++++------------- 3 files changed, 62 insertions(+), 14 deletions(-) create mode 100644 src/Collision.hs (limited to 'src') diff --git a/src/CPUPlayer.hs b/src/CPUPlayer.hs index 0276de3..4a6fb37 100644 --- a/src/CPUPlayer.hs +++ b/src/CPUPlayer.hs @@ -16,4 +16,4 @@ data CPUPlayer = CPUPlayer Micro deriving (Typeable, Show) instance Player CPUPlayer where - playerUpdate (CPUPlayer angle) _ = (CPUPlayer (if (angle+0.1) > 180 then angle-359.9 else angle+0.1), Just angle, True, Just (-angle), False) + playerUpdate (CPUPlayer angle) _ = (CPUPlayer (if (angle+0.1) > 180 then angle-359.08 else angle+0.02), Just angle, True, Just (-angle), False) diff --git a/src/Collision.hs b/src/Collision.hs new file mode 100644 index 0000000..d29738a --- /dev/null +++ b/src/Collision.hs @@ -0,0 +1,41 @@ +module Collision ( collisionTankBorder + ) where + +import Game + +import Data.Fixed +import Data.Ratio + +tankWidth :: Micro +tankWidth = 0.95 + +tankLength :: Micro +tankLength = 0.95 + +collisionTankBorder :: Micro -> Micro -> Tank -> Tank +collisionTankBorder lw lh tank = tank {tankX = newx, tankY = newy} + where + dir = (fromRational . toRational . tankDir $ tank)*pi/180 + cosd = fromRational (round ((cos dir)*1000000)%1000000) + sind = fromRational (round ((sin dir)*1000000)%1000000) + + points = [ (tankLength/2, tankWidth/2) + , (-tankLength/2, tankWidth/2) + , (-tankLength/2, -tankWidth/2) + , (tankLength/2, -tankWidth/2) + ] + + rotp (x, y) = (cosd*x - sind*y, sind*x + cosd*y) + transp (x, y) = (x + tankX tank, y + tankY tank) + + pointst = map (transp . rotp) points + minx = minimum $ map fst pointst + maxx = maximum $ map fst pointst + miny = minimum $ map snd pointst + maxy = maximum $ map snd pointst + + dx = if minx < 0 then (-minx) else if maxx > lw then (-maxx+lw) else 0 + dy = if miny < 0 then (-miny) else if maxy > lh then (-maxy+lh) else 0 + + newx = (tankX tank) + dx + newy = (tankY tank) + dy diff --git a/src/Simulation.hs b/src/Simulation.hs index f45ab99..33465cc 100644 --- a/src/Simulation.hs +++ b/src/Simulation.hs @@ -1,6 +1,7 @@ module Simulation ( simulationStep ) where +import Collision import Game import Level import MainLoop @@ -47,8 +48,8 @@ updateAngle angle = do modify $ \tank -> tank {tankDir = newangle180} -updateTank :: Maybe Micro -> Bool -> Maybe Micro -> State Tank () -updateTank angle move aangle = do +updateTank :: GameState -> Maybe Micro -> Bool -> Maybe Micro -> State Tank () +updateTank game angle move aangle = do when (isJust angle) $ updateAngle $ fromJust angle @@ -56,19 +57,24 @@ updateTank angle move aangle = do modify $ \tank -> tank {tankAim = fromJust aangle} when move $ do - tdir <- gets tankDir - tspeed <- gets tankSpeed - moved <- gets tankMoving + tank <- get + let tdir = tankDir tank + tspeed = tankSpeed tank + moved = tankMoving tank when (isNothing angle || (isJust angle && (tdir == fromJust angle)) || moved) $ do let anglej = (fromRational . toRational $ tdir)*pi/180 - x = tspeed * fromRational (round ((cos anglej)*1000)%1000000) - y = tspeed * fromRational (round ((sin anglej)*1000)%1000000) + dx = tspeed * fromRational (round ((cos anglej)*1000)%1000000) + dy = tspeed * fromRational (round ((sin anglej)*1000)%1000000) - modify $ \tank -> tank {tankX = x + tankX tank, tankY = y + tankY tank, tankMoving = True} + put tank {tankX = dx + tankX tank, tankY = dy + tankY tank, tankMoving = True} when (not move) $ do modify $ \tank -> tank {tankMoving = False} + + let lw = fromIntegral . levelWidth . level $ game + lh = fromIntegral . levelHeight . level $ game + modify $ collisionTankBorder lw lh updateBullet :: GameState -> State Bullet Bool @@ -96,9 +102,10 @@ updateBullet game = do simulationStep :: Main () simulationStep = do oldplayers <- gets players - oldtanks <- lift $ gets tanks + game <- lift get + let oldtanks = tanks game - let (p, t, s) = unzip3 $ map updateTank' $ zip oldplayers oldtanks + let (p, t, s) = unzip3 $ map (updateTank' game) $ zip oldplayers oldtanks ts = zip3 t s [0..] shootingtanks = map (\(tank, _, n) -> (tank, n)) $ filter (\(tank, shoot, _) -> shoot && (tankBulletsLeft tank) > 0) $ ts newtanks = map (\(tank, shoot, _) -> if (shoot && (tankBulletsLeft tank) > 0) then tank {tankBulletsLeft = (tankBulletsLeft tank) - 1} else tank) $ ts @@ -117,8 +124,8 @@ simulationStep = do thetanks = map (\(tank, n) -> tank {tankBulletsLeft = (tankBulletsLeft tank) + (countLostTankBullets n thebullets)}) $ zip newtanks [0..] in state {tanks = thetanks, bullets = map snd . filter fst $ thebullets} where - updateTank' (player, tank) = let (p, angle, move, aangle, bullet) = playerUpdate player tank - t = execState (updateTank angle move aangle) tank - in (p, t, bullet) + updateTank' game (player, tank) = let (p, angle, move, aangle, bullet) = playerUpdate player tank + t = execState (updateTank game angle move aangle) tank + in (p, t, bullet) countLostTankBullets n (x:xs) = (if ((not . fst $ x) && (n == (bulletTank . snd $ x))) then 1 else 0) + (countLostTankBullets n xs) countLostTankBullets n [] = 0 -- cgit v1.2.3