2013-05-10 4 views
7

Ich bin an dem Punkt in meinem Traveller Ich versuche Player-unabhängige Updates zum Spielstatus zu verarbeiten. Als Referenz ist das Projekt here (der Entwicklungszweig ist der relevante für diese Frage).Functional Banana Traveller - Timer und playerunabhängige Events

Libraries/Universe/GameState.hs hat eine Funktion, updateGS, die alle Player-Updates auf den Spielstatus behandelt. Die EventNetwork sieht jetzt so aus.

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 

Das Problem mit diesen Timer bei der Implementierung ist, dass alle Beispiele, die ich auf einen Anwendungsfall anders haben ausgesehen haben von mir, Physik-Simulation. Es gibt keine Physik in diesem Spiel. Ich versuche, einen Timer zu verwenden, um den Spielstatus unabhängig von Spieleraktionen zu bewerten. Fürs Erste, das einzige, was ich verwalten möchte, ist Hyperraum-Reisen. Wenn es vollständig implementiert ist, ändert sich der Wechsel von einem Planeten zum anderen von Agent zu location zu Right Hyperspace. Was jetzt passieren muss ist, dass wenn tick passiert, distanceTraversed um eins erhöht wird. Wenn distanceTraversed gleich totalDistanceAgent ist, wird der Standort Left Planet.

Also was würde das aus der Sicht EventNetwork aussehen?

let bHyperspace = accumB initialGS $ foo <$> eTick 

jetzt Verhaltensweisen zu kombinieren

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

Ist das der richtige Weg?

Antwort

2

Die Frage ist etwas vage und nicht einfach zu beantworten, aber ich werde mein Bestes versuchen.

Zuerst, wenn ich Ihren Code betrachte, finde ich es merkwürdig, dass Sie die eigentliche Gameplay-Logik auf den monolithischen GameState Typ und die updateGS Funktion "ausgelagert" haben. Nun, das ist keine schlechte Sache, es ist nur so, dass es keinen Vorteil von der Verwendung von FRP in diesem Stil gibt. Sie können die makeNetworkDescription Funktion komplett entfernen und stattdessen einen even thandler mit addCommandEvent von Hand registrieren.

Der Vorteil von FRP besteht darin, dass Sie den Spielstatus als ein Netzwerk von Verhaltensweisen und Ereignissen modellieren können. Wenn der Zustand modular genug ist, vereinfacht dies den Code erheblich.


Zweitens, zu Ihrer Frage über die Modellierung von Hyperraum Reisen.

Hier ist eine Möglichkeit, es zu tun:

-- 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 

Sie wollen wahrscheinlich diesen Vorgang mehrmals in einem Spiel wiederholen, though. Bedauerlicherweise bietet reactive-banana derzeit keine Abstraktion an, die man zuerst machen, dann tun kann. Es gibt einen dynamischen Ereigniswechsel, aber es kann ein wenig unhandlich sein.

+0

Ich hatte gemerkt, dass updateGS ein Problem sein würde, aber ich rettete diese Frage für einen anderen Tag. –