【问题标题】:Play and wait for Animation/Animator to finish playing播放并等待 Animation/Animator 完成播放
【发布时间】:2017-03-27 23:44:21
【问题描述】:

在我的脚本中,当玩家位于平台顶部时,我将其向上移动。 它工作正常。但现在我想在它启动后播放“Down”剪辑。

using UnityEngine;
using System.Collections;
using System.Reflection;

public class DetectPlayer : MonoBehaviour {

    GameObject target;

    public void ClearLog()
    {
        var assembly = Assembly.GetAssembly(typeof(UnityEditor.ActiveEditorTracker));
        var type = assembly.GetType("UnityEditorInternal.LogEntries");
        var method = type.GetMethod("Clear");
        method.Invoke(new object(), null);
    }

    void OnCollisionEnter(Collision collision)
    {
        if (collision.gameObject.name == "Platform")
        {
            Debug.Log("Touching Platform");
        }

    }

    void OnTriggerEnter(Collider other)
    {
        if (other.gameObject.name == "OnTop Detector")
        {
            Debug.Log("On Top of Platform");
            GameObject findGo = GameObject.Find("ThirdPersonController");
            GameObject findGo1 = GameObject.Find("Elevator");
            findGo.transform.parent = findGo1.transform;
            target = GameObject.Find("Elevator");
            target.GetComponent<Animation>().Play("Up");
        }
    }
}

行后

target.GetComponent<Animation>().Play("Up");

我想在它播放完后向下播放:

target.GetComponent<Animation>().Play("Down");

【问题讨论】:

    标签: c# unity3d


    【解决方案1】:

    虽然这两个答案都应该有效,但使用协程和IsPlaying 函数的另一种方法。如果您还想在动画之后执行其他任务,您可以使用协程解决方案。

    对于Animation系统

    旧的 Unity 动画播放系统。这应该在您的新项目中使用,除非您仍在使用旧的 Unity 版本。

    IEnumerator playAndWaitForAnim(GameObject target, string clipName)
    {
        Animation anim = target.GetComponent<Animation>();
        anim.Play(clipName);
    
        //Wait until Animation is done Playing
        while (anim.IsPlaying(clipName))
        {
            yield return null;
        }
    
        //Done playing. Do something below!
        Debug.Log("Done Playing");
    }
    

    对于Animator系统

    这是新的 Unity 动画播放系统。这应该在您的新项目中使用,而不是 Animation API。在性能方面,最好使用Animator.StringToHash并通过哈希数比较当前状态,而不是比较字符串的IsName函数,因为哈希是faster

    假设您有名为JumpMoveLook 的州名。你得到他们的哈希值如下,然后使用函数在下面播放和等待他们:

    const string animBaseLayer = "Base Layer";
    int jumpAnimHash = Animator.StringToHash(animBaseLayer + ".Jump");
    int moveAnimHash = Animator.StringToHash(animBaseLayer + ".Move");
    int lookAnimHash = Animator.StringToHash(animBaseLayer + ".Look");
    
    public IEnumerator PlayAndWaitForAnim(Animator targetAnim, string stateName)
    {
        //Get hash of animation
        int animHash = 0;
        if (stateName == "Jump")
            animHash = jumpAnimHash;
        else if (stateName == "Move")
            animHash = moveAnimHash;
        else if (stateName == "Look")
            animHash = lookAnimHash;
    
        //targetAnim.Play(stateName);
        targetAnim.CrossFadeInFixedTime(stateName, 0.6f);
    
        //Wait until we enter the current state
        while (targetAnim.GetCurrentAnimatorStateInfo(0).fullPathHash != animHash)
        {
            yield return null;
        }
    
        float counter = 0;
        float waitTime = targetAnim.GetCurrentAnimatorStateInfo(0).length;
    
        //Now, Wait until the current state is done playing
        while (counter < (waitTime))
        {
            counter += Time.deltaTime;
            yield return null;
        }
    
        //Done playing. Do something below!
        Debug.Log("Done Playing");
    
    }
    


    对于专门针对您的碰撞回调函数 (OnTriggerEnter) 的特定问题的解决方案,有两种可能的方法:

    1.触发检测后启动协程函数播放动画:

    void OnTriggerEnter(Collider other)
    {
        if (other.gameObject.name == "OnTop Detector")
        {
            Debug.Log("On Top of Platform");
            GameObject findGo = GameObject.Find("ThirdPersonController");
            GameObject findGo1 = GameObject.Find("Elevator");
            findGo.transform.parent = findGo1.transform;
            target = GameObject.Find("Elevator");
            StartCoroutine(playAnim(target));
        }
    }
    
    IEnumerator playAnim(GameObject target)
    {
        Animation anim = target.GetComponent<Animation>();
        anim.Play("Up");
    
        //Wait until Up is done Playing the play down
        while (anim.IsPlaying("Up"))
        {
            yield return null;
        }
    
        //Now Play Down
        anim.Play("Down");
    }
    

    2.使OnTriggerEnter函数成为协程(IEnumerator)而不是void函数:

    IEnumerator OnTriggerEnter(Collider other)
    {
        if (other.gameObject.name == "OnTop Detector")
        {
            Debug.Log("On Top of Platform");
            GameObject findGo = GameObject.Find("ThirdPersonController");
            GameObject findGo1 = GameObject.Find("Elevator");
            findGo.transform.parent = findGo1.transform;
            target = GameObject.Find("Elevator");
            Animation anim = target.GetComponent<Animation>();
            anim.Play("Up");
    
            //Wait until Up is done Playing the play down
            while (anim.IsPlaying("Up"))
            {
                yield return null;
            }
    
            //Now Play Down
            anim.Play("Down");
        }
    }
    

    【讨论】:

    • 这是有效的。如果我想让它不停地上下移动?我尝试在 OnTriggerEnter 中调用 StartCoroutine 来创建更新函数,并在我所做的更新函数内部: if (target != null) StartCoroutine(playAnim(target));但这使它只会一直向上移动,不会停止,也不会下降。
    • 我不明白你的评论。你能再解释一下吗?
    • 我现在的意思是 StartCoroutine(playAnim(target));让它上下移动,但只移动一次。我想做的是它会继续向上向下向上向下移动......不停。
    • 您所需要的只是将 Play to down 代码包装在 while(true) 代码中。由于这不是您最初的问题,因此我发布了解决方案here。告诉我是否还有问题。就像您想要的那样,这将永远播放上下动画!
    • 谢谢你,工作。
    【解决方案2】:

    一种完全不需要手动检查的方法是使用排队

    target.GetComponent<Animation>().PlayQueued("Down", QueueMode.CompleteOthers);
    

    此代码将等待对象上当前正在播放的任何其他动画完成,然后再播放排队的动画。

    The Unity API page regarding this topic

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-08-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-14
      相关资源
      最近更新 更多