Unity Animancer插件(二)精确控制

这篇具有很好参考价值的文章主要介绍了Unity Animancer插件(二)精确控制。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、通过名称播放动画

前面我们讲的都是直接通过动画片段的引用播放动画,Animancer也提供了直接通过动画名称来播放动画的方法。但这并不是推荐的使用方式,因为通过字符串播放比通过引用播放效率略低,且更难维护。

首先我们需要在角色身上挂载NamedAnimancerComponent组件。NamedAnimancerComponent继承于AnimancerComponent,它的内部多了一个字典,可以用来映射动画名称与动画引用的对应关系。我们可以在面板上指定一个默认动画状态,这里指定为Idle,但取消自动播放选项。
unity animator插件,# 动画系统,unity,动画,游戏引擎

接下来创建一个脚本NamedAnimations,并编写如下代码。

public class NamedAnimations : MonoBehaviour
{
	public NamedAnimancerComponent animancer;
	public AnimationClip walk;
	public AnimationClip run;
	
	public void PlayIdle()
	{
		animancer.TryPlay("Relax-Idle");
	}

	public void PlayWalk()
	{
		var state = animancer.TryPlay("Relax-Walk-Forward");

		if (state == null)
			Debug.LogWarning("'Relax-Walk-Forward' 没有被注册");
	}

	public void InitializeWalkState()
	{
		animancer.States.Create(walk);
		Debug.Log("创建状态:" + walk, this);
	}

	public void PlayRun()
	{
		animancer.Play(run);
	}
	
}

将脚本挂载到角色身上,并对变量进行赋值。然后在场景中添加四个按钮,分别绑定脚本中的四个方法
unity animator插件,# 动画系统,unity,动画,游戏引擎

接下来运行游戏。先来看PlayIdle的效果
unity animator插件,# 动画系统,unity,动画,游戏引擎

正常播放。这是因为在NamedAnimancerComponent的字典中,我们事先添加了Idle动画,从而可以映射成功。
unity animator插件,# 动画系统,unity,动画,游戏引擎

接下来再试试PlayWalk
unity animator插件,# 动画系统,unity,动画,游戏引擎

显然,Walk动画并不在字典中,所以播放失败了。要在运行时动态注册动画,只需要像脚本中的InitializeWalkState()方法一样,创建一个包含对应动画剪辑的状态即可。
unity animator插件,# 动画系统,unity,动画,游戏引擎

最后PlayRun就是直接通过动画剪辑的引用播放动画,并不需要字典中持有该动画的映射。
unity animator插件,# 动画系统,unity,动画,游戏引擎

二、控制动画的速度和时间

接下来我们来实现一个蜘蛛机器人的动画。它只有MoveWakeUp两个动画,我们要利用这两个动画实现两种状态间的无缝切换。这就需要对动画的速度和时间进行控制。
unity animator插件,# 动画系统,unity,动画,游戏引擎

首先创建一个Spider Bot脚本。对于机器人当前的状态,我们可以通过对外界暴露一个IsMoving属性来进行控制。

public class SpiderBot : MonoBehaviour
{
	private bool _isMoving;

	public bool IsMoving
	{
		get => _isMoving;
		set => _isMoving = value;
	}
}

然后在Toggle的值改变事件中绑定这个属性,就可以通过UI来控制机器人的状态了。
unity animator插件,# 动画系统,unity,动画,游戏引擎

接下来,我们要让机器人一开始就处于Sleep状态。这可以通过反向播放WakeUp动画实现。因为WakeUp动画并不是循环的,所以如果动画的Time达到0时,将会一直保持第一帧的姿势。一种简单的实现方式是直接把动画的Speed设置为-1。

public AnimancerComponent animancer;
public ClipTransition wakeUp;
public ClipTransition move;

private void Awake()
{
	var state = animancer.Play(wakeUp);
	state.Speed = -1;
}

但这种方式存在一些问题:首先,动画的Time会变成负数;其次,虽然实际上没有播放动画,但动画仍然会在每一帧进行计算,这会造成性能上的浪费。除此之外,将Speed设置为0或将IsPlaying设置为false,都无法避免类似的性能消耗。

一种更好的方式是直接暂停整个Playable Graph,这样就可以避免无意义的计算了。

private void Awake()
{
	animancer.Play(wakeUp);
	// 暂停整个图
	animancer.Playable.PauseGraph();
	// 计算第一帧
	animancer.Evaluate();
}

接下来就是在IsMoving的值改变时,进行动画的切换了。定义两个方法WakeUp()GoToSleep(),在IsMoving发生变化时调用

public bool IsMoving
{
	get => _isMoving;
	set
	{
		if (value)
			WakeUp();
		else
			GoToSleep();
	}
}

WakeUp()方法中,我们需要播放WakeUp动画,将其速度设置为1,并解除暂停Playable Graph

private void WakeUp()
{
	if(_isMoving) return;
	_isMoving = true;

	var state = animancer.Play(wakeUp);
	state.Speed = 1;
	
	animancer.Playable.UnpauseGraph();
}

WakeUp播放结束后,我们需要播放Move动画,可以通过添加结束事件实现(注意需要区分是唤醒还是睡眠)

private void Awake()
{
	// ...
	wakeUp.Events.OnEnd = OnWakeUpEnd;
}

private void OnWakeUpEnd()
{
	// 速度大于0是唤醒
	if (wakeUp.State.Speed > 0)
	{
		animancer.Play(move);
	}
	// 否则是睡眠
	else
	{
		animancer.Playable.PauseGraph();
	}
}

GoToSleep()方法中,我们需要反向播放WakeUp动画。这里需要注意,WakeUp动画在播放结束时NormalizedTime等于1,但向Move过渡时,NormalizedTime仍会继续增长并超过1。这意味着如果我们反转动画,NormalizedTime也需要花时间回到1,并在达到1时触发OnEnd事件,导致Playable Graph被暂停。此时角色会卡在一个奇怪的姿势。所以我们需要将NormalizedTime手动赋值为1。

private void GoToSleep()
{
	if(!_isMoving) return;
	_isMoving = false;

	var state = animancer.Play(wakeUp);
	state.Speed = -1;
	
	if (state.Weight == 0 || state.NormalizedTime > 1)
	{
		state.NormalizedTime = 1;
	}
}

最后来看下效果
unity animator插件,# 动画系统,unity,动画,游戏引擎

三、更新频率

为了节省性能,在某些情况下,当角色离相机较远时,我们希望降低动画的更新频率。Animancer也可以很轻松地实现这点,只需要在Evaluate()方法的参数中传入一个时间差x,就可以计算出距离上次更新x秒后动画的动作,并更新到角色身上。

首先创建一个脚本LowUpdateRate,并编写如下代码

public class LowUpdateRate : MonoBehaviour
{
	public AnimancerComponent animancer;
	// 更新速率
	public float updatesPerSecond = 10;
	// 上次更新时间
	private float _lastUpdateTime;

	private void OnEnable()
	{
		animancer.Playable.PauseGraph();
		_lastUpdateTime = Time.time;
	}

	private void OnDisable()
	{
		if (animancer != null && animancer.IsPlayableInitialized)
			animancer.Playable.UnpauseGraph();
	}

	private void Update()
	{
		var time = Time.time;
		// 计算距离上次更新的时间差
		var timeSinceLastUpdate = time - _lastUpdateTime;
		// 如果时间差超过了更新速率则更新动画
		if (timeSinceLastUpdate > 1 / updatesPerSecond)
		{
			animancer.Evaluate(timeSinceLastUpdate);
			_lastUpdateTime = time;
		}
	}
}

可以给角色挂载NamedAnimancerComponent,并指定一个默认播放动画。运行一下看看效果
unity animator插件,# 动画系统,unity,动画,游戏引擎

左侧是正常播放的机器人,右侧是低速率动画的机器人。可以看出左侧机器人的动画要更丝滑一些(受录制帧率的限制可能不明显)。

下面来实现根据摄像机距离动态启用/禁用LowUpdateRate的脚本。创建一个脚本DynamicUpdateRate,并编写如下代码

public class DynamicUpdateRate : MonoBehaviour
{
	public LowUpdateRate lowUpdateRate;
	public float slowUpdateDistance = 5;

	private Transform _camera;

	private void Awake()
	{
		_camera = Camera.main.transform;
	}

	private void Update()
	{
		// 计算相机与角色的距离
		var offset = _camera.position - transform.position;
		var squaredDistance = offset.sqrMagnitude;
		// 根据距离启用/禁用LowUpdateRate脚本
		lowUpdateRate.enabled = squaredDistance > slowUpdateDistance * slowUpdateDistance;
	}
}

将挂载LowUpdateRate的机器人复制一份,并挂载上面这个脚本。运行游戏看下效果
unity animator插件,# 动画系统,unity,动画,游戏引擎

最左侧是正播放的机器人,中间是始终低速率播放动画的机器人,最右侧是应用了动态控制动画速率的机器人。

四、独播动画

有些物体只有一个动画,且不需要任何控制播放的逻辑,那就不需要前面那样复杂的操作,我们只需要挂载一个SoloAnimation组件即可实现。
unity animator插件,# 动画系统,unity,动画,游戏引擎

如图所示,我们只需要指定一个动画片段,它就能在游戏运行时自动进行播放。
unity animator插件,# 动画系统,unity,动画,游戏引擎

五、参考资料

[1]. https://kybernetik.com.au/animancer/docs/文章来源地址https://www.toymoban.com/news/detail-549592.html

到了这里,关于Unity Animancer插件(二)精确控制的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Unity3D小技巧】Unity3D中Animation和Animator动画的播放、暂停、倒放控制

    推荐阅读 CSDN主页 GitHub开源地址 Unity3D插件分享 简书地址 我的个人博客 大家好,我是佛系工程师 ☆恬静的小魔龙☆ ,不定时更新Unity开发技巧,觉得有用记得一键三连哦。 在日常开发中,常常会遇到要控制动画的播放、暂停和倒放的情况。 这篇文章就总结一下, Animation

    2024年02月02日
    浏览(96)
  • Unity老动画系统Animation

    1、创建老动画系统 给要制作动画的GameObeject添加Animation组件 2、Animation参数 Animation:默认播放的动画 Animations:该动画组件可以控制的所有动画 Play AutoMatically:是否一开始就自动播放默认动画 Animate Physics:动画是否与物理交互 Culling Type:决定什么时候不播放动画     Alwa

    2024年02月06日
    浏览(40)
  • Unity新动画系统之动画状态机Animator Controller

    1、创建动画状态机文件 (1)会在创建动画时自动创建 (2)Create----Animator Controller 2、动画状态机窗口相关 层级:可以在右侧齿轮设置参数大小   3、添加动画 为对象添加动画后会自动添加到状态机中 4、状态切换 动画会在1和2之间不断切换  添加条件 点击转换箭头  在这

    2024年02月05日
    浏览(42)
  • Unity Animancer插件(三)运动

    Animancer的根运动系统与原生的工作原理完全相同,但我们可以通过继承 Transition 类型或实现 ITransition 接口,来将额外的数据与动画绑定,从而更方便地控制根运动。 在下面这个示例中,我们通过自定义的 Transition 类实现动画根运动的灵活控制。 首先创建一个脚本 RootMotion ,

    2024年02月10日
    浏览(33)
  • Unity Animancer插件(一)基本使用

    Animancer是什么?资源商店主页 我们来通过Animancer实现一个最基本的动画播放效果。 首先创建一个脚本 PlayAnimationOnEnable ,编写如下代码 很容易理解,就是在 OnEnable() 时播放一个指定的动画片段。 接下来为角色添加 Animator 、 Animancer Component 和刚刚编写的 PlayAnimationOnEnable ,并

    2024年02月02日
    浏览(37)
  • Unity Animation -- 导入动画

            尽管Unity中的动画工具已经比较强大了,但对于非常复杂的或很长的动画,通常是由外部DCC创建。特别是对于角色动画来说,需要在动画过程中进行复杂的控制。因此我们通常需要将外部制作的动画导入到Unity中。         对于复杂的动画,制作过程会非常耗时。动

    2024年02月12日
    浏览(51)
  • Unity Animation动画时间设置

    遇到一个需求,需要给角色添加一个翻滚动作,在翻滚同时无敌且可穿越敌人。 目前已有翻滚的动画,是使用Sprite制作的动画剪辑。如何匹配动画时间和脚色无敌时间?做到在翻滚结束时同时结束无敌与无碰撞设置。 在Animation设置窗口中,有Samples字段,可设置动画的采样帧

    2024年02月01日
    浏览(51)
  • Unity Animation -- 改进动画效果

          在上一篇笔记中(Unity Animation -- Overview_亦枫Leonlew的博客-CSDN博客),我们制作了简单的小球弹跳的动画,但这个动画看起来很不自然,小球的弹跳看起来就像是不受重力影响的物体,没有加速度的影响。要让小球的弹跳动画看起来更自然(不使用物理引擎,只使用动画

    2023年04月12日
    浏览(78)
  • Unity animator动画倒放的方法

    在Unity中, 我们有时候不仅需要 animator 正放的效果,也需要倒放的效果。但我们在实际制作动画的时候可以只制作一个正放的动画,然后通过代码控制倒放。 实现方法其实很简单,只需要把 animator 动画的 speed 设置为-1即为倒放, speed 设置为1即为正放: 比如我制作了一个从

    2024年01月23日
    浏览(45)
  • Unity 制作动画 - Animation 的使用

    1. unity 顶部导航栏点击 Window  Animation 打开 Animation 窗口 通过这个窗口可以创建、编辑动画,也可以查看导入的动画。Animation 窗口同一时间只能查看、编辑同一段Clip中的动画 2. 选中 Hierarchy 面板中的节点, 也就是要制作动画的物体,该物体上没有动画,可以点击Animation窗口

    2024年02月15日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包