|
Zoglu
|
Posté le 27 Juin 2008 à 15:59
|
|

Messages : 366
GCPoints : 22183
|
Voilà un problème sur lequel j'ai bien du perdre 2 heures, sons trouver la solution
Ce problème concerne un peu MMF 2, mais il n'est pas nécessaire de connaître ce programme pour le résoudre (donc, même si vous ne connaissez pas MMF 2, viendez )
J'essaye de faire une sorte de petit jeu (c'est juste un essai, rien de sérieux) en vue isométrique. On peut déplacer un personnage (le cube jaune dans le screenshot en bas) dans toutes les directions, et sauter. Le décor et le personnage son tous constitués de blocs, ayant une longueur X, une largeur Y, et une hauteur Z variable, tout cela étant placé dans une grille 10 x 10 x 10.
Tout fonctionne pour la partie déplacement, mais le problème vient de la vue isométrique. Pour réaliser cette vue, il faut placer certains objets devant ou derrière les autres.
Pour cela, dans MMF2, j'attribue une valeur à chaque objet, et MMF2 "trie" les objets, en plaçant devant ou derrière ceux qui ont la plus petite ou la plus grande valeur (dans l'ordre croissant ou décroissant des valeurs, c'est comme on veut).
(les valeurs 1,2,3 que je mets ici étant prises complètement au pif, c'est juste pour l'exemple)
Le problème est donc là : quelle valeur dois-je attribuer aux objets pour qu'ils s'affichent convenablement? Quelle est la formule magique?
On peut mettre, dans cette formule, tous les paramètres possibles et imaginables : coordonnée X, Y, Z des blocs ou du personnage à déplacer, longueur, largeur et hauteur des blocs ou du perso, taille de la grille (10 x 10 x 10)...
Voilà. Merci d'avance à tous ceux qui chercheront une solution à ce problème
Dernière édition le 27 Juin 2008 à 16:01
|
|
Darktib
|
Posté le 27 Juin 2008 à 16:42
|
|

Messages : 4017
GCPoints : 347288
|
En 3D ca ressemble énormément au Z-Buffer. Du coup pourquoi ne pas s'en inspirer?
Le Z-Buffer attribue une valeur a chaque pixel, valeur correspondant à la profondeur. Peut etre que tu peut rentrer pour chaque vertex sa distance à la 'caméra', distance qui pourrait etre utilisée comme trieur.
|
|
Mod
|
Posté le 27 Juin 2008 à 19:24
|
|

Messages : 4954
GCPoints : 2100823
|
Tu as la chance d'avoir un expert es isométrie à portée de clavier .
Ce problème, j'y ai passé un temps incroyable (comme pour tout ce qui concerne l'isométrie d'ailleurs), mais j'ai trouvé la solution. Je comptais en faire d'ailleurs un tutoriel (gestion des maps isométriques à relief), donc on pourrait dire qu'en voici un morceau. Ce n'est pas réfléchi comme pourrait l'être un tutoriel, donc pas nécessairement simple à comprendre. D'autant plus que j'ai résolu ce problème il y a plusieurs mois, donc expliquer le cheminement algorithmique peut être difficile.
Algorithme d'affichage :
Pour la gestion d'une map isométrique à relief, il fait clairement commencer par définir l'unité de base. Typiquement, ce sera un parallélépipède approchant le cube. Tout élément graphique plus grand que cette unité de base devra être découpée en plusieurs unités de taille inférieure. Long et fastidieux, mais c'est ainsi que l'on s'assure d'avoir un rendu propre sans bug.
Mon système part du principe que la case de coordonées (0,0,0) est située tout en haut de la carte, et que la map isométrique est de largeur et de longueur égales. Ceci n'a pas été testé sur une map rectangulaire, je ne saurais dire pour l'instant si cela fonctionne aussi parfaitement, même si c'est en théorie correct (qui plus est, même si l'on affiche uniquement une portion rectangulaire d'une map, on peut l'extrapoler à un carré).
Un calcul tout simple permet alors d'attribuer alors un ordre de rendu à un cube :
Code :
(x + y) * f1 + z * f2 + x
On a x et y qui sont les abscisses isométriques d'une case, et z sa hauteur. Je nommerai mx la largeur de la map isométrique et my sa longueur. f1 et f2 sont des constantes détaillées juste après.
1/ La somme de x et de y permet de donner une première estimation de l'ordre de priorité. La case tout en haut, de coordonnées (0,0,0), aura un ordre de rendu de par 0, et celle tout en bas (disons pour une map de 10x10) sera à 100. Par ce premier calcul, on a immédiatement une problématique de résolue : les cases sur une diagonale de la map (affiché sur une ligne à l'écran) ont toutes un ordre de rendu égal, ce qui est parfaitement logique.
2/ Cette somme doit être multipliée par un facteur tel que f1 > (mx * my) et f1 > f2. Ce premier terme de la somme est celui que je qualifierai de "haut niveau", il permet de déterminer l'ordre de rendu des cases sur un plan bidimensionnel.
3/ On ajoute ensuite z, que l'on multiplie par un facteur qui doit être tel que f2 > mx et f2 > my. Ce deuxième terme est celui de "moyen niveau", il permet de différencier les niveaux de case de map entre eux. Attention que cela sert à différencier les cases pour une abscisse et une ordonnée de la map donnée. Une cause d'échec sur ce type de problème c'est justement que l'on prend le problème à l'envers en faisant de la gestion de la hauteur une priorité.
4/ Enfin, on ajoute x, qui permet d'obtenir un ordre de rendu unique pour chaque case. On a ici le troisième terme de "bas niveau". Il peut ne pas être utile selon le mode de rendu utilisé, mais c'est toujours préférable d'avoir une différence marquée entre chaque case.
Ce calcul devrait être réalisé au chargement de la map et attribué définitivement à chaque case pour des raisons de performances. Cela évite de calculer à chaque affichage l'ordre de rendu. Dans le cas où il faudrait bouger une case, il suffit de recalculer son ordre de rendu.
Gestion de l'affichage :
Ici, un sprite = une case au sens général.
Deux cas pour deux modes de rendus possibles :
Soit il est possible d'afficher directement des sprites avec une profondeur donnée (c'est le cas des sprites de DirectX, par exemple), et il faut alors remercier le ciel de ce don, le travail est simplifié. Il suffit d'indiquer l'ordre de rendu calculé plus haut en profondeur d'affichage du sprite (dans le cas de DirectX, par défaut une profondeur positive dessine un sprite après celui d'une profondeur inférieure, mais cela peux nécessiter des changements selon le cas).
Soit, on ne peut afficher des sprites qu'avec une ordonnée et une abscisse (bref, de la 2D pure), et il va donc falloir passer par ... une liste chaînée :D.
La liste doit contenir les cases par ordre croissant suivant leur ordre de rendu. Travail à effectuer au chargement de la map, toujours pour des raisons de performances. Liste doublement chaînée, bien évidemment, il faut pouvoir l'explorer de haut en bas et de bas en haut.
L'affichage consistera à lire cette liste de bas en haut, et d'afficher les sprites suivant l'ordre lu.
Ajouter un élément mobile (personnage...) :
La présence d'un personnage se fait typiquement de cette façon : il est situé en case (0,0,0) par exemple. Problème, en utilisant le même algorithme que pour les cases normales, il se retrouvera à la même hauteur, alors qu'en principe il devrait se retrouver une case au-dessus. Problème d'affichage en perspective.
La solution est simple : ajouter au calcul de l'algorithme une constante f3. Typiquement, on prendra f3 = f1 à la base. De cette manière, on simule en quelque sorte l'affichage du personnage comme s'il était une case en dessous (visuellement) de sa position réelle. Donc à hauteur égale, il sera affiché au dessus de la case.
Le soucis, c'est juste qu'il faut s'arranger pour que que f3 tiennent compte de la valeur de bas niveau qui est ajoutée à une case pour son identification unique. Valeur qui peut prendre comme maximum mx ou my. On ajoute donc à f3 un nombre supérieur à mx et my (mais inférieur à f2 pour ne pas poser un problème de superposition avec les niveaux de cases) pour résoudre ce problème.
Exemple :
Un exemple pratique, je travaille souvent avec des maps isométriques de 100x100 cases en largeur et longueur, j'ai donc des valeurs toutes prêtes sous la main.
On a donc :
mx = my = 100
f1 = 100000 (supérieur à mx * my et supérieur à f2)
f2 = 1000 (supérieur à mx et my)
f3 = 100500 (f1 plus un nombre supérieur à mx et my, et inférieur à f2)
Pour le calcul des cases :
Code :
(x + y) * 100000 + z * 1000 + x
Pour le calcul des éléments mobiles :
Code :
(x + y) * 100000 + z * 1000 + 100500 + x
|
|
Zoglu
|
Posté le 28 Juin 2008 à 04:19
|
|

Messages : 366
GCPoints : 22183
|
Merci beaucoup, vraiment, pour cette aide très complète
Je vais tester tout ça
|
|
Darktib
|
Posté le 28 Juin 2008 à 14:40
|
|

Messages : 4017
GCPoints : 347288
|
Ps mal! Ca donne envie de tester^^
Au fait, tu a fait cet algorithme pour Advanced Sprites?
|
|
Mod
|
Posté le 28 Juin 2008 à 15:40
|
|

Messages : 4954
GCPoints : 2100823
|
A la base c'était surtout pour un tactical que je développe, mais j'ai pu l'exploiter grâce à AdvancedSPRITES? oui, justement via les commandes d'affichage de profondeur des sprites.
Mais même avant cela, j'ai eu l'occasion de créer des tas d'algorithme liés à la 2D isométrique. Etant un grand fan de jeux de gestion, j'ai toujours voulu développer un jeu au moins aussi bon que Sim City... J'ai donc en stocks des algo de calcul de coordonées (convertir une position souris en position isométrique sur la map), de détection de zone (savoir si un point est ou non sur un tile isométrique), etc.
Tôt ou tard, tout ce travail se retrouvera sur GameCorp, dans les tutoriels ^^.
|
|
Darktib
|
Posté le 28 Juin 2008 à 19:32
|
|

Messages : 4017
GCPoints : 347288
|
Ca donne envie tout ca^^
|
|
Aeon Syx
|
Posté le 29 Juin 2008 à 13:41
|
|

Messages : 660
GCPoints : 26061
|
Ca donne encore plus envie si on peut faire ça facilement sous RM
|
|
Mod
|
Posté le 29 Juin 2008 à 14:27
|
|

Messages : 4954
GCPoints : 2100823
|
C'est une question ?
Il existe déjà des scripts pour gérer la 2D isométrique dans RPG Maker XP, et sans doute dans RPG Maker VX.
A mon avis ce système de 2D isométrique est impossible à réaliser pour Ruby. J'ai déjà eu l'occasion de jeter un oeil aux scripts RGSS, qui ne permettaient pas l'utilisation d'une profondeur d'affichage des sprites (bitmap). Ce qui voudrait dire utilisation de liste chaînées, et donc de gestion de pointeurs. En gros quelque chose de difficile à faire en RGSS sans tout faire ramer. En supposant d'ailleurs qu'il soit possible de court-circuiter le module de rendu des maps.
|
|
Zoglu
|
Posté le 29 Juin 2008 à 15:05
|
|

Messages : 366
GCPoints : 22183
|
En attendant, une fois qu'on connait la formule (merci encore, Mod ), on peut le faire facilement sous MMF2
|