2010-09-19 4 views
9

J'essaie de simuler une balle rebondissante avec le Yampa-Framework: Avec une position initiale, une hauteur et une vitesse initiales, la balle devrait rebondir selon les règles de la gravité. La fonction signal prend un "Tip-Event" en entrée, l'idée étant "quand la balle est inclinée, sa vitesse devrait doubler". La balle rebondit bien, mais chaque fois qu'il y a un événement de basculement, la fonction entre dans une boucle sans fin. J'ai pensé que je devrais probablement ajouter un délai (dSwitch, pre, notYet?), Mais je ne sais pas comment. Toute aide serait appréciée!Pourquoi ce ball-ball de Yampa va-t-il dans une boucle sans fin?

{-# 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: J'ai réussi à éviter la boucle sans fin en réinjectant un drapeau quand une pointe a eu lieu, mais cela ne me sens pas encore comme la bonne façon de le faire ...

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) 

Répondre

3

Après quelques jours de piratage je pense avoir trouvé la réponse. L'astuce consiste à utiliser notYet pour retarder l'événement de commutation au moment suivant, de sorte que la commutation (et donc l'appel récursif à fly) se produit lorsque l'ancien événement de basculement a disparu. La fonction second s'assure que seule la deuxième partie du tuple de résultat (Ball, Event (..)) passera par notYet. Cela supprime la boucle sans fin, mais change également la sémantique: La commutation se fait maintenant un "pas de temps" plus tard, ce qui conduit à une vitesse différente.

Cette chose Yampa est en fait assez agréable, malheureusement, il n'y a pas beaucoup de documentation à trouver. Je ne pouvais toujours pas savoir à quoi servent les fonctions pre et iPre, je suppose qu'elles peuvent être utilisées dans un contexte similaire.

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

iirc sont décrits dans le document Yampa Arcade. –

Questions connexes