Edycja: aby odpowiedzieć na pytanie, tak, masz rację, używając przybliżenia, którego używasz, jest to metoda Eulera rozwiązywania równania różniczkowego pierwszego rzędu i jest wystarczająco dokładna dla twoich celów, szczególnie, że użytkownik robi nie mają wartości bezwzględnej dla prędkości kątowej leżącej wokół, aby cię osądzić. Zmniejszenie odstępu czasu sprawiłoby, że byłby on dokładniejszy, ale to nieważne.
Możesz to zrobić na mniejszej, większej liczbie kroków (patrz niżej), ale ta metoda wydaje mi się najjaśniejsza, mam nadzieję, że to dla ciebie.
Po co zawracać sobie głowę tym dłuższym rozwiązaniem? Działa to nawet, gdy eDisplay
dzieje się w nieregularnych odstępach czasu, ponieważ oblicza eDeltaT
.
Dajmy sobie zdarzenie czasu:
eTime :: Event t Int
eTime = bTime <@ eDisplay
Aby uzyskać DeltaT, musimy śledzić przedziale czasowym Podania:
type TimeInterval = (Int,Int) -- (previous time, current time)
więc możemy je konwertować do delt:
delta :: TimeInterval -> Int
delta (t0,t1) = t1 - t0
W jaki sposób powinniśmy zaktualizować przedział czasu, kiedy otrzymamy nowy t2
?
tick :: Int -> TimeInterval -> TimeInterval
tick t2 (t0,t1) = (t1,t2)
Więc częściowo zastosować że do czasu, aby dać nam przedział updater:
eTicker :: Event t (TimeInterval->TimeInterval)
eTicker = tick <$> eTime
i wtedy możemy accumE
-accumulate że działają na początkowym przedziale czasowym:
eTimeInterval :: Event t TimeInterval
eTimeInterval = accumE (0,0) eTicker
Ponieważ czas trwania eTime jest mierzony od początku renderowania, odpowiedni jest początkowy (0,0)
.
Wreszcie możemy mieć nasze zdarzenie DeltaT, poprzez zastosowanie (fmap
ping) delta
w przedziale czasu.
eDeltaT :: Event t Int
eDeltaT = delta <$> eTimeInterval
Teraz musimy zaktualizować kąt, używając podobnych pomysłów.
Zrobię updater kąt, po prostu obracając bAngularVelocity
do mnożnika:
bAngleMultiplier :: Behaviour t (Double->Double)
bAngleMultiplier = (*) <$> bAngularVelocity
wtedy możemy używać, aby dokonać eDeltaAngle
: (edit: zmieniono (+)
i konwertowane do Double
)
eDeltaAngle :: Event t (Double -> Double)
eDeltaAngle = (+) <$> (bAngleMultiplier <@> ((fromInteger.toInteger) <$> eDeltaT)
i gromadzą się, aby uzyskać kąt:
eAngle :: Event t Double
eAngle = accumE 0.0 eDeltaAngle
Jeśli lubisz jednej wkładki, można napisać
eDeltaT = delta <$> (accumE (0,0) $ tick <$> (bTime <@ eDisplay)) where
delta (t0,t1) = t1 - t0
tick t2 (t0,t1) = (t1,t2)
eAngle = accumE 0.0 $ (+) <$> ((*) <$> bAngularVelocity <@> eDeltaT) =
ale nie sądzę, że jest strasznie pouczające, i szczerze mówiąc, nie jestem pewien, mam moje fixities prawo odkąd nie testowałem tego w ghci.
Oczywiście, ponieważ zrobiłem eAngle
zamiast bAngle
, trzeba
reactimate $ (draw gears) <$> eAngle
zamiast oryginalnego
reactimate $ (draw gears) <$> (bAngle <@ eDisp)
Jeśli chcesz, możesz ominąć rachunek różniczkowy, pozwalając użytkownikowi oszacować czas trwania bTime w taki sam sposób jak asteroids przykład: – AndrewC
@AndrewC, myślę [to] (https://github.com/HeinrichApfelmus/reactive-banana/blob/master/reactive-banana -wx/src/Asteroids.hs) jest linkiem, którego szukasz? – huon
Tak,. Wady: szarpanie przy małych prędkościach, przeciążanie silnika graficznego przy dużych prędkościach, brzydota. Odbieram moją sugestię: użycie prędkości kątowej jest o wiele bardziej elegancki –
AndrewC