سؤال

أحاول محاكاة كرة كذبة مع Yampa-Framework: بالنظر إلى موضع X ، الطول والسرعة ، يجب أن ترتد الكرة وفقًا لقواعد الجاذبية. تأخذ وظيفة الإشارة "حدثًا طرفًا" كمدخلات ، وهي الفكرة "عندما يتم تمييز الكرة ، يجب أن تتضاعف السرعة".

ترتد الكرة بشكل جيد ، ولكن في كل مرة يكون هناك حدث تحول ، تنتقل الوظيفة إلى حلقة لا نهاية لها. كنت أحسب أنني ربما أحتاج إلى إضافة تأخير (dswitch ، pre ، notyet؟) ، لكنني لا أعرف كيف. سيكون موضع تقدير أي مساعدة!

{-# 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])

تحرير: تمكنت من تجنب الحلقة التي لا نهاية لها عن طريق تغذية العلم عند حدوث طرف ، لكن هذا لا يزال لا يشعر بالطريقة الصحيحة للقيام بذلك ...

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)   
هل كانت مفيدة؟

المحلول

بعد بضعة أيام من القرصنة ، أعتقد أنني وجدت الجواب. الحيلة هي الاستخدام notYet لتأخير حدث التبديل إلى النقطة التالية ، بحيث يتم التبديل (وبالتالي الدعوة العودية إلى fly) يحدث عندما يختفي الحدث "القديم". ال second تأكيد الوظيفة من أن الجزء الثاني فقط من النتيجة (Ball, Event (..)) سيتم وضعه من خلال notYet. هذا يزيل الحلقة التي لا نهاية لها ، ولكنها تغير أيضًا الدلالات: يحدث التبديل الآن "خطوة زمنية" واحدة في وقت لاحق ، وهذا بدوره يؤدي إلى سرعة مختلفة.

هذا الشيء في Yampa هو في الواقع لطيف للغاية ، للأسف لا يوجد الكثير من الوثائق التي يجب العثور عليها. ما زلت لا أستطيع معرفة ما pre و iPre الوظائف جيدة ، وأنا أظهر أنها يمكن استخدامها في سياق مماثل.

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)   
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top