如何在Unity中得知哪个碰撞器触发了OnTriggerEnter调用(在具有多个碰撞器的游戏对象上)

3
我最近遇到的问题如下:
我有一个Player对象,附加了一个名为“Player”的脚本。
我的游戏对象层次结构类似于这样:

enter image description here

Player (parent)           // Has Player.cs and a RigidBody attached to it.
    - GFX                 // Holds graphics like sprites
    - PhysicsHolder       // Empty object
        - Body            // Has a box trigger 2d defining the player body
        - Feet            // Has a box trigger 2d  defining the player feet area

我想在Player.cs中处理所有与玩家有关的碰撞事件,这样它们就可以集中在一个地方。问题是,很难区分是Feet对象还是Body对象触发了OnTriggerEnter2D的调用。
如果您已经像我一样设置了层次结构,则Body和Feet触发器都将在它们的父脚本中调用OnTriggerEnter2D,从而调用Player.OnTriggerEnter2D
OnCollisionEnter中,您可以使用collision.other获取触发调用的碰撞体的引用。然后,您可以轻松地为每个相应的碰撞体设置一个标签,并执行collision.other.CompareTag()
由于OnTriggerEnter没有Collision对象作为参数,而是一个Collider2D,并且Collider2D没有对other或类似物的引用,因此在想要处理触发事件的情况下,您无法做到相同。 在Player.cs中使用this.CompareTag()也不够,因为您将比较父级Player对象的标记,而不是Feet或Body对象的标记。

我后来找到了解决这个问题的方法,在此提供给大家。也许对遇到这个问题的任何人都有用。

1个回答

1
我的解决方案如下:
首先,我将以下脚本添加到我的项目中。
using UnityEngine;
using UnityEngine.Events;

/// <summary>
/// Delegates the call to OnTrigger2D for this object to another object.
/// </summary>
public class OnTrigger2DDelegator : MonoBehaviour
{
    private Collider2D caller;

    private void Awake()
    {
        caller = GetComponent<Collider2D>();
    }

    [Tooltip("Which function should be called when trigger was entered.")]
    public UnityEvent<OnTriggerDelegation> Enter;

    [Tooltip("Which function should be called when trigger was exited.")]
    public UnityEvent<OnTriggerDelegation> Exit;

    void OnTriggerEnter2D(Collider2D other) => Enter.Invoke(new OnTriggerDelegation(caller, other));
    void OnTriggerExit2D(Collider2D other) => Exit.Invoke(new OnTriggerDelegation(caller, other));
}

/// <summary>
/// Stores which collider triggered this call and which collider belongs to the other object.
/// </summary>
public struct OnTriggerDelegation {

    /// <summary>
    /// Creates an OnTriggerDelegation struct.
    /// Stores which collider triggered this call and which collider belongs to the other object.
    /// </summary>
    /// <param name="caller">The trigger collider which triggered the call.</param>
    /// <param name="other">The collider which belongs to the other object.</param>
    public OnTriggerDelegation(Collider2D caller, Collider2D other)
    {
        Caller = caller;
        Other = other;
    }

    /// <summary>
    /// The trigger collider which triggered the call.
    /// </summary>
    public Collider2D Caller { get; private set; }

    /// <summary>
    /// The other collider.
    /// </summary>
    public Collider2D Other { get; private set; }
}

大部分的解释已经在我写的摘要中了,但这里有更多细节。
将此脚本添加到例如Feet对象中(记住,它具有BoxCollider2D,是代表我的玩家脚的触发器),将会向检查器添加一些字段。然后,您可以拖入您的Player对象,并选择应在Player对象上运行的函数。
如果我们现在将以下代码添加到我们的Player.cs中,我们可以在Player.cs中处理触发事件,同时访问进入离开传入传出碰撞体。
public void OnFeetTriggerEnter(OnTriggerDelegation delegation)
{
    // will print out "Feet" in my example
    Debug.Log(delegation.Caller.name); 
    // will print out "Ground" in my example if the feet trigger was entered by an object called Ground.
    Debug.Log(delegation.Other.name); 
}

在检视器中的 OnTrigger2DDelegator 区域选择这种方法,将会得到以下类似的结果:

added fields in the inspector

大功告成!现在您可以像在Player.cs中添加OnBodyTriggerEnter函数一样,在同一文件中设置所有触发事件,只需为身体对象添加另一个委托并在检查器中选择该函数。

这使您可以在同一文件中设置所有触发事件。

注意:如果您不需要访问进入或退出的碰撞器,但确实想要区分对不同触发器的调用,您可以使用我在此处展示的相同设置,但跳过结构。只需将UnityEvent<OnTriggerDelegation>替换为UnityEvent<Collider(2D)>并将other传递给Enter.Invoke()。然后,您的Player.cs处理函数可能看起来像public void OnFeetTriggerEnter(Collision(2D) other)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接