Falsificación de gráficos isométricos en un juego espacial en 2D

15

En primer lugar, sé exactamente cuál es mi problema de dibujo y tengo varias ideas sobre cómo abordarlo para resolverlo. Estoy aquí para descubrir cómo ajustar qué marco se dibuja para mantener la "ilusión" isométrica.

Estoy escribiendo un juego 2D a vista de pájaro que tiene lugar en el espacio. Estoy tratando de usar gráficos isométricos en un mundo donde Up is North, sin rotación del mundo del juego como en los juegos isométricos tradicionales (recuerden, el juego tiene lugar en el espacio, sin terreno). Aquí hay un ejemplo de sprite que estoy tratando de usar: http://cell.stat-life.com/images/stories/AsteroidOutpost/Spaceship64.png Rotó 64 veces sobre su propio eje vertical con un ángulo de visión de 35 grados (también conocido como Yo asi). La imagen se generó, por lo que esto se puede cambiar.

En aras de la claridad, he dictado que el Norte (Arriba) es 0 grados y el Este (Derecha) es 90.

Mi problema es que mi sprite no siempre parece estar orientado hacia donde el juego cree que se debe a una diferencia en los planos 3D utilizados. No estoy seguro si estoy usando la terminología correctamente, pero mi nave espacial se rotó en un plano, y el plano de vista espera que las cosas se roten en su propio plano. Aquí hay una descripción del problema:

http://cell.stat-life.com/images/stories/AsteroidOutpost/ProjectionIssue.png A la izquierda, tengo vistas laterales, a la derecha tengo vistas de arriba hacia abajo. En la parte superior, tengo la vista de la nave espacial / hoja de sprites del mundo. En la parte inferior, tengo el aspecto del sprite cuando se dibuja en la pantalla.

En la parte superior derecha hay una versión simplificada de cómo se rotó mi nave espacial (incluso separaciones de grados entre cada cuadro). En la parte inferior derecha está el ángulo al que se ve el sprite cuando se dibuja un ángulo particular en la pantalla. El problema es más evidente a unos 45 grados. Aquí hay una imagen que se superpone con una línea de "plano de pantalla" que apunta en la dirección que se supone que debe estar enfrentando la nave: http://cell.stat-life.com/images/stories/AsteroidOutpost/Spaceship64RedLine.png La línea roja siempre debe apuntar exactamente en la misma dirección que la nave, pero como puede ver, el problema de la proyección está causando un problema. Espero describir el problema lo suficientemente bien.

EDITAR: La línea roja gira en el plano de la pantalla, mientras que la nave espacial gira en el "plano de la nave", de ahí la gran diferencia entre el ángulo de la nave y el ángulo de la pantalla cuando se dibuja. EDICIÓN FINAL

Parece bastante extraño cuando esta nave está disparando un rayo láser a un objetivo que está a un lado, cuando debería disparar en línea recta.

Entonces ... las soluciones que he encontrado son:

  1. Deja de intentar fingir una vista isométrica, ve a lo grande o vete a casa. Rota mi mundo ya. (PD: esto solucionará mi problema, ¿verdad?)
  2. Modifique mi hoja de sprites (de alguna manera) para que tenga marcos que representen el "ángulo de pantalla" en el que se verá el modelo. Entonces, cuando solicito una imagen de 45 grados, en realidad se verá como si estuviera orientada a 45 grados en la pantalla.
  3. Modifique mi sistema de representación de sprites para tomar un marco diferente de la hoja de sprite (de alguna manera), sabiendo que agarrar el marco "normal" se verá divertido. Entonces, en lugar de tomar el marco de 45 grados, tomará el marco de ... 33 grados (solo adivinando) para que se vea correcto para el usuario.
  4. ¡Solo usa 3D! Es mucho más fácil hombre

Por un lado: ¿Qué solución recomendarías? Me inclino hacia 2, aunque sé que está mal. Recuerda que tengo acceso completo a la herramienta de generación de sprites. El método 3 sería mi segunda opción. Ambos métodos simplemente requieren que aplique algunas matemáticas a los ángulos para obtener el resultado deseado. Por cierto, agregué el # 4 allí como una broma, no quiero pasar a 3D.

Para dos: Usando los métodos 2 o 3, ¿cómo ajustaría los ángulos de entrada o salida? No soy tan bueno con las proyecciones 3D y las matrices 3D (y mucho menos las matrices 2D), y cualquier otra matemática que pueda usarse para lograr el resultado deseado.

Pensando en voz alta aquí: si tomo un vector unitario orientado en la dirección que quiero que mire la nave (en el plano de la pantalla), luego lo proyecto en el plano de la nave, luego calculo cuál es el ángulo entre esa línea proyectada y la del avión norte es, debería tener el ángulo del gráfico del barco que quiero mostrar. ¿Derecho? (¿Solución para el # 3?) Hombre ... No puedo resolver eso.

EDITAR:

Sé que el problema es difícil de visualizar con imágenes estáticas, por lo que cumplí con mi Comprobador visual de la biblioteca Sprite para mostrar el problema: http://cell.stat-life.com/downloads/SpriteLibVisualTest.zip Requiere XNA 4.0 Esta aplicación es simplemente girando el sprite y dibujando una línea desde su punto central hacia afuera en el ángulo que el juego cree que la nave debería estar enfrentando.

EDITAR 8 de septiembre

Continuando con mi párrafo "pensando en voz alta": en lugar de usar una proyección (porque parece difícil) estoy pensando que podría tomar un vector unitario orientado al norte (0x, 1y, 0z), usar una matriz para rotarlo al ángulo el sprite realmente está orientado, luego gírelo nuevamente desde el "plano de visualización" hacia afuera al "plano del sprite" alrededor del eje X, luego ... ¿aplanar? el vector (esencialmente lo proyecta) de vuelta al plano de visualización usando solo X e Y (ignorando Z). Luego, usando ese nuevo vector aplanado, podría determinar su ángulo y usarlo para ... algo. Lo pensaré más tarde.

EDITAR 8 de septiembre (2)

Intenté seguir mi idea desde arriba con cierto éxito, ¡yay! Entonces ... para que parezca que una línea roja sale directamente de mi nave espacial (solo con fines de prueba), hice lo siguiente:

Vector3 vect = new Vector3(0, 1, 0);
vect = Vector3.Transform(vect, Matrix.CreateRotationZ(rotation));
vect = Vector3.Transform(vect, Matrix.CreateRotationY((float)((Math.PI / 2) - MathHelper.ToRadians(AngleFromHorizon))));
Vector2 flattenedVect = new Vector2(vect.X, vect.Y);

float adjustedRotation = (float)(getAngle(flattenedVect.X, flattenedVect.Y));

¿Dónde rotationestá el ángulo de la pantalla y adjustedRotationahora ese ángulo de la pantalla se ve en el plano del sprite? No sé por qué necesitaba rotar Y en lugar de X, pero probablemente sea algo relacionado con 3D que no conozco.

Entonces, ahora tengo una información adicional, pero ¿cómo la uso para elegir un marco más apropiado? Tal vez en lugar de girar desde el plano de vista hacia el plano del sprite, luego proyectar hacia atrás, debería intentar hacerlo al revés. Aquí está mi sprite con una línea roja ajustada, pero lo que realmente quiero hacer es ajustar el modelo, no la línea: http://cell.stat-life.com/images/stories/AsteroidOutpost/Spaceship64RedLineCorrected.png

EDITAR 9 de septiembre

HORAY! ¡Está arreglado! Describiré lo que hice para solucionarlo:

Seguí el consejo de eBusiness y me "aplasté" por el sistema de coordenadas mundiales (¿o estirado ...?). Esta es esencialmente la solución n. ° 1, aunque tenía la impresión de que tendría que rotar mi sistema de coordenadas mundiales en relación con el sistema de coordenadas de la pantalla. ¡No es verdad! Arriba sigue siendo + y, y Derecha sigue siendo + x. Modifiqué mis métodos WorldToScreen y ScreenToWorld para convertir correctamente entre el mundo y las coordenadas de la pantalla. Es posible que estos métodos no sean óptimos, pero estos son los únicos dos métodos en mi base de código que tuvieron que cambiar.

public Vector2 ScreenToWorld(float x, float y)
{
    float deltaX = x - (size.Width / 2f);
    float deltaY = y - (size.Height / 2f);

    deltaX = deltaX * scaleFactor / (float)Math.Sqrt(3);
    deltaY = deltaY * scaleFactor;

    return new Vector2(focusWorldPoint.X + deltaX, focusWorldPoint.Y + deltaY);
}

public Vector2 WorldToScreen(float x, float y)
{
    float deltaX = x - focusWorldPoint.X;
    float deltaY = y - focusWorldPoint.Y;

    deltaX = deltaX / scaleFactor * (float)Math.Sqrt(3);
    deltaY = deltaY / scaleFactor;

    return new Vector2(size.Width / 2f + deltaX, size.Height / 2f + deltaY);
}

¡Eso fue todo! Cambiar esos dos métodos afectó todo lo demás: lo que estaba mirando, dónde se dibujaban los objetos, dónde estaba haciendo clic, todo. Mi nave espacial ahora mira directamente al objetivo que está disparando, y todo está cayendo en su lugar. Voy a experimentar con la proyección ortográfica, ver si hace que todo parezca más "real".

John McDonald
fuente
Felicidades. No olvides meterme una vez que tengas algo jugable, me gustaría ver a dónde va esto.
aaaaaaaaaaaa
@eBusiness Según lo prometido: cell.stat-life.com/images/stories/AsteroidOutpost/… y cell.stat-life.com/images/stories/AsteroidOutpost/AOOhNoes.png ¿ Te das cuenta de cómo se ve la nave mirando esa torre? : D Gracias!
John McDonald
@eBusiness, un video youtube.com/watch?v=Q8pR9KDBsCo También hay un enlace para descargar, ya que lo solicitó.
John McDonald

Respuestas:

4

Cuando haya elegido la perspectiva isométrica, debe corregir la escala entre el eje X y el eje Y. Si una distancia determinada se proyecta a 1 en el eje Y de la pantalla, la misma distancia se proyectará a sqrt (3) en el eje X de la pantalla. Entonces, si dibujas cosas planas en la pantalla, harías algo como:

draw(object.image, object.x*sqrt(3), object.y)

Notas sin respuesta:

  • ¿Por qué te meterías con hojas de sprites y esas cosas? Puede obtener un renderizador 3D para hacer isométricos si lo desea.
  • Ya que estás usando hojas de sprites, ¿por qué no están suavizadas?
  • Isométrico en el espacio, no creo haber visto un juego usar eso, no estoy seguro de qué tan bien funcionará dada la falta de un terreno claramente isométrico para referencia visual.
aaaaaaaaaaaa
fuente
1
Creo que ... Esto podría arreglarlo todo. Es una solución fácil, y puedo dejar la hoja sola. Probaré esto lo antes posible y te diré cómo va. Para responder a sus notas: 1) Estoy usando 2D porque es con lo que estoy familiarizado, y estoy generando mis hojas a partir de modelos 3D. 2) Los bordes deben ser afilados, pero dentro de los bordes duros podría usar el canal alfa para anti-alias, eso vendrá. 3) No planeo simular la tercera dimensión (mucho), principalmente quiero gráficos 2D que no sean de arriba hacia abajo y le permitan ver los lados de las cosas.
John McDonald
5

¿Cómo se genera el sprite girado? ¿Son estas capturas de pantalla de un modelo 3D giratorio? El ángulo de orientación podría estar apagado debido a la perspectiva de la cámara de la herramienta de modelado 3D. La perspectiva isométrica no es una representación precisa del espacio 3D. Las cosas lejos de la 'cámara' no se hacen más pequeñas.

Si solo quieres una solución rápida. La solución 2 puede ser difícil de acertar. La solución 3 parece fácil, simplemente cambie los marcos que no coinciden con el ángulo con uno que se ajuste mejor al ángulo.

Los láseres todavía estarán apagados a veces. Como no está haciendo una rotación suave, sino que muestra diferentes marcos para ciertos rangos de grados.

EDITAR:

Su problema es que las capturas de pantalla generadas no son una perspectiva isométrica, sino una vista de cámara 3D normal.

ingrese la descripción de la imagen aquí

La vista isométrica simula el espacio 3D pero no es una representación precisa. Las cosas se vuelven más pequeñas a medida que aumenta la distancia de la cámara. Esto no se hace para la perspectiva isométrica ya que esto causaría artefactos de escalamiento feos en el sprite.

Las capturas de pantalla de tu nave espacial están hechas con una perspectiva de cámara 3D. Es por eso que el disparo con láser está apagado. Compare la línea roja en el 'isométrico' y la 'perspectiva'.

Su generador de sprites debe usar Matrix.CreateOrthographic () en lugar de Matrix.CreatePerspective () para la matriz de proyección.

Stephen
fuente
El sprite se genera utilizando una herramienta 3D a 2D que estoy desarrollando, por lo que el problema podría estar en esa herramienta. La herramienta simplemente carga un modelo 3D, luego para lograr Spaceship64.png (arriba), gira el modelo en (360/64) = 5.625 grados, lo guarda como un marco, luego lo gira nuevamente en la misma cantidad hasta que tenga todo 64 cuadros. El código utilizado para representar el modelo está aquí: code.google.com/p/sprite-maker/source/browse/trunk/XNAWindow/… La rotación se realiza en otra clase. También estaba pensando que las soluciones 2 y 3 eran inversas, ¿no?
John McDonald
Edité mi respuesta. Véase más arriba.
Stephen
Creo que podría necesitar hacer ambas cosas: hacer que mi generador de sprites use una proyección ortográfica Y altere mi sistema de coordenadas mundiales como lo que dice @eBusiness. Probé la proyección ortográfica anoche, y ciertamente cambió la apariencia de mi nave, pero por sí sola no solucionó el problema de ángulo que estoy experimentando.
John McDonald
Acabo de ver tu edición. El sprite corregido parece que el centro del barco está alejado del centro de la línea roja. Tal vez sea suficiente para dibujar la nave uno o dos píxeles más arriba que el punto de partida de la línea roja. ¿Cambia el error visible mientras la nave se aleja de su origen mundial? Luego, escalar el eje X podría solucionar esto.
Stephen
1

Creo que lo que tienes aquí es simplemente cómo se ve isométrico. Tienes razón en eso, visualmente hablando, parece haber una mayor diferencia entre 0deg y 10deg que entre 90deg y 100deg. . . pero eso es porque isométrica comprime intrínsecamente un eje. Si no quieres esa apariencia, no quieres isométrica.

Dicho esto, creo que los problemas visuales que tienes son gracias a no tener un punto de referencia visual. Tu cerebro está asumiendo que lo estás mirando de arriba hacia abajo, oye, es espacio, por qué no lo estarías, y también lo está interpretando como una vista de arriba hacia abajo estándar. En aras de las pruebas, intente agregar algunos puntos de referencia holográficos flotantes. Una cuadrícula angulada de 45 grados, por ejemplo, o un conjunto de círculos de alcance alrededor de su nave espacial. Asegúrese de que estén distorsionados adecuadamente como si estuvieran en el mismo plano isométrico en el que se representa la nave espacial. Apostaría a que su cerebro descubrirá la perspectiva y de repente se verá bien.

Ahora, descubriendo cómo transmitir eso a sus usuarios. . . Esa es otra cuestión por completo.

ZorbaTHut
fuente
¿No necesitaré también rotar el eje mundial para completar la ilusión usando este método (método # 1 en la pregunta)?
John McDonald
Por lo que puedo decir, la nave ya se está renderizando correctamente: las vistas laterales lo muestran en el ángulo que debería ser para que la isométrica se vea "correcta". Supongo que no estoy seguro de lo que quieres decir con "rotar el eje mundial".
ZorbaTHut
Por "rotar el eje del mundo", me refiero a rotar el mundo en relación con la cámara 45 grados para hacer que "Norte" esté hacia la esquina superior derecha o superior izquierda de la pantalla en diagonal en lugar de que "Norte" esté recto hacia arriba hacia la parte superior de la pantalla.
John McDonald
Eso podría ayudar, pero en el espacio no debería hacer tanta diferencia de todos modos. A menos que tenga una cuadrícula superpuesta en el mundo, simplemente no debería importar.
ZorbaTHut