New generic player implementation
This commit is contained in:
parent
d4db00ce9b
commit
8586ef7b85
4 changed files with 129 additions and 62 deletions
35
DefaultPlayer.hs
Normal file
35
DefaultPlayer.hs
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
{-# LANGUAGE DeriveDataTypeable, PatternGuards #-}
|
||||||
|
|
||||||
|
module DefaultPlayer ( DefaultPlayer(..)
|
||||||
|
) where
|
||||||
|
|
||||||
|
|
||||||
|
import qualified Data.Set as S
|
||||||
|
import Data.Fixed
|
||||||
|
import Data.Ratio ((%))
|
||||||
|
import Data.Typeable
|
||||||
|
|
||||||
|
import GLDriver
|
||||||
|
import Player
|
||||||
|
import Tank
|
||||||
|
|
||||||
|
|
||||||
|
data DefaultPlayer = DefaultPlayer (S.Set Key)
|
||||||
|
deriving (Typeable, Show)
|
||||||
|
|
||||||
|
instance Player DefaultPlayer where
|
||||||
|
playerMovement (DefaultPlayer keys) _ = playerMovement' keys
|
||||||
|
|
||||||
|
handleEvent (DefaultPlayer keys) ev
|
||||||
|
| Just (KeyPressEvent key) <- fromEvent ev = DefaultPlayer $ S.insert key keys
|
||||||
|
| Just (KeyReleaseEvent key) <- fromEvent ev = DefaultPlayer $ S.delete key keys
|
||||||
|
| otherwise = DefaultPlayer keys
|
||||||
|
|
||||||
|
|
||||||
|
playerMovement' :: S.Set Key -> (DefaultPlayer, Maybe Micro, Bool)
|
||||||
|
playerMovement' keys = (DefaultPlayer keys, angle, move)
|
||||||
|
where
|
||||||
|
x = (if (S.member KeyLeft keys) then (-1) else 0) + (if (S.member KeyRight keys) then 1 else 0)
|
||||||
|
y = (if (S.member KeyDown keys) then (-1) else 0) + (if (S.member KeyUp keys) then 1 else 0)
|
||||||
|
move = (x /= 0 || y /= 0)
|
||||||
|
angle = if move then Just $ fromRational $ round ((atan2 y x)*1000000*180/pi)%1000000 else Nothing
|
129
HTanks.hs
129
HTanks.hs
|
@ -4,6 +4,8 @@ import Game
|
||||||
import Level
|
import Level
|
||||||
import Render
|
import Render
|
||||||
import Tank
|
import Tank
|
||||||
|
import Player
|
||||||
|
import DefaultPlayer
|
||||||
|
|
||||||
import GLDriver
|
import GLDriver
|
||||||
import GLX
|
import GLX
|
||||||
|
@ -22,7 +24,7 @@ data MainState = MainState
|
||||||
{ run :: !Bool
|
{ run :: !Bool
|
||||||
, driver :: !SomeDriver
|
, driver :: !SomeDriver
|
||||||
, time :: !UTCTime
|
, time :: !UTCTime
|
||||||
, keyset :: !(S.Set Key)
|
, players :: ![SomePlayer]
|
||||||
}
|
}
|
||||||
|
|
||||||
newtype MainT m a = MainT (StateT MainState m a)
|
newtype MainT m a = MainT (StateT MainState m a)
|
||||||
|
@ -40,7 +42,7 @@ main = do
|
||||||
|
|
||||||
when (initialized gl) $ do
|
when (initialized gl) $ do
|
||||||
currentTime <- getCurrentTime
|
currentTime <- getCurrentTime
|
||||||
let mainState = MainState {run = True, driver = SomeDriver gl, time = currentTime, keyset = S.empty}
|
let mainState = MainState {run = True, driver = SomeDriver gl, time = currentTime, players = [SomePlayer $ DefaultPlayer S.empty]}
|
||||||
gameState = GameState {level = testLevel, tanks = [Tank 0.0 0.0 0 0 2 360 False], textures = M.empty}
|
gameState = GameState {level = testLevel, tanks = [Tank 0.0 0.0 0 0 2 360 False], textures = M.empty}
|
||||||
|
|
||||||
runGame gameState $ do
|
runGame gameState $ do
|
||||||
|
@ -80,82 +82,87 @@ mainLoop = do
|
||||||
when runnext mainLoop
|
when runnext mainLoop
|
||||||
|
|
||||||
|
|
||||||
playerMovement :: Main (Maybe Micro, Bool)
|
|
||||||
playerMovement = do
|
updateAngle :: Micro -> State Tank ()
|
||||||
keys <- gets keyset
|
updateAngle angle = do
|
||||||
|
oldangle <- gets dir
|
||||||
|
tspeed <- gets turnspeed >>= return . (/1000)
|
||||||
|
|
||||||
let x = (if (S.member KeyLeft keys) then (-1) else 0) + (if (S.member KeyRight keys) then 1 else 0)
|
let diff = angle - oldangle
|
||||||
y = (if (S.member KeyDown keys) then (-1) else 0) + (if (S.member KeyUp keys) then 1 else 0)
|
let diff360 = if (diff > 180)
|
||||||
|
then (diff-360)
|
||||||
|
else if (diff <= -180)
|
||||||
|
then (diff+360)
|
||||||
|
else diff
|
||||||
|
|
||||||
if (x /= 0 || y /= 0)
|
let (diff180, angle180) = if (diff360 > 90)
|
||||||
then return (Just $ fromRational $ round ((atan2 y x)*1000000*180/pi)%1000000, True)
|
then (diff360-180, oldangle+180)
|
||||||
else return (Nothing, False)
|
else if (diff360 <= -90)
|
||||||
|
then (diff360+180, oldangle-180)
|
||||||
|
else (diff360, oldangle)
|
||||||
|
|
||||||
|
let turn = if (diff180 > tspeed)
|
||||||
|
then tspeed
|
||||||
|
else if (diff180 < -tspeed)
|
||||||
|
then (-tspeed)
|
||||||
|
else diff180
|
||||||
|
|
||||||
|
let newangle = angle180 + turn
|
||||||
|
|
||||||
|
let newangle180 = if (newangle > 180)
|
||||||
|
then (newangle-360)
|
||||||
|
else if (newangle <= -180)
|
||||||
|
then (newangle+360)
|
||||||
|
else newangle
|
||||||
|
|
||||||
|
modify $ \tank -> tank {dir = newangle180}
|
||||||
|
|
||||||
|
updateTank :: Maybe Micro -> Bool -> State Tank ()
|
||||||
|
updateTank angle move = do
|
||||||
|
when (isJust angle) $
|
||||||
|
updateAngle $ fromJust angle
|
||||||
|
|
||||||
|
when move $ do
|
||||||
|
tdir <- gets dir
|
||||||
|
tspeed <- gets speed
|
||||||
|
moved <- gets moving
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
modify $ \tank -> tank {posx = x + posx tank, posy = y + posy tank, moving = True}
|
||||||
|
|
||||||
|
when (not move) $ do
|
||||||
|
modify $ \tank -> tank {moving = False}
|
||||||
|
|
||||||
|
|
||||||
simulationStep :: Main ()
|
simulationStep :: Main ()
|
||||||
simulationStep = do
|
simulationStep = do
|
||||||
(angle, move) <- playerMovement
|
oldplayers <- gets players
|
||||||
|
oldtanks <- lift $ gets tanks
|
||||||
|
|
||||||
when (isJust angle) $ do
|
let pt = unzip $ map updateTank' $ zip oldplayers oldtanks
|
||||||
tank <- lift $ gets (head . tanks)
|
|
||||||
let oldangle = dir tank
|
|
||||||
|
|
||||||
let diff = fromJust angle - oldangle
|
|
||||||
let diff360 = if (diff > 180)
|
|
||||||
then (diff-360)
|
|
||||||
else if (diff <= -180)
|
|
||||||
then (diff+360)
|
|
||||||
else diff
|
|
||||||
|
|
||||||
let (diff180, angle180) = if (diff360 > 90)
|
|
||||||
then (diff360-180, oldangle+180)
|
|
||||||
else if (diff360 <= -90)
|
|
||||||
then (diff360+180, oldangle-180)
|
|
||||||
else (diff360, oldangle)
|
|
||||||
|
|
||||||
let tspeed = (turnspeed tank)/1000
|
|
||||||
let turn = if (diff180 > tspeed)
|
|
||||||
then tspeed
|
|
||||||
else if (diff180 < -tspeed)
|
|
||||||
then (-tspeed)
|
|
||||||
else diff180
|
|
||||||
|
|
||||||
let newangle = angle180 + turn
|
|
||||||
|
|
||||||
let newangle180 = if (newangle > 180)
|
|
||||||
then (newangle-360)
|
|
||||||
else if (newangle <= -180)
|
|
||||||
then (newangle+360)
|
|
||||||
else newangle
|
|
||||||
|
|
||||||
lift $ modify $ \state -> state {tanks = (tank {dir = newangle180}):(tail . tanks $ state)}
|
|
||||||
|
|
||||||
when move $ do
|
modify $ \state -> state {players = fst pt}
|
||||||
tank <- lift $ gets (head . tanks)
|
lift $ modify $ \state -> state {tanks = snd pt}
|
||||||
let moved = moving tank
|
where
|
||||||
|
updateTank' (player, tank) = let (p, angle, move) = playerMovement player tank
|
||||||
when (isNothing angle || (isJust angle && (dir tank == fromJust angle)) || moved) $ do
|
t = execState (updateTank angle move) tank
|
||||||
let angle = (fromRational . toRational $ dir tank)*pi/180
|
in (p, t)
|
||||||
x = (speed tank) * fromRational (round ((cos angle)*1000)%1000000)
|
|
||||||
y = (speed tank) * fromRational (round ((sin angle)*1000)%1000000)
|
|
||||||
|
|
||||||
lift $ modify $ \state -> state {tanks = (tank {posx = x + posx tank, posy = y + posy tank, moving = True}):(tail . tanks $ state)}
|
|
||||||
|
|
||||||
when (not move) $ do
|
|
||||||
tank <- lift $ gets (head . tanks)
|
|
||||||
lift $ modify $ \state -> state {tanks = (tank {moving = False}):(tail . tanks $ state)}
|
|
||||||
|
|
||||||
handleEvents :: Main ()
|
handleEvents :: Main ()
|
||||||
handleEvents = do
|
handleEvents = do
|
||||||
event <- gets driver >>= liftIO . nextEvent
|
event <- gets driver >>= liftIO . nextEvent
|
||||||
when (isJust event) $ do
|
when (isJust event) $ do
|
||||||
handleEvent $ fromJust event
|
Main.handleEvent $ fromJust event
|
||||||
|
modify $ \state -> state {players = map (\p -> Player.handleEvent p $ fromJust event) $ players state}
|
||||||
handleEvents
|
handleEvents
|
||||||
|
|
||||||
handleEvent :: SomeEvent -> Main ()
|
handleEvent :: SomeEvent -> Main ()
|
||||||
handleEvent ev
|
handleEvent ev
|
||||||
| Just (ResizeEvent w h) <- fromEvent ev = lift $ resize w h
|
| Just (ResizeEvent w h) <- fromEvent ev = lift $ resize w h
|
||||||
| Just (KeyPressEvent key) <- fromEvent ev = modify $ \state -> state {keyset = S.insert key (keyset state)}
|
|
||||||
| Just (KeyReleaseEvent key) <- fromEvent ev = modify $ \state -> state {keyset = S.delete key (keyset state)}
|
|
||||||
| Just QuitEvent <- fromEvent ev = modify $ \state -> state {run = False}
|
| Just QuitEvent <- fromEvent ev = modify $ \state -> state {run = False}
|
||||||
| otherwise = return ()
|
| otherwise = return ()
|
||||||
|
|
2
Makefile
2
Makefile
|
@ -1,5 +1,5 @@
|
||||||
HSCFILES = Bindings/GLX.hsc Bindings/GLPng.hsc
|
HSCFILES = Bindings/GLX.hsc Bindings/GLPng.hsc
|
||||||
HSFILES = $(HSCFILES:%.hsc=%.hs) GLDriver.hs GLX.hs Texture.hs Tank.hs Level.hs Game.hs Render.hs HTanks.hs
|
HSFILES = $(HSCFILES:%.hsc=%.hs) GLDriver.hs GLX.hs Texture.hs Tank.hs Player.hs DefaultPlayer.hs Level.hs Game.hs Render.hs HTanks.hs
|
||||||
|
|
||||||
all: HTanks
|
all: HTanks
|
||||||
|
|
||||||
|
|
25
Player.hs
Normal file
25
Player.hs
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
{-# LANGUAGE ExistentialQuantification, DeriveDataTypeable #-}
|
||||||
|
|
||||||
|
module Player ( Player(..)
|
||||||
|
, SomePlayer(..)
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Data.Fixed
|
||||||
|
import Data.Typeable
|
||||||
|
|
||||||
|
import Tank
|
||||||
|
import GLDriver (SomeEvent)
|
||||||
|
|
||||||
|
|
||||||
|
class Player a where
|
||||||
|
playerMovement :: a -> Tank -> (a, Maybe Micro, Bool)
|
||||||
|
handleEvent :: a -> SomeEvent -> a
|
||||||
|
|
||||||
|
handleEvent player _ = player
|
||||||
|
|
||||||
|
|
||||||
|
data SomePlayer = forall a. Player a => SomePlayer a
|
||||||
|
|
||||||
|
instance Player SomePlayer where
|
||||||
|
playerMovement (SomePlayer player) tank = (\(p, angle, move) -> (SomePlayer p, angle, move)) $ playerMovement player tank
|
||||||
|
handleEvent (SomePlayer player) event = SomePlayer $ handleEvent player event
|
Reference in a new issue