我已经具有在Haskell的乒乓球游戏中移动2个桨的功能。我要更改,因此现在使用MVars。
我知道我需要将wHeld,sHeld,downHeld和upHeld更改为MVars,但是关于如何更改movePaddle以处理MVars的任何想法?
另外,当我声明将MVars举为节目时,也会显示错误((Show MVar Bool的非实例)
None
data PongGame = Game
{ ballLoc :: (Float, Float) -- ^ Pong ball (x, y) location.
, ballVel :: (Float, Float) -- ^ Pong ball (x, y) velocity.
, player1 :: Float -- ^ Left player paddle height.
-- Zero is the middle of the screen.
, player2 :: Float -- ^ Right player paddle height.
, playerRPos :: Float -- posicao do player right
, playerLPos :: Float --- posicao do player left
, ghci :: Bool -- pausar
, showMenu :: Bool -- mostrar o menu
, wHeld :: MVar Bool -- segura o w
, sHeld :: Bool -- segura os
, downHeld :: Bool -- segura down
, upHeld :: Bool -- segura para cima
, playerLScore :: Int -- score do jogador left
, playerRScore :: Int -- score do jogador right
, paused :: Bool
} deriving Show
答案 0 :(得分:3)
MVars的工作方式是类型MVar Bool
的值是一个不透明的“令牌”,它引用了Bool
的存储位置。您可以创建此类令牌,并使用IO操作读取和修改其关联存储位置的内容。
默认情况下,令牌本身(MVar Bool
值)没有Show
实例。为了进行调试,您可以添加一个:
instance Show (MVar a) where show _ = "<MVar>"
这将允许您派生Show
的{{1}}实例而不会收到错误消息。但是,PongGame
实例在没有严重的IO滥用的情况下无法显示MVars
中存储的值,因此您可能需要考虑编写一个功能漂亮的Show
函数具有所有MVar值的当前游戏状态,可让您完全跳过dumpGame :: PongGame -> IO ()
实例。
无论如何,要重写程序以在键Show
字段中使用MVar:
PongGame
您将要重写data PongGame = Game
{
...
, wHeld :: MVar Bool -- segura o w
, sHeld :: MVar Bool -- segura os
, downHeld :: MVar Bool -- segura down
, upHeld :: MVar Bool -- segura para cima
...
}
及其子功能以在IO monad中运行:
movePaddle
在movePaddle :: PongGame -> IO PongGame
moveLeftPaddle :: PongGame -> IO PongGame
moveRightPaddle :: PongGame -> IO PongGame
中,您可以将movePaddle
中的.
替换为<=<
的{{1}}运算符,这等效于函数组合的单子形式:
Control.Monad
这基本上是以下简称:
movePaddle = moveLeftPaddle <=< moveRightPaddle
然后,您需要通过执行IO操作来重写movePaddle game = do
game1 <- moveRightPaddle game
game2 <- moveLeftPaddle game1
return game2
和moveLeftPaddle
来访问MVar的内容:
moveRightPaddle
与moveLeftPaddle game
= do up <- readMVar (wHeld game)
dn <- readMVar (sHeld game)
case (up, dn) of
(True, False) -> return $ game {playerLPos = paddleUp (playerLPos game)}
(False, True) -> return $ game {playerLPos = paddleDn (playerLPos game)}
_ -> return game
的定义类似。
要清楚,函数调用moveRightPaddle
是一个简单的纯函数调用,它检索与wHeld game
字段关联的类型MVar Bool
的令牌。然后,我们执行IO操作wHeld
以实际获取readMVar <this_token>
的值,然后可以在Bool
语句中对其进行操作以更新游戏状态。
在程序的其他地方,您将需要一个case
例程来创建这些MVar:
setup
您可能会有一些线程正在运行类似这样的函数:
initGame :: IO PongGame
initGame = do
...
wHeld <- newMVar False
sHeld <- newMVar False
...
return $ Game ... wHeld sHeld ...