Animancer Event
Table of Contents
请尊重原作者的工作,转载时请务必注明转载自:www.xionggf.com
结束事件(End Events) 在Animancer Lite中可用,但是除非您购买Animancer Pro,否则在运行时版本中将无法使用设置自定义结束时间"(custom end time) 和使用其他事件的功能。有关更多信息,请参见功能比较。
Animancer包含一个自定义事件系统,该系统与Unity自带的Animation Events有所不同。使用animation clip transitions机制,或者使用代码时,可以在inspector面板中配置事件。请注意,常规事件和结束事件之间有一些区别。
Events in Transitions
可以在inspector面板中,在transition条上,设置事件激活
- 通过过渡预览窗口(Transition Preview Window) 可以看到事件在什么时间发生。
- 过渡定义了淡入的方式,而不是淡出的方式(因为它由下一个过渡确定),因此Inspector时间轴显示仅使用默认值。如果结束时间小于动画长度,则会显示淡出在动画结束时结束。或者,如果结束时间大于长度,则会显示默认的0.25秒淡入。
- 无论使用哪个字段输入值,“事件时间”字段始终会序列化为(normalized time)单位化时间。
- 每个使用过渡机制播放特定动画的脚本,都将具有该动画自己的事件序列(event sequence),但是您也可以使用过渡资产(transition asset),过渡资产共享相同的事件,可以复用。
Controls
- 可以一次选择并编辑一个事件,也可以单击时间轴旁边的折叠箭头,以一次显示所有事件
- 在时间轴中双击以添加一个事件。
- 选择事件后:
- 左箭头和右箭头将事件时间向侧面微移一个像素。
- 按住Shift键一次可移动10个像素。
- 空格将事件时间舍入一位数字。例如:
0.123
将成为0.12
并且0.999将成为1。
Events in Code
Animancer Events也可以使用如下代码进行配置:
// MeleeAttack.cs:
[SerializeField] private AnimancerComponent _Animancer;
[SerializeField] private AnimationClip _Animation;
public void Attack()
{
// Play clears all events from all states (see Auto Clear below for details).
var state = _Animancer.Play(_Animation);
// Call OnHitStart to activate the hit box when the animation passes 40% of its length.
state.Events.Add(0.4f, OnHitStart);
// Call OnHitEnd to deactivate the hit box when the animation passes 60% of its length.
state.Events.Add(0.6f, OnHitEnd);
// Return to Idle when the animation finishes.
state.Events.OnEnd = EnterIdleState;
}
您可以使用Lambda表达式和匿名方法来定义要运行事件的代码,而无需创建另一个单独的方法:
void PlayAnimation(AnimancerComponent animancer, AnimationClip clip)
{
var state = animancer.Play(clip);
// All of the following options are functionally identical:
// Lambda expression:
state.Events.OnEnd = () =>
{
Debug.Log(clip.name + " ended");
};
// One-line Lambda expression:
state.Events.OnEnd = () => Debug.Log(clip.name + " ended");
// Anonymous method:
state.Events.OnEnd = delegate()
{
Debug.Log(clip.name + " ended");
};
}
AnimancerEvent.CurrentEvent
并AnimancerEvent.CurrentState
允许您访问当前正在触发的事件及其触发状态:
[SerializeField] private AnimancerComponent _Animancer;
[SerializeField] private AnimationClip _Animation;
private void Awake()
{
var state = _Animancer.Play(_Animation);
state.Events.OnEnd = OnEnd;
}
public void OnEnd()
{
Debug.Log(AnimancerEvent.CurrentState + " ended due to " + AnimancerEvent.CurrentEvent);
}
Shared Event Sequences
播放一个特定过渡( particular Transition )的每个物体,都将共享相同的事件序列,这意味着一个物体对其进行的任何修改,也会影响其他物体。当使用由“过渡资产(transition asset)”机制提供的,在多个对象之间共享相同的过渡时,但仍需要为它们提供特定于每个物体的事件时,通常会发生这种情况。最简单的解决方法是在启动时仅Instantiate复制过渡资产:
[SerializeField] private ClipTransition _Animation;
private void Awake()
{
_Animation = Instantiate(_Animation);
// Now you can modify the _Animation.Transition.Events as necessary.
}
这为每个对象提供了过渡的单独副本,因此它们不再共享相同的事件序列,而是浪费了额外的处理时间和内存,因为所有其他过渡数据也被复制了。一个更有效的解决方案是为每个对象制作事件序列的自己的副本:
[SerializeField] private AnimancerComponent _Animancer;
[SerializeField] private ClipTransition _Animation;
private AnimancerEvent.Sequence _Events;
private void Awake()
{
// Initialise your events by copying the sequence from the transition.
// 只复制事件,不复制事件
_Events = new AnimancerEvent.Sequence(_Animation.Transition.Events);
// Now you can modify the _Events as necessary.
}
private void PlayAnimation()
{
// Then when you play it, you just replace the transition events with your own:
var state = _Animancer.Play(_Animation);
state.Events = _Events;
}
Hybrid Events
在动画剪辑的过渡条中,根据动画的实际表现去选某一个时刻去设置事件,通常是根据动画配置其时间的最佳方法,但是在代码中设置事件,通常更有助于创建可靠的脚本,并避免错误。幸运的是,您可以通过使用Transition来配置,然后把callback项留为空白,并改为在代码中指定,如下图及下代码所示。
[SerializeField] private ClipState.Transition _GolfSwing;
private void Awake()
{
// Set the event named "Hit" to call the HitBall method when it is triggered.
_GolfSwing.Events.SetCallback("Hit", HitBall);
}
private void HitBall() { ... }