播放并等待动画/动画师完成播放 [英] Play and wait for Animation/Animator to finish playing

查看:102
本文介绍了播放并等待动画/动画师完成播放的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的脚本中,我做到了在播放器位于平台顶部时将其向上移动. 一切正常.但是,现在我想使它弹起时播放剪辑"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");

解决方案

虽然两个答案都应该起作用,但是另一种使用协程和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 比较字符串的函数,因为哈希值更快.

假设您有一个名为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");
}

OR

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");
    }
}

In my script i did that when the player is on the top of the platform move it up. It's working fine. But now i want to make that once it got up play the clip "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");
        }
    }
}

After the line

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

I want when it finish playing it play the down:

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

解决方案

While both answers should work, another method of doing this with coroutine and the IsPlaying function. You use the coroutine solution if you also want to perform other task after the animation.

For the Animation system:

The old Unity animation playback system. This should not be used in your new Project unless you are still using old Unity version.

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");
}

For the Animator system

This is the new Unity animation playback system. This should be used in your new Project instead of the Animation API. In terms of performance, it's better to use the Animator.StringToHash and compare the current state by hash number instead of the IsName function which compares string since the hash is faster.

Let's say that you have state names called Jump, Move and Look. You get their hashes as below then use the function for playing and waiting for them them below:

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");

}



For a solution specifically for your particular problem with the collision callback function (OnTriggerEnter), there are two possible ways to do that:

1.Start a coroutine function to play the animation after trigger detection:

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");
}

OR

2.Make the OnTriggerEnter function a coroutine(IEnumerator) instead of void function:

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");
    }
}

这篇关于播放并等待动画/动画师完成播放的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆