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:
- 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?)
- 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.
- 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.
- ¡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 rotation
está el ángulo de la pantalla y adjustedRotation
ahora 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".