Question

Quelle est la bonne façon de dessiner des tuiles isométriques dans un jeu 2D?

J'ai lu des références (comme celui-ci ) suggèrent que les tuiles rendue d'une manière qui va en zig-zag de chaque colonne dans la représentation du tableau 2D de la carte. J'imagine qu'ils devraient tirer plus d'une manière de diamant, où ce qui est dessiné à l'écran plus étroitement concerne ce que le tableau 2D ressemblerait, juste tourné un peu.

Y at-il des avantages ou des inconvénients à ces deux méthodes?

Était-ce utile?

La solution

Mise à jour:. Correction algorithme de rendu de la carte, a ajouté plus d'illustrations, changé formating

Peut-être l'avantage de la technique « zig-zag » pour mettre en correspondance les tuiles à l'écran peut dire que les coordonnées de tuiles x et y sont sur les axes verticaux et horizontaux.

approche "Dessin dans un diamant":

En dessinant une carte isométrique en utilisant « dessin dans un diamant », qui je crois fait référence à la carte juste du rendu en utilisant une boucle for reposant sur un tableau à deux dimensions, comme cet exemple:

tile_map[][] = [[...],...]

for (cellY = 0; cellY < tile_map.size; cellY++):
    for (cellX = 0; cellX < tile_map[cellY].size cellX++):
        draw(
            tile_map[cellX][cellY],
            screenX = (cellX * tile_width  / 2) + (cellY * tile_width  / 2)
            screenY = (cellY * tile_height / 2) - (cellX * tile_height / 2)
        )

Avantage:

L'avantage de cette approche est qu'il est un simple for-boucle imbriquée avec une logique assez simple qui fonctionne de manière cohérente dans toutes les tuiles.

Inconvénient:

Un inconvénient de cette approche est que les x et les coordonnées y des tuiles sur la carte augmentera dans les lignes diagonales, ce qui pourrait rendre plus difficile à cartographier visuellement l'emplacement sur l'écran de la carte représentée comme un tableau:

 image de carte de tuiles

Cependant, il va être un écueil à la mise en œuvre du code exemple ci-dessus - l'ordre de rendu causera des tuiles qui sont censées être derrière certaines tuiles à tirer sur le dessus des tuiles en face:

 image résultante de l'ordre de rendu incorrect

Pour modifier ce problème, l'ordre de for boucle intérieure doit être inversée - à partir de la valeur la plus élevée, et le rendu vers la valeur inférieure:

tile_map[][] = [[...],...]

for (i = 0; i < tile_map.size; i++):
    for (j = tile_map[i].size; j >= 0; j--):  // Changed loop condition here.
        draw(
            tile_map[i][j],
            x = (j * tile_width / 2) + (i * tile_width / 2)
            y = (i * tile_height / 2) - (j * tile_height / 2)
        )

Avec le correctif ci-dessus, le rendu de la carte doit être corrigée:

 image résultante du bon ordre de rendu

approche "Zig-Zag":

Avantage:

Peut-être l'avantage de l'approche « zig-zag » approche est que la carte rendue peut sembler être un peu plus verticalement compact que le « diamant »:

 approche Zig-zag pour le rendu semble compact

Inconvénient:

De essayer de mettre en œuvre la technique zig-zag, l'inconvénient est peut-être qu'il est un peu plus difficile à écrire le code de rendu, car il ne peut pas être écrit aussi simple que for boucle imbriquée sur chaque élément dans un tableau:

tile_map[][] = [[...],...]

for (i = 0; i < tile_map.size; i++):
    if i is odd:
        offset_x = tile_width / 2
    else:
        offset_x = 0

    for (j = 0; j < tile_map[i].size; j++):
        draw(
            tile_map[i][j],
            x = (j * tile_width) + offset_x,
            y = i * tile_height / 2
        )

En outre, il peut être un peu difficile d'essayer de comprendre les coordonnées d'une tuile en raison de la nature décalée de l'ordre de rendu:

 coordonnées sur un ordre zig-zag rendu

Note: Les illustrations fournies dans cette réponse ont été créés avec une implémentation Java du code de rendu de tuiles présenté, avec le tableau suivant int comme la carte:

tileMap = new int[][] {
    {0, 1, 2, 3},
    {3, 2, 1, 0},
    {0, 0, 1, 1},
    {2, 2, 3, 3}
};

Les images de tuiles sont:

  • tileImage[0] -> Une boîte avec une boîte à l'intérieur.
  • tileImage[1] -> Une boîte noire.
  • tileImage[2] -> Une boîte blanche.
  • tileImage[3] -> Une boîte avec un grand objet gris en elle.

Une note sur Largeurs de tuiles et hauteurs

Les variables tile_width et tile_height qui sont utilisés dans les exemples de code ci-dessus se réfèrent à la largeur et la hauteur de la dalle de sol dans l'image représentant la tuile:

Image montrant la largeur de la tuile et de hauteur

En utilisant les dimensions de l'image fonctionnera, tant que les dimensions de l'image et les dimensions de tuiles correspondance. Dans le cas contraire, la carte de tuile pourrait être rendue avec des espaces entre les tuiles.

Autres conseils

De toute façon fait le travail. Je suppose que par zigzag vous dire quelque chose comme ceci: (les chiffres sont ordre de rendu)

..  ..  01  ..  ..
  ..  06  02  ..
..  11  07  03  ..
  16  12  08  04
21  17  13  09  05
  22  18  14  10
..  23  19  15  ..
  ..  24  20  ..
..  ..  25  ..  ..

Et par le diamant que vous voulez dire:

..  ..  ..  ..  ..
  01  02  03  04
..  05  06  07  ..
  08  09  10  11
..  12  13  14  ..
  15  16  17  18
..  19  20  21  ..
  22  23  24  25
..  ..  ..  ..  ..

La première méthode a besoin plus de tuiles de sorte que l'rendue plein écran est dessiné, mais vous pouvez facilement faire une vérification limite et sauter toutes les tuiles complètement hors écran. Les deux méthodes, il faudra un certain crissement numéro pour savoir ce qui est l'emplacement de la tuile 01. En fin de compte, les deux méthodes sont à peu près égales en termes de mathématiques requis pour un certain niveau d'efficacité.

Si vous avez des tuiles qui dépassent les limites de votre diamant, je vous recommande de dessin pour la profondeur:

...1...
..234..
.56789.
..abc..
...d...

La réponse de Coobird est correcte, on complète. Cependant, je combiné ses notes avec celles d'un autre site pour créer un code qui fonctionne dans mon application (iOS / Objective-C), que je voulais partager avec tous ceux qui viennent ici à la recherche d'une telle chose. S'il vous plaît, si vous aimez / haut-vote cette réponse, faire la même chose pour les originaux; tout ce que je faisais était « debout sur les épaules de géants ».

En ce qui concerne ordre de tri, ma technique est un algorithme de peintre modifié: chaque objet a (a) une altitude de la base (je l'appelle « niveau ») et (b) un X / Y pour la « base » ou " pied » de l'image (exemples: la base de avatar est à ses pieds, la base de l'arbre est à ses racines, la base de l'avion est le centre-image, etc.) ensuite, je viens trier du plus bas au plus haut niveau, puis le plus bas (le plus haut sur l'écran) pour la plus élevée de base Y, alors le plus bas (le plus à gauche) à la base-X le plus élevé. Cela rend les tuiles comme on peut s'y attendre.

Code pour convertir l'écran (point) à carreaux (cellule) et arrière:

typedef struct ASIntCell {  // like CGPoint, but with int-s vice float-s
    int x;
    int y;
} ASIntCell;

// Cell-math helper here:
//      http://gamedevelopment.tutsplus.com/tutorials/creating-isometric-worlds-a-primer-for-game-developers--gamedev-6511
// Although we had to rotate the coordinates because...
// X increases NE (not SE)
// Y increases SE (not SW)
+ (ASIntCell) cellForPoint: (CGPoint) point
{
    const float halfHeight = rfcRowHeight / 2.;

    ASIntCell cell;
    cell.x = ((point.x / rfcColWidth) - ((point.y - halfHeight) / rfcRowHeight));
    cell.y = ((point.x / rfcColWidth) + ((point.y + halfHeight) / rfcRowHeight));

    return cell;
}


// Cell-math helper here:
//      http://stackoverflow.com/questions/892811/drawing-isometric-game-worlds/893063
// X increases NE,
// Y increases SE
+ (CGPoint) centerForCell: (ASIntCell) cell
{
    CGPoint result;

    result.x = (cell.x * rfcColWidth  / 2) + (cell.y * rfcColWidth  / 2);
    result.y = (cell.y * rfcRowHeight / 2) - (cell.x * rfcRowHeight / 2);

    return result;
}

vrai problème est quand vous avez besoin tirer des tuiles / sprites intersection / couvrant deux ou plusieurs autres tuiles.

Après 2 (dur) mois de analisys personnels de problème j'ai finalement trouvé et mis en œuvre une « bonne render dessin » pour mon nouveau jeu cocos2d-js. Solution consiste dans la cartographie, pour chaque tuile (sensible), qui sont sprites « avant, arrière, haut et derrière ». Une fois que faire, vous pouvez les dessiner la suite d'une « logique récursive ».

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top