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

时间:2013-05-10 14:14:10

标签: haskell frp reactive-banana

我正处于旅行者的这一点我正试图处理与游戏状态无关的玩家更新。作为参考,项目是here(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

实现此计时器的问题在于,我所看到的所有示例都有一个与我的物理模拟不同的用例。这场比赛没有物理参与。我正在尝试使用计时器来评估独立于玩家行为的游戏状态。目前,我唯一想管理的是超空间旅行。完全实施后,从一个星球移动到另一个星球会将Agent的{​​{1}}更改为location。现在需要做的是,当Right Hyperspace发生时,tick递增1。如果distanceTraversed等于distanceTraversed totalDistance的位置变为Agent

那么从Left Planet的角度来看会是什么样的呢?

EventNetwork

现在要结合行为

let bHyperspace = accumB initialGS $ foo <$> eTick

这是正确的轨道吗?

1 个答案:

答案 0 :(得分:2)

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

首先,看看你的代码,我发现很奇怪你将实际的游戏玩法逻辑“外包”到整体GameState类型和updateGS函数。现在,这不是一件坏事,只是在这种风格中使用FRP没有任何好处。您可以完全删除makeNetworkDescription功能,然后手动注册偶数thandler 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

你可能想在游戏中多次重复这个过程。不幸的是,反应性香蕉目前不提供“先做这个,然后做那种”的抽象。有动态事件切换,但可能有点笨拙。