Unidade: como detectar colisão que ocorre no objeto filho, a partir de um script pai?

12

Eu tenho um inimigo, com essa estrutura

  • Inimigo
    • Corpo
      • Cabeça
      • Braço esquerdo
      • Braço direito

E assim por diante.

Eu também tenho um colisor para cada parte do corpo. No meu objeto "Inimigo", anexei um script e gostaria de interceptar uma possível colisão (uma bala) de corpo, cabeça, braço, esquerda etc.

Existe uma maneira de fazer isso?

firme
fonte

Respostas:

16

Se você estiver usando um corpo rígido com o personagem, poderá tirá-lo da caixa. :)

Portanto, sua hierarquia pode ficar assim:

  • Personagem (possui corpo rígido e script de controle)
    • criança (talvez tenha colisores)
      • neto (talvez tenha colisores)

As mensagens OnCollisionEnter serão acionadas no GameObject que contém o Rigidbody, atingindo o script de controle pai sem a necessidade de escrever um script de retransmissão extra para colar em cada colisor.

Se você precisar descobrir qual colisor de filhos estava envolvido na colisão, faça o seguinte:

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
fonte
5

Uma maneira de resolver isso seria ter dois scripts: um para o objeto Inimigo e outro para o filho (que você precisa atribuir aos filhos do objeto Inimigo)

Script pai

using UnityEngine;

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

Script filho

using UnityEngine;

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

Dessa forma, você deve ser notificado sempre que ocorrer uma colisão com uma criança


fonte
2
Se você usar uma solução como essa e essas colisões acontecerem muito, recomendo que os filhos armazenem em cache o GameObject dos pais que os recebem. É um bom hábito sempre que você chamar muito o mesmo GetComponent e permitir que você faça uma das mais difíceis "descobertas que pais da cadeia enviar para a lógica" precisam acontecer apenas uma vez. Lembre-se também de que transform.parent obterá apenas o pai imediato .
Lunin
2

Você pode simplesmente passar o objeto superior para os filhos e chamar uma função diretamente nele. Isso garante que você não precisa confiar na propagação dos pais. Então você não acaba fazendo coisas tolas comotransform.parent.parent

No entanto, você pode automatizar esse processo com GetComponentInParent . Isso recupera o primeiro script encontrado. Em seguida, armazene em cache isso no seu objeto de colisão, chame diretamente funções no referido objeto em cache.

Como alternativa, você pode usar o UnityEvents (não use Mensagens) para vincular funções ao objeto filho. Com os eventos de unidade, você pode adicionar qualquer ouvinte arbitrário para poder fazer mais do que apenas notificar o objeto de nível superior do objeto filho que está sendo atingido.

Sidar
fonte
1

Citação direta da Unity Answers (escrita por Ashish Dwivedi ):

Adicione um script ao filho e dentro dele tenha uma referência do script do objeto pai. Agora escreva 3 métodos no script pai como (OnCollisionEnter2DChild, OnCollisionStay2DChild, OnCollisionExit2DChild) e chame o método respectivo dos métodos (OnCollisionEnter2D, OnCollisionStay2D, OnCollisionExit2D) que estão no script de objeto filho passando o objeto de colisão.

S. Tarık Çetin
fonte
1

Você pode verificar a colisão e ver qual caixa de ocorrências foi atingida e também obter o ponto de impacto, se necessário.

nota: o corpo rígido é colocado no mesmo objeto que possui o script de verificação de colisão.

Este exemplo está verificando para qual hitbox o 'projétil' atingiu um alvo.

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
fonte