前言

  今天在做人物攻击的部分时遇到一个问题,因为攻击动画是东平西凑的素材,所以每个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)在脚本中的操控相关推荐

  1. Unity用户手册-动画系统Animator

    动画系统Animator 动画类型 Legacy 基础的动画 Generic 动画,包含动画状态机 Humanoid 人形动画,包含动画状态机 Update Mode Normal 动画播放将与Upd ...

  2. unity新动画系统之动画层和动画遮罩

    这一节来说说unity动画层layer和遮罩avatarMask: weight 权重,对应着这一层动画在所有层动画中所占的比例.以上图来说明,new layer中的weight为0,模型的动画效果就 ...

  3. 解决unity内置动画系统播放完回到原点问题

    今天在逛论坛的时候,无意中解决了一个困扰我巨久巨久的问题(差不多几个月咯,烦死人...)那就是在用unity自带的动画系统建立动画之后,你会发现,当你勾选Apply Root Motion的时候,动画 ...

  4. 【Unity】让动画系统支持相对坐标

    假如你有一个很简单的动画,并且需要应用到许多物体上 但如果你挂载同一个动画到两个物体上,就会这样: 解决方案 (仅测试过 legacy 动画) 挂载此脚本到物体上: using System.Coll ...

  5. Unity——在运行时修改Animator Controller状态机中的动画片段

    在开发中,经常会有在运行时根据对象的不同状态来修改播放动画的需求.比如做一个射击游戏,那么持手枪时.攻击使用的动画片段明显是不能与持匕首时相同的. 原先用Legacy Animation时,是可以很方 ...

  6. Unity-BattleStar丨6. 动画系统-让BattleStar游戏中的角色动起来

    文件下载:地址 项目目标:实现NPC防御和踢腿动作 一.导入模型 1.新建一个空项目,导入Cha07.unitypackage,打开Scenes里的BattleStar_GuideScene并进入,点 ...

  7. Unity使用新输入系统InputSystem制作飞机大战Demo(对象池设计模式及应用)

    @作者 : SYFStrive @博客首页 : HomePage

  8. Unity使用新输入系统InputSystem制作飞机大战Demo

    @作者 : SYFStrive @博客首页 : HomePage

  9. Unity使用新输入系统InputSystem制作飞机大战Demo(实现能量技能)

    @作者 : SYFStrive @博客首页 : HomePage

最新文章

  1. 重磅!2021泰晤士世界大学排名公布,清华排名首次挺进top20
  2. python文字教程-Python 爬虫零基础教程(3):输出一个网页上的文字
  3. Android中利用隐式意图发送短信
  4. Setup Factory打包时实现第三方DLL文件的注册
  5. html背景图片尺寸位置百分比,css – 如何计算背景大小百分比?
  6. 工作3年,可视化毫无进步?小白都能看懂的干货,我真不想告诉你
  7. php 模拟表单提交-get-post
  8. linux 使cpu使用率升高_linux性能优化
  9. 启动计算机需要配置,Win10 office2007每次启动都要配置的解决方案
  10. STLink连接与资源下载
  11. php中百度编辑器的使用
  12. 传统IT架构下面临的挑战?
  13. 网易游戏互娱 笔试题2021.8.7 Java版
  14. 僵尸进程(Zombie process )
  15. IT运维的相关需求分析报告(第一篇)
  16. 进入html+css世界的正确姿势
  17. 微博舆情 之 热点话题分析
  18. 鸭脚木开花 蜜蜂大搬家
  19. 数字电路实验(01)基本逻辑运算及其电路实现
  20. 电子工程师比掌握的知识

热门文章

  1. linux 程序切换wifi,linux wpa_supplicant连接无线网络(转)
  2. 腾讯云王帅:你喜欢可乐,怎么能给你推荐雪碧呢?
  3. C# unity网络游戏实战泡泡堂(服务端+客户端整套源码)
  4. 解决MDict3在PPC下乱码的问题
  5. 强化学习技巧四:模型训练速度过慢、GPU利用率较低,CPU利用率很低问题总结与分析。
  6. 分享一款好用的图表制作软件,简单、美观又高效!
  7. 期货限仓包含套保(期货品种限仓)
  8. mac下搭建码云gitee+hexo博客
  9. 常见车规级芯片汇总 ---高通820A、高通8155P、高通8195 和 特斯拉HW3.0芯片
  10. 风吹雨名片互赞系统PHP程序