Unity Animator
播放控制
Animator animator;
animator.speed=0;//停止播放
animator.speed=-1;//倒放
animator.Play("stateName",0,0);//播放指定状态(stateName是Animator窗口里各个状态的名称)
跳到指定帧,并停止
Animator animator;
animator.speed=0;//停止播放
AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(0);
AnimatorClipInfo clipInfo = animator.GetCurrentAnimatorClipInfo(0)[0]; // 注意:'动画剪辑' 与 '状态(stateName是Animator窗口里各个状态的名称)' 对应
//AnimatorOverrideController overrideController = new AnimatorOverrideController(animator.runtimeAnimatorController);
// 通过子符串获取AnimationClip,注意并不是Animator窗口里各个状态的名称,而是在Animator窗口中选择的状态在Inspector面板的motion属性显示的名称
//AnimationClip clip = overrideController["motionName"];
//float stateSpeed = stateInfo.speed;
float clipLength = clipInfo.clip.length;
float frameRate = clipInfo.clip.frameRate;
float normalizedTime = 5f / frameRate / clipLength; // 跳到第5帧
animator.Play("stateName", 0, normalizedTime); // 播放指定状态(stateName是Animator窗口里各个状态的名称)
/*
float totalFrames = clipInfo.clip.length * clipInfo.clip.frameRate; // 动画剪辑的总帧数
void Update(){
float currentNormalizedTime = stateInfo.normalizedTime; // 播放头的所在的单位化时间位置
float currentTime = stateInfo.normalizedTime * clipInfo.clip.length; // 播放头的所在的时间位置
float currentFrameNO = stateInfo.normalizedTime * totalFrames; // 播放头所在的帧
Debug.Log($"currentNormalizedTime:{currentNormalizedTime}, currentTime:{currentTime}, currentFrameNO:{currentFrameNO}");
}
*/
动画播放到指定时间做某事
方法1: 在动画剪辑指定的时间里,添加事件函数
注意:
- 函数所在的脚本和Animator 组件必须绑定到同一个GameObject
- 在Animator里如果两个动画存在过渡,请注意动画的过渡时间,如果某个时间处于过渡时间内将不会收到事件,根据下图的调整 attack 动画才能收到播放完成事件,使用代码添加事件时请不要添加到时间的最末尾,否则在不同设备上依旧会出现末尾时间处的事件不触发的问题。
using UnityEngine;
using System.Collections;
public class TestAnimationEvent : MonoBehaviour {
private void Awake () {
Animator animator = GetComponent<Animator>();//Animator组件和此脚本必须绑定到同一个GameObject
AnimatorOverrideController overrideController = new AnimatorOverrideController(animator.runtimeAnimatorController);
//通过子符串获取AnimationClip,注意并不是Animator窗口里各个状态的名称,而是在Animator窗口中选择的状态在Inspector面板的motion属性显示的名称
AnimationClip clip = overrideController["CINEMA_4D___"];
//在动画指定的时间,添加事件
AnimationEvent onCompleteEvent = new AnimationEvent();
onCompleteEvent.objectReferenceParameter = this;
onCompleteEvent.functionName = nameof(OnAnimationClipComplete);
onCompleteEvent.time = clip.length;//clip.length动画长度,单位为秒。这里表示在结束时添加事件
clip.AddEvent(onCompleteEvent);
}
//注意:参数类型是UnityEngine.Object不是object
private void OnAnimationClipComplete (UnityEngine.Object objectReference) {
//注意:当内存中拥有多个当前类的实例时,将会调用多次此函数,使用objectReferenceParameter属性传递this区分
if (objectReference != this) return;
Debug.Log("onShakeAnimComplete;");
}
}
方法2: 通过AnimatorStateInfo.normalizedTime判断播放到的时间
using UnityEngine;
using System.Collections;
public class Test : MonoBehaviour {
public Animator animator;
private void Awake () {
animator.Play("attack");
InvokeRepeating(nameof(CheckStateComplete), 0.02f, 0.02f);
}
private void CheckStateComplete () {
AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(0);
if (stateInfo.IsName("attack")) {
//normalizedTime:表示动画的标准化时间,区间:[0,1]
if (stateInfo.normalizedTime >= 1.0f) {
OnStateComplete();
CancelInvoke(nameof(CheckStateComplete));
}
}
}
private void OnStateComplete () {
Debug.Log("OnStateComplete");
}
private void OnDestroy () {
CancelInvoke("checkStateComplete");
}
}