Carte hexagonal - Version imprimable +- JeuWeb - Crée ton jeu par navigateur (https://jeuweb.org) +-- Forum : Discussions, Aide, Ressources... (https://jeuweb.org/forumdisplay.php?fid=38) +--- Forum : Programmation, infrastructure (https://jeuweb.org/forumdisplay.php?fid=51) +--- Sujet : Carte hexagonal (/showthread.php?tid=1200) |
RE: Carte hexagonal - barst - 22-05-2007 Ton exemple est vraiment bien. J'attends tes explications avec impatience. RE: Carte hexagonal - naholyr - 22-05-2007 Un autre moyen est "bêtement" de prendre une map hexa "à plat", et de la tordre en appliquant un angle de 30° par exemple : On déforme juste le fond de la carte, les nouvelles coordonnées des centres sont très simple à calculer (un coup de sinus/cosinus), et on place par-dessus les décors et personnages non déformés. C'est la méthode que j'avais décidé d'implémenter car très simple, et ne nécessitant pas d'avoir des images exactement à la bonne taille tout de suite (par exemple ça me permet de réutiliser les images de Wesnoth), mais je n'ai pas réussi à trouver une fonction qui fasse cette déformation dans GD et le faire pixel/pixel bonjour :gla: RE: Carte hexagonal - Harparine - 22-05-2007 Tu as raison naholyr : pour un fond uni, ta technique est plus facile mais dans tous les cas, il faut placer les persos, décors et reliefs comme si tu avais des vrais hexagones isométriques. Et dans le cas contraire (c'est à dire, si tu places tes décors sur la map avant déformation), tout les éléments un peu en relief (comme mon arbre) seront complètement déformés. Pour les images à la bonne taille, on peut très facilement "récupérer" ses anciennes tuiles 2D. Bon allez, je suis motivé, accrochez-vous, j'essaie de vous expliquer comment je calcule mon truc. Par contre, je précise que je suis seulement étudiant en histoire (donc des études ultra littéraires^^) et ça fait des années que je n'ai pas suivi un cours de maths. Même si j'aime bien me creuser la tête, mon niveau "académique" n'est pas exceptionnel et j'aimerais bien qu'un vrai matheux optimise ma formule (qui est surement redondante par bien des côtés). 1. Créer des tuiles isométriques Avant tout, je rappelle la procédure pour créer des tuiles isométriques. C'est le standard utilisé dans le pixel-art, entre autres, et la même manipulation est applicable pour tout objet en 2D, quelle que soit sa forme. Il suffit d'appliquer une rotation de 45° sur la droite puis compresser la figure obtenue en divisant sa hauteur par 2. Ce qui donne ceci pour un carré et un hexagone : On se retrouve donc avec des images rectangulaires contenant des formes tordues, d'où la difficulté de les coller les unes aux autres. Je rappelle que si l'on considère la carte comme un plan orthonormé, l'origine est en haut à gauche (standard en CSS, GD, Flash et j'imagine bien d'autres langages). Idem pour nos images de tuiles qui ressemblent à ça : 2. Des formules différentes En prenant l'exemple d'un carré en 2D en iso, on voit bien que la position de chaque case ne peut être déterminée de la même façon si l'on est en 2D ou en 3D isométrique. L'exemple suivant montre le problème que l'on rencontre si l'on place les tuiles de la même manière en utilisant la formule pour la 2D qui est la suivante : Code : posX = X*n Avant d'attaquer les hexotuiles, je donne juste la formule permettant d'aligner les carrés iso sur une carte, comme ceci (je marque l'entourage des images pour que vous repériez bien où est l'origine de la tuile) : (pour cet exemple, je ne vais pas utiliser la taille théorique des côtés - c'est à dire la taille en vue 2D - car il est plus facile de se baser sur l'image mais je le ferai pour les hexagones). Il y a quelques temps j'avais trouvé sur jeflash.com la formule suivante (facilement vérifiable si vous étudiez le schéma précédent) pour placer les tuiles isométriques de forme carrée : Code : posX = (X-Y) * largeur tuile 3. Etude des hexagones Maintenant que l'on connait la formule de positionnement de tuiles iso carrées et que l'on sait les contraintes de la représentation isométrique appliquée à la forme la plus simple, on peut commencer à regarder du côté des hexagones. En regardant des maps d'hexagones isométriques, je me suis rendu compte qu'il serait peu commode de travailler de façon abstraite sur la taille des images et qu'il valait mieux tenir compte des dimensions réelles de la figure contenue dans l'image. La formule d'Oncle James contenue dans son tuto est très bien pour des images aux dimensions bien précises. Je l'ai cependant réécrite pour quelle soit applicable d'après les dimensions de l'hexagone en lui même et non pas selon la taille de l'image qui le contient. Tout d'abord, voilà les dimensions d'un hexagone en vue 2D : On constate donc qu'un hexagone de côté n prend une largeur valant n + n/2*2 soit simplement n*2. Pour résumer, un hexagone de 50 pixels de côté prendra 100 pixels de large. Pour calculer la hauteur, je calcule tout d'abord une moitiée de hauteur en me basant sur un triangle rectangle dont l'hypoténuse vaut n et les deux autres angles 60° (la moitié d'un angle d'hexagone) et 30°. Avec un peu de trigonométrie, on apprend que la moitié de la hauteur d'un hexagone fait sin(60)*n (on aurait pu utiliser cos(30)*n aussi). Un hexagone fait donc sin(60)*n*2 unités de hauteur. Code : LargeurHexa = n*2 Sachant celà, réfléchissons à la création d'une carte hexagonale simple (en 2D) dans ce style là : Je n'ai pas tracé de repères mais en regardant bien, on constate qu'en abscisse, une tuile est placée un peu sur la tuile précédente : elle débute à l'endroit où arrive le côté le plus haut de sa voisine (qui vaut n, si on regarde le schéma précédent). Il ne faut pas oublier de compter le coté adjacent de gauche qui fait n/2 de largeur. On a donc une tuile qui se place n+n/2 pixels plus loin que sa voisine de gauche. Si on multiplie par le numéro de colonne (X), on obtient la formule suivante : Code : posX = X*1.5*n; Pour la position de la tuile en Y, c'est à peine plus compliqué : on place les hexagones les uns sur les autres. Il nous suffit donc de multiplier le numéro de la ligne (Y, qui commence à 0, ne l'oublions pas) par la hauteur d'un hexagone, ce qui nous donne : posY = Y*sin(60)*2*n. Oui mais là, notre formule est incomplète car les cartes hexagonales nécessitent d'alterner les cases paires et impaires (c'est cet effet dentelé que l'on a en haut et en bas de la carte). Pour celà, on rajoute va simplement décaler d'une demie hauteur de plus les hexagones impairs en X. La formule X%2 renvoie 0 ou 1 : l'opérateur % (le modulo) retourne le reste d'une division euclidienne. A nous de multiplier ce chiffre par une demie hauteur (si la case est paire, ce décalage sera nul). La formule finale de posY est donc la suivante : Code : posY = Y*sin(60)*2*n + (X%2)*sin(60)*n 4. Passons à l'isométrique Bien, enfin le coeur du sujet ! La difficulté va maintenant être l'association des contraintes liées à l'isométrique (que nous avons vues plus haut) et des contraintes liées à l'hexagonal. Comme précédemment, j'ai passé beaucoup de temps sur l'étude des hexagones en eux-mêmes. Voici le schéma d'un hexagone ayant subi une simple rotation à 45° vers la droite : Cette figure va nous servir jusqu'à la fin pour trouver la formule. J'ai tracé des triangles rectangles dans la figure pour pouvoir connaitre les hauteurs et largeurs des différents côtés de notre hexagone tourné grâce à la trigonométrie. Je ne m'attarde pas sur la figure et je continue. Dans un premier temps, voilà ce que je cherche à obtenir : Si vous avez l'oeil exercé à la vue isométrique, vous constaterez que cette carte est fausse car elle part trop vers le haut. Mais si nous parvenons à placer les tuiles de cette façon, une très légère modification, tenant compte du crènelage propre à l'hexagonal, permettra d'avoir une carte parfaite. Bon, je rajoute un schéma de plus (encore^^!) pour voir où est l'origine de nos hexotuiles isométriques : Alors, si on regarde la première ligne et que l'on cherche la position en X, on constate qu'une tuile commence là où se terminent les deux côtés les plus bas de sa voisine de gauche (le deuxième trait rouge, en haut). Il faut donc mesurer la largeur prise par ces deux côtés (qui sont tordus). Pour celà, on va utiliser le schéma de l'hexagone tourné (même si il n'est pas écrasé, la largeur reste la même). Comme les côtés opposés sont identiques, on peut utiliser les formules que j'ai notées et la somme des largeurs des deux côtés fait donc : sin(75)*n + sin(45)*n. Il suffit de multiplier par le numéro de colonne, et on place les tuiles à la suite les unes des autres. Mais ce positionnement en abscisse est valable uniquement pour la première ligne : si vous vous rappelez la formule utilisée par les carrés isométriques, chaque nouvelle ligne est décalée sur la gauche. On va donc reprendre ce principe et regarder de combien sont décalées les lignes les unes par rapport au autres. Un peu d'observation nous apprend que le point le plus à gauche de la deuxième ligne est séparé par deux côtés du point le plus à gauche de la première ligne. Un coup d'oeil au schéma précédent et on sait que ce décalage vaut sin(15)*n + sin(75)*n. Puisque l'on reproduit ce décalage à chaque nouvelle ligne créée, on multiplie cette petite formule par le numéro de la ligne. La formule finale est donc la suivante : Code : posX = X*(sin(75)+sin(45))*n - Y*(sin(15) + sin(75))*n Il reste maintenant à trouver le positionnement vertical. Même chose que précédemment : on regarde le nombre de côtés d'écart. Par exemple, le côté le plus haut de l'hexagone situé en bas à gauche est à 2 côtés de distance du coin le plus haut de son voisin de dessus. On se reporte au schéma des distances et on calcule l'ensemble, ce qui nous donne sin(75)*n + sin(15)*n unités de distance. Mais ce schéma n'était pas écrasé (la dernière étape pour transformer une forme en son équivalent isométrique). On divise donc la valeur obtenue par deux, sans oublier de la multiplier par le nombre de lignes, ce qui nous donne posY = Y(sin(75)+sin(15))*n/2 Bon, mais on a encore un léger problème, lié à la représentation isométrique. On est obligé de décaler légèrement une case vers le bas quand on ajoute une nouvelle colonne. Si on observe la première ligne bleue sur le schéma contenant les quatre tuiles hexagonales, on se rend compte que, pour la première fois, on ne tombe pas sur un angle. On ne va donc pas pouvoir utiliser la même technique que précédemment (celle du comptage de côtés^^) pour mesurer ce décalage. J'ai beaucoup chercher un moyen de trouver la valeur exacte (sin(75)-sin(45) s'en rapproche beaucoup) mais je ne l'ai pas trouvé (si un super matheux est motivé, il peut chercher ). J'ai donc recherché la valeur approchée la plus précise possible à l'aide de sin-1 sur un cas d'application. Bref, le décalage est de sin(13.5)*n à peu de choses près, et comme on en tient compte à chaque nouvelle colonne, il ne faut pas oublier de la multiplier pour chaque valeur de X. On se retrouve donc avec la formule finale suivante : Code : posX = X*(sin(75)+sin(45))*n - Y*(sin(15) + sin(75))*n Ouf. On y est presque ! Cette formule permet donc de générer la carte (fausse) que je vous ai présenté au début du point n°4. Mais une vraie carte hexagonale isométrique ressemble plutôt à ça : Nous devons donc respecter le crènelage des bords et les hexagones doivent suivre une ligne plus naturelle. Pour celà, il suffit juste de modifier la formule précédente. Si on veut le crènelage en abscisses, on décale d'une hauteur d'hexagone toutes les deux colonnes. Pour celà, il suffit remplacer la valeur Y des deux formules précédentes par Y+un arrondi au supérieur de X/2, ce qui nous donne : Code : posX = X*(sin(75)+sin(45))*n - (Y+arrondi.sup(X/2))*(sin(15) + sin(75))*n Enfin, la dernière chose à prendre en compte est le décalage à gauche occasionné par la 3D isométrique. Pour compenser tout ça, nous devons donc ajouter une variable "decalage" à posX, pour forcer le placement plus loin vers la droite. Si le crènelage est en abscisse, le décalage est facile à trouver car il est basé sur le décalage négatif de chaque nouvelle ligne (sin(15)+sin(75))*n. Si on multiplie cela par le nombre total de lignes - 1 (on commence à 0), on a le décalage final. Code : decalage = (H-1)*(sin(15)+sin(75))*n Code : decalage = arrondi.inf((H-1)*1.5)*sin(15)*n Voilà ! Normalement, on a une carte nickel ! Ouf, pas fâché d'avoir terminé^^ C'est un vrai tuto, finalement ! Je précise une dernière chose : n'oubliez pas que la valeur n (taille des côtés de l'hexagone) est toujours basée sur la représentation à plat de la tuile (en 2D). C'est à dire qu'il suffit de connaitre la taille de notre hexagone avant la transformation pour utiliser cette formule. Enfin, prenez garde : beaucoup de langages de programmation utilisent les radians plutôt que les degrés dans les fonctions de trigo. Si nécessaire, vous devez donc convertir vos degrés en radians en multipliant par PI et en divisant par 180. Bon, j'arrête pour l'instant. J'expliquerai juste à la suite quelles mesures prendre pour dessiner du relief et des éléments de décor utilisables. (je posterai plus loin). J'essaierai aussi de proposer un vrai code PHP et pas seulement de la théorie. Mais le mieux est de créer deux fonctions prenant les coordonnées de la case en paramètre et renvoyant l'abscisse pour l'une et l'ordonnée pour l'autre. Après, une simple boucle suffit à assembler la carte. (J'essaierai peut-être de transformer ces explications en un vrai tuto plus tard) ! @+ (pour ceux qui m'ont lu jusqu'au bout) RE: Carte hexagonal - OncleJames - 22-05-2007 hu poste le en tuto apart :good: RE: Carte hexagonal - Harparine - 22-05-2007 Pourquoi pas, mais il faut que j'écrive encore deux parties : une sur la manière d'intégrer des tuiles spéciales (genre le relief et tout et tout^^) et une autre contenant une application plus pratique de toute cette théorie avec du code php (appliqué à GD et à une mise en page par div) et en Flash. Ca viendra. Peut-être dans la soirée... RE: Carte hexagonal - naholyr - 22-05-2007 Je n'aurai qu'un mot : respect. D'une part pour ta reflexion bien construite, et pour ta pédagogie, c'est extra. Je suis pas une bille en maths loin de là mais je n'avais pas eu le courage de me pencher dessus et grâce à tes explications je n'aurai aucun souci. Si un jour tu doutes de tes capacités dis-toi que tu viens de donner une leçon à un ancien Maths Spé qui était loin d'être dernier de sa classe RE: Carte hexagonal - Harparine - 22-05-2007 Merci beaucoup de ta remarque, naholyr : ça me fait vraiment plaisir que ça soit utile parce que je me suis galéré un bout de temps sur le sujet^^ Bref, je suis content que quelqu'un comme toi me dise ça, parce que j'étais moi-même resté en admiration devant tes explications et ton code sur les cartes hexagonales sur Tour de Jeu @+ RE: Carte hexagonal - Mysterarts - 22-05-2007 Et bien là, bravo !! Superbe tuto, illustré, sympa à lire, et très clair : en un mot : MERCIBRAVORESPECT ! Mysterarts, mais où trouve tu le temps d'écrire ça ? RE: Carte hexagonal - Harparine - 22-05-2007 Mysterarts a écrit :Mysterarts, mais où trouve tu le temps d'écrire ça ? Hum ... :weird: Euh... Ben, justement, comme je l'ai dit au début du tuto, je suis en études d'Histoire et je n'ai aucune heure de cours car je suis libéré pour faire de la recherche (en archives) mais à cette époque-ci de l'année, je suis censé rédiger la synthèse de mon boulot de toute l'année... Donc je suis sur mon PC toute la journée et quand j'en ai marre de jouer à l'historien, je code (je sais, c'est pas bien mais je me suis planté d'études^^). Voilà voilà C'est bien la fac en fin de cursus, parce qu'on a du temps, mais c'est aussi très chiant parce qu'il faut quand même faire le boulot... et si est pas trop gratte-papier, comme moi, c'est très vite gonflant :guitare: Donc, pour les p'tits jeunes qui ont découvert l'informatique AVANT de commencer leurs études supérieures, hésitez pas !^^ RE: Carte hexagonal - blackduty - 22-05-2007 Mmmh, effectivement sur un autre tuto, ce serait mieux Beau travail dans tout les cas. Par contre, petite question, est ce normal d'avoir ceci: Code PHP :
Alors que le champ vision se trouve dans la table "Carte". Ce qui correspond plus a cette requête Code PHP :
Et donc la variable $terrain. Bon mes connaissances ne sont pas extraordinaire donc je peux me planter joyeusement Au passage, ta table est perso_info et non perso (le plus rapide étant de corriger le nom de ta table) |