Editar: para responder a la pregunta, sí, está en lo cierto al usar la aproximación que está usando, es el método de Euler de resolver una ecuación diferencial de primer orden, y es lo suficientemente preciso para sus propósitos, especialmente dado que el usuario no No tiene un valor absoluto para la velocidad angular que se encuentra alrededor para juzgarlo en contra. Disminuir su intervalo de tiempo lo haría más preciso, pero eso no es importante.
Puede hacer esto en menos pasos, más grandes (vea a continuación), pero de esta manera me parece más claro, espero que sea para usted.
¿Por qué molestarse con esta solución más larga? Esto funciona incluso cuando eDisplay
ocurre a intervalos irregulares, porque calcula eDeltaT
.
Vamos a darnos un evento de tiempo:
eTime :: Event t Int
eTime = bTime <@ eDisplay
Para obtener Delta T, tendremos que hacer un seguimiento del tiempo de paso de intervalo:
type TimeInterval = (Int,Int) -- (previous time, current time)
por lo que puede convertirlos en los deltas:
delta :: TimeInterval -> Int
delta (t0,t1) = t1 - t0
¿Cómo debemos actualizar un intervalo de tiempo cuando tenemos una nueva t2
?
tick :: Int -> TimeInterval -> TimeInterval
tick t2 (t0,t1) = (t1,t2)
Así que vamos a aplicar parcialmente que a la vez, para darnos un actualizador intervalo:
eTicker :: Event t (TimeInterval->TimeInterval)
eTicker = tick <$> eTime
y luego podemos accumE
-accumulate que funcionan en un intervalo de tiempo inicial:
eTimeInterval :: Event t TimeInterval
eTimeInterval = accumE (0,0) eTicker
Dado que eTime se mide desde el inicio de la representación, es apropiado un (0,0)
inicial.
Finalmente podemos tener nuestro evento DeltaT, simplemente aplicando (fmap
ping) delta
en el intervalo de tiempo.
eDeltaT :: Event t Int
eDeltaT = delta <$> eTimeInterval
Ahora tenemos que actualizar el ángulo, usando ideas similares.
Voy a hacer un actualizador ángulo, con sólo girar el bAngularVelocity
en un multiplicador:
bAngleMultiplier :: Behaviour t (Double->Double)
bAngleMultiplier = (*) <$> bAngularVelocity
entonces podemos utilizar eso para hacer eDeltaAngle
: (edit: cambió a (+)
y se convierte en Double
)
eDeltaAngle :: Event t (Double -> Double)
eDeltaAngle = (+) <$> (bAngleMultiplier <@> ((fromInteger.toInteger) <$> eDeltaT)
y se acumulan para obtener el ángulo:
eAngle :: Event t Double
eAngle = accumE 0.0 eDeltaAngle
Si te gusta de una sola línea, puede escribir
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) =
pero no creo que eso es terriblemente iluminación, y para ser honesto, no estoy seguro de que tengo mis empotramientos derecho desde que he no probado esto en ghci.
Por supuesto, desde que hice eAngle
en lugar de bAngle
, necesita
reactimate $ (draw gears) <$> eAngle
en lugar de su
reactimate $ (draw gears) <$> (bAngle <@ eDisp)
Si lo desea, puede evitar el cálculo dejando que el usuario vea el intervalo de su bTime, de la misma manera que el asteroids example does. – AndrewC
@AndrewC, supongo que [esto] (https://github.com/HeinrichApfelmus/reactive-banana/blob/master/reactive-banana -wx/src/Asteroids.hs) es el enlace que quería? – huon
Sí.. Desventajas: desigual a velocidades lentas, sobrecargando el motor de gráficos a altas velocidades, feo. Retiro mi sugerencia: usar la velocidad angular es mucho más elegante. –
AndrewC