1.代码
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// 播放Animator并加入播放完成回调。
[RequireComponent(typeof(Animator))]
public class AnimatorCallback : MonoBehaviour
{
private string startFunName = "StartCallBack";
private string endFunName = "EndCallBack";
private Animator mAnim;
private AnimatorOverrideController mController;
private Dictionary<string, AnimationClip> mClipDic = new Dictionary<string, AnimationClip>();
private Action endCallBack; // 动画结束回调
private Action startCallBack; // 动画开始回调
private AnimationEvent endEvt; // 结束帧
private AnimationEvent startEvt; // 结束帧
public void Awake()
{
mController = new AnimatorOverrideController();
mAnim = transform.GetComponent<Animator>();
ResetEvent();
mController.runtimeAnimatorController = mAnim.runtimeAnimatorController;
}
public void Play(string animName, Action beginAction = null, Action endAction = null)
{
startCallBack = beginAction;
endCallBack = endAction;
if (!mClipDic.ContainsKey(animName))
{
mClipDic.Add(animName, mController[animName]);
endEvt = new AnimationEvent();
endEvt.time = mClipDic[animName].length;
startEvt = new AnimationEvent();
startEvt.time = 0;
endEvt.functionName = endFunName;
startEvt.functionName = startFunName;
mClipDic[animName].AddEvent(endEvt);
mClipDic[animName].AddEvent(startEvt);
}
if (!mAnim.enabled) mAnim.enabled = true;
mAnim.Play(animName, 0, 0);
}
private void EndCallBack()
{
if (endCallBack != null)
endCallBack.Invoke();
}
private void StartCallBack()
{
if (startCallBack != null)
startCallBack.Invoke();
}
#region help
// 主要是为了防止已用的动画帧事件被移除
private void ResetEvent()
{
foreach (var clip in mAnim.runtimeAnimatorController.animationClips)
{
List<AnimationEvent> evts = new List<AnimationEvent>();
foreach (var curEvt in clip.events)
{
var newEvt = new AnimationEvent();
if (curEvt.functionName.Equals(startFunName) || curEvt.functionName.Equals(endFunName))
continue;
CloneEvent(newEvt, curEvt);
evts.Add(newEvt);
}
clip.events = null;
foreach (var evt in evts)
{
clip.AddEvent(evt);
}
evts = null;
}
}
private void CloneEvent(AnimationEvent newEvt, AnimationEvent oldEvt)
{
newEvt.functionName = oldEvt.functionName;
newEvt.floatParameter = oldEvt.floatParameter;
newEvt.intParameter = oldEvt.intParameter;
newEvt.objectReferenceParameter = oldEvt.objectReferenceParameter;
newEvt.time = oldEvt.time;
}
#endregion
}
2.使用方式
- 在需要调用事件的Animator物体上添加上面的脚本
- 调用Play方法
3.注意事项
如果你将Animator的某个AnimationClip的Speed设置为了-1(即倒播),动画的开始播放事件和结束播放事件任然是对应的开始帧和结束帧。