|
|
|
|
La gestion des collisionsLa gestion des collisions est sans doute l'une des plus grandes difficultés auquel sont confrontés les développeurs. Il n'est pas rare de voir des bugs de gestion de collisions dans les jeux vidéo. Dans notre cas, cette gestion est simple et nous allons essayer de la faire comme il faut.
Sommaire du chapitre :
![]() Le principeIl n'est pas possible de tester tous les polygones avec tout les murs et personnages. Généralement, les collisions entre adversaires ne sont pas gérés par c'est compliqué et plutôt gênant. A mon avis, dans notre cas, le plus simple et de considérer le personnage comme un carré. Étant donné que les murs sont des carrés, il suffira de tester si un côté du carré du personnage est en collision avec un côté du carré d'un mur et si c'est le cas, on repositionne le personnage à la limite de la collision. Le personnage est plus petit qu'une unité. Son centre est toujours dans un carré, et autour de lui il y a 8 murs ou creux. Prenons un exemple. L'angle horizontal du personnage est de -135° (Sud-Est). Sa position initiale est P et la destination pour l'image à construire est P'. Il faut donc vérifier si le personnage est en collision avec l'un des murs 4, 6 et 7. Pour le mur 4, il y a collision si le côté Est du personnage est plus à l'Est que le côté Ouest du mur. ![]() Voici un exemple de collision : ![]() Bien entendu, tout les tests devront être effectués. Il est important de bien comprendre le principe pour comprendre la suite de ce chapitre. Connaissance de l'environnementTel qu'est structuré le jeu, le personnage sait où il est mais n'a pas connaissance de son environnement car il n'y a pas de lien entre la carte et le personnage. En revanche, la scène contient les deux et peut prendre connaissance de l'environnement du personnage pour lui décrire. Connaissance son environnement, le personnage pourra se déplacer en prenant en compte les informations relatives à son environnement. Position sur la cartePour demander à la carte de lui fournir une vue de l'environnement, la scène à besoin de récupérer la position du personnage sur la carte de façon discrète.
La scène peut maintenant prendre connaissance de la position du personnage et la fournir à la scène pour lui demander de lui construire une vue de l'entourage du personnage. Construction de la vue de l'entourageLa méthode prend en paramètre la position (X;Y) de la case à partir de laquelle sera construite la vue de l'entourage. Ce dernier sera écrit dans le tableau à 8 cases fourni dans un 3ème paramètre. Ensuite, connaissant la largeur de la carte, on peut déterminer s'il y a un mur ou non sur les 8 cases qui entour la case sur laquelle repose le personnage.
Afin d'assurer le fait que la case existe lors de sa récupération, j'ai fait le test que la case du personnage ne se trouve pas sur un bord. Si c'est le cas, la lecture est faussée. C'est pourquoi il sera indispensable d'empêcher le personnage s'approcher de la bordure de la carte en plaçant un mur tout autour. Lorsqu'il s'agira d'avancer...Pour le moment, lorsqu'on souhaite faire avancer le personnage, on fait un simple appel à la méthode Personnage::avancer(). Maintenant, les choses se passeront de façon un peu différente. On récupèrera la case sur laquelle est placé le personnage, on demandera à la carte de nous fournir une vue de l'entourage du personnage puis nous demanderons au personnage d'avancer en tenant compte de son entourage.
L'axe des X pour le personnage dans la scène correspond à l'axe des Y pour la carte. De même, l'axe des Y du personnage correspond à l'axe des X pour la carte. Il y a donc une "inversion" des axes entre l'opération de lecture de la position du personnage et celle de la demander de création de l'entourage. ![]() Remarquez que j'ai ajouté un paramètre à la méthode Personnage::avancer(). Dans la partie qui suis, nous déterminerons la destination du personnage en prenant en faisant la gestion des collisions grâce à l'entourage maintenant connu de la méthode avancer(). La gestion des collisionsDétection de collisionNous l'avons vu, détecter la collision n'est pas très compliquée. Faisons le test avec un mur Est (mur 4). On se rend compte qu'il nous manque encore une donnée : le "rayon" du personnage. ![]() On l'ajoute donc en attribut et on fait le test :
Dans l'expression du test, on parle de la position cible du personnage.
La droite du personnage se calcule en faisait (positionCibleY + this->rayon). Et celle-ci est dans le mur si elle est dans une case différente de celle du centre, ce qui parait logique. Pour récupérer la "case", on tronque pour ne garder que la partie entière, d'où les deux (sint32). Gestion de la collisionLa collision est détectée. Il ne reste plus qu'à la gérer : faire revenir le personnage en limite de collision. Par exemple, si la droite du personnage est en Y=4.247, et qu'il y a un mur en case 4, le dépassement est alors de 0.247. ![]() Le calcule du débordement devient maintenant évident : ((positionCibleY + this->rayon) - (sint32)(positionCibleY + this->rayon)). On le soustrait au déplacement théoriquement prévu suivant les Y de la scène.
Vous savez maintenant comment gérer les collisions avec les murs Nord, Sud, Ouest et Est. Je vous laisse les gérer. N'oubliez pas d'affecter vos résultats aux coordonnées finales de votre personnage.
Test des collisions géréesPour tester, il vous suffit d'essayer de traverser les murs. N'hésitez pas à modifier la carte ou déplacer la caméra. Les Y vers la gauche, les X vers la droite. Seule la collision Est est gérée. Remarquez la collision qui est n'est pas gérée lorsque le personnage est en bordure de carte, au début de la vidéo. Lorsque les 4 collisions sont géréesLorsque vos 4 collisions sont gérées, vous devez obtenir le résultat suivant. En réalité, il y a encore un problème. Regardez la vidéo : Lorsque le personnage passe "parfaitement" par un angle de mur, la collision n'est pas gérée. Explication du bugLe bug vient du fait qu'il manque encore des tests. Les tests actuels ne sont pas suffisant. Regardez l'exemple ci-dessous : ![]() Le personnage est dans l'angle Sud-Est de la case centrale et se dirige vers le Sud-Est. Il n'y a de mur ni en case 4 ni en case 6. Le personnage passe donc les 4 tests de collision sans y entrer ; le personnage avance donc sans rencontrer de mur. Le personnage arrive alors en case 7, il est déjà trop tard, la collision a été raté. Correction du bugPour résoudre ce problème nous allons gérer le cas du personnage qui passe le sommet Sud-Est dans la case 7.
Ensuite, on distingue 3 cas possibles, les voici en image : ![]() Pour les deux premiers cas, la détection et la gestion de la collision sont simple. En revanche, dans le dernier cas, il faudra déterminer le mur sur lequel va glisser le personnage. Après réflexion, je me suis rendu compte qu'il été assez simple de savoir comment arrive le personnage sur le mur pour déterminer de quel côté il doit glisser. Regardez ces 2 schémas : ![]() Ici, le personnage doit glisser vers les X+ (vers le bas). ![]() Ici, le personnage doit glisser vers les Y+ (vers la droite). Si le décision du glissement ne pouvait pas être prise, les pentes des deux flèches serait identique. Je n'ai pas cherché à le démontrer, j'ai simplement suivis mon intuition, ce qui n'est pas forcément une bonne chose. Ceci dit, je n'ai pas rencontré de problème par la suite. On va donc calculer les 2 pentes et en fonction de la plus grande, le personnage sera translaté soit vers les X- soit vers les Y-. Voici le code complet de la gestion de la collision avec le mur 7 :
Je vous laisse réfléchir et coder la gestion des collisions avec les autres murs de vos propre mains. Il s'agit d'un exercice difficile malgré tout. Bugs rencontrésCollision non gérée pour les angles multiples de 90°Lorsque l'azimut du personnage est un multiple de 90° exactement, aucun des 3 test n'est validé. La solution naïve est de se dire qu'il suffirait d'accepter l'égalité lors de la comparaison pour entrer dans l'un des tests. Tant qu'à faire, on évite que ce soit celui qui provoquerait une division par zéro. Il nous reste alors deux choix. Mais en acceptant l'égalité, on provoquerait la détection d'une collision lorsque le personnage glisserait le long d'un long mur composé de plusieurs murs. Ce qui rendrait le jeu insupportable pour le joueur. La solution pour laquelle j'ai opté, c'est de m'arranger pour que l'azimut du personnage ne soit jamais proche d'un multiple de 90°. J'ai demandé conseil sur developpez.net pour résoudre ce genre de problème. Merci à stardeath. Je vous laisse implémenter ce code à votre jeu. Cette méthode n'est pas très jolie. Si vous avez mieux à proposer, merci de me le faire savoir. Je vous en remercie d'avance. Déplacement accéléré en diagonaleTemps que nous sommes dans les corrections de bug, j'ai remarqué un déplacement accéléré lorsqu'on appui sur Z et D (avancer / droite) en même temps. Ce bug est très simple à comprendre. On se déplace deux fois. Pour compenser la vitesse de déplacement, il faut diviser par racine de 2 lorsque le test suivant est validé.
Maintenant, le déplacement du personnage est constant. Il reste encore un petit bug : dans le cas ou le joueur appuis sur 3 touches de déplacement, la vitesse est atténuée alors qu'elle ne le devrait pas. L'appuie de 3 touches n'étant pas une situation logique, on peut considérer qu'il est normal de pénaliser le joueur. Division par zéroVous avons 4 tests semblables à celui-ci :
On se rend compte qu'il y a 2 divisions et que chacune d'elle peut provoquer une division par zéro. Pour éviter la division par zéro, on détecte le cas critique à l'aide d'un test puis on apporte une correction. Dans le cas où le problème ne se pose pas, on laisse faire.
On fait la même chose pour les 3 autres tests. Comme vous avez pu le constater, même pour un simple jeu de FPS, la gestion des collisions n'est pas évidente. Vous comprendrez maintenant pourquoi il n'est pas rare de voir que dans les jeux vidéo de nos jours les collisions ne sont pas toujours très bien gérées. Pour ce chapitre, je ne vous donne volontairement pas les sources pour que vous cherchiez par vous même et que vous puissiez être fier du travail que vous aurez fournit. Si vous rencontrez des difficultés pour en venir à bout, le forum est là pour vous aider. Après réflexion, je pense qu'il aurait été préférable de ne faire qu'une seule méthode avancer() qui prendrait en paramètre la distance et l'angle de déplacement : 0° pour aller tout droit, 90° pour aller à gauche... et l'appuie simultané des touches Z et Q aurait définit l'angle à 45°. Si vous mettez en place cette méthode, je serait ravi de voir la façon dont elle a été implémenté et le résultat obtenu. Merci. Dans ce chapitre, je comptais faire en sorte que la cameras soit le point du vu du personnage mais le chapitre est déjà trop long. Je vous laisse donc le faire vous même dans une méthode Personnage::regarder(). Dans le chapitre suivant, nous allons nous amuser à afficher la scène en relief grâce à des lunettes 3D. ![]() ![]() Rédigé par David
Consulté 6369 fois |
||||||||||||||||||||||||||
|
Hébergeur du site : 1and1.fr Site de création de Jeux Vidéo Apprenez à créer vos propres Jeux Video |
1393676 pages ont été consultées sur le site ! Dont 1358 pages pendant les 24 dernières heures. Page générée en 0.461 secondes Nos partenaires - Otium Production : Aide aux débutants à créer leurs jeux - Les bibliothèques de développement de jeux vidéo |