Unity的新动画系统(animator)在脚本中的操控
前言
今天在做人物攻击的部分时遇到一个问题,因为攻击动画是东平西凑的素材,所以每个clip的时长并不符合我项目中
的实际武器攻击时长,对每一个clip做帧的删除和添加又太过麻烦,我希望能够通过我期望的攻击间隔(攻击动画播放
时间)和当前的动画时间计算一个动画播放速度来动态的修改animator中state的speed,原本以为很简单的操作却扯
出一片我以前都不知道的动画脚本操作。
探索
Animator为我们提供的与state和clip有关的操作少的可怜,你只能通过GetCurrentStateInfo和GetCurrentClipInfo获取当前正在播放的动画和所处状态,而且返回值均为Info,也就是只读信息不能进行修改,换句话说unity压根就没想让你通过Animator这个类进行动态的state和clip修改参数。
但是只利用这些也是可以实现我上述问题的,虽然有点牵强,代码如下
animator.SetTrigger("Attack");
float speed = animator.GetCurrentAnimatorStateInfo(0).length / attackDuration;
animator.speed = speed;
如果你的状态转换中有Exit Time的话就要换成GetNextAnimatorStateInfo因为在ExitTime过渡状态时还是算做上一个状态的,这里直接修改了整个animator的speed,动画结束后记得改回1即可。
这就是我们能用animator做的所有事情了,要想对动画操纵更多你需要引入一个新的命名空间UnityEditor.Animations,我们需要编辑器层面的操作才能实现对state和clip的修改,其实原因也很简单,这里有一个容易忽视的地方那就是state不是属于我们挂载在物体上的Animator组件的,state能持久保存说明它是一个persistent asset,你不可能通过Animator(MonoBehaviour)来对它进行修改因为MonoBehaviour是游戏运行时才存在的,所有对Asset的操作基本都需要UnityEditor这一命名空间。那很容易想到它是属于这个东西的
它对应的类叫做AnimatorController,实际上我们的代码在正常逻辑中几乎不会用到它,但我们经常会用到它的基类RuntimeAnimatiorController,每个Animator组件都包含一个RuntimeAnimatorController的成员,可以用它实现运行时替换AnimatorController。
public sealed class AnimatorController : RuntimeAnimatorController
这同时就带来一个问题,如果你通过变量直接加载对应的Animator Controller Asset然后进行修改当然没有问题,所有以它作为RuntimeAnimatorController的Animator都会同时被修改。
但如果你想通过Animator去访问该Animator正在引用的AnimatorController,Animator只包含RuntimeAnimatorController成员,你需要将RuntimeAnimatorController强制转换为AnimatorController(父转子),这个转换不是安全的,正常情况下是没问题的无论你是直接在Inspector窗口为Animator的RuntimeAnimatorController赋值还是用代码运行时赋值,因为你的赋值都是一个AnimatorController所以这个转换可以完成
但我有个手残的操作在这里作为一个提醒,我们一般替换RuntimeAnimatorController都会使用OverrideAnimatorController,在替换时你可以有以下两种方式
animator.runtimeAnimatorController = overrideAnimator;
animator.runtimeAnimatorController = overrideAnimator.runtimeAnimatorController;
因为OverrideAnimatorController也是继承自RuntimeAnimatorController,所以第一种可以直接完成隐式转换,单就效果来说也是完全相同的。但也就是说它和AnimatorController是兄弟关系,在这种情况下你如果再尝试把runtimeAnimatorController转换为AnimatorController的话就会报错因为它其中的值实际上是一个OverrideAnimatorController。
public class AnimatorOverrideController : RuntimeAnimatorController
从这个问题我们也可以看出来,OverrideAnimatorController保留了父类RuntimeAnimatorController的clips等信息,但它实际上完全没有存储独立的State等信息而是保留了一个runtimeAnimatorController的成员(实际上其中存储的是AnimatorController对象也就是它Override的那个Controller),所以以后还是注意一下使用第二种比较好
修正
之前说错了,如果使用第二种的话改了等于没改(没有用到override的部分),已经说过RuntimeAnimatorController是AnimatorController和OverrideAnimatorController的基类,并且OverrideAnimatorController中的runtimeAnimatorControlle本质上是它所override的那个AnimatorController,所以如果直接使用第二种的话就相当于没有把Override的信息交给Animator组件(Override的部分在OverrideAnimatorController里面)只是应用了没override前的那个AnimatorController
至于具体如何使用的话我决定还是把动画名统一了(即没有使用上面说的一堆东西),因为如果要像最初设想的一样通过AnimatorController获取state,然后根据state获取clip就行不通了,overridecontroller无法提供state获取方法(GetAnimationState),如果使用runtime即覆盖前的controller的话获取到的state中的clip名字还是未override的,除非再通过未override版本去使用overridecontroller中提供的GetOverrides查找替换后的clip名字,但那样也就太麻烦了
解决方案
现在最初要解决的问题就已经可以完美解决了,我使用了ExtensionMethod方便操作,代码如下
public static class ExtensionAnimator
{public static AnimatorState GetAnimatorState(this AnimatorController ac, int layer, string statename){AnimatorControllerLayer acl = ac.layers[layer];foreach (var state in acl.stateMachine.states){if(state.state.name == statename) return state.state;}return null;}public static AnimationClip GetAnimationClip(this Animator animator, string name){foreach (var clip in animator.runtimeAnimatorController.animationClips){if(clip.name == name) return clip;}return null;}
}
如果你没有使用overrideAnimatorController的话可以使用下面这个版本
void Attack()
{/*animator.SetTrigger("Attack");float speed = animator.GetCurrentAnimatorStateInfo(0).length / attackDuration;animator.speed = speed;*/AnimatorController ac = (AnimatorController)animator.runtimeAnimatorController;AnimatorState state = ac.GetAnimatorState(0, "Attack");AnimationClip clip = animator.GetAnimationClip(state.motion.name);state.speed = clip.length / attackDuration;animator.SetTrigger("Attack");
}
我最后使用的是统一动画名字为Attack
void Attack()
{/*animator.SetTrigger("Attack");float speed = animator.GetCurrentAnimatorStateInfo(0).length / attackDuration;animator.speed = speed;*/inAttack = true;AnimatorController ac = animator.runtimeAnimatorController as AnimatorController;if(!ac) ac = (animator.runtimeAnimatorController as AnimatorOverrideController).runtimeAnimatorController as AnimatorController;AnimatorState state = ac.GetAnimatorState(0, "Attack");AnimationClip clip = animator.GetAnimationClip("Attack");state.speed = clip.length / combat.attackDuration;animator.SetTrigger("Attack");
}
Unity的新动画系统(animator)在脚本中的操控相关推荐
- Unity用户手册-动画系统Animator
动画系统Animator 动画类型 Legacy 基础的动画 Generic 动画,包含动画状态机 Humanoid 人形动画,包含动画状态机 Update Mode Normal 动画播放将与Upd ...
- unity新动画系统之动画层和动画遮罩
这一节来说说unity动画层layer和遮罩avatarMask: weight 权重,对应着这一层动画在所有层动画中所占的比例.以上图来说明,new layer中的weight为0,模型的动画效果就 ...
- 解决unity内置动画系统播放完回到原点问题
今天在逛论坛的时候,无意中解决了一个困扰我巨久巨久的问题(差不多几个月咯,烦死人...)那就是在用unity自带的动画系统建立动画之后,你会发现,当你勾选Apply Root Motion的时候,动画 ...
- 【Unity】让动画系统支持相对坐标
假如你有一个很简单的动画,并且需要应用到许多物体上 但如果你挂载同一个动画到两个物体上,就会这样: 解决方案 (仅测试过 legacy 动画) 挂载此脚本到物体上: using System.Coll ...
- Unity——在运行时修改Animator Controller状态机中的动画片段
在开发中,经常会有在运行时根据对象的不同状态来修改播放动画的需求.比如做一个射击游戏,那么持手枪时.攻击使用的动画片段明显是不能与持匕首时相同的. 原先用Legacy Animation时,是可以很方 ...
- Unity-BattleStar丨6. 动画系统-让BattleStar游戏中的角色动起来
文件下载:地址 项目目标:实现NPC防御和踢腿动作 一.导入模型 1.新建一个空项目,导入Cha07.unitypackage,打开Scenes里的BattleStar_GuideScene并进入,点 ...
- Unity使用新输入系统InputSystem制作飞机大战Demo(对象池设计模式及应用)
@作者 : SYFStrive @博客首页 : HomePage
- Unity使用新输入系统InputSystem制作飞机大战Demo
@作者 : SYFStrive @博客首页 : HomePage
- Unity使用新输入系统InputSystem制作飞机大战Demo(实现能量技能)
@作者 : SYFStrive @博客首页 : HomePage
最新文章
- 重磅!2021泰晤士世界大学排名公布,清华排名首次挺进top20
- python文字教程-Python 爬虫零基础教程(3):输出一个网页上的文字
- Android中利用隐式意图发送短信
- Setup Factory打包时实现第三方DLL文件的注册
- html背景图片尺寸位置百分比,css – 如何计算背景大小百分比?
- 工作3年,可视化毫无进步?小白都能看懂的干货,我真不想告诉你
- php 模拟表单提交-get-post
- linux 使cpu使用率升高_linux性能优化
- 启动计算机需要配置,Win10 office2007每次启动都要配置的解决方案
- STLink连接与资源下载
- php中百度编辑器的使用
- 传统IT架构下面临的挑战?
- 网易游戏互娱 笔试题2021.8.7 Java版
- 僵尸进程(Zombie process )
- IT运维的相关需求分析报告(第一篇)
- 进入html+css世界的正确姿势
- 微博舆情 之 热点话题分析
- 鸭脚木开花 蜜蜂大搬家
- 数字电路实验(01)基本逻辑运算及其电路实现
- 电子工程师比掌握的知识
热门文章
- linux 程序切换wifi,linux wpa_supplicant连接无线网络(转)
- 腾讯云王帅:你喜欢可乐,怎么能给你推荐雪碧呢?
- C# unity网络游戏实战泡泡堂(服务端+客户端整套源码)
- 解决MDict3在PPC下乱码的问题
- 强化学习技巧四:模型训练速度过慢、GPU利用率较低,CPU利用率很低问题总结与分析。
- 分享一款好用的图表制作软件,简单、美观又高效!
- 期货限仓包含套保(期货品种限仓)
- mac下搭建码云gitee+hexo博客
- 常见车规级芯片汇总 ---高通820A、高通8155P、高通8195 和 特斯拉HW3.0芯片
- 风吹雨名片互赞系统PHP程序