Jump to content
Unity Insider Forum

Boxcollider2D die Seiten einzeln ansprechen


STU

Recommended Posts

Hi,

kann man bei einem Boxcollider2D die Seiten einzeln ansprechen? Ich würde gerne das so haben, wenn ich von oben drauf springe, dass etwas anderes passiert als wenn ich seitlich getroffen werden.

Aktuell habe ich zwei collider einem in der Hauptfigur und einem in einem EmptyBody darunter. Das hat alles funktioniert bis ich einen ridigbody eingefügt habe. Jetzt gibt es probleme im EmptyBody er wird zwar noch erkannt aber das Skript in welchem ein Ereignis passieren soll, bei Kollision, funktioniert nicht mehr. Nehme ich den rigidbody wirder raus läuft alles wieder wie gehabt.

Danke

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hi Thariel,

dann muss ich haber vorher meine größe von dem Collider kennen, oder? Ich würde das skipt gerne für verschiedene gegner anwenden. Gibt es da eine möglichkeit?

Wenn ich es ermittelt habe, dann mit if abfragen ob der eine höher ist als der andere?

Danke

Link zu diesem Kommentar
Auf anderen Seiten teilen

Die grösse des BoxCillider2D kannst du natürlich schon ermitteln. Hier siehst du alles Relevante zum BoxCollider2D:

https://docs.unity3d.com/ScriptReference/BoxCollider2D.html

Interessant sind da sicher size und bounds.

Wenn dein Charakter zum Beispiel auf ein Gegner springen soll, so wie in Mario, dann kannst du einfach das Zentrum der Gegner-BoxCollider nehmen und die Hälfte der Höhe der Box addieren. Das selbe machst du mit der Charakter Box, aber subtrahierst die Halbe Höhe. Wenn der Y Wert nun etwa gleich gross ist, ist der Charakter auf den Gegner gesprungen.

Aber du kannst auch einfach mehrere BoxCollider nehmen. Das ist sicher am einfachsten.

Du kannst auch nach der Kollision noch ein Linecast machen und dann hast du einen genauen HitPoint, aber die Seite musst du dann immer noch ermitteln.

Es gibt da wirklich viele Möglichkeiten.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Das klingt interessant und ich werde es morgen auf jeden Fall mal ausprobieren.

Noch eine Anfängerfrage 😄 Wenn ich zwei collider habe und die mit Tigger anspreche kann ich ja z.b mit OnTiggerEnter2D (Boxcollider2D) oder eben Circlecollider machen.
Wie macht man das mit  oncollisionenter2d das man einen ganz bestimmten collider anspricht?

Link zu diesem Kommentar
Auf anderen Seiten teilen

Wenn du die Kontaktpunkte und die Normalen-Vektoren bei einer Kollision ausliest, dann sieht das in etwa so aus. An der Richtung der (beiden) Normalenvektoren kannst du also erkennen, auf welcher Seite des Box-Colliders die Kollision stattgefunden hat (wie Sascha schon geschrieben hatte).

(rot = Normalenvektoren / blau = Kollisionspunkte / grün Boxcollider)
XFpIMgb.png

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hi,

ich habe mal so angefangen. Das habe ich uf der Seite von Unity gefunden. In der Console wird das auch angezeigt.

In der erklärung steht, dass der Vektor auch in der SceneView sichtbar ist. Denke mal so wie oben in dem Bild. Ich sehe die Linien aber nicht. Was muss ich einstellen das ich diese auch sehe?

 void OnCollisionEnter(Collision other)
    {
        print("Points colliding: " + other.contacts.Length);
        print("First normal of the point that collide: " + other.contacts[0].normal);
    }

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 15 Minuten schrieb STU:

Das habe ich uf der Seite von Unity gefunden. In der Console wird das auch angezeigt.

In der erklärung steht

Wär halt irgendwo sinnvoll, wenn du mal verlinkst, was du da gefunden hast. Auf allen Seiten, die ich jetzt extra rausgesucht habe; von denen ich angenommen habe, du könntest sie meinen, steht das im Beispielcode, wie man das macht.

https://docs.unity3d.com/ScriptReference/MonoBehaviour.OnCollisionEnter.html

https://docs.unity3d.com/ScriptReference/Collision-contacts.html

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hi,

ich habe zwar noch nicht die Linien sichtbar bekommen, dafür klappt es jetzt mit dem collider. Wenn ich oben drauf springe verschieben sie und wenn ich sie seitlich berühre, verliere ich Leben 😄 

also schon mal vielen Dank für die Tipps.

Auf die gleiche weiße habe ich es so programmiert, wenn ein Gegner seitlich einen collider trifft, dass er umdreht. Dabei ist mir aufgefallen, dass dies bei boxcollider funktioniert, aber nicht bei edgecollider. Was ist der Unterschied? Ich verwende obcollisionEnter2D. Ich kann morgen auch das Skript hochladen wenn das hilft. 

 

zu den Linien hatte ich hier nachgeschaut.

https://docs.unity3d.com/ScriptReference/ContactPoint-normal.html

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 58 Minuten schrieb STU:

ich habe zwar noch nicht die Linien sichtbar bekommen

Die grünen Linien der BoxCollider siehst du ja und die anderen wurden gezeichnet. Du kannst mit der Gizmos Klasse selber Linien und vieles mehr zeichnen:

https://docs.unity3d.com/ScriptReference/Gizmos.html

 

Zum Beispiel kannst du genau diese Funktion in dein Script kopieren und es wird eine gelbe Kugel im Editor Window gezeichnet. Du kannst deine eigene Funktion schreiben um Dinge zu visualisieren und so verstehen, ob dein Script richtig arbeitet.

void OnDrawGizmos()
{
        // Draw a yellow sphere at the transform's position
        Gizmos.color = Color.yellow;
        Gizmos.DrawSphere(transform.position, 1);
}

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ich hatte die Punkte und Linien so "gemalt" und den Quellcode unterschlagen, da es quick und dirty war, aber wenn es dir hilft.

Diese Klasse an den 2D-Collider hängen der die Collision bekommt (die Gizmos siehst du nur im Sceneview).
Wenn gerade keine Collision stattfindet zeichnet er trotzdem die letzte Collision.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class DrawCollider2D : MonoBehaviour
{

    private List<Vector3> contactPoints;
    private List<Vector3> normalPoints;

    void OnCollisionEnter2D(Collision2D collision)
    {
        contactPoints = new List<Vector3>();
        normalPoints = new List<Vector3>();
        ContactPoint2D[] contactPoint2d = collision.contacts;
        foreach (ContactPoint2D cPoint in contactPoint2d)
        {
            contactPoints.Add(cPoint.point);
            normalPoints.Add(cPoint.normal);
        }
    }

    void OnDrawGizmosSelected()
    {
        if (contactPoints != null)
        {
            Gizmos.color = Color.blue;
            foreach (Vector3 cPoint in contactPoints)
            {
                Gizmos.DrawWireSphere(cPoint, 0.02f);
            }
        }
        if (normalPoints != null)
        {
            Gizmos.color = Color.red;
            int i = 0;
            foreach (Vector3 nPoint in normalPoints)
            {
                Gizmos.DrawLine(contactPoints[i], contactPoints[i] + nPoint);
                i++;
            }
        }

    }
}

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Also die Regeln lauten bei zwei GameObjects mit Collidern muss einer davon Rigidbody haben, damit sie mit einander kollidieren können und da wird auch OnCollision usw. gecallt. Daher komisch, dass es bei dir nicht mehr geht, wenn man Rigidbody hinzufügt. 

  

vor 18 Stunden schrieb Zer0Cool:

Ich hatte die Punkte und Linien so "gemalt" und den Quellcode unterschlagen, da es quick und dirty war, aber wenn es dir hilft.

Diese Klasse an den 2D-Collider hängen der die Collision bekommt (die Gizmos siehst du nur im Sceneview).
Wenn gerade keine Collision stattfindet zeichnet er trotzdem die letzte Collision.


using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class DrawCollider2D : MonoBehaviour
{

    private List<Vector3> contactPoints;
    private List<Vector3> normalPoints;

    void OnCollisionEnter2D(Collision2D collision)
    {
        contactPoints = new List<Vector3>();
        normalPoints = new List<Vector3>();
        ContactPoint2D[] contactPoint2d = collision.contacts;
        foreach (ContactPoint2D cPoint in contactPoint2d)
        {
            contactPoints.Add(cPoint.point);
            normalPoints.Add(cPoint.normal);
        }
    }

    void OnDrawGizmosSelected()
    {
        if (contactPoints != null)
        {
            Gizmos.color = Color.blue;
            foreach (Vector3 cPoint in contactPoints)
            {
                Gizmos.DrawWireSphere(cPoint, 0.02f);
            }
        }
        if (normalPoints != null)
        {
            Gizmos.color = Color.red;
            int i = 0;
            foreach (Vector3 nPoint in normalPoints)
            {
                Gizmos.DrawLine(contactPoints[i], contactPoints[i] + nPoint);
                i++;
            }
        }

    }
}

 

Muss dein Code kritisieren :P.  Jedes mal contactPoints = new List<Vector3>(); zu machen finde ich nicht gut, aber ist in dem Beispiel ist es nicht so schlimm. Man kann dennoch da contactPoints.Clear() benutzen. New Object lässt den GarbageCollector arbeiten. Wie gesagt: In dem Beispiel ist das jetzt nicht schlimm, aber hätten wir 500 Objekte, die mit einander Kollidieren dann vllt schon.

Warum ich generell das nicht machen würde ist, wenn man Logger.contactPoints = contactPoints hat und man nun contactPoints = new  macht.. dann ist Logger.contactPoints nicht null, sondern hat noch den Reference zu alten Speicher von contactPoints. Das heißt wenn man nun contactPoints.Add macht würde Logger.contactPoints nicht mehr sich ändern. Ich wiederhole, ist hier in dem Beispiel aber ok.

Ich hab trotzdem das mal abgeändert und auch Clean-Code-Prinzip eingebaut.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class DrawCollider2D : MonoBehaviour
{
    private List<Vector3> contactPoints = new List<Vector3>();
    private List<Vector3> normalPoints = new List<Vector3>();

    void OnCollisionEnter2D(Collision2D collision)
    {
        contactPoints.Clear();
        normalPoints.Clear();
        
        ContactPoint2D[] contactPoint2d = collision.contacts;
        foreach (ContactPoint2D contactPoint in contactPoint2d)
        {
            contactPoints.Add(contactPoint.point);
            normalPoints.Add(contactPoint.normal);
        }
    }

    void OnDrawGizmosSelected()
    {
        if (contactPoints.Count > 0)
        {
            Gizmos.color = Color.blue;
            foreach (Vector3 contactPoint in contactPoints)
            {
                Gizmos.DrawWireSphere(contactPoint, 0.02f);
            }
        }
        
        if (normalPoints.Count > 1)
        {
            Gizmos.color = Color.red;
            int i = 0;
            foreach (Vector3 normalPoint in normalPoints)
            {
                Gizmos.DrawLine(contactPoints[i], contactPoints[i] + normalPoint);
                i++;
            }
        }

    }
}

 

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

  • 6 months later...

Guten Morgen,

ja schon. Mich würde in diesem Fall aber auch mehr der Kontakt am Collider interessieren. Ich würde gerne wissen wo das GameObject selbst getroffen worden ist. Also seitlich ober oben. Dies bekomme ich aber nicht von "meinem Objekt" sondern von dem getroffenen Objekt.

   Vector2 newColliderContact = new Vector2(collision.contacts[0].normal.x, collision.contacts[0].normal.y);
            Debug.Log ("newColliderContact: " + newColliderContact);

            if (newColliderContact.y > -0.5f)
            {...

Danke

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ich würde es nicht so kompliziert machen und EdgeCollider benutzen. Danach hat man ja pro Seite ein Collider. Geht natürlich auch mit BoxCollider pro Seite.


EDIT: Huch hab gesehen hab schon mal hier geantwortet und nicht bemerkt, dass es ein alter Post ist :D. Dieser Post kann gelöscht werden. Kann leider nicht selbst tun.

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 10 Stunden schrieb STU:

Ich würde gerne wissen wo das GameObject selbst getroffen worden ist. Also seitlich ober oben. Dies bekomme ich aber nicht von "meinem Objekt" sondern von dem getroffenen Objekt.

Wie gesagt... Kontaktpunkte sind da, wo beide Collider sich berühren. Alle Kontaktpunkte liegen damit gleichermaßen auf beiden Collidern.

Link zu diesem Kommentar
Auf anderen Seiten teilen

nehmen wir an dass ich mit meinem Spieler auf einen Gegner Spring, dann wird beim Spieler der Collider unten angesprochen werden und wenn das Skipt im GameObjekt vom Gegner hängt würde doch dieser Fall stimmen, oder?   newCollider.Contact.y   ==   -1

Und jetzt meine Frage: Wenn ich im demselben Skript gerne wissen würde, wo der Collider vom GameObjekt selbst angesprochen wurde (also in diesem Fall oben +1) wie kann ich das abfragen?

Danke

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 13 Stunden schrieb STU:

würde doch dieser Fall stimmen, oder?   newCollider.Contact.y   ==   -1

Nö. Kontaktpunkt sind in World Space und nicht relativ zu den Collidern. Heißt: Wenn deine Charaktere irgendwo um (1000,1000,1000) rumdüsen, dann wird er Kontaktpunkt auch irgendwo in dieser Gegend sein.

vor 13 Stunden schrieb STU:

Und jetzt meine Frage: Wenn ich im demselben Skript gerne wissen würde, wo der Collider vom GameObjekt selbst angesprochen wurde (also in diesem Fall oben +1) wie kann ich das abfragen?

Bin mir nicht sicher, was du meinst, aber OnCollisionEnter und seine Freunde werden immer auf allen Komponenten von beiden beteiligten GameObjects aufgerufen.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Archiviert

Dieses Thema ist jetzt archiviert und für weitere Antworten gesperrt.

×
×
  • Neu erstellen...