Aller au contenu

daemondragon

Melinyen
  • Compteur de contenus

    31
  • Inscription

  • Dernière visite

  • Days Won

    2

Tout ce qui a été posté par daemondragon

  1. Et voila le deuxieme tutoriel où je vais vous expliquer tout le code du pathfinding ( et oui enfin ! ) Tout d'abord n'hésitez pas a télécharger les sources en bas du post afin de les lire en même temps, c'est plus pratique pour comprendre de quoi je parle. On va commencer par le prototype de la fonction : path_direction* create_path(const int largueur, const int hauteur, int map[][hauteur], const path_pos debut, const path_pos fin, int pivot) Cette fonction retourne un pointeur vers une structure, je vais vous expliquer a quoi elle sert vers la fin. Il faut donc en paramètre la largueur et la hauteur de la map (attention, la map doit être de format map[largueur][hauteur] et non, map[hauteur][largueur] la map qui contient des nombres afin de représenter votre terrain, et maintenant les trucs intéressant : la structure path_pos ne contient que deux int, x et y, pour connaître la position du début et celle de la fin. Attention, le début de la map commence a (0, 0), il faut faire attention ! Et enfin le pivot, mais qu'est ce que c'est ? C'est tout simplement tout les nombres qui sont supérieur ou égal a lui sont traversables, tout ceux inférieur sont des murs par exemples. cela nécessite par contre de penser a cela dès le début e la conception du jeu mais c'est pas très difficile. personnellement, j'utilise souvent des énumération pour définir les différentes tiles (blocs) de la map. ensuite : if(debut.x == fin.x && debut.y == fin.y) { return NULL; } assez explicite je crois, on retourne NULL afin de savoir qu'il n'y a pas de chemin. On doit créer ensuite une grille de coût , de la taille qui faut exactement, et on initialise le tout a 0, c'est très important ! on met a jour a grille de coût, en mettant a 1 le début. Ainsi, on sait que tout les blocs avec un coût égal a zéro sont non explorés Il faut ensuite créer une file, les positions actuelle et les suivantes, ce qui donne : path_pos actuel; path_pos suivant; control control_list; la structure control et donc se qui va nous servir a contrôler la file, on va mettre les donnée en file a partir de cette structure là. Elle contient un pointeur vers la première donnée, pour la récupérer. (n'hésitez pas a regarder le précédent tutoriel pour voir de quoi je veux parler) Et aussi un pointeur vers la dernière données, afin de mettre les données dans la file plus rapidement. S'il n'y en avait pas, on aurait du parcourir TOUTES les données de la file une par une afin de trouver la fin. Vous imaginez sur une énorme file de 1000 données ? Il faut initialiser la file avec la position de début et on commence les choses sérieuse. Il faut ensuite créer une boucle qui s’arrête quand on a trouvé la fin ou que la file est vide. dedans, on met a jour la position actuelle qui erre égale a la valeur du début de file. si la position actuelle est égale a celle de fin on sort de la boucle, sinon on regarde sur le coté. Cela donne en code: while(control_list.premier != NULL && fini) { actuel.x = control_list.premier->actuel.x; actuel.y = control_list.premier->actuel.y; if(actuel.x == fin.x && actuel.y == fin.y) { fini = 0; } if(actuel.x != 0) { if(map[actuel.x-1][actuel.y] >= pivot && poid[actuel.x-1][actuel.y] == 0) { suivant.x = actuel.x-1; suivant.y = actuel.y; poid[suivant.x][suivant.y] = poid[actuel.x][actuel.y] + 1; add_to_file(&control_list, suivant); } } if(actuel.x != largueur -1) { if(map[actuel.x+1][actuel.y] >= pivot && poid[actuel.x+1][actuel.y] == 0) { suivant.x = actuel.x+1; suivant.y = actuel.y; poid[suivant.x][suivant.y] = poid[actuel.x][actuel.y] + 1; add_to_file(&control_list, suivant); } } if(actuel.y != 0) { if(map[actuel.x][actuel.y-1] >= pivot && poid[actuel.x][actuel.y-1] == 0) { suivant.x = actuel.x; suivant.y = actuel.y-1; poid[suivant.x][suivant.y] = poid[actuel.x][actuel.y] + 1; add_to_file(&control_list, suivant); } } if(actuel.y != hauteur - 1) { if(map[actuel.x][actuel.y+1] >= pivot && poid[actuel.x][actuel.y+1] == 0) { suivant.x = actuel.x; suivant.y = actuel.y+1; poid[suivant.x][suivant.y] = poid[actuel.x][actuel.y] + 1; add_to_file(&control_list, suivant); } } remove_to_file(&control_list); } Il faut bien entendu éviter de partir sur les coté de la map, sinon on risque d'avoir des problèmes de mémoires. Vous vous dites aussi sûrement : "mais c'est quoi add_to_file et remove to file" non ? Ce sont les structure qui servent a mettre les données dans la file, ou a les enlever. (regardez dans le code source fournit, elle y sont au début.) A partir de là, la grille de coût est fini, on peut vider totalement la file, on n'en a plus besoin. ( il faut éviter les fuites mémoires) : while(control_list.premier != NULL) { remove_to_file(&control_list); } Et non ce n'est toujours pas fini : Il faut regarder la variables fini, qui si elle est égale a zéro, signifie qu'on a trouvé la fin ,sinon, il faut encore retourner NULL. si le chemin est trouvé, on se place sur la position de fin et regarde a coté. On va dans la direction on le coût est égal au coût - 1 de la case. Il ne faut surtout PAS prendre la case qui a un coût inférieur a celle autour, car a ce stade la, certaine case n'ont pas encore été explorer ( se n'était pas la peine, on avait trouver le plus court chemin jusqu’à la fin) et sont donc encore égale a 0. On risque alors de se trompé totalement de chemin. On met ensuite dans la pile les directions contraire ou on va aller. (on part de la fin je vous rappelle) et on retourne a la fin cette pile. En code : if (fini == 0) { fini = 1; actuel.x = fin.x; actuel.y = fin.y; path_direction *control = NULL; char direction; while((actuel.x != debut.x && fini) || (actuel.y != debut.y && fini)) { //les directions sont inversé car le png va aller dans l'autre sens if(poid[actuel.x][actuel.y+1] == poid[actuel.x][actuel.y] - 1) { direction = NORD; actuel.y++; } else if(poid[actuel.x][actuel.y-1] == poid[actuel.x][actuel.y] - 1) { direction = SUD; actuel.y--; } else if(poid[actuel.x+1][actuel.y] == poid[actuel.x][actuel.y] - 1) { direction = OUEST; actuel.x++; } else { direction = EST; actuel.x--; } empile(&control, direction); } return (control); } La structure path_direction comporte, une direction sous forme de point cardinaux (NORD, SUD...) et un pointeur vers la donnée suivante (c'est une pile je vous rappelle). la fonction empile sert a empiler la direction dans la pile (elle va tout au début). A la fin, on retourne la pile, qu'il faut récupérer avec un pointeur sur une structure path_direction Le seul problème de ce path_finding actuel, c'est qu'il faut éviter que le chemin, se trouve sur les bord, sinon on peut passer de l'autre coté de la map dans certain cas, ce qu'il faut a tout prix empêcher. Dans le cas de situation différentes a celle d'un labyrinthe, (quand les chemins ont une grande chance d'être droit, vous pouvez dirigez le path_finding en lui faisant allez dans la direction vers la fin et en transformant la file de départ en pile. Il faut alors pouvoir réécrire un coût d'une bloc si la deuxième fois, le coût est plus faible. Bref, il est facilement améliorable et il ne tiens qu'à vous de le récréer totalement. Et voila le tour est joué, vous avez maintenant un path_finding qui marche https://github.com/daemondragon/pathfinding.git
  2. Bonjour a tous ! Cette suite de tutoriel va vous expliquez comment faire une IA basique pour des pnj que vous pourrez adapter pour des jeux simples(non ce n'est pas une super grosse IA de la mort qui tue qui va faire vos problèmes de math toute seule). Dans la première partie du tutoriel, nous allons voir une partie fondamentale des IA dans les jeux vidéos : le pathfinding. Le code du pathfinding était trop long pour être expliqué dans un seul tutoriel, le premier traitera de la théorie et le deuxième de la pratique. Le pathfinding, qu'est ce que c'est ? Le pathfinding c'est le fait de dire a une personne : tu vas du point A au point B en évitant les obstacles. (c'est mieux que de se prendre les murs non ? ) Pour le pathfinding, nous allons mettre en place un algorithme A*, qui est très célèbre et qui peut être utilisé un peu partout, surtout dans le jeu utilisant un système de grille(starcraft, zelda etc...) A* tiens son nom de la recherche "en étoile" qu'il fait : pour chaque case, il va regarder celles d'autour qui n'ont pas été déjà exploré et va dire : celle la elle est plus loin de la case de départ que la précédente. petite image : Le 0 correspond au début. Plus on s'éloigne du 0, plus le coût (ou le poids, c'est la même chose) augmente. Le but, c'est de prendre le chemin, qui possède le plus faible coût. Par exemple, si vous voulez partir du point (0, 3) -> le 4eme point tout en haut a gauche, vous n'allez pas partir carrément a gauche, faire X fois le tour du gros truc noir, non ? Vous allez simplement prendre le chemin le plus court. Pour réaliser donc ce merveilleux pathfinding, vous allez donc partir du début (le point (7, 6)) et regarder autour, si ce bloc n'est pas un mur. Vous augmenter alors le coût du déplacement pour cette case, puis on refait cela jusqu’à ce qu'on trouve la fin voulu ou jusqu’à ce qu'il n'y ai plus de possibilité de passer car tous les blocs ont été explorés, il n'y a donc pas de possibilité d'aller du point A au point B. Puis on part de la fin et on passe par les blocs qui ont le plus faible coût. Pour réaliser cela, on commence par créer une file (oui je parle enfin de code). Une file est une structure de données qui permet de mettre des variables l'une après l'autre. La première donnée qui rentre dans la file est la première à sortir. Pour ceux qui ne savent pas ce que c'est : Donc ont la créer, cette file et on met, si ce n'est pas des murs, et s'il n'ont pas été déjà explorés,la position des blocs d’à coté, tout a la fin. A chaque tour de boucle, ont prend la première position et on refait la même chose. Pour les minecraftien, c'est comme l'eau qui coule déjà sur la case la plus proche, puis sur celles plus éloignées. Quand on a trouvé la fin, la où le pnj par exemple veut aller, on arrête, ou alors quand il n'y a plus de blocs a explorer, alors le pnj est triste car il ne peut pas y aller. Si on a trouvé la fin, on met alors dans une pile, (les dernières données qui arrivent dedans seront les premières à sortir), car le chemin doit être pris dans le sens contraire où l'on va. On cherche alors, a partir de la fin, la case autour d'elle qui a le plus faible coût, puis on enregistre sa position et on mets la direction contraire (n'oublier pas que le pnj va parcourir le chemin dans l'autre sens) dans la pile et on refait ça jusqu’à ce qu'on trouve le début. Et voila vous pouvez maintenant, grâce à ces explication créer vous même votre pathfinding, ou alors attendre le prochain tutoriel qui ne devrait pas tarder a suivre. En utilisant uniquement le pathfinding et intelligemment vous pouvez déjà créer un planning pour chaque pnj, ce qui va permettre de rendre une ville plus vivante (je pense surtout au village pnj de zelda qui sont toujours au même endroit, c'est un peu triste non ?).
  3. daemondragon

    Concept de jeu

    Bonjour ! Je vous présente aujourd'hui une idée qui serait de créer une section / sous-section pour la création de jeu. Explication : La première personne ne sait rien faire mais elle à une idée de jeu qui peut être amusant, elle écrit le concept du jeu dans un sujet. La deuxième sait programmer dans un langage X, elle dit qu'elle va commencer le développement de ce jeu. Elle précise le langage et les bibliothèques quelle va utilisée La troisième est un graphiste, il va alors faire les images de ce jeu La 4ème code dans un autre langage, Y. Il entame lui aussi le développement du jeu. Du coup chacune des personnes qui ont rejointes le projet poste (je ne sais ou) les parties de code qu'il à faites pour le jeu, ce qui permet en cas d'abandon d'une personnes du projet, de laisser le jeu à continuer de se développer ! À la fin, on pourrait avoir plusieurs jeu différent, mais avec le même concept . On pourrait même élire le meilleur des jeux ! Attention ! : ce n'est pas une copie de projet des membres que je propose, c'est une développement de jeu ou toutes personnes arrivant sur ce forum pourrat voir instantanément toutes les sources du projet et apporter une aide (même petite) au projet. En espérant que cette idée vous plaira :-)
  4. Bonjour a tous ! Je m'appelle daemondragon ou alors jérémy IRL, et j'ai 16 ans. j'aime : les jeux video, coder , et l'escalade je n'aime pas : aucune idée je ne suis pas douer : en graphisme Pour ceux qui le demanderaient je code en C avec un niveau intermédiaire j'ai connu le forum grâce à Demil ( qui lui l'a connut grâce a Nitram, qui lui l'a connut grâce à ...) Voici une petite présentation que je pourrait étoffer si vous le voulez.
×
×
  • Créer...