我正在使用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 ()
Run Code Online (Sandbox Code Playgroud)
这是world我正在使用的类型:
data Game = Game
{ levelNumber :: Int,
currentLevel :: Level Square,
won :: Bool }
Run Code Online (Sandbox Code Playgroud)
其中Levels包含当前级别的块.我正在Game使用类似的东西读取(实际上还没有实现广义的,但这基本上就是文件名参数):
startGame = do
lvl <- readFile "levels/level001.lvl"
let lvl' = parseLevel lvl
return $ Game 1 lvl' False
Run Code Online (Sandbox Code Playgroud)
所以,我的困难是由于更新功能而产生的play.如果我只是在单个级别上操作,我可以很容易地获取Game并生成一个Picture(和一个Game等),而不必从文件系统中读取任何数据,但是因为我在文件中间加载了文件中的级别.游戏,我不知道如何避免制作我Game的所有IO Game.也许在这种情况下这是不可能的,也许这是有充分理由的?我将始终在运行Game,从文件中提取,但是我不知道这是否是可以避免的,在任何给定的点,如果是,我想避免它.
我最终使用了Graphics.Gloss.Interface.IO.GameplayIO的Gloss 。我需要更改我的几个函数以对纯数据类型进行操作并将它们包装在 monad 中输出。以下是我必须更改的类型:IO
worldToPicture :: World -> IO Picture
eventHandler :: Event -> World -> IO Picture
stepWorld :: Float -> World -> IO World
Run Code Online (Sandbox Code Playgroud)
在大多数情况下,这只会在我当前现有的功能中添加一些return功能,但最终会添加很多功能(例如即时保存、加载新关卡、使用 BMP 文件进行图形等)。我还能够保留几乎所有当前现有的代码,IO因为新函数仍然采用纯数据类型作为参数。它最终成为一个非常简单的重构并完美地解决了我的问题。