Jump to content
Unity Insider Forum

Boxcollider2D die Seiten einzeln ansprechen


STU
 Share

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 to comment
Share on other sites

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 to comment
Share on other sites

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 to comment
Share on other sites

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 to comment
Share on other sites

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 to comment
Share on other sites

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 to comment
Share on other sites

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 to comment
Share on other sites

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 to comment
Share on other sites

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 to comment
Share on other sites

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 to comment
Share on other sites

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++;
            }
        }

    }
}

 

 

  • Like 1
Link to comment
Share on other sites

  • 6 months later...

Hi zusammen,

ich hätte doch zu diesem Thema nochmal eine Frage. Ich lese hier immer die Kontaktpunkte von dem anderen Objekt aus. Kann ich das auch umdrehen und mir den Punkt ausgeben von dem Objekt welches das Skript hat?

Danke

Link to comment
Share on other sites

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 to comment
Share on other sites

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 to comment
Share on other sites

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 to comment
Share on other sites

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 to comment
Share on other sites

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 to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

×
×
  • Create New...