5

我正在学习如何使用 Gloss 库在 Haskell 中制作一些动画。

考虑下面的代码,它动画了一个随时间缩小和扩大其半径的圆。

import Graphics.Gloss
import Graphics.Gloss.Interface.Pure.Game

type Radius = Float
type RealTime   = Float

data World = World Radius RealTime

main :: IO ()
main
 = do   let initWorld = World 100.0 0
        let windowSize = (800,800)
        let windowPosition = (200,200)
        putStrLn "Before play"
        play (InWindow "Wobbling Circle" windowSize windowPosition)
              white 40 initWorld renderWorld handleEvent stepWorld
        putStrLn "After play"

renderWorld :: World -> Picture
renderWorld (World rad rtime ) = Pictures [ Circle rad ]

handleEvent :: Event -> World -> World
handleEvent _ = id

stepWorld ::  Float -> World -> World -- wobbling circle
stepWorld  _ (World _ rtime)  = World (100 * sin rtime) (rtime+0.1) 

ghc --make -O2 -threaded Main.hs我在 Ubuntu 14.04 机器上编译了这段代码。

当我运行代码时,会打印出“播放前”语句,然后动画按预期开始。但是,当我关闭动画窗口时,代码会立即终止,而不会打印“播放后”语句。这是为什么?

4

1 回答 1

2

大概您正在使用 GLUT 后端(默认)。查看一些源代码gloss与注释完全相同):

instance Backend GLUTState where
        initBackendState           = glutStateInit
        initializeBackend          = initializeGLUT

        -- non-freeglut doesn't like this: (\_ -> GLUT.leaveMainLoop)
        exitBackend                = (\_ -> System.exitWith System.ExitSuccess)

....

当它退出主循环时,无论它是什么,gloss都会调用。exitBackend对于 GLUT,这只是调用System.exitWith自然会终止您的程序。更明智的做法是调用leaveMainLoop,但正如代码中的注释所说,glut其他的freeglut实现不能很好地与该函数一起工作(为什么?谁知道。这就是光泽的作者声称的)。

您可能的解决方案是freeglut专门使用并修改源代码gloss来更改exitBackend;或者使用没有这个问题的 GLFW 后端。

于 2016-09-21T16:43:35.500 回答