Si deux objets interagissent, que contient le code d'interaction?

28

Pensez à une balle et à un ennemi, ou au joueur et au sol. Si ces objets interagissent, que contient le code d'interaction?

ThatOneGuy
la source
2
Interagir de quelle manière? Voulez-vous dire la détection de collision? Si c'est le cas, il est très probable que vous implémentiez à la fois une classe de détection de collision et un gestionnaire de résolution de collision.
CaptainRedmuff
En partie oui, je m'intéresse à la fois à la collision et à ce qui se passe après la collision. La balle vérifie-t-elle si elle est proche de l'ennemi, ou l'inverse? Et que se passe-t-il après la collision, un objet balle peut-il simplement dire à un objet ennemi qu'il a été touché? Comme vous pouvez le voir, je suis assez confus à propos de tout cela, et cela rend le code très difficile à lire.
ThatOneGuy

Réponses:

23

TL; DR:

Vos objets de jeu ne se connaissent pas et ne vérifient pas les autres objets. Vous créez un modèle de détection et de résolution des collisions qui vérifie vos objets de jeu et effectue les actions appropriées pour simuler la physique de votre jeu.

Les bonnes choses

D'après les tentatives précédentes d'écrire la détection de collision et de lire ce livre , il y a deux étapes pour la détection de collision et la résolution de collision. La première étape (détection de collision) est une passe de sortie anticipée où vous déterminez si deux objets peuvent avoir une collision potentielle. Si deux objets forment une collision potentielle, vous passez ensuite ces objets dans la deuxième étape (résolution de la collision) pour effectuer une vérification plus fine des objets et tenter de résoudre la collision.

Quelque part dans votre moteur / jeu, vous détiendrez un tableau de tous les objets de votre monde. Sur chaque trame, vous boucleriez à travers le tableau et vérifieriez chaque objet par rapport à tous les autres objets avec une simple détection de collision boîte / sphère.

Pseudocode:

dectectCollisions(objects)
{
    for(objectA in objects)
    {
        for(objectB in objects)
        {
            if(objectA != objectB) //ignore self
            {
                if(BoundingSpheresIntersect(objectA, objectB))
                {
                    collisionResolver.addObjects(objectA, objectB);
                }
            }
        }
    }
}

Ce type de boucle est plutôt inefficace mais laisse place à amélioration via l'utilisation du partitionnement spatial comme sortie anticipée pour les objets qui sont garantis trop éloignés pour entrer en collision.

Après avoir vérifié les deux objets pour une collision potentielle (c'est-à-dire que les deux objets sont suffisamment proches pour entrer en collision), les objets sont passés pour effectuer une routine de détection de collision plus précise.

Imaginez que vous ayez deux polygones de formes et de tailles aléatoires suffisamment proches pour potentiellement se croiser mais qui ne le sont pas en raison de leur géométrie:

Image trouvée via google

À l'aide de sphères englobantes, ces deux objets créeraient un faux positif pour une collision potentielle. C'est là que vous effectuez ensuite une passe plus approfondie pour déterminer si les deux objets se croisent réellement.

Une fois que vous avez trouvé une véritable collision, votre étape de résolution de collision effectuera alors l'action appropriée pour résoudre les objets en appliquant des forces ou des moments en fonction de la granularité et des besoins de votre physique de jeu.

Dans cet esprit, vous pouvez faire abstraction de l'ensemble du processus de détection et de résolution des collisions afin que vos objets n'aient besoin de rien savoir les uns des autres, ni du processus requis pour déterminer et résoudre les collisions. Les deux classes / gestionnaires qui gèrent cela pour vous n'ont besoin que de connaître les propriétés de base de chaque objet pour effectuer une vérification rapide et sale des collisions, puis une vérification plus approfondie si cela est nécessaire.

CaptainRedmuff
la source
2
En particulier, le modèle de conception Mediator serait approprié. Le modèle Observer serait une bonne alternative, qui a une intention très différente. Vous pouvez en obtenir un assez bon résumé sur ce post Stackoverflow .
kurtzbot
12

Un moyen qu'Unreal Engine 3 gère:

La balle reçoit un message de collision disant qu'elle a touché quelque chose, avec un argument lui disant ce qu'elle a frappé. Il peut ensuite appeler objectHit.takeDamage (self). La cible reçoit alors le message TakeDamage, avec un pointeur sur la chose qui l'a frappée, et prend l'action appropriée.

Personnellement, j'aime cette approche, car cela signifie que la balle peut prendre des mesures spéciales (comme faire une sorte d'effet d'explosion en fonction du type de chose touchée) et que la cible peut prendre des mesures spéciales en fonction du type de balle.

Il est également possible que la puce sache ce qu'elle fait aux cibles et puisse appeler une fonction dessus, comme objectHit.freeze (self). Ensuite, la cible sait qu'elle a été touchée par quelque chose qui la gèle, et quel type d'objet c'était.

EDIT: Cette réponse est conçue comme une image générale de la façon dont cela peut fonctionner, car vous ne travaillez probablement pas avec UE3. :)

Almo
la source
10

Thief l'a très bien fait dans le Dark Engine avec Sources et Receptrons. Un objet peut avoir ces deux propriétés, avec des types différents. Par exemple, une flèche d'eau aurait une source pour WaterStim au contact. Une explosion aurait un FireStim AoE.

Lorsqu'une flèche d'eau frappe un objet, l'objet cible recherche ensuite dans ses receptrons tout ce qui recherche un WaterStim avec les valeurs d'intensité appropriées. Ensuite, il exécute la commande qui lui est associée (dans ce cas, transformer une torche allumée en une torche éteinte et émettre une bouffée de fumée.)

Étant donné que le même moteur est utilisé dans SystemShock2, c'est ainsi que tous les différents types de dégâts sont traités, différentes balles ont des Stims différents, et différents monstres ont ensuite des Receptrons pour les différents types de Stim et font des dégâts égaux à 1 *, 2 *, 1 / 2 l'intensité selon que le type de munitions est "super efficace" ou non.

Cela semblait être un système très flexible car vous pouviez ajouter des sources et des receptrons aux objets dans l'éditeur de niveau (pour créer une porte unique qui s'ouvrirait en cas de feu, par exemple). Bien que vous puissiez également dire à un receptron d'envoyer un script message "si l'objet était associé à des scripts spéciaux.

Ce que vous ne voulez pas faire, c'est coder en dur une matrice d'interaction nXn de tous les objets possibles entrant en collision avec tous les objets possibles! EN généralisant les interactions à travers des messages standardisés, vous simplifiez le processus.

Entaille
la source
Du point de vue des scripts, cette approche semble la plus flexible et la plus expressive. Très sympa.
drhayes
-2

Une solution consiste à conserver les conteneurs de balles et de joueurs dans des classes distinctes, puis à avoir la fonction main () qui garde la boucle de trame responsable de l'interaction.

tp1
la source