Antes de aplicar la extrapolación al movimiento de mi sprite, mi colisión funcionó perfectamente. Sin embargo, después de aplicar la extrapolación al movimiento de mi sprite (para suavizar las cosas), la colisión ya no funciona.
Así es como funcionaban las cosas antes de la extrapolación:
Sin embargo, después de implementar mi extrapolación, se rompe la rutina de colisión. Supongo que esto se debe a que está actuando sobre la nueva coordenada producida por la rutina de extrapolación (que se encuentra en mi llamada de renderizado).
Después de aplicar mi extrapolación
¿Cómo corregir este comportamiento?
Intenté poner un control de colisión adicional justo después de la extrapolación; esto parece aclarar muchos de los problemas, pero lo descarté porque poner la lógica en mi renderizado está fuera de discusión.
También he intentado hacer una copia de la posición spritesX, extrapolando eso y dibujando usando eso en lugar del original, dejando así el original intacto para que la lógica lo adquiera; esta parece una mejor opción, pero aún produce algunos efectos extraños cuando choca con paredes. Estoy bastante seguro de que esta tampoco es la forma correcta de lidiar con esto.
He encontrado un par de preguntas similares aquí, pero las respuestas no me han ayudado.
Este es mi código de extrapolación:
public void onDrawFrame(GL10 gl) {
//Set/Re-set loop back to 0 to start counting again
loops=0;
while(System.currentTimeMillis() > nextGameTick && loops < maxFrameskip){
SceneManager.getInstance().getCurrentScene().updateLogic();
nextGameTick+=skipTicks;
timeCorrection += (1000d/ticksPerSecond) % 1;
nextGameTick+=timeCorrection;
timeCorrection %=1;
loops++;
tics++;
}
extrapolation = (float)(System.currentTimeMillis() + skipTicks - nextGameTick) / (float)skipTicks;
render(extrapolation);
}
Aplicando extrapolación
render(float extrapolation){
//This example shows extrapolation for X axis only. Y position (spriteScreenY is assumed to be valid)
extrapolatedPosX = spriteGridX+(SpriteXVelocity*dt)*extrapolation;
spriteScreenPosX = extrapolationPosX * screenWidth;
drawSprite(spriteScreenX, spriteScreenY);
}
Editar
Como mencioné anteriormente, he intentado hacer una copia de las coordenadas del sprite específicamente para dibujar ... esto tiene sus propios problemas.
En primer lugar, independientemente de la copia, cuando el sprite se está moviendo, es súper suave, cuando se detiene, se tambalea ligeramente hacia la izquierda / derecha, ya que todavía extrapola su posición en función del tiempo. ¿Es este comportamiento normal y podemos "apagarlo" cuando el sprite se detiene?
Intenté tener banderas para izquierda / derecha y solo extrapolar si alguno de estos está habilitado. También he intentado copiar las últimas y actuales posiciones para ver si hay alguna diferencia. Sin embargo, en lo que respecta a la colisión, estos no ayudan.
Si el usuario presiona decir, el botón derecho y el sprite se mueve hacia la derecha, cuando golpea una pared, si el usuario continúa presionando el botón derecho, el sprite seguirá animando a la derecha, mientras se detiene por la pared ( por lo tanto, en realidad no se mueve), sin embargo, debido a que la bandera derecha todavía está configurada y también porque la rutina de colisión está constantemente moviendo el sprite fuera de la pared, todavía le parece al código (no al jugador) que el sprite todavía se está moviendo, y por lo tanto La extrapolación continúa. Entonces, lo que el jugador vería es el sprite 'estático' (sí, está animando, pero en realidad no se mueve por la pantalla), y de vez en cuando se sacude violentamente cuando la extrapolación intenta hacer su cosa ..... .. Espero que esto ayude
Respuestas:
Todavía no puedo publicar un comentario, así que lo publicaré como respuesta.
Si entiendo el problema correctamente, es algo así:
Puedo pensar en 3 posibles soluciones. Los enumeraré en el orden que sea más deseable para menos en mi humilde opinión.
Código de ejemplo para el n. ° 2.
Creo que el n. ° 2 probablemente sería el más rápido y fácil de poner en marcha, aunque el n. ° 1 parece ser una solución más precisa desde el punto de vista lógico. Dependiendo de cómo maneje su solución de tiempo delta # 1, un gran delta podría dividirlo de la misma manera, en cuyo caso es posible que tenga que usar tanto el # 1 como el # 2 juntos.
EDITAR: no entendí su código anteriormente. Los bucles están diseñados para renderizarse lo más rápido posible y actualizarse en un intervalo establecido. Es por eso que estaría interpolando la posición del sprite, para manejar el caso en el que está dibujando más que actualizando. Sin embargo, si el bucle se queda atrás, sondea la actualización hasta que te atrape o saltes el número máximo de dibujos de cuadros.
Dicho esto, el único problema es que el objeto se mueve después de una colisión. Si hay una colisión, el objeto debe dejar de moverse en esa dirección. Por lo tanto, si hay una colisión, establezca su velocidad en 0. Esto debería evitar que la función de procesamiento mueva más el objeto.
fuente
Parece que necesita separar por completo la representación y la actualización de la física. Por lo general, la simulación subyacente se ejecutará en pasos de tiempo discretos, y la frecuencia nunca cambiará. Por ejemplo, podría simular el movimiento de su bola cada 1/60 de segundo, y eso es todo.
Para permitir una velocidad de fotogramas variable, el código de representación debe operar en una frecuencia variable, pero cualquier simulación debe realizarse en un intervalo de tiempo fijo. Esto permite que los gráficos lean la memoria de la simulación como de solo lectura y le permite configurar la interpolación en lugar de la extrapolación.
Dado que la extrapolación está tratando de predecir dónde estarán los valores futuros, los cambios repentinos en el movimiento pueden generar enormes errores de extrapolación. En su lugar, es mejor renderizar su escena sobre un cuadro detrás de la simulación e interpolar entre posiciones discretas conocidas.
Si desea ver algunos detalles de la implementación, ya he escrito una breve sección sobre este tema en un artículo aquí . Consulte la sección llamada "Timestepping".
Aquí está el código psuedo importante del artículo:
La
RenderGame
función es de mayor interés. La idea es utilizar la interpolación entre posiciones de simulación discretas. El código de representación puede hacer sus propias copias de los datos de solo lectura de la simulación y utilizar un valor interpolado temporal para representar. ¡Esto le dará un movimiento muy suave sin problemas tontos como lo que parece estar teniendo!fuente