web-dev-qa-db-fra.com

Comment empêcher les collisionneurs de se croiser?

J'ai du mal à garder les objets du jeu à l'intérieur d'un espace confiné. Quand ils atteignent l’Edge, il y a une poussée momentanée mais ils traverseront le mur.

J'utilise un collisionneur de boîte sur le joueur et un collisionneur de maillage pour le mur du niveau. Je rencontre des problèmes avec un personnage de joueur (un vaisseau spatial), le mouvement étant contrôlé par le joueur. Et avec les projectiles, qui sont feu et oublient de se déplacer à une vitesse constante.

Ceci est mon code de mouvement pour mon joueur. Il est exécuté dans la fonction FixedUpdate().

//Movement
    haxis = Input.GetAxis("Horizontal") * speed;
    vaxis = Input.GetAxis("Vertical") * speed;

    moveVector.x = haxis;
    moveVector.z = vaxis;

    if(moveVector.magnitude > 1)
    {
        moveVector.Normalize();
    }

    rigidbody.MovePosition(transform.position + moveVector * speed);

Avec les balles, ils reçoivent une vitesse et le moteur calcule leurs mouvements. Ils utilisent Box Collider et le jeu est défini comme un déclencheur, ils n'ont donc pas de physique. Mais j'utilise OnTriggerEnter pour les détruire.

//Projectiles without physics collisiions
function OnTriggerEnter (other : Collider) {
    Destroy(gameObject);
}

Certaines des balles, mais pas toutes, seront détruites si vous frappez le mur du collisionneur. Le joueur le frappe parfois et s’arrête, mais peut généralement le faire passer. Comment puis-je faire en sorte que les collisions avec le collisionneur de maillage fonctionnent à chaque fois?

13
Chris

La collision avec des objets en mouvement rapide est toujours un problème. Un bon moyen de vous assurer que vous détectez toutes les collisions est d'utiliser Raycasting au lieu de vous fier à la simulation physique. Cela fonctionne bien pour les puces ou les petits objets, mais ne donnera pas de bons résultats pour les gros objets . http://unity3d.com/support/documentation/ScriptReference/Physics.Raycast.html

Pseudo-codeish (je n'ai pas de code complet ici et une mémoire insuffisante):

void FixedUpdate()
{
    Vector3 direction = new Vector3(transform.position - lastPosition);
    Ray ray = new Ray(lastPosition, direction);
    RaycastHit hit;
    if (Physics.Raycast(ray, hit, direction.magnitude))
    {
        // Do something if hit
    }

    this.lastPosition = transform.position;
}
10
Petrucio

J'ai un prototype de flipper qui m'a également causé beaucoup de problèmes dans les mêmes domaines. Voici toutes les mesures que j'ai prises pour résoudre presque (mais pas encore entièrement) ces problèmes:

Pour les objets en mouvement rapide:

  • Réglez Interpolate de rigidbody sur 'Interpolate' (cela n'affecte pas la simulation physique réelle, mais met correctement à jour le rendu de l'objet. Utilisez cette option uniquement pour les objets importants du point de vue du rendu, comme le lecteur ou un flipper, pour les projectiles)

  • Définir la détection de collision sur dynamique continue

  • Attachez le script DontGoThroughThings ( https://www.auto.tuwien.ac.at/wordpress/?p=260 ) à votre objet. Ce script utilise intelligemment la solution Raycasting que j'ai publiée dans mon autre réponse pour récupérer les objets incriminés avant les points de collision.

Dans Modifier -> Paramètres du projet -> Physique :

  • Réglez Min Penetration for Penalty sur une valeur très faible. J'ai mis le mien à 0.001

  • Définissez le nombre d'itérations du solveur sur une valeur supérieure. J'ai réglé le mien à 50, mais vous pouvez probablement vous en tirer avec beaucoup moins.

Tout cela aura une pénalité en performance, mais c'est inévitable. Les valeurs par défaut sont faibles en termes de performances, mais ne sont pas vraiment destinées à la simulation correcte d’objets de petite taille ou à mouvements rapides.

12
Petrucio

Pourquoi ne pas définir la détection de collision de corps rigide sur Continuous ou Continuous Dynamic?

http://unity3d.com/support/documentation/Components/class-Rigidbody.html

6
Chchwy
  • Édition ---> Paramètres du projet ---> Temps ... diminuez la valeur "Timestep" .. Cela résoudra le problème, mais les performances risquent d’être affectées négativement.

  • Une autre solution est de calculer les coordonnées (par exemple, vous avez une balle et un mur. La balle va toucher le mur. Calculez donc les coordonnées du mur et définissez le processus de frappe en fonction de ces coordonnées)

1
fmp

Je n'ai donc pas réussi à faire fonctionner les collisionneurs maillés. J'ai créé un collisionneur composite à l'aide de simples collisionneurs à boîte et il a fonctionné exactement comme prévu.

D'autres tests avec de simples collisionneurs de maillage sont sortis les mêmes.

Il semble que la meilleure solution consiste à construire un collisionneur composite à partir de simples collisionneurs boîte/sphère.

Dans mon cas particulier, j’ai écrit un Wizard qui crée un collisionneur composé en forme de tuyau.

@script AddComponentMenu("Colliders/Pipe Collider");
class WizardCreatePipeCollider extends ScriptableWizard
{
    public var outterRadius : float = 200;
    public var innerRadius : float = 190;
    public var sections : int = 12;
    public var height : float = 20;

    @MenuItem("GameObject/Colliders/Create Pipe Collider")
    static function CreateWizard()
    {
        ScriptableWizard.DisplayWizard.<WizardCreatePipeCollider>("Create Pipe Collider");
    }

    public function OnWizardUpdate() {
        helpString = "Creates a Pipe Collider";
    }

    public function OnWizardCreate() {
        var theta : float = 360f / sections;
        var width : float = outterRadius - innerRadius;

        var sectionLength : float = 2 * outterRadius * Mathf.Sin((theta / 2) * Mathf.Deg2Rad);

        var container : GameObject = new GameObject("Pipe Collider");
        var section : GameObject;
        var sectionCollider : GameObject;
        var boxCollider : BoxCollider;

        for(var i = 0; i < sections; i++)
        {
            section = new GameObject("Section " + (i + 1));

            sectionCollider = new GameObject("SectionCollider " + (i + 1));
            section.transform.parent = container.transform;
            sectionCollider.transform.parent = section.transform;

            section.transform.localPosition = Vector3.zero;
            section.transform.localRotation.eulerAngles.y = i * theta;

            boxCollider = sectionCollider.AddComponent.<BoxCollider>();
            boxCollider.center = Vector3.zero;
            boxCollider.size = new Vector3(width, height, sectionLength);

            sectionCollider.transform.localPosition = new Vector3(innerRadius + (width / 2), 0, 0);
        }
    }
}
1
Chris

Old Question mais peut-être que ça aide quelqu'un.

Accédez à Paramètres du projet> Heure et essayez de diviser par deux ou par quatre le pas fixe et le maximum autorisé.

J'ai eu le problème que mon joueur était capable de se faufiler à travers des ouvertures plus petites que le collisionneur de joueurs et cela l'a résolu. Cela aide également à arrêter des objets en mouvement rapide.

0
Timanious

1.) Ne jamais utiliser le COLLIDER DE MAILLE. Utilisez une combinaison de collisionneur de boîtes et de capsules.

2.) Vérifier les contraintes dans RigidBody. Si vous cochez Freeze Position X, il traversera l'objet sur l'axe des X. (Idem pour l'axe des y). 

0
Simran Singh