Unity3D 获取动画控制器当前动画时间



嗨,我试图构建一个应用程序并尝试在滚动上做事。

我在 Unity 的动画控制器中有 3 个不同的层,重量均为 1。在第一层中具有加载动画,在第2层中具有滚动动画,该动画需要在第1层动画的顶部播放。

因此,为了在滚动上调用动画,我编写了一个程序,该程序在滚动的底部调用动画,因此第 2 层"take001"上的动画在滚动上播放取决于滚动发生的次数。

现在我想获取第 2 层动画的当前时间。

找到下面的代码和我在 Unity 中创建的层的屏幕截图:

[参考图片] : https://i.stack.imgur.com/1huCM.jpg

using UnityEngine;
using System.Collections;
public class MouseMovementScript : MonoBehaviour {
Animator anim;
AnimatorStateInfo stateInfo;
AnimatorClipInfo[] myAnimatorClip;
double speedBase = 1;
void Start () {
anim = GetComponent<Animator>();
stateInfo = anim.GetCurrentAnimatorStateInfo(1);
//Output the name of the starting clip
}
// Update is called once per frame
void Update () {
var d = Input.GetAxis("Mouse ScrollWheel");
if (d > 0f)
{
Time.timeScale = 1;
anim.SetFloat("Direction", 1.0f);
anim.Play("take001");
StartCoroutine(TestCoroutine(d));
anim.Play("BoxAnimation001");
}
else if (d < 0f)
{
Time.timeScale = 1;
anim.SetFloat("Direction", -1.0f);
}
// Cursor
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if(Physics.Raycast (ray, out hit))
{
if (Input.GetMouseButtonDown(0)){
if(hit.transform.tag == "Popup_1")
{
Application.ExternalCall("OpenPopup", 0);
} 
else if(hit.transform.tag == "Popup_2")
{
Application.ExternalCall("OpenPopup", 1);
} 
else if(hit.transform.tag == "Popup_3")
{
Application.ExternalCall("OpenPopup", 2);
} 
else if(hit.transform.tag == "Popup_4")
{
Application.ExternalCall("OpenPopup", 3);
} 
}
}
}

IEnumerator TestCoroutine(float d){
yield return new WaitForSeconds(d);
Time.timeScale = 0; } }

最简单的方法是将当前动画状态规范化时间除以1,并从除法中返回余数。

public float GetCurrentAnimatorTime(Animator targetAnim, int layer = 0)
{
AnimatorStateInfo animState = targetAnim.GetCurrentAnimatorStateInfo(layer);
float currentTime = animState.normalizedTime % 1;
return currentTime;
}

这在大多数情况下都有效,但我见过它没有按预期工作的地方


执行此操作的正确方法有点复杂,因为 Unity 不允许您访问Animator使用的AnimationClip,您需要AnimationClip通过将AnimationClip.length乘以AnimationState.normalizedTime; 来检索当前时间。

为此,您必须保留对公共变量中使用的AnimationClip的引用。创建一个字典,该字典使用Animator.StringToHash作为键,并将相应的AnimationClip用作值。要获取当前AnimationClipAnimator.GetCurrentAnimatorStateInfo.fullPathHash传递给字典,它将为您提供正确的AnimationClip。您可以使用此剪辑通过将其长度乘以AnimationState.normalizedTime来获取当前时间。


您的AnimationClip参考:

public AnimationClip jumpClip;
public AnimationClip moveClip;
public AnimationClip lookClip;

获取每个动画状态的动画状态哈希:

const string animBaseLayer = "Base Layer";
int jumpAnimHash = Animator.StringToHash(animBaseLayer + ".Jump");
int moveAnimHash = Animator.StringToHash(animBaseLayer + ".Move");
int lookAnimHash = Animator.StringToHash(animBaseLayer + ".Look");

将每个动画状态哈希与其动画剪辑链接的字典:

Dictionary<int, AnimationClip> hashToClip = new Dictionary<int, AnimationClip>();

初始化Awake函数中的Dictionary

void Awake()
{
hashToClip.Add(jumpAnimHash, jumpClip);
hashToClip.Add(moveAnimHash, moveClip);
hashToClip.Add(lookAnimHash, lookClip);
}

从动画状态哈希获取AnimationClip的函数:

AnimationClip GetClipFromHash(int hash)
{
AnimationClip clip;
if (hashToClip.TryGetValue(hash, out clip))
return clip;
else
return null;
}

最后,一个获取当前动画师时间的函数:

public float GetCurrentAnimatorTime(Animator targetAnim, int layer = 0)
{
AnimatorStateInfo animState = targetAnim.GetCurrentAnimatorStateInfo(layer);
//Get the current animation hash
int currentAnimHash = animState.fullPathHash;
//Convert the animation hash to animation clip
AnimationClip clip = GetClipFromHash(currentAnimHash);
//Get the current time
float currentTime = clip.length * animState.normalizedTime;
return currentTime;
}

用法

public Animator anim;
void Update()
{
float time = GetCurrentAnimatorTime(anim, 0);
Debug.Log(time);
}

最新更新