Modifica: per rispondere alla domanda, sì, hai ragione a usare l'approssimazione che stai utilizzando, è il metodo di Eulero per risolvere un'equazione differenziale del primo ordine ed è abbastanza preciso per i tuoi scopi, in particolare dal momento che l'utente non avere un valore assoluto per la velocità angolare che giace intorno per giudicarti contro. La riduzione dell'intervallo di tempo lo renderebbe più preciso, ma non è importante.
Si può fare questo in pochi passi, più grandi (vedi sotto), ma in questo modo mi sembra più chiaro, spero che sia per voi.
Perché preoccuparsi di questa soluzione più lunga? Funziona anche quando eDisplay
si verifica a intervalli irregolari, poiché calcola eDeltaT
.
Diamo noi stessi un evento di tempo:
eTime :: Event t Int
eTime = bTime <@ eDisplay
Per ottenere DeltaT, avremo bisogno di tenere traccia del tempo di intervallo che passa:
type TimeInterval = (Int,Int) -- (previous time, current time)
in modo che possiamo convertirli in delta:
delta :: TimeInterval -> Int
delta (t0,t1) = t1 - t0
Come dovremmo aggiornare un intervallo di tempo in cui si ottiene una nuova t2
?
tick :: Int -> TimeInterval -> TimeInterval
tick t2 (t0,t1) = (t1,t2)
Quindi cerchiamo di parte si applicano che al tempo, per darci un programma di aggiornamento intervallo:
eTicker :: Event t (TimeInterval->TimeInterval)
eTicker = tick <$> eTime
e poi possiamo accumE
-accumulate che funzionano su un intervallo di tempo iniziale:
eTimeInterval :: Event t TimeInterval
eTimeInterval = accumE (0,0) eTicker
Poiché eTime viene misurato dall'inizio del rendering, è opportuno un (0,0)
iniziale.
Finalmente possiamo avere il nostro evento DeltaT, semplicemente applicando (fmap
ping) delta
nell'intervallo di tempo.
eDeltaT :: Event t Int
eDeltaT = delta <$> eTimeInterval
Ora abbiamo bisogno di aggiornare l'angolo, usando idee simili.
Farò un programma di aggiornamento angolo, semplicemente ruotando il bAngularVelocity
in un moltiplicatore:
bAngleMultiplier :: Behaviour t (Double->Double)
bAngleMultiplier = (*) <$> bAngularVelocity
allora possiamo utilizzare che per fare eDeltaAngle
: (edit: cambiato per (+)
e convertito in Double
)
eDeltaAngle :: Event t (Double -> Double)
eDeltaAngle = (+) <$> (bAngleMultiplier <@> ((fromInteger.toInteger) <$> eDeltaT)
ed accumulare per ottenere l'angolo:
eAngle :: Event t Double
eAngle = accumE 0.0 eDeltaAngle
Se ti piace one-liners, è possibile scrivere
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) =
ma non credo che sia terribilmente illuminante, e ad essere onesti, non sono sicuro che ho ottenuto il mio diritto fissità da quando ho non testato questo in ghci.
Naturalmente, da quando ho fatto eAngle
invece di bAngle
, è necessario
reactimate $ (draw gears) <$> eAngle
al posto dell'originale
reactimate $ (draw gears) <$> (bAngle <@ eDisp)
Se lo desideri, puoi evitare il calcolo facendo in modo che l'utente esegua l'intervallo del tuo bTime, allo stesso modo di asteroids esempio – AndrewC
@AndrewC, credo [questo] (https://github.com/HeinrichApfelmus/reactive-banana/blob/master/reactive-banana -wx/src/Asteroids.hs) è il collegamento che si desidera? – huon
Sì.. Svantaggi: a scatti a bassa velocità, sovraccarico del motore grafico ad alta velocità, brutto. Riprendo il mio suggerimento: utilizzando la velocità angolare è molto più elegante –
AndrewC