2013-01-23 2 views
8

J'ai des problèmes avec les murs isométriques.Dessin de murs isométriques

Je dessine des carreaux de sol isométriques en utilisant la méthode de rendu de face à face, et cela fonctionne bien. Je garde également mes carreaux de sol alignés correctement dans une belle grille. Le code (et cela semble être à peu près standard pour le dessin au sol isométrique) est la suivante:

for(int x = 0; x < 6; x++){ 
    for(int y = 3; y >=0 ; y--){ 

     int xCo = (y+x)*(tileWidth/2); 
     int yCo = (x-y)*(tileHeight/2); 
     tile.draw(g, xCo, yCo); 
    }    
} 

Cela fait un joli petit étage:

multiple floor tiles

La grille est construite à partir de cette tuile :

A single tile

Malheureusement, lorsque j'utilise la même logique pour les murs, tout va Righ t en enfer.

for(int x = 0; x < 6; x++){ 
    for(int y = 3; y >= 0 ; y--){ 

     int xCo = (y+x)*(wallWidth()/2); 
     int yCo = (x-y)*(wallHeight()/2); 
     walls.draw(g, xCo, yCo);  
} 
} 

J'utilise cela comme mon carrelage mural:

Single wall tile

(c'est un espace réservé de la recherche d'image de Google, mais il devrait fonctionner tout de même)

C'est le résultat que j'obtiens:

Multiple wall tiles

L'ordre de rendu de mes murs est clairement correct, les murs plus proches se trouvent au-dessus de murs plus éloignés, ce que je veux, mais le positionnement est aussi douloureusement incorrect, et je ne sais pas exactement comment je devrais corriger cela. en utilisant des valeurs de pixels. Pour référence, j'ai fait un essai en utilisant des valeurs de pixel codées en dur, parce que j'ai trouvé que du coin droit d'un mur au coin droit du mur suivant, le changement était exactement (200, -100) pixels. Quand je fait mon compte rendu de la boucle pour que

int xCo = (x+y)*200; 
int yCo = (y-x)*-100; 

il a bien fonctionné, mais ce n'est pas une solution viable parce qu'elle ne permet pas de polyvalence. Donc, en cherchant des suggestions sur la façon de faire mes murs isométriques aligner. Qu'est-ce que je fais mal?

Merci!

+0

Merci d'avoir rendu mes photos visibles. J'ai aussi posté sur gamedev.stackexchange, et ils sont très restrictifs sur les liens et les images, donc je n'ai pas essayé ici. –

+0

J'ai remarqué un motif avec vos murs: le bord horizontal supérieur avant du premier mur est colinéaire avec le bord horizontal inférieur avant du troisième mur. En outre, le bord vertical avant droit du premier mur est colinéaire avec le bord vertical arrière gauche du troisième mur. La même chose est vraie des deuxième et quatrième murs. Donc, ils sont en quelque sorte alignés. Juste pas comme tu le veux. – Kevin

+0

Haha oui, c'est vrai.Je vais prendre un certain réconfort dans ce fait, mais je ne suis pas sûr de savoir quoi en faire, sauf que "ma méthode est à moitié mauvaise" –

Répondre

2

Vous ne pouvez pas simplement utiliser le même code de dessin pour les murs que pour les sols car les murs et les sols ne sont pas dans le même plan: les sols sont plats (horizontaux) tandis que les murs sont verticaux. Vous devez donc les dessiner légèrement différemment. Vos coordonnées x et y dans le plancher signifient quelque chose comme «gauche/droite» et «avant/arrière» en termes de placement des carreaux. Pour les briques, gauche et droite ont encore du sens, mais nous voulons remplacer vers l'avant/vers l'arrière avec haut et bas pour refléter la direction verticale. Donc, notre "y" prend un nouveau sens. Maintenant, en Maths, l'axe y pointe généralement vers le haut tandis que dans l'infographie 2D, il pointe vers le bas. Vous pouvez faire votre choix - le code ci-dessous suppose qu'il pointe vers le haut afin que y = 0 signifie "au niveau du sol". Alors commençons à penser à la commande. L'exemple de brique que vous avez affiché concerne un mur qui serait l'extrémité gauche (supérieure) d'un étage. En raison des parties noires de la brique (la profondeur du mur), nous devons nous assurer que nous dessinons d'abord les briques les plus droites afin que la profondeur noire sur le côté gauche soit couverte par des briques plus proches. Le même argument s'applique pour le noir sur la partie supérieure du mur, nous devons d'abord tirer les briques inférieures. Si nous nous en tenons aux directions x et y mentionnées plus haut (x va de gauche à droite, y va de bas en haut), cela signifie que nous devons exécuter nos deux boucles for dans des directions négatives:

for (int y = 3; y >= 0; y--) { 
     for (int x = 5; x >= 0; x--) { 
      ... 
     } 
    } 

la principale question est maintenant combien nous devons compenser le dessin de chaque brique par rapport aux autres briques. Faisons cela une direction à la fois, en commençant par la direction x.

Imaginons que deux briques à côté de l'autre:

two bricks horizontally

La gauche des deux a la partie de la profondeur noire visible, mais le droit on ne doit pas le montrer.Ainsi, nous ne pouvons pas simplement décaler l'image de droite sur toute la largeur du PNG. En fait, en supposant que les briques s'alignent avec vos carreaux de sol, la largeur de la partie avant réelle du mur devrait être la même que la moitié de la largeur d'une tuile.

int xCo = x * tileWidth/2; 

La profondeur de mur noir sur la gauche ne doit pas être ignoré, parce que nous voulons probablement compenser chaque brique un peu à gauche, de sorte que la coordonnée x du coin avant des lignes de mur vers le haut avec le carreaux de sol, pas les coordonnées x du coin arrière.

Maintenant, la coordonnée y de chaque brique est un peu plus compliquée car elle dépend non seulement de la rangée de briques, mais aussi de la coordonnée x: plus la droite est haute, plus nous devons dessiner. Mais nous allons ignorer la direction x pour un moment et essayer d'en tirer simplement une colonne de briques:

two bricks vertically

Encore une fois, le delta entre les coordonnées y des deux briques n'est pas la hauteur de la PNG . Contrairement au cas gauche/droite où nous avons supposé que les briques s'alignaient avec des tuiles qui nous permettaient d'utiliser tileWidth comme delta-x, les briques peuvent avoir des hauteurs arbitraires. Mais nous pouvons toujours calculer la hauteur réelle de la brique à partir de la hauteur de l'image, car nous savons que la profondeur du côté gauche et la profondeur du sommet doivent s'aligner. Si nous regardons le petit triangle transparent dans le coin supérieur droit de la brique PNG, nous remarquons que le rapport entre sa largeur et sa hauteur doit être le même que le rapport entre la largeur et la hauteur d'une dalle. Cela nous permet de calculer un yoffset du xoffset calculé ci-dessus, et à l'utiliser pour en déduire la hauteur réelle de la brique:

int yoffset = xoffset * tileHeight/tileWidth; 
int wallHeight = wallHeight() - tileHeight/2 - yoffset; 

Notez que cela ne fonctionne que sous l'hypothèse qu'il n'y a pas d'espace vide à la frontière le PNG et il pourrait encore échouer en raison d'erreurs d'arrondi. Donc, vous pouvez ajouter un Math.ceil() (ou simplement + 1) ici si nécessaire. Donc pour les colonnes simples, il est bon d'y aller maintenant: nous pouvons simplement multiplier notre variable y par la wallHeight ci-dessus. Mais comme indiqué précédemment, la position x d'une brique influence également la coordonnée des pixels y. Si nous regardons à nouveau la première image avec les deux briques l'une à côté de l'autre, combien avons-nous dû déplacer la brique droite pour l'aligner avec la brique gauche? Eh bien, celui-ci est vraiment facile, parce que c'est la même chose que pour les carreaux de sol: la moitié de la hauteur d'une tuile!

Donc, nous sommes tous ensemble. Si nous mettons tout ensemble, nous nous retrouvons avec un peu de code comme ceci:

int xoffset = wallWidth() - tileWidth/2; 
int yoffset = xoffset * tileHeight/tileWidth; 
int wallHeight = wallHeight() - tileHeight/2 - yoffset; 

for (int y = 3; y >= 0; y--) { 
    for (int x = 5; x >= 0; x--) { 

     int xCo = x * tileWidth/2; 
     int yCo = y * wallHeight - x * tileHeight/2; 

     walls.draw(g, xCo - xoffset, yCo - yoffset); 
    } 
} 

(Je suppose que wallWidth() et wallHeight() renvoient la largeur et la hauteur de la brique PNG.)

Notez que les trois constantes avant les boucles for peuvent être déplacées du code de dessin réel - elles dépendent uniquement des propriétés de l'image et d'autres constantes et ne doivent pas être recalculées chaque fois que nous dessinons le mur.

+0

Donc, d'abord je tiens à vous remercier pour une réponse incroyablement approfondie.Vous êtes une sorte de magicien. D'abord, je ne comprends pas ce qui se passe ici: "En fait, en supposant que les briques s'alignent avec vos carreaux de sol, la largeur de la réelle » Si elles sont alignées, leurs largeurs ne devraient-elles pas être les mêmes? Également, pourriez-vous expliquer comment obtenir la coordonnée y de la paroi? Si je veux les aligner au lieu d'empiler votre première image des deux murs côte à côte est ce que je vais pour –

+0

Aussi, ho w dois-je gérer les coordonnées x si les murs ne sont pas alignés avec des carreaux de sol? Comment puis-je gérer les murs indépendamment, fondamentalement. –

+1

Pas de soucis - si vous n'avez pas besoin d'empiler les murs, remplacez simplement la boucle for-for externe par 'int y = 0'. A part ça, avez-vous essayé le code et voyez s'il fait quelque chose de proche de ce que vous voulez? Il pourrait être plus facile pour vous de simplement copier et coller, puis commencer à jouer avec. --- Concernant votre question avec les largeurs: le problème ici est que parfois j'utilise le mot largeur pour faire référence à la largeur d'un mur ou d'une tuile, et parfois à la largeur de l'image. En raison de la vue isométrique, ces deux largeurs sont différentes. Dans la phrase citée, je fais référence aux largeurs d'image. – Thomas

0

Si vous regardez le carreau qui a la forme d'un losange, le fait de le déplacer d'une demi-largeur et de l'autre côté de la moitié de la longueur de deux arêtes s'alignera.
La dalle murale n'est pas un losange; par conséquent, en déplaçant la moitié de la largeur et en travers de la moitié de la longueur, les bords que vous souhaitez aligner ne s'alignent pas.

dans ce cas

Étant donné u = distance pour se déplacer dans et v = distance pour déplacer vers le haut et A l'angle isométrique

v = u*tan(A)

u est la largeur de la face avant de l'image.

si le visage (le bit texturé) de l'image murale correspond à la longueur de bord de la dalle de plancher ce qui donne

int offset = ?;// this is the width of the black stripe on the image. 

for(int x = 0; x < 6; x++){ 
    for(int y = 3; y >=0 ; y--){ 

     int xCo = ((y+x+1)*(tileWidth/2))-offset; 
     int yCo = (x-y)*(tileHeight/2); 
     wall.draw(g, xCo, yCo); 
    }    
} 
+0

Je peux travailler avec ça. Je suis sur mon téléphone, donc je vais le tester plus tard, mais merci! Je veux m'assurer que je suis clair sur les termes ici: Lorsque vous dites «si le visage de l'image correspond à la longueur du bord de la dalle», de quoi parlez-vous exactement? Il y a trop de sens possible là pour que je sois sûr (la largeur de l'image qui est rectangulaire, la longueur réelle de la tuile qui est difficile à trouver et ennuyeuse parce qu'elle n'est pas carrée, etc.). Merci encore! –

+1

Je voulais dire la texture sur l'image du mur, par opposition à la partie de profondeur noire. Par le bord de la tuile de plancher je veux dire la ligne entre deux points adjacents sur le diamant, pas les côtés du rectangle qui contient l'image. – BevynQ

+0

donc j'ai juste besoin de faire le décalage d'une partie cohérente de la largeur de l'image, de sorte qu'il peut accepter plusieurs images faites à la même spécification, non? –

0

Dans un domaine isométrique, il y a trois axes que vous pouvez déplacer - Z jusqu'à et vers le bas, X et Y pour vos «diagonales».

D'abord, imaginons la représentation de pixel d'une 1 unité par unité 1 par 1 unité cube isométrique, avec toutes les parties représentées aussi longue:

Il serait pixels de haut sur l'axe Z. Ses autres bords seraient également A pixels de longueur, mais tourné de 60 degrés - donc ce serait sin (30) * A pixels haute et cos (30) * A pixels de long dans les directions X et Y - aka, 0,5 * A et sqrt (3)/2 * A.

Ainsi, pour positionner un objet en forme de cube de taille isométrique en X, Y et Z nous devons traduire son sur l'écran x et y par ce qui suit:

y += Z*A 
x += X*A/2 - Y*A/2 
y += (X+Y)*A*sqrt(3)/2 

Tant que les hypothèses j'ai fait tenir ce devrait travail.

EDIT: A ce propos, A devra être codé en dur si l'image a une profondeur et donc vous ne pouvez pas extraire automatiquement A des dimensions de l'image.

Questions connexes