Функциональный Banana Traveler — события, независимые от таймера и игрока

Я нахожусь в своем Traveler, я пытаюсь обрабатывать независимые от игрока обновления состояния игры. Для справки: проект находится здесь (для этого вопроса подходит ветка 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

Проблема с реализацией этого таймера заключается в том, что все примеры, которые я рассмотрел, имеют вариант использования, отличный от моего, симуляции физики. В этой игре нет никакой физики. Я пытаюсь использовать таймер, чтобы состояние игры оценивалось независимо от действий игрока. На данный момент, единственное, чем я хочу управлять, это путешествия в гиперпространстве. После полной реализации перемещение с одной планеты на другую изменит location Agent на Right Hyperspace. Что должно произойти сейчас, так это то, что когда происходит tick, distanceTraversed увеличивается на единицу. Затем, если distanceTraversed равно totalDistance, местоположение Agent становится Left Planet.

Так как бы это выглядело с точки зрения EventNetwork?

let bHyperspace = accumB initialGS $ foo <$> eTick

Теперь, чтобы объединить поведение

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

Это правильный трек?


person Michael Litchard    schedule 10.05.2013    source источник


Ответы (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

Однако вы, вероятно, захотите повторить этот процесс несколько раз в игре. К сожалению, в настоящее время реактивный банан не предлагает абстракции типа «сначала сделайте то, а потом то». Есть динамическое переключение событий, но оно может быть немного громоздким.

person Heinrich Apfelmus    schedule 18.05.2013
comment
Я понял, что с updateGS возникнут проблемы, но отложил этот вопрос на другой день. - person Michael Litchard; 19.05.2013