Classe de collision descendante réutilisable

8

J'ai récemment choisi le jeu monogame et je travaille sur un simple jeu descendant pour me lancer et apprendre les bases.
J'ai réglé le mouvement et la rotation pour suivre la souris, mais je suis coincé avec les collisions.
Ce que je veux savoir, en gros, ce sont deux choses:

  1. Quelle serait la meilleure façon de gérer les collisions? Je sais que cela Rectangle.Intersects(Rectangle1, Rectangle2)renvoie le rectangle qui se chevauchent, mais, comme le mouvement de haut en bas est sur l'axe x / y, je voudrais savoir où la collision se produit afin que je puisse créer une sorte de "glissement de mur" où le joueur n'obtient pas collé au mur.
    Vérifier les coordonnées x / y du joueur par rapport aux coordonnées des objets solides, puis lancer le joueur à sa position précédente s'il entre dans les limites d'un objet solide est-il vraiment la meilleure approche? Que suggérerais-tu?
  2. Quelle serait la meilleure façon d'appliquer des collisions à tous les solides, aux PNJ, etc.? Je pense actuellement à créer une gameObjectclasse dont tous les objets hériteront et géreront simplement les collisions.

Merci d'avoir lu et j'espère que quelqu'un pourra me donner quelques conseils.

Eliah John
la source
Pour quelques réflexions sur votre deuxième question, jetez un œil à cette réponse sur l'architecture de jeu .
Andrew Russell

Réponses:

9

En règle générale, la plupart des moteurs physiques gèrent ce problème en séparant les objets qui se croisent .


Donc, si vos objets sont représentés par des rectangles (également appelés "boîtes de délimitation alignées sur les axes"), et qu'ils entrent en collision sur un cadre donné comme suit:

Collision


Vous mesureriez alors la quantité d'interpénétration sur chaque axe. Sélectionnez ensuite l'axe avec la plus petite interpénétration et séparez les objets le long de cet axe.

Séparé


Vous enregistreriez alors cela comme une "collision" et appliqueriez la dynamique appropriée.

Par exemple, si vous voulez glisser le long du mur, vous devez simplement mettre à zéro la vitesse sur l'axe sur lequel vous vous êtes séparé (l'axe X, dans l'illustration ci-dessus), en laissant la vitesse sur l'autre axe seul.

Mais vous pouvez également appliquer une friction ou faire rebondir les objets.


Voici un excellent didacticiel interactif qui montre comment procéder de manière beaucoup plus détaillée.

Bien que, si vous allez loin dans cette voie (autre chose que de simples collisions AABB), vous voudrez peut-être envisager d'utiliser un moteur existant comme Farseer Physics .


Enfin, une note sur l'implémentation (si vous ne suivez pas la voie Farseer): Rectangleutilise des intvaleurs, qui ne sont pas vraiment appropriées pour faire de la physique dans la plupart des cas. Pensez à créer votre propre AABBclasse qui utilise à la floatplace.

Votre deuxième question est assez bien répondue par mon ancienne réponse sur l'architecture de jeu ici , donc je ne la répéterai pas ici.

Andrew Russell
la source
Peut-être qu'il y a quelque chose que je ne comprends pas, mais cette approche n'est-elle pas défectueuse? J'ai illustré le problème ici: jmp.sh/jEW2lvR Cela entraînerait parfois un comportement étrange.
BjarkeCK
@BjarkeCK: Oui, vous devez faire un travail supplémentaire pour gérer de tels cas. Je ne connais pas assez bien pour bien expliquer comment les gérer correctement (j'utilise Farseer et je l'appelle un jour). Jetez éventuellement un œil à la "Section 5" de ce lien .
Andrew Russell
1

1: J'ai également travaillé sur un jeu d'action descendant relativement simple, et après une semaine (-s?) De lutte, j'ai fini par utiliser une sorte d'approche pas à pas pour la détection et la réponse aux collisions. La raison principale étant que l'utilisation de l'interpénétration la plus courte entraînerait dans certains cas une "téléportation" vers une nouvelle position dans laquelle l'objet en mouvement ne se trouvait pas auparavant.

donc, quand un objet veut bouger,

  1. Je crée une boîte englobante de l'objet à la position de l'objet + vecteur moveAmount, créant une sorte de boîte englobante cible
  2. puis je vérifie cette zone de délimitation cible pour toute intersection avec les objets de jeu, les tuiles, etc. s'il y en a, je les ajoute à une nouvelle liste, qui contient toutes les collisions potentielles pour l'image actuelle
  3. s'il n'y a pas d'intersections, l'objet se déplace. mais s'il y a une intersection,
  4. J'ai divisé le mouvement recherché en «étapes». puis je lance une boucle pour le nombre d'étapes que j'ai. chaque étape déplace l'objet juste pour 1 pixel dans les directions x et y.
  5. pour chaque étape, je vérifie chaque nouvelle position projetée pour les collisions, si rien, j'ajoute le vecteur de déplacement de l'étape au vecteur de déplacement final.
  6. s'il y a collision (intersection renvoie vrai), je compare la position précédente (position à l'étape précédente) de l'objet en mouvement avec la chose avec laquelle il entre en collision.
  7. en fonction de cette position précédente, j'arrête le mouvement le long de l'axe en conflit (par exemple, si l'objet en mouvement vient au-dessus de l'objet en collision, je fixe la valeur y du vecteur de déplacement à 0, etc.).
  8. Je répète cela pour chaque étape consécutive, en ajoutant les vecteurs d'étape ajustés ensemble pour créer un vecteur moveAmount ajusté final que je peux utiliser en toute sécurité pour déplacer l'objet sans collision.

cette approche garantit à la fois que l'objet "rebondit" dans sa position précédente correcte et permet de glisser contre les murs, les objets, etc.

2: J'utilise moi-même une classe de collision statique qui peut être utilisée par n'importe quoi. il contient des méthodes de détection de collision et d'ajustement vectoriel, qui peuvent être appelées par à peu près n'importe quoi. que ces méthodes soient appelées à partir d'une classe de jeu "maître" ou par une sous-classe d'objets n'a pas vraiment d'importance dans mon cas, car la classe de collision crée une nouvelle liste à chaque trame pour tous les rectangles avec lesquels l'objet en mouvement se croise. ces rectangles peuvent provenir de tuiles, de décorations, de PNJ, tout ce qui a des limites et est collable, en gros. cela signifie que la simple nécessité pour tous les objets de jeu qui sont en collision est d'avoir un rectangle de délimitation. s'ils l'ont, la classe de collision gérera le reste.

espérons que cela était compréhensible.

UN V
la source
0

1: J'ai réussi à utiliser une technique pour résoudre ce problème: en utilisant la vitesse et la position, vous pouvez découvrir la collision et recommencer jusqu'à ce que la position soit très proche du point de collision exact.

Cela ne fait pas partie de la réponse à votre première question, mais si vous avez beaucoup d'objets qui peuvent entrer en collision les uns avec les autres, vous devez utiliser des arbres quadruples pour améliorer les performances. Il y a un très bon tutoriel avec beaucoup d'exemples ici .

2: Je recommande toujours Entity-Systems .

Filipe Borges
la source