7

我在我的 Traveler 中尝试处理与玩家无关的游戏状态更新。作为参考,项目在这里(开发分支是这个问题的相关分支)。

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's更改locationRight Hyperspace。现在需要发生的是,当 atick发生时,distanceTraversed加一。那么如果distanceTraversedequalstotalDistance Agent的位置就变成了Left Planet

EventNetwork那么从的角度来看,这会是什么样子呢?

let bHyperspace = accumB initialGS $ foo <$> eTick

现在结合行为

let bBaz = (++) <$> bGameState <*> bHyperspace

这是正确的轨道吗?

4

1 回答 1

2

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

首先,查看您的代码,我发现您将实际游戏逻辑“外包”给了单体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

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

于 2013-05-18T08:33:46.840 回答