6

我正在使用 Gloss 库在 Haskell 中编写 Sokoban 程序,并且我已经达到了我想要的程度,当玩家通过关卡时,从文本文件加载新关卡并让程序继续.

由于 Gloss 的限制,我对此有点困难——play设置游戏并使其不断更新的功能如下所示:

play    :: forall world
        .  Display                      -- ^ Display mode.
        -> Color                        -- ^ Background color.
        -> Int                          -- ^ Number of simulation steps to take for each second of real time.
        -> world                        -- ^ The initial world.
        -> (world -> Picture)           -- ^ A function to convert the world a picture.
        -> (Event -> world -> world)    -- ^ A function to handle input events.
        -> (Float -> world -> world)    -- ^ A function to step the world one iteration.
                                        --   It is passed the period of time (in seconds) needing to be advanced.
        -> IO ()

(直接从http://hackage.haskell.org/packages/archive/gloss/1.7.4.1/doc/html/Graphics-Gloss-Interface-Pure-Game.html复制)

这是world我正在使用的类型:

data Game = Game
  { levelNumber  :: Int,
    currentLevel :: Level Square,
    won          :: Bool }

其中Levels 包含当前关卡中的块。我正在Game使用类似这样的东西在 s 中阅读(实际上还没有制作一个通用的,但这基本上就是使用文件名参数的全部内容):

startGame = do
  lvl <- readFile "levels/level001.lvl"
  let lvl' = parseLevel lvl
  return $ Game 1 lvl' False

所以,我的困难是由于play. 如果我只是在单个级别上操作,我可以轻松地获取 aGame并生成 a Picture(和 aGame等),而无需从文件系统中读取任何数据,但是因为我在中间加载文件中的级别游戏,我不知道如何避免让我所有Game的s IO Game。也许在这种情况下这是不可能的,也许这是有充分理由的?我始终对Game从文件中提取的内容进行操作,但我不知道在任何给定点是否可以避免,如果可以,我想避免它。

4

1 回答 1

3

我最终使用了playIO来自Graphics.Gloss.Interface.IO.Game的 Gloss 。我需要更改我的几个函数以对纯数据类型进行操作并将它们输出包装在IOmonad 中。以下是我必须更改的类型:

worldToPicture :: World -> IO Picture
eventHandler   :: Event -> World -> IO Picture
stepWorld      :: Float -> World -> IO World 

在大多数情况下,这只会在return我当前存在的函数中添加一些 s,但最终会添加很多功能(例如即时保存、加载新关卡、使用 BMP 文件进行图形等)。IO由于新函数仍将纯数据类型作为参数,因此我还能够保留几乎所有当前存在的代码。它最终成为一个非常简单的重构并完美地解决了我的问题。

于 2013-04-03T02:47:20.900 回答