Unity3D学习笔记(十六):Animator新动画
新动画系统:
给模型选择动画类型
普通动画:Generic
人形动画:Humanoid
建立动画控制器 - 在Project右击 - 选择Create-AnimatorContorller
将对应动画控制器拖入到Animator的Contorller
双击动画控制器可以打开Animator窗口
将对应动画片段拖入生成新节点,就可以编辑了
橙色节点:相当于旧动画系统的默认片段
灰色节点:
Any State:代表所有动画状态
设置默认片段
建立基础连线
箭头代表两个动画的过渡
Transition Duration:代表融合
任何状态都可以连线到death,甚至包括自己到自己
取消death过渡到自己的选择
动画鬼畜问题,自己过渡到自己
建立过渡条件
添加参数,有4种
通过代码激活参数,实现动画切换
默认过渡条件:Has Exit Time,播放完当前动画才会进行到下一动画的过渡
有条件,取消勾选
无条件,默认勾选,跳跃,浮空
给游戏物体添加脚本,控制参数的激活
代码不能越权:越过动画状态机设置的逻辑(动画连线)的权限
using System.Collections; using System.Collections.Generic; using UnityEngine; public class HellephantAnimator : MonoBehaviour { public Animator anim; // Use this for initialization void Start () { } // Update is called once per frame void Update () { if (Input.GetKeyDown(KeyCode.Alpha1)) { anim.SetBool("isMove", true); } if (Input.GetKeyDown(KeyCode.Alpha2)) { anim.SetBool("isMove", false); } if (Input.GetKeyDown(KeyCode.Alpha3)) { anim.SetTrigger("Death"); } } }
用一个怪物管理器,管理两个怪物的父类
两种方法:
1、管理两个怪物的父类
2、把方法写成接口
父类:全部写成虚函数
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.AI; public enum EnemySta { Move, Idle, Death } public class NewMonsterBase : MonoBehaviour { public PlayerControl moveTarget;//设置目标点 public MonsterManager manager;//怪物属于那个管理器 public virtual void Action() { } public virtual void Move() { } public virtual void Idle() { } public virtual void Damage() { } public virtual void Death() { } public virtual void DeathEvent() { } }
这两个需要初始化,要放在父类里
public PlayerControl moveTarget;//设置目标点 public MonsterManager manager;//怪物属于那个管理器
子类:继承父类,并重写父类方法
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.AI; public class HellephantControl : NewMonsterBase { public Animator anim; public EnemySta enemySta; //因为我们需要经常用到目标的状态,所以把TransForm改成了PlayerControl public NavMeshAgent navMeshAgent;//引用寻路系统 private int enemyHealth = 30;//设置怪物生命值 // Use this for initialization void Start()//子类添加新动画系统 { enemySta = EnemySta.Move; anim.SetBool("isMove", true); } // Update is called once per frame void Update() { Action(); } public override void Action() { switch (enemySta) { case EnemySta.Move: Move(); break; case EnemySta.Idle: Idle(); break; case EnemySta.Death: Death(); break; } } public override void Move() { //anim.CrossFade("Move", 0.2f); navMeshAgent.SetDestination(moveTarget.transform.position); //如果怪物的目标死了 if (moveTarget.playSta == PlaySta.Death) { //寻路停止 navMeshAgent.isStopped = true; //状态切换到闲置 enemySta = EnemySta.Idle; anim.SetBool("isMove", false); } } public override void Idle() { //anim.CrossFade("Idle", 0.2f); } public override void Damage() { //受伤减血 enemyHealth -= 10; //Debug.Log("怪物生命"+enemyHealth); //如果血到了0 if (enemyHealth <= 0) { //状态变成死亡状态 enemySta = EnemySta.Death; anim.SetTrigger("Death"); navMeshAgent.isStopped = true; gameObject.GetComponent<SphereCollider>().enabled = false; //gameObject.tag = "Untagged"; } } public override void Death()//子类关闭老动画系统 { //anim.CrossFade("Death", 0.2f); } public override void DeathEvent() { //在管理器列表中移除自己 manager.monsterList.Remove(this); //销毁自己 Destroy(this.gameObject); } }
怪物管理器的怪物列表全部改成父类
怪物管理器的怪物生成
怪物预制体改成数组
using System.Collections; using System.Collections.Generic; using UnityEngine; public class MounsterManager : MonoBehaviour { List<Transform> birthPoint; public GameObject[] monsterPreGo; //最大怪物数 public int MaxMonsterCount; public List<NewMonsterBase> monsterList; public NewPlayer player; // Use this for initialization void Start () { birthPoint = new List<Transform>(); monsterList = new List<NewMonsterBase>(); //遍历所有的子物体,将其加到出生点列表中 for (int i = 0; i < transform.childCount; i++) { birthPoint.Add(transform.GetChild(i)); } } void CreateMonster() { monsterCont++; GameObject go; if (monsterCont%5==0) { go = Instantiate<GameObject>(monsterPreGo[1]); } else { //实例化一个怪物 go = Instantiate<GameObject>(monsterPreGo[0]); } //怪物的位置设置任意出生点 go.transform.position = birthPoint[Random.Range(0, birthPoint.Count)].position; //取得怪物脚本 NewMonsterBase monster = go.GetComponent<NewMonsterBase>(); //把怪物放到管理器列表里 monsterList.Add(monster); //指定怪物的目标 monster.moveTarget = player; //指定怪物的管理者 monster.manager = this; } int monsterCont = 0; void CheckMonster() { if (monsterList.Count < MaxMonsterCount) { CreateMonster(); } } // Update is called once per frame void Update () { } private void FixedUpdate() { CheckMonster(); } }
怪物动画添加死亡检测事件
骨骼动画锁定:只允许动画控制器修改
在动画状态机的设置里,取消骨骼动画锁定
怪物添加碰撞体
新动画系统的新功能
融合树功能:一个和多个参数,来决定播放哪个动画
更改动画类型
动画和模型分开
拖拽模型生成预制体
添加动画控制器
任意窗口最大化:shift+空格
中键拖动,滚轮缩放
动画本身带有位移动画,根据实际情况决定
好处:过渡自然
坏处:代码不可控,代码强拉,会显得不自然
勾选动画自带的位移动画
建立三个动画的融合树
添加参数,保存键值,保证参数正确传递
右键新建 融合树
双击融合树,打开融合树窗口,右键可以再添加融合树
添加motion
第一列:默认融合区间0到1 ,三个动画过渡0,0.5,1
第二列:动画速度
默认融合区间均等分开,取消勾选,可自行修改
旧动画系统修改动画片段的速度
添加脚本
using System.Collections; using System.Collections.Generic; using UnityEngine; public class DefaultAvatarAnimator : MonoBehaviour { public Animator anim; public int speedHashID; public int angleHashID; public int attackHashID; private float slowSpeed;//速度修正 // Use this for initialization void Start () { speedHashID = Animator.StringToHash("Speed");//哈希Code,效能略高,不用每次调用都转换 angleHashID = Animator.StringToHash("Angle"); attackHashID = Animator.StringToHash("Attack"); } // Update is called once per frame void Update () { if (Input.GetKey(KeyCode.LeftShift)) { slowSpeed = 0.5F; } else { slowSpeed = 1.0F; } anim.SetFloat(speedHashID, Mathf.Clamp01(Input.GetAxis("Vertical")) * slowSpeed);//Mathf.Clamp01,剔除向后走的值 anim.SetFloat(angleHashID, Input.GetAxis("Horizontal") * slowSpeed); if (Input.GetMouseButtonDown(0)) { anim.SetTrigger(attackHashID); } } }
给Walk和Run添加融合树
层级关系
两个动画融合,要和动画师沟通,融合动作容易变形,最后让动画师手动新建动画
边跑动,边射箭
添加Attack层,添加射箭节点,添加Attack参数
点击齿轮,修改层级权重为1
Blending融合模式
Override,两个动作折中,一般选则
Aaditive,两个动作叠加
添加Avatar Mask,阿凡达遮罩
如果动画类型是人形动画:Humanoid,可选择Humanoid的Mask
分配骨骼权重:点击区域激活失活
动画模型来自同一骨骼(同一Avatar)
添加代码