Jedność: jak wykryć kolizję na obiekcie podrzędnym ze skryptu nadrzędnego?

12

Mam wroga z tą strukturą

  • Wróg
    • Ciało
      • Głowa
      • Ramię w lewo
      • Ramię w prawo

I tak dalej.

Mam również zderzacz dla każdej części ciała. Do mojego obiektu „Wróg” załączyłem skrypt, w tym skrypcie chciałbym przechwycić możliwą kolizję (pocisk) ciała, głowy, ramienia, lewej itd.

Czy jest na to sposób?

mocny
źródło

Odpowiedzi:

16

Jeśli używasz Rigidbody z postacią, możesz wyciągnąć to z pudełka. :)

Twoja hierarchia może wyglądać następująco:

  • Postać (ma Sztywne ciało i skrypt sterujący)
    • dziecko (może ma zderzaki)
      • wnuk (może ma zderzaczy)

Wiadomości OnCollisionEnter będą uruchamiane na GameObject zawierającym Rigidbody, docierając do rodzica skryptu kontrolnego bez potrzeby pisania dodatkowego skryptu przekazywania, aby przykleić się do każdego zderzacza.

Jeśli chcesz dowiedzieć się, który z twoich dzieci zderzających się uczestniczył w kolizji, możesz to zrobić w następujący sposób:

void OnCollisionEnter(Collision collision) {
    Collider myCollider = collision.contacts[0].thisCollider;
    // Now do whatever you need with myCollider.
    // (If multiple colliders were involved in the collision, 
    // you can find them all by iterating through the contacts)
}
DMGregory
źródło
5

Jednym ze sposobów rozwiązania tego byłoby posiadanie dwóch skryptów: jeden dla obiektu Wróg i drugi dla dziecka (które należy przypisać do dzieci wroga obj)

Skrypt nadrzędny

using UnityEngine;

 public class ParentScript : MonoBehaviour 
 {
     public void CollisionDetected(ChildScript childScript)
     {
         Debug.Log("child collided");
     } 
 }

Skrypt potomny

using UnityEngine;

public class ChildScript : MonoBehaviour 
{
     void OnCollisionEnter(Collision collision)
     {
         transform.parent.GetComponent<ParentScript>().CollisionDetected(this);
     }
 }

W ten sposób powinieneś otrzymywać powiadomienia za każdym razem, gdy nastąpi kolizja z dzieckiem


źródło
2
Jeśli użyjesz takiego rozwiązania, a te kolizje zdarzają się często, zdecydowanie polecam dzieciom buforowanie GameObject otrzymującego rodzica. Jest to dobry nawyk za każdym razem, gdy będziesz często dzwonić do tego samego GetComponent i pozwala ci dokonać trudniejszego „ustalenia, który z rodziców w łańcuchu, aby wysłać do” logiki, musi się zdarzyć tylko raz. Pamiętaj również, że transform.parent otrzyma tylko bezpośredniego rodzica.
Lunin,
2

Możesz po prostu przekazać górny obiekt dzieciom i wywołać funkcję bezpośrednio na nim. Gwarantuje to, że nie musisz polegać na propagacji rodziców. Więc nie robisz głupich rzeczytransform.parent.parent

Możesz jednak zautomatyzować ten proces za pomocą GetComponentInParent . Pobiera pierwszy znaleziony skrypt. Następnie buforuj to w swoim obiekcie kolizyjnym, bezpośrednio wywołuj funkcje na tym buforowanym obiekcie.

Alternatywnie możesz użyć UnityEvents (nie używaj Wiadomości) do powiązania funkcji z obiektem potomnym. Za pomocą zdarzeń jedności możesz dodać dowolny dowolny detektor, dzięki czemu możesz zrobić coś więcej niż tylko powiadomić obiekt najwyższego poziomu o trafieniu obiektu potomnego.

Sidar
źródło
1

Bezpośredni cytat z Unity Answers (napisany przez Ashisha Dwivedi ):

Dodaj skrypt do dziecka, a wewnątrz niego znajduje się odwołanie do skryptu obiektu nadrzędnego. Teraz napisz 3 metody w skrypcie nadrzędnym, takie jak (OnCollisionEnter2DChild, OnCollisionStay2DChild, OnCollisionExit2DChild) i wywołaj odpowiednią metodę z metod (OnCollisionEnter2D, OnCollisionStay2D, OnCollisionExit2D), które są w skrypcie obiektu podrzędnego, przekazując obiekt kolizji.

S. Tarık Çetin
źródło
1

Możesz sprawdzić kolizję i sprawdzić, które pole trafienia zostało trafione, a także w razie potrzeby uzyskać punkt uderzenia.

Uwaga: ciało sztywne jest umieszczane na tym samym obiekcie, który ma skrypt sprawdzania kolizji.

W tym przykładzie sprawdzono, który hitbox trafił „pocisk” w cel.

private void OnCollisionEnter(Collision collision)
{                 
    if (collision.contacts[0].otherCollider.transform.gameObject.name == "HeadShot")                
       //DO STUFF            

    if (collision.contacts[0].otherCollider.transform.gameObject.name == "BodyShot")
       //DO STUFF    
}
Justin Markwell
źródło