Haskell中的计算机游戏 - 小工具工具包需要

Nik*_*gyu 8 user-interface haskell sdl

我正在Haskell中编写一个小型RTS游戏,现在是时候为它创建一些GUI(按钮,菜单等).但是,我没有任何GUI工具包创建经验,所以我要感谢有关如何选择正确的数据类型,事件处理例程等的想法.

所需功能:菜单屏幕(主要,加载/保存,设置,网络游戏),文本输入,游戏界面(主屏幕(C&C)),按钮,选择和复选框.

我当前的方法是将整个GUI表示为一个状态机,它在它们之间有许多状态和转换,当事件到达时触发它们:

-- Local client state.  Actual game state is stored on the server
-- and is updated/synced separately.
data ClientState = […]

-- Keyboard state, mouse state, quadtree of clickables, list of
-- widgets.
data UIState = […]

uiCycle :: UIState -> ClientState -> IO ()
uiCycle uiState clientState = do
  event <- waitEvent
  let widget = findWidget uiState event
  let (uiState', clientStateAction, ioAction) =
        uiTransition widget event uiState clientState
  -- Update game state (execute game logic).
  let clientState' = clientStateAction clientState
  -- Redraw appropriate surfaces etc.
  ioAction
  uiCycle uiState' clientState'
Run Code Online (Sandbox Code Playgroud)

小工具就像

data Widget =
  Widget { wtType          :: WidgetType
         , wtParent        :: Maybe Widget
         --, wtRelated       :: [Widget] -- Feels hacky.
         , wtBox           :: Rect
         , wtPosition      :: WidgetPosition
         , wtAnchors       :: [WidgetAnchor]
         , wtEventHandlers :: Map Event EventHandler
         , wtDisabled      :: Bool
         }
Run Code Online (Sandbox Code Playgroud)

哪里

type EventHandler = (Event -> (UIState, ClientState) ->
                    (UIState, ClientState, IO ()))
Run Code Online (Sandbox Code Playgroud)

当一个事件到来并找到适当的小部件时,我的程序会wtEventHandlers为这个小部件查找此类事件的处理程序,并在找到此类处理程序时执行操作.

创建窗口小部件时,会将其rect添加到a QuadTree,查询该窗口findWidget.创建或删除窗口小部件时会更新树.

但是,以这种方式编程是非常困难的,因为UI状态已经很多(即使对于具有几个按钮且没有菜单的简单UI).

我考虑将每个小部件实现为状态机并组合这些机器,以便减少状态和转换的数量.也许将它包装成monad会很好(就像在XMonad中完成的那样).

我看过的事情:

我的问题是:

  • 将窗口小部件描述为对某些事件做出"反应"并"忽略"所有其他事件的状态机是否对窗口小部件工具包设计者有意义?有更好(更容易)的方式吗?
  • 组织界面描述是Monad个好主意吗?

E. g.

mkGameScreenButtons = runGuiDef $ do
  panicExitButton /// MouseDown ==> liftM exitGameNow
  panicExitButton /// MouseIn ==> do hideGameScreen
                                     muteSounds
                                     muteMusic
  panicExitButton /// MouseOut ==> do unhideGameScreen
                                      unmuteSounds
                                      unmuteMusic
  gameSpeedSlider /// MouseUp ==> changeSpeed (wtValue gameSpeedSlider)
  [...]
 where panicExitButton = mkButton (5, 5) [AnchorTop, AnchorRight] "BOSS BUTTON"
 [...]
Run Code Online (Sandbox Code Playgroud)
  • 在进一步推进之前,我还能阅读哪些相关文献吗?强调功能方法会很好.
  • 有没有办法避免完全编写小工具包?我希望我的游戏能够以全屏模式运行,因此Gtk2hs无法运行.