Tout d'abord, je sais exactement quel est mon problème de dessin et j'ai différentes idées sur la façon d'aborder le problème. Je suis ici pour comprendre comment ajuster le cadre qui est dessiné afin que "l'illusion" isométrique soit maintenue.
J'écris un jeu 2D à vue d'oiseau qui se déroule dans l'espace. J'essaie d'utiliser des graphiques isométriques dans un monde où Up is North, pas de rotation du monde du jeu comme dans les jeux isométriques traditionnels (rappelez-vous, le jeu se déroule dans l'espace, pas de terrain). Voici un exemple de sprite que j'essaie d'utiliser: http://cell.stat-life.com/images/stories/AsteroidOutpost/Spaceship64.png Tourné 64 fois autour de son propre axe vertical avec un angle de vue de 35 degrés (aka, iso). L'image a été générée, elle peut donc être modifiée.
Par souci de clarté, j'ai dicté que le nord (haut) est de 0 degré et l'est (droite) de 90 degrés.
Mon problème est que mon sprite n'a pas toujours l' air comme ça face où le jeu pense qu'il est dû à une différence dans les plans 3D utilisés. Je ne sais pas si j'utilise correctement la terminologie, mais mon vaisseau spatial a été tourné sur un plan, et le plan de vue s'attend à ce que les choses tournent sur son propre plan. Voici une description du problème:
http://cell.stat-life.com/images/stories/AsteroidOutpost/ProjectionIssue.png A gauche, j'ai des vues de côté, à droite j'ai des vues de haut en bas. En haut, j'ai la vue vaisseau spatial / feuille de sprite du monde. En bas, j'ai à quoi ressemble le sprite quand il est dessiné à l'écran.
En haut à droite se trouve une version simplifiée de la rotation de mon vaisseau spatial (même des degrés de séparation entre chaque image). En bas à droite se trouve l'angle auquel le sprite ressemble face à quand un angle particulier est dessiné sur l'écran. Le problème est plus évident à environ 45 degrés. Voici une image qui est superposée avec une ligne "écran plan" qui est pointée dans la direction à laquelle le navire est censé faire face: http://cell.stat-life.com/images/stories/AsteroidOutpost/Spaceship64RedLine.png La ligne rouge doit toujours être pointée dans la même direction que le navire, mais comme vous pouvez le voir, le problème de projection pose problème. J'espère que je décris assez bien le problème.
EDIT: La ligne rouge pivote sur le plan de l'écran, tandis que le vaisseau spatial est tourné sur le "plan du navire", d'où la grande différence entre l'angle du navire et l'angle de l'écran lorsqu'il est tracé. FIN DE LA MODIFICATION
Cela semble plutôt étrange lorsque ce navire tire un faisceau laser sur une cible qui se trouve sur un côté, alors qu'il devrait tirer droit devant.
Donc ... les solutions que j'ai trouvées sont:
- Arrêtez d'essayer de simuler une vue isométrique, de grandir ou de rentrer chez vous. Faites déjà tourner mon monde. (PS: cela résoudra mon problème, non?)
- Modifiez ma feuille de sprite (en quelque sorte) pour avoir des cadres qui représentent "l'angle d'écran" auquel le modèle sera affiché. Donc, quand je demande une image à 45 degrés, elle ressemblera en fait à 45 degrés sur l'écran.
- Modifiez mon système de rendu de sprite pour saisir une image différente de la feuille de sprite (en quelque sorte), sachant que saisir l'image "normale" sera drôle. Ainsi, au lieu de saisir le cadre à 45 degrés, il saisira le cadre à ... 33 degrés (juste en devinant) afin qu'il semble correct pour l'utilisateur.
- Utilisez simplement la 3D! C'est tellement plus facile mec
Premièrement: quelle solution recommanderiez-vous? Je penche vers 2, même si je sais que c'est faux. N'oubliez pas que j'ai un accès complet à l'outil de génération de sprites. La méthode 3 serait mon deuxième choix. Ces deux méthodes nécessitent simplement que j'applique des mathématiques aux angles pour obtenir le résultat souhaité. Btw, j'ai ajouté # 4 là-dedans comme une blague, je ne veux pas passer à la 3D.
Pour deux: en utilisant les méthodes 2 ou 3, comment ajuster les angles d'entrée ou de sortie? Je ne suis pas très bon avec les projections 3D et les matrices 3D (sans parler des matrices 2D), et tout autre calcul qui pourrait être utilisé pour atteindre le résultat souhaité.
Penser à haute voix ici: si je prends un vecteur unitaire orienté dans la direction dans laquelle je veux que le navire regarde (sur le plan de l'écran), puis le projeter sur le plan du navire, puis comprendre quel est l'angle entre cette ligne projetée et celle de l'avion nord est, je devrais avoir l'angle du graphique du navire que je veux afficher. Droite? (solution pour # 3?) Mec ... Je ne peux pas résoudre ça.
ÉDITER:
Je sais que le problème est difficile à visualiser avec des images statiques, j'ai donc respecté mon Sprite Library Visual Tester pour afficher le problème: http://cell.stat-life.com/downloads/SpriteLibVisualTest.zip Il nécessite XNA 4.0 Cette application est il suffit de faire tourner le sprite et de tracer une ligne de son point central vers l'extérieur à l'angle auquel le jeu pense que le navire doit faire face.
EDIT 8 septembre
Suite de mon paragraphe «penser à haute voix»: Au lieu d'utiliser une projection (parce que ça a l'air difficile), je pense que je pourrais prendre un vecteur unitaire orienté au nord (0x, 1y, 0z), utiliser une matrice pour le faire pivoter à l'angle le sprite est en fait tourné, puis faites-le pivoter à nouveau du "plan d'observation" vers le "plan du sprite" autour de l'axe X, puis ... aplatir? le vecteur (essentiellement le projeter) sur le plan de visualisation en utilisant uniquement les X et Y (en ignorant Z). Ensuite, en utilisant ce nouveau vecteur aplati, je pouvais déterminer son angle et l'utiliser pour ... quelque chose quelque chose. J'y penserai plus tard.
MODIFIER le 8 septembre (2)
J'ai essayé de suivre mon idée d'en haut avec un certain succès, yay! Donc ... pour obtenir une ligne rouge qui semble sortir directement de mon vaisseau spatial (à des fins de test uniquement), j'ai fait ce qui suit:
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));
Où rotation
est l'angle de l'écran et adjustedRotation
est maintenant cet angle de l'écran sur le plan de l'image-objet. Je ne sais pas pourquoi je devais faire pivoter Y au lieu de X, mais c'est probablement quelque chose à voir avec la 3D que je ne connais pas.
Donc, j'ai maintenant une information supplémentaire, mais comment puis-je l'utiliser pour choisir un cadre plus approprié? Peut-être qu'au lieu de tourner du plan de vue dans le plan de sprite, puis de projeter en arrière, je devrais essayer de le faire dans l'autre sens. Voici mon sprite avec une ligne rouge ajustée, mais ce que je veux vraiment faire, c'est ajuster le modèle, pas la ligne: http://cell.stat-life.com/images/stories/AsteroidOutpost/Spaceship64RedLineCorrected.png
EDIT 9 septembre
HORAY! C'est réparé! Je vais décrire ce que j'ai fait pour y remédier:
J'ai suivi les conseils de eBusiness et "écrasé" par le système de coordonnées mondial (ou étiré ...?). Il s'agit essentiellement de la solution n ° 1, même si j'avais l'impression que je devrais faire pivoter mon système de coordonnées universelles par rapport au système de coordonnées d'écran. Pas vrai! Haut est toujours + y, et Droite est toujours + x. J'ai modifié mes méthodes WorldToScreen et ScreenToWorld pour convertir correctement entre les coordonnées du monde et de l'écran. Ces méthodes ne sont peut-être pas optimales, mais voici les deux seules méthodes de ma base de code qui ont dû changer.
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);
}
C'était ça! Changer ces deux méthodes a affecté tout le reste: ce que je regardais, où les objets étaient dessinés, où je cliquais, tout. Mon vaisseau spatial regarde maintenant directement la cible qu'il tire, et tout se met en place. J'expérimenterai avec la projection orthographique, voir si elle rend tout plus «réel».