功能性香蕉旅行者 - 定时器和播放器独立活动

Mic*_*ard 7 haskell frp reactive-banana

我正处于旅行者的关键时刻我正试图处理与游戏状态无关的玩家更新.作为参考,该项目在这里(devel分支是这个问题的相关分支).

Libraries/Universe/GameState.hs有一个功能,updateGS处理游戏状态的所有玩家更新.现在EventNetwork看起来像这样.

makeNetworkDescription :: AddHandler PlayerCommand ->
                          AddHandler () ->
                          TChan GameState ->
                          IO EventNetwork
makeNetworkDescription addCommandEvent tickHandler gsChannel = compile $ do
    eInput <- fromAddHandler addCommandEvent
    eTick <- fromAddHandler tickHandler
    let bGameState = accumB initialGS $ updateGS <$> eInput
    eGameState <- changes bGameState
    reactimate $ (\n -> (atomically $ writeTChan gsChannel n)) <$> eGameState
Run Code Online (Sandbox Code Playgroud)

实现这个计时器的问题在于我所看到的所有例子都有一个与我的物理模拟不同的用例.这场比赛没有物理参与.我正在尝试使用计时器来评估独立于玩家行为的游戏状态.目前,我唯一想管理的是超空间旅行.当完全实现,从一个行星移动到另一个将改变一个AgentlocationRight Hyperspace.现在需要做的是,当一个tick发生时,distanceTraversed增加一个.然后,如果distanceTraversedequals totalDistance Agent的位置变为Left Planet.

那么从EventNetwork观点来看会是什么样子呢?

let bHyperspace = accumB initialGS $ foo <$> eTick
Run Code Online (Sandbox Code Playgroud)

现在结合行为

let bBaz = (++) <$> bGameState <*> bHyperspace
Run Code Online (Sandbox Code Playgroud)

这是正确的轨道吗?

Hei*_*mus 1

这个问题有点模糊,不容易回答,但我会尽力回答。

首先,查看您的代码,我发现您将实际的游戏逻辑“外包”给了整体GameState类型和updateGS函数,这很奇怪。现在,这并不是一件坏事,只是以这种方式使用 FRP 没有任何好处。您可以完全删除该函数并手动makeNetworkDescription注册一个偶数处理程序。addCommandEvent

FRP 的好处是您可以将游戏状态建模为行为和事件的网络。如果状态足够模块化,那么这将显着简化代码。


其次,关于你关于超空间旅行建模的问题。

这是一种方法:

-- indicates whether hyperspace travel is currently happening
bTravelling :: Behavior t Bool

-- increment travel distance, but only when travelling
bTravelDistance :: Behavior t Distance
bTravelDistance = accumB 0 $ (+1) <$> whenE bTravelling eTick

-- calculate player location from travel distance
bPlayerLocation :: Behavior t Location
bPlayerLocation =
    (\distance -> if distance > total then Left Planet else Right HyperSpace)
    <$> bTravelDistance
Run Code Online (Sandbox Code Playgroud)

不过,您可能想在游戏中多次重复此过程。不幸的是,reactive-banana 目前不提供“先做这个,然后做那个”的抽象。有动态事件切换,但可能有点笨拙。