Façonner des graphiques isométriques dans un jeu spatial 2D


15

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:

  1. 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?)
  2. 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.
  3. 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.
  4. 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));

rotationest l'angle de l'écran et adjustedRotationest 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».


Toutes nos félicitations. N'oubliez pas de me piquer une fois que vous avez quelque chose de jouable, j'aimerais voir où cela va.
aaaaaaaaaaaa

@eBusiness Comme promis: cell.stat-life.com/images/stories/AsteroidOutpost/… et cell.stat-life.com/images/stories/AsteroidOutpost/AOOhNoes.png Remarquez à quoi ressemble le navire qui regarde cette tour? : D Merci!
John McDonald,

@eBusiness, une vidéo youtube.com/watch?v=Q8pR9KDBsCo Il y a aussi un lien à télécharger, comme vous l'avez demandé.
John McDonald

Réponses:


4

Lorsque vous avez choisi la perspective isométrique, vous devez corriger l'échelle entre les axes X et Y. Si une distance donnée se projette sur 1 sur l'axe Y des écrans, alors la même distance se projettera sur sqrt (3) sur l'axe X des écrans. Donc, si vous dessinez des choses à plat sur l'écran, vous feriez quelque chose comme:

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

Notes de non-réponse:

  • Pourquoi voudriez-vous jouer avec des feuilles de sprite et d'autres choses? Vous pouvez obtenir un rendu 3D pour faire de l'isométrique si vous le souhaitez.
  • Puisque vous utilisez des feuilles de sprite, pourquoi ne sont-elles pas anti-aliasées?
  • Isométrique dans l'espace, je ne pense pas avoir jamais vu un jeu utiliser cela, je ne sais pas comment cela fonctionnera compte tenu de l'absence d'un terrain clairement isométrique pour une référence visuelle.

1
Je pense ... Cela pourrait tout arranger. C'est une solution facile et je peux laisser la feuille seule. Je vais essayer cela dès que possible et vous faire savoir comment ça se passe. Pour répondre à vos notes: 1) J'utilise la 2D car c'est ce que je connais et je génère mes feuilles à partir de modèles 3D. 2) Les bords doivent être nets, mais à l'intérieur des bords durs, je pourrais utiliser le canal alpha pour l'anti-alias, cela viendra. 3) Je ne prévois pas (beaucoup) de simuler la troisième dimension, je veux principalement des graphismes 2D qui ne sont pas de haut en bas et vous permettent de voir les côtés des choses.
John McDonald,

5

Comment le sprite tourné est-il généré? S'agit-il de captures d'écran d'un modèle 3D rotatif? L'angle d'orientation pourrait être désactivé en raison de la perspective de la caméra de l'outil de modélisation 3D. La perspective isométrique n'est pas une représentation précise de l'espace 3D. Les objets éloignés de la «caméra» ne diminuent pas.

Si vous voulez juste une solution rapide. La solution 2 peut être difficile à obtenir correctement. La solution 3 semble facile, il suffit d'échanger les cadres ne correspondant pas à l'angle avec un cadre qui correspond mieux à l'angle.

Les lasers seront toujours éteints parfois. Comme vous ne faites pas une rotation en douceur mais que vous montrez des images différentes pour certaines plages de degrés.

ÉDITER:

Votre problème est que les captures d'écran générées ne sont pas une perspective isométrique, mais une vue de caméra 3D normale.

entrez la description de l'image ici

La vue isométrique simule l'espace 3D mais n'est pas une représentation précise. Les choses deviennent plus petites avec l'éloignement de la caméra. Cela n'est pas fait pour la perspective isométrique car cela provoquerait des artefacts de mise à l'échelle laids dans l'image-objet.

Les captures d'écran de votre vaisseau spatial sont faites avec une perspective de caméra 3D. C'est pourquoi la prise de vue au laser est désactivée. Comparez la ligne rouge dans le «isométrique» et la «perspective».

Votre générateur de sprites doit utiliser Matrix.CreateOrthographic () au lieu de Matrix.CreatePerspective () pour la matrice de projection.


Le sprite est généré à l'aide d'un outil 3D à 2D que je développe, donc le problème pourrait très bien être dans cet outil. L'outil charge simplement un modèle 3D, puis pour atteindre Spaceship64.png (ci-dessus), il fait pivoter le modèle de (360/64) = 5,625 degrés, l'enregistre en tant que cadre, puis le fait pivoter à nouveau du même montant jusqu'à ce qu'il ait tout 64 images. Le code utilisé pour rendre le modèle est ici: code.google.com/p/sprite-maker/source/browse/trunk/XNAWindow/… La rotation est effectuée dans une autre classe. Je pensais aussi que les solutions 2 et 3 étaient l'inverse l'une de l'autre, non?
John McDonald, le

Modifié ma réponse. Voir au dessus.
Stephen

Je pense que je devrais peut-être faire les deux: faire en sorte que mon générateur de sprites utilise une projection orthographique ET modifier mon système de coordonnées mondial comme ce que dit @eBusiness. J'ai essayé la projection orthographique la nuit dernière, et cela a certainement changé l'apparence de mon navire, mais cela ne résout pas à lui seul le problème d'angle que je rencontre.
John McDonald,

Je viens de voir votre montage. Le sprite corrigé semble que le centre du navire soit éloigné du centre de la ligne rouge. Peut-être qu'il suffit de dessiner le navire un ou deux pixels plus haut que le point de départ de la ligne rouge. L'erreur visible change-t-elle lorsque le navire s'éloigne de votre origine mondiale? Ensuite, la mise à l'échelle de l'axe X pourrait résoudre ce problème.
Stephen

1

Je pense que ce que vous avez ici est simplement à quoi ressemble isométrique. Vous avez raison, visuellement, il semble y avoir une plus grande différence entre 0deg et 10deg qu'entre 90deg et 100deg. . . mais c'est parce que l'isométrique comprime intrinsèquement un axe. Si vous ne voulez pas ce look, vous ne voulez pas d'isométrie.

Cela dit, je pense que les problèmes visuels que vous rencontrez sont dus à l'absence de point de référence visuel. Votre cerveau suppose que vous le regardez de haut en bas - hé, c'est l'espace, pourquoi ne le seriez-vous pas - et il en va de même pour l'interpréter comme une vue de haut en bas standard. À des fins de test, essayez d'ajouter des points de référence holographiques flottants. Une grille inclinée à 45 degrés, par exemple, ou un ensemble de cercles de portée autour de votre vaisseau spatial. Assurez-vous qu'ils sont correctement déformés comme s'ils se trouvaient sur le même plan isométrique que votre vaisseau spatial. Je parie que votre cerveau va comprendre la perspective et qu'il semblera soudainement droit.

Maintenant, découvrez comment transmettre cela à vos utilisateurs. . . c'est une tout autre affaire.


N'ai-je pas besoin également de faire pivoter l'axe mondial pour compléter l'illusion en utilisant cette méthode (méthode n ° 1 dans la question)?
John McDonald, le

Pour autant que je sache, le vaisseau est déjà rendu correctement - les vues latérales le montrent à l'angle qu'il devrait être pour que l'isométrique ait l'air "correct". Je suppose que je ne suis pas sûr de ce que vous entendez par "faire pivoter l'axe mondial".
ZorbaTHut

Par "faire pivoter l'axe du monde", je veux dire faire pivoter le monde par rapport à la caméra de 45 degrés pour que "Nord" soit en haut à droite ou en haut à gauche de l'écran en diagonale au lieu de "Nord" étant droit vers le haut vers le haut de l'écran.
John McDonald, le


Cela pourrait aider, mais dans l'espace, cela ne devrait pas faire une grande différence de toute façon. À moins que vous ayez une grille superposée au monde, cela ne devrait pas avoir d'importance.
ZorbaTHut
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.