有什么办法可以在Haskell程序中使用GLUT来满足这个要求吗?

问题描述 投票:2回答:1

我正在使用Haskell和OpenGL开发一个开源3D游戏引擎。初始化窗口和OpenGL上下文的代码,以及获取用户输入的代码当前使用直接WinAPI调用。我现在想要使应用程序成为多平台,并且最初认为GLUT可以用来代替上述解决方案,但是遇到了与回调相关的问题。

在我的应用程序中,函数update_play(在IO monad中)具有以下行。

control <- messagePump (hwnd_ io_box)

其中messagePump是一个IO操作,它检查窗口消息队列中是否有键盘输入,并返回一个Int来指示按下某个有效键或没有有效输入。 update_play对结果进行分支并递归以更新游戏状态。如果您想要更多上下文,请链接到Github上的相关模块:https://github.com/Mushy-pea/Game-Dangerous/blob/master/Game_logic.hs

我对GLUT的问题是它使用回调来处理键盘输入,并且最接近我的要求(在Hackage上的Graphics.UI.GLUT中的绑定)定义如下。

type KeyboardCallback = Char -> Position -> IO ()

下面是一个测试程序,我希望能证明这种方法可行。由于GLUT事件循环使用表示用户输入的参数调用回调(下面的handle_input),因此似乎无法从我的程序的其余部分获取任何信息。因此,我的程序似乎无法从中获取结果,因为它执行此操作可能执行的任何IO操作(例如写入IORef)将要求它具有对此类对象的引用。

在示例中,我尝试使用异常进行通信,但它们没有被捕获,我怀疑是由于handle_input被外部库调用。如果有人可以建议我如何解决这个问题(即从回调中获取一个Int,就像我在实际应用中从messagePump那样做),我将不胜感激。谢谢。

module Main where

import System.IO
import Data.Bits
import Control.Exception
import Graphics.GL.Core33
import Graphics.UI.GLUT

data ControlButton = W_key | S_key | A_key | D_key | Default_control deriving (Eq, Show)

instance Exception ControlButton

main = do
  initialize "test.exe" []
  initialWindowSize $= (Size 800 800)
  initialDisplayMode $= [RGBAMode, WithAlphaComponent, WithDepthBuffer, DoubleBuffered]
  window_id <- createWindow "Test"
  actionOnWindowClose $= Exit
  displayCallback $= repaint_window
  keyboardCallback $= (Just handle_input)
  glClearColor 0 0 0.75 0
  iteration 0

iteration :: Int -> IO ()
iteration c = do
  threadDelay 33333
  putStr ("\nc: " ++ show c)
  control <- catch check_events (\e -> map_control e)
  if control == 1 then putStr "\nW pressed"
  else if control == 2 then putStr "\nS pressed"
  else if control == 3 then putStr "\nA pressed"
  else if control == 4 then putStr "\nD pressed"
  else return ()
  iteration (c + 1)

check_events :: IO Int
check_events = do
  mainLoopEvent
  return 0

map_control :: ControlButton -> IO Int
map_control e = do
  if e == W_key then return 1
  else if e == S_key then return 2
  else if e == A_key then return 3
  else if e == D_key then return 4
  else return 0

repaint_window :: IO ()
repaint_window = do
  glClear (GL_COLOR_BUFFER_BIT .|. GL_DEPTH_BUFFER_BIT)
  swapBuffers

handle_input :: Char -> Position -> IO ()
handle_input key position = do
  if key == 'w' then throw W_key
  else if key == 's' then throw S_key
  else if key == 'a' then throw A_key
  else if key == 'd' then throw D_key
  else throw Default_control

史蒂芬

haskell opengl glut
1个回答
4
投票

你说

它可能执行的任何IO操作(例如写入IORef)都需要它对这样的对象的引用

所以给它一个这样一个对象的参考!

handle_input :: IORef ControlButton -> Char -> Position -> IO ()
handle_input = {- I bet you can write this yourself -}

iteration :: IORef ControlButton -> Int -> IO ()
iteration = {- same -}

main = do
    {- ... -}
    ref <- newIORef Default_control
    keyboardCallback $= Just (handle_input ref)
    {- ... -}
    iteration ref 0
© www.soinside.com 2019 - 2024. All rights reserved.