2010-09-19 10 views
9

Ich versuche einen springenden Ball mit dem Yampa-Framework zu simulieren: Bei gegebener x-Position, Höhe und Geschwindigkeit sollte der Ball nach den Schwerkraftregeln springen. Die Signalfunktion nimmt ein "Tip-Event" als Eingabe, die Idee ist "wenn der Ball gekippt wird, sollte sich die Geschwindigkeit verdoppeln".Warum springt dieser Yampa Ball-Bouncing in eine Endlosschleife?

Der Ball springt gut, aber jedes Mal, wenn ein Kippereignis eintritt, geht die Funktion in eine Endlosschleife über. Ich dachte, dass ich wahrscheinlich eine Verzögerung hinzufügen muss (dSwitch, pre, notYet?), Aber ich weiß nicht wie. Jede Hilfe wäre willkommen!

{-# LANGUAGE Arrows #-} 

module Ball where 

import FRP.Yampa 

type Position = Double 
type Velocity = Double 
type Height = Double 

data Ball = Ball { 
     height :: Height, 
     width :: Position, 
     vel :: Velocity 
} deriving (Show) 

type Tip = Event() 

fly :: Position -> (Height, Velocity) -> SF Tip (Ball, Event (Height,Velocity)) 
fly w0 (h0, v0) = proc tipEvent -> do 
    let tip = (tipEvent == Event()) 
    v <- (v0+) ^<< integral -< -10.0 
    h <- (h0+) ^<< integral -< v 
    returnA -< (Ball h w0 v, 
       if h < 0 then Event (0,(-v*0.6)) 
        else if tip then Event (h, (v*2)) 
        else NoEvent) 

bounce w (h,v) = switch (fly w (h,v)) (bounce w) 

runBounce w (h,v) = embed (bounce 10 (100.0, 10.0)) (deltaEncode 0.1 [NoEvent, NoEvent, NoEvent, Event(), NoEvent]) 

EDIT: habe ich es geschafft durch Zurück eine Fahne, um die Endlosschleife zu vermeiden, wenn eine Spitze aufgetreten ist, aber das immer noch nicht wie die richtige Art und Weise fühlt es zu tun ...

fly :: Position -> (Height, Velocity, Bool) -> SF Tip (Ball, Event (Height,Velocity,Bool)) 
fly w0 (h0, v0, alreadyTipped) = proc tipEvent -> do 
    let tip = tipEvent == Event() && (not alreadyTipped) 
    v <- (v0+) ^<< integral -< -10.0 
    h <- (h0+) ^<< integral -< v 
    returnA -< (Ball h w0 v, 
       if h < 0 then Event (0,(-v*0.6), False) 
        else if tip then Event (h, (v*2), True) 
        else NoEvent) 

bounce w (h,v,alreadyTipped) = switch (fly w (h,v,alreadyTipped)) (bounce w) 

Antwort

3

Nach ein paar Tage Hacking Ich glaube, ich habe die Antwort gefunden. Der Trick besteht darin, das Schaltereignis mit notYet auf den nächsten Zeitpunkt zu verzögern, so dass das Umschalten (und somit der rekursive Aufruf an fly) stattfindet, wenn das "alte" Tippereignis weg ist. Die second Funktion stellt sicher, dass nur der zweite Teil des Ergebnistupels (Ball, Event (..)) durch notYet gesetzt wird. Damit entfällt die Endlosschleife, aber auch die Semantik ändert sich: Die Umschaltung erfolgt nun erst um einen "Zeitschritt" später, dies wiederum führt zu einer anderen Geschwindigkeit.

Diese Yampa Sache ist eigentlich ganz nett, leider gibt es nicht viel Dokumentation zu finden. Ich konnte immer noch nicht herausfinden, was die pre und iPre Funktionen sind gut, ich denke, sie können in einem ähnlichen Kontext verwendet werden.

fly :: Position -> (Height, Velocity) -> SF Tip (Ball, Event (Height,Velocity)) 
fly w0 (h0, v0) = proc tipEvent -> do 
    let tip = tipEvent == Event() 
    v <- (v0+) ^<< integral -< -10.0 
    h <- (h0+) ^<< integral -< v 
    returnA -< (Ball h w0 v, 
       if h < 0 then Event (0,-v*0.6) 
        else if tip then Event (h, v*2) 
        else NoEvent) 

bounce w (h,v) = switch (fly w (h,v) >>> second notYet) (bounce w) 
+0

sind die in The Yampa Arcade Papier beschrieben. –

Verwandte Themen