我如何使用MVars在我的乒乓haskell游戏中移动球拍? [英] How can i use MVars to move paddles on my pingpong haskell game?

查看:112
本文介绍了我如何使用MVars在我的乒乓haskell游戏中移动球拍?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经具有在Haskell的乒乓球游戏中移动2个桨的功能.我要更改,因此现在使用MVars.

I already have a function that moves 2 paddles in a ping pong game in haskell. I want to change so it uses MVars now.

我知道我需要将wHeld,sHeld,downHeld和upHeld更改为MVars,但是关于如何更改movePaddle以处理MVars的任何想法?

I know that i need to change wHeld, sHeld, downHeld and upHeld to MVars but any ideas on how to change movePaddle to deal with MVars?

另外,当我声明将MVars举为MVar时,它在派生show时也会显示错误((Show MVar Bool的非实例)

Also when i declare wHeld an MVars it shows a error on deriving show (Non instance for (Show MVar Bool))

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 

movePaddle :: PongGame -> PongGame
movePaddle = moveLeftPaddle . moveRightPaddle 
moveLeftPaddle game
          | (wHeld game) = game {playerLPos = paddleUp (playerLPos game)}
          | (sHeld game) = game {playerLPos = paddleDn (playerLPos game)}
          | otherwise = game
moveRightPaddle game
          | (upHeld   game) = game {playerRPos = paddleUp (playerRPos game)}
          | (downHeld game) = game {playerRPos = paddleDn (playerRPos game)}
          | otherwise = game

paddleUp pos = min (pos + 10) paddleMax
paddleDn pos = max (pos - 10) paddleMin

推荐答案

MVars的工作方式是类型MVar Bool的值是不透明的令牌",引用了Bool的存储位置.您可以创建此类令牌,​​并使用IO操作读取和修改其关联存储位置的内容.

The way MVars work is that a value of type MVar Bool is an opaque "token" referencing a storage location for a Bool. You create such a token and read and modify the contents of its associated storage location using IO actions.

默认情况下,令牌本身(MVar Bool值)没有Show实例.为了进行调试,您可以添加以下内容:

The token itself (the MVar Bool value) has no Show instance by default. For debugging purposes, you could add one:

instance Show (MVar a) where show _ = "<MVar>"

这将允许您派生PongGameShow实例,而不会收到错误消息.但是,如果没有严重的IO滥用,Show实例将无法显示存储在MVars中的值,因此您可能需要考虑编写一个函数dumpGame :: PongGame -> IO (),该函数可以用所有MVar值,可让您完全跳过Show实例.

This will allow you to derive a Show instance for PongGame without getting an error message. However, the values stored in the MVars can't be displayed by the Show instance without some egregious IO abuse, so you might want to consider writing a function dumpGame :: PongGame -> IO () that pretty-prints the current game state with all the MVar values, letting you skip the Show instance entirely.

无论如何,要重写程序以在关键的PongGame字段中使用MVar:

Anyway, to rewrite your program to use MVars in key PongGame fields:

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
  ...
  }

您将要重写movePaddle及其子功能以在IO monad中运行:

you'll want to rewrite your movePaddle and its subfunctions to run in the IO monad:

movePaddle :: PongGame -> IO PongGame
moveLeftPaddle :: PongGame -> IO PongGame
moveRightPaddle :: PongGame -> IO PongGame

movePaddle中,您可以将.运算符替换为Control.Monad中的<=<,这是功能组合的单原子等效项:

In movePaddle, you can replace the . operator with <=< from Control.Monad, which is the monadic equivalent of function composition:

movePaddle = moveLeftPaddle <=< moveRightPaddle

这基本上是以下简称:

movePaddle game = do
    game1 <- moveRightPaddle game
    game2 <- moveLeftPaddle game1
    return game2

然后,您需要通过执行IO操作来重写moveLeftPaddlemoveRightPaddle来访问MVar的内容:

Then, you'll need to rewrite moveLeftPaddle and moveRightPaddle to access the contents of the MVars by executing IO actions:

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是一个简单的纯函数调用,它检索与wHeld字段关联的类型MVar Bool令牌.然后,我们执行IO操作readMVar <this_token>以实际检索Bool值,然后可以在case语句中对其进行操作以更新游戏状态.

To be clear, the function call wHeld game is a simple, pure function call that retrieves the token of type MVar Bool associated with the wHeld field. We then execute the IO action readMVar <this_token> to actually retrieve the Bool value, which we can then act on in a case statement to update the game state.

在程序的其他地方,您将需要一个setup例程来创建这些MVar:

Elsewhere in your program, you'll need a setup routine that creates these MVars:

initGame :: IO PongGame
initGame = do
  ...
  wHeld <- newMVar False
  sHeld <- newMVar False
  ...
  return $ Game ... wHeld sHeld ...

您可能会有一些线程正在运行类似这样的函数:

and you'll presumably have some thread that's running a function like:

processKeyEvent :: KeyEvent -> PongGame -> IO ()
processKeyEvent event game = do
  ...
  case event of
     ...
     KeyDown 'W' -> void $ swapMVar (wHeld game) True
     KeyUp   'W' -> void $ swapMVar (wHeld game) False
     ...

这篇关于我如何使用MVars在我的乒乓haskell游戏中移动球拍?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆