首页 > 解决方案 > 如何用两个相同的盒子碰撞器打开相同的动画?

问题描述

我在游戏中有一个关卡,当你进入一个盒子对撞机时,一个传送门会打开,当你离开它时,它会关闭。当我进入 box collider 1 时,两个门户都需要打开,而当我离开它时,两者都需要关闭。当我进入第二个门户的框碰撞器 2 时,这也需要发生。我有一个盒子对撞机 1 的脚本,并将它应用到盒子对撞机 2。它检查玩家是否在对撞机中。我有一个动画器 bool,它直接从盒子对撞机脚本中获取变量来检查范围。我使用那个布尔动画。但是,该 animator bool 不适用于 box collider 2。box collider 的变量有效,但 animator bool 无效。有没有办法连接第二个,或者我需要为那个盒子对撞机制作一个新脚本?

盒子对撞机代码:


    public bool inRange;

    private void OnTriggerEnter2D(Collider2D other)
    {
        if (other.CompareTag("Player"))
        {
            inRange = true;
        }
    }

    private void OnTriggerExit2D(Collider2D other)
    {
        if (other.CompareTag("Player"))
        {
            inRange = false;
        }
    } 
}

门户脚本代码:

public class Portal : MonoBehaviour {

    private Animator anim;

    private bool inPortalRange;

    public GameObject portalBorder;

    void Start ()
    {
        anim = GetComponent<Animator>();
    }

    void Update ()
    {
        OpenPortal();
        UpdateAnimation();
    }

    private void UpdateAnimation()
    {
        anim.SetBool("inPortalRange", inPortalRange);
    }

    private void OpenPortal()
    {
        PortalBorder poborder = portalBorder.GetComponent<PortalBorder>();
        inPortalRange = poborder.inRange;
    }
}

一张情况图:

门户网站

标签: c#unity3d

解决方案


  • 首先,您不应该使用GetComponent每一帧。要么像anim你应该立即存储它。或者您可以简单地制作portalBorder类型,PortalBorder然后在通过 Inspector 引用它时自动设置相应的引用。

  • 那么是的,目前您只更新其中一个动画师。为了控制它们,你必须以某种方式连接它们。

我会做这样的事情

public class Portal : MonoBehaviour 
{
    private Animator anim;
    private bool inPortalRange;
    // Public read-only access
    public bool InPortalRange => inPortalRange;

    // Reference each other via the Inspector in both portals
    public Portal OtherPortal;

    // Give this directly the according type so you don't need GetComponent at all
    public PortalBorder portalBorder;

    // I would recommend to do things always as early as possible
    // Awake is executed before Start
    private void Awake()
    {
        anim = GetComponent<Animator>();
    }

    private void Update ()
    {
        OpenPortal();
        UpdateAnimation();
    }

    private void UpdateAnimation()
    {
        // Here now use the range of either this or the other portal
        anim.SetBool("inPortalRange", InPortalRange || OtherPortal.inPortalRange );
    }

    private void OpenPortal()
    {
        inPortalRange = portalBorder.inRange;
    }
}

然而,与其将其作为轮询调用,Update我实际上宁愿使用事件驱动的方法:

public class PortalBorder : MonoBehaviour
{
    public UnityEvent OnEnteredPortalRange;
    public UnityEvent OnLeftPortalRange;

    private void OnTriggerEnter2D(Collider2D other)
    {
        if (other.CompareTag("Player"))
        {
            OnEnteredPortalRange.Invoke();
        }
    }

    private void OnTriggerExit2D(Collider2D other)
    {
        if (other.CompareTag("Player"))
        {
            OnEnteredPortalRange.Invoke();
        }
    } 
}

现在您的脚本必须UnityEvent(就像onClick按钮一样)您可以通过检查器或使用代码添加回调

public class Portal : MonoBehaviour 
{
    public Animator anim;
    private bool inPortalRange;
    // Public read-only access
    public bool InPortalRange => inPortalRange;

    // Reference each other via the Inspector in both portals
    public Portal OtherPortal;

    // Give this directly the according type so you don't need GetComponent at all
    public PortalBorder portalBorder;

    // I would recommend to do things always as early as possible
    // Awake is executed before Start
    private void Awake()
    {
        anim = GetComponent<Animator>();

        // Instead of checking a bool in Update simply
        // wait until the according events get invoked
        portalBorder.OnEnteredPortalRange.AddListener(EnablePortal);
        portalBorder.OnLeftPortalRange.AddListener(DisablePortal);
    }

    private void OnDestroy()
    {
        // always make sure to remove callbacks when not needed anymore
        // in roder to avoid NullReferenceExceptions
        portalBorder.OnEnteredPortalRange.RemoveListener(EnablePortal);
        portalBorder.OnLeftPortalRange.RemoveListener(DisablePortal);
    }

    public void EnablePortal()
    {
        anim.SetBool("inPortalRange", true);
        OtherPortal.anim.SetBool("inPortalRange", true);
    }

    public void DisablePortal()
    {
        anim.SetBool("inPortalRange", false);
        OtherPortal.anim.SetBool("inPortalRange", false);
    }
}

推荐阅读