diff options
Diffstat (limited to 'src/Simulation.hs')
-rw-r--r-- | src/Simulation.hs | 82 |
1 files changed, 36 insertions, 46 deletions
diff --git a/src/Simulation.hs b/src/Simulation.hs index c1debb2..3cf4fec 100644 --- a/src/Simulation.hs +++ b/src/Simulation.hs @@ -7,31 +7,33 @@ import Level import MainLoop import Player import Tank +import Transformable +import Vector import Control.Monad.State -import Data.Fixed import Data.List import Data.Maybe -import Data.Ratio +import Data.VectorSpace -updateAngle :: Micro -> Tank -> Tank -updateAngle angle tank = tank {tankDir = newangle180} +updateAngle :: Vector -> Tank -> Tank +updateAngle dir tank = tank {tankDir = rotate newangle >< Vector 1 0} where - oldangle = tankDir tank + oldangle = toAngle . tankDir $ tank + angle = toAngle dir tspeed = (tankTurnspeed tank)/100 diff = angle - oldangle - diff360 = if (diff > 180) - then (diff-360) - else if (diff <= -180) - then (diff+360) + diff360 = if (diff > pi) + then (diff-2*pi) + else if (diff <= -pi) + then (diff+2*pi) else diff - (diff180, angle180) = if (diff360 > 90) - then (diff360-180, oldangle+180) - else if (diff360 <= -90) - then (diff360+180, oldangle-180) + (diff180, angle180) = if (diff360 > pi/2) + then (diff360-180, oldangle+pi) + else if (diff360 <= -pi/2) + then (diff360+pi, oldangle-pi) else (diff360, oldangle) turn = if (diff180 > tspeed) @@ -41,21 +43,19 @@ updateAngle angle tank = tank {tankDir = newangle180} else diff180 newangle = angle180 + turn - - newangle180 = if (newangle > 180) - then (newangle-360) - else if (newangle <= -180) - then (newangle+360) - else newangle +approx :: Vector -> Vector -> Bool +approx (Vector x1 y1) (Vector x2 y2) = x1 `approx'` x2 && y1 `approx'` y2 + where + approx' a b = (abs (a-b)) < 0.000001 -updateTank :: GameState -> Maybe Micro -> Bool -> Maybe Micro -> State Tank () -updateTank game angle move aangle = do - when (isJust angle) $ - modify $ updateAngle $ fromJust angle +updateTank :: GameState -> Maybe Vector -> Bool -> Maybe Vector -> State Tank () +updateTank game dir move aim = do + when (isJust dir) $ + modify $ updateAngle $ fromJust dir - when (isJust aangle) $ - modify $ \tank -> tank {tankAim = fromJust aangle} + when (isJust aim) $ + modify $ \tank -> tank {tankAim = fromJust aim} when move $ do tank <- get @@ -63,12 +63,8 @@ updateTank game angle move aangle = do tspeed = tankSpeed tank moved = tankMoving tank - when (isNothing angle || (isJust angle && (tdir == fromJust angle)) || moved) $ do - let anglej = (fromRational . toRational $ tdir)*pi/180 - dx = tspeed * fromRational (round ((cos anglej)*1000)%100000) - dy = tspeed * fromRational (round ((sin anglej)*1000)%100000) - - put tank {tankX = dx + tankX tank, tankY = dy + tankY tank, tankMoving = True} + when (isNothing dir || (isJust dir && (tdir `approx` fromJust dir) || moved)) $ + put $ translateV (tdir ^* (tspeed/100)) >< tank {tankMoving = True} when (not move) $ do modify $ \tank -> tank {tankMoving = False} @@ -79,22 +75,17 @@ updateTank game angle move aangle = do updateBullet :: GameState -> Bullet -> (Bullet, Bool) -updateBullet game bullet = (bullet {bulletX = newx, bulletY = newy, bulletDir = dir3, bulletBouncesLeft = bounces3}, bounces3 >= 0) +updateBullet game bullet = (bullet {bulletPos = Vertex x' y', bulletDir = Vector dx' dy', bulletBouncesLeft = bounces3}, bounces3 >= 0) where - angle = (fromRational . toRational . bulletDir $ bullet)*pi/180 speed = bulletSpeed bullet - dx = speed * fromRational (round ((cos angle)*1000)%100000) - dy = speed * fromRational (round ((sin angle)*1000)%100000) - x = dx + bulletX bullet - y = dy + bulletY bullet + d@(Vector dx dy) = bulletDir bullet + Vertex x y = translateV (d ^* (speed/100)) >< bulletPos bullet + bounces = bulletBouncesLeft bullet lw = fromIntegral . levelWidth . level $ game lh = fromIntegral . levelHeight . level $ game - dir = bulletDir bullet - bounces = bulletBouncesLeft bullet - sg = if dir < 0 then -1 else 1 - (newx, dir2, bounces2) = if x < 0 then (-x, sg*180 - dir, bounces-1) else if x > lw then (2*lw-x, sg*180 - dir, bounces-1) else (x, dir, bounces) - (newy, dir3, bounces3) = if y < 0 then (-y, -dir2, bounces2-1) else if y > lh then (2*lh-y, -dir2, bounces2-1) else (y, dir2, bounces2) + (x', dx', bounces2) = if x < 0 then (-x, -dx, bounces-1) else if x > lw then (2*lw-x, -dx, bounces-1) else (x, dx, bounces) + (y', dy', bounces3) = if y < 0 then (-y, -dy, bounces2-1) else if y > lh then (2*lh-y, -dy, bounces2-1) else (y, dy, bounces2) gameStep :: [(Tank, Bool)] -> GameState -> GameState gameStep tanksshoot state = state {tanks = thetanks, bullets = newbullets ++ (map snd . filter fst $ leftbullets2)} @@ -104,8 +95,7 @@ gameStep tanksshoot state = state {tanks = thetanks, bullets = newbullets ++ (ma thetanks = map (\(tank, n) -> tank {tankBulletsLeft = (tankBulletsLeft tank) + (countLostTankBullets n leftbullets2)}) $ zip newtanks2 [0..] newtanks = map (\(tank, shoot, _) -> if (shoot && (tankBulletsLeft tank) > 0) then tank {tankBulletsLeft = (tankBulletsLeft tank) - 1} else tank) $ ts newbullets = map (\(tank, n) -> Bullet - { bulletX = tankX tank - , bulletY = tankY tank + { bulletPos = tankPos tank , bulletDir = tankAim tank , bulletSpeed = tankBulletSpeed tank , bulletBouncesLeft = tankBulletBounces tank @@ -144,6 +134,6 @@ simulationStep = do modify $ \state -> state {players = p, gameState = gameStep (zip t s) (gameState state)} where updateTank' game (player, tank) = do - (p, angle, move, aangle, shoot) <- playerUpdate player tank - let t = execState (updateTank game angle move aangle) tank + (p, dir, move, aim, shoot) <- playerUpdate player tank + let t = execState (updateTank game dir move aim) tank return $ if (tankLife tank > 0) then (p, t, shoot) else (player, tank, False) |