Nice tank-border collision detection
This commit is contained in:
parent
f3d9814ad5
commit
e85dc20a48
4 changed files with 65 additions and 16 deletions
|
@ -14,6 +14,7 @@ data-files: tex/*.png
|
||||||
executable: HTanks
|
executable: HTanks
|
||||||
hs-source-dirs: src
|
hs-source-dirs: src
|
||||||
main-is: HTanks.hs
|
main-is: HTanks.hs
|
||||||
other-modules: CPUPlayer, DefaultPlayer, Game, GLDriver, GLX, Level, MainLoop, Paths_htanks, Player, Render, Simulation, Texture, Bindings.GLX, Bindings.GLPng
|
other-modules: Collision, CPUPlayer, DefaultPlayer, Game, GLDriver, GLX, Level, MainLoop, Paths_htanks, Player, Render, Simulation, Texture,
|
||||||
ghc-options: -threaded
|
Bindings.GLX, Bindings.GLPng
|
||||||
|
ghc-options: -threaded -O2
|
||||||
extra-libraries: glpng
|
extra-libraries: glpng
|
||||||
|
|
|
@ -16,4 +16,4 @@ data CPUPlayer = CPUPlayer Micro
|
||||||
deriving (Typeable, Show)
|
deriving (Typeable, Show)
|
||||||
|
|
||||||
instance Player CPUPlayer where
|
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)
|
||||||
|
|
41
src/Collision.hs
Normal file
41
src/Collision.hs
Normal file
|
@ -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
|
|
@ -1,6 +1,7 @@
|
||||||
module Simulation ( simulationStep
|
module Simulation ( simulationStep
|
||||||
) where
|
) where
|
||||||
|
|
||||||
|
import Collision
|
||||||
import Game
|
import Game
|
||||||
import Level
|
import Level
|
||||||
import MainLoop
|
import MainLoop
|
||||||
|
@ -47,8 +48,8 @@ updateAngle angle = do
|
||||||
modify $ \tank -> tank {tankDir = newangle180}
|
modify $ \tank -> tank {tankDir = newangle180}
|
||||||
|
|
||||||
|
|
||||||
updateTank :: Maybe Micro -> Bool -> Maybe Micro -> State Tank ()
|
updateTank :: GameState -> Maybe Micro -> Bool -> Maybe Micro -> State Tank ()
|
||||||
updateTank angle move aangle = do
|
updateTank game angle move aangle = do
|
||||||
when (isJust angle) $
|
when (isJust angle) $
|
||||||
updateAngle $ fromJust angle
|
updateAngle $ fromJust angle
|
||||||
|
|
||||||
|
@ -56,20 +57,25 @@ updateTank angle move aangle = do
|
||||||
modify $ \tank -> tank {tankAim = fromJust aangle}
|
modify $ \tank -> tank {tankAim = fromJust aangle}
|
||||||
|
|
||||||
when move $ do
|
when move $ do
|
||||||
tdir <- gets tankDir
|
tank <- get
|
||||||
tspeed <- gets tankSpeed
|
let tdir = tankDir tank
|
||||||
moved <- gets tankMoving
|
tspeed = tankSpeed tank
|
||||||
|
moved = tankMoving tank
|
||||||
|
|
||||||
when (isNothing angle || (isJust angle && (tdir == fromJust angle)) || moved) $ do
|
when (isNothing angle || (isJust angle && (tdir == fromJust angle)) || moved) $ do
|
||||||
let anglej = (fromRational . toRational $ tdir)*pi/180
|
let anglej = (fromRational . toRational $ tdir)*pi/180
|
||||||
x = tspeed * fromRational (round ((cos anglej)*1000)%1000000)
|
dx = tspeed * fromRational (round ((cos anglej)*1000)%1000000)
|
||||||
y = tspeed * fromRational (round ((sin 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
|
when (not move) $ do
|
||||||
modify $ \tank -> tank {tankMoving = False}
|
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
|
updateBullet :: GameState -> State Bullet Bool
|
||||||
updateBullet game = do
|
updateBullet game = do
|
||||||
|
@ -96,9 +102,10 @@ updateBullet game = do
|
||||||
simulationStep :: Main ()
|
simulationStep :: Main ()
|
||||||
simulationStep = do
|
simulationStep = do
|
||||||
oldplayers <- gets players
|
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..]
|
ts = zip3 t s [0..]
|
||||||
shootingtanks = map (\(tank, _, n) -> (tank, n)) $ filter (\(tank, shoot, _) -> shoot && (tankBulletsLeft tank) > 0) $ ts
|
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
|
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..]
|
thetanks = map (\(tank, n) -> tank {tankBulletsLeft = (tankBulletsLeft tank) + (countLostTankBullets n thebullets)}) $ zip newtanks [0..]
|
||||||
in state {tanks = thetanks, bullets = map snd . filter fst $ thebullets}
|
in state {tanks = thetanks, bullets = map snd . filter fst $ thebullets}
|
||||||
where
|
where
|
||||||
updateTank' (player, tank) = let (p, angle, move, aangle, bullet) = playerUpdate player tank
|
updateTank' game (player, tank) = let (p, angle, move, aangle, bullet) = playerUpdate player tank
|
||||||
t = execState (updateTank angle move aangle) tank
|
t = execState (updateTank game angle move aangle) tank
|
||||||
in (p, t, bullet)
|
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 (x:xs) = (if ((not . fst $ x) && (n == (bulletTank . snd $ x))) then 1 else 0) + (countLostTankBullets n xs)
|
||||||
countLostTankBullets n [] = 0
|
countLostTankBullets n [] = 0
|
||||||
|
|
Reference in a new issue