2010-09-19 32 views
9

Tôi đang cố gắng mô phỏng một quả bóng nảy với khung hình Yampa: Với một vị trí x ban đầu, chiều cao và vận tốc, quả bóng sẽ bị trả lại theo các quy tắc trọng lực. Chức năng tín hiệu có một "Tip-Sự kiện" là đầu vào, ý tưởng là "khi bóng được lật, tốc độ của nó sẽ tăng gấp đôi".Tại sao quả bóng Yampa nảy vào vòng lặp vô tận?

Quả bóng bị trả lại độc đáo, nhưng mỗi khi có sự kiện lật, chức năng sẽ chuyển sang vòng lặp vô tận. Tôi figured tôi có lẽ cần phải thêm một sự chậm trễ (dSwitch, trước, notYet?), Nhưng tôi không biết làm thế nào. Bất kỳ trợ giúp sẽ được đánh giá cao!

{-# 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: Tôi quản lý để tránh các vòng lặp vô tận bằng cách cho ăn trở lại một lá cờ khi một mẹo xảy ra, nhưng điều đó vẫn không cảm thấy như đúng cách để làm điều đó ...

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) 

Trả lời

3

Sau một vài ngày hack tôi nghĩ rằng tôi tìm thấy câu trả lời. Bí quyết là sử dụng notYet để trì hoãn sự kiện chuyển đổi sang điểm tiếp theo trong thời gian, để chuyển đổi (và do đó cuộc gọi đệ quy đến fly) xảy ra khi sự kiện "cũ" bị mất. Hàm second đảm bảo rằng chỉ phần thứ hai của kết quả tuple (Ball, Event (..)) sẽ được đặt qua notYet. Điều này loại bỏ các vòng lặp vô tận, nhưng cũng thay đổi ngữ nghĩa: Việc chuyển đổi bây giờ diễn ra một "bước thời gian" sau này, điều này lần lượt dẫn đến một tốc độ khác nhau.

Điều Yampa này thực sự khá tốt, đáng buồn là không có nhiều tài liệu để tìm. Tôi vẫn không thể tìm ra các chức năng preiPre phù hợp, tôi có thể sử dụng chúng trong một ngữ cảnh tương tự.

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 được mô tả trong giấy Yampa Arcade. –

Các vấn đề liên quan