Animator & Timeline
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 using System.Collections; 2 using System.Collections.Generic; 3 using UnityEngine; 4 using UnityEngine.Playables; 5 6 public class Player : MonoBehaviour { 7 8 private Animator anim; 9 //private int speedID = Animator.StringToHash("Speed"); //走 10 //private int isSpeedUPID = Animator.StringToHash("isSpeedUP"); //跑 11 //private int turnAroundID = Animator.StringToHash("TurnAround"); //转向 12 13 private int speedRotateID = Animator.StringToHash("SpeedRotate"); 14 private int speedZID = Animator.StringToHash("SpeedZ"); 15 16 private int isHoldLogID = Animator.StringToHash("isHoldLog"); 17 private int slideID = Animator.StringToHash("Slide"); 18 private int vaultID = Animator.StringToHash("Vault"); 19 private Vector3 matchTarget = Vector3.zero; 20 21 private CharacterController characterController; 22 private int colliderID = Animator.StringToHash("Collider"); 23 24 public GameObject unityLog = null; //角色身上的木头 25 public Transform rightHand; //木头左右边的节点(空的gameobject) 26 public Transform leftHand; 27 public PlayableDirector playable; 28 29 // Use this for initialization 30 void Start () { 31 anim = GetComponent<Animator>(); 32 characterController = GetComponent<CharacterController>(); 33 //unityLog = transform.Find("Reference/Hips/Unity_Log (1)").gameObject; //找到Log 34 } 35 36 // Update is called once per frame 37 void Update () { 38 //2D混合树控制移动和旋转 39 anim.SetFloat(speedZID, Input.GetAxis("Vertical") * 4.1f); 40 anim.SetFloat(speedRotateID, Input.GetAxis("Horizontal") * 126f); 41 42 ProcessVault(); 43 ProcessSlide(); 44 //if(anim.GetFloat(colliderID)>0.5f) 45 //{ 46 // characterController.enabled = false; 47 //} 48 //else 49 //{ 50 // characterController.enabled = true; 51 //} 52 //上面判断语句的简写 53 //滑动或FQ时禁用角色控制器 54 characterController.enabled = anim.GetFloat(colliderID) < 0.05f; 55 56 57 //走 58 //anim.SetFloat(speedID, Input.GetAxis("Vertical")*4.1f); 59 60 ////转向 61 //anim.SetFloat(turnAroundID, Input.GetAxis("Horizontal")); 62 ////跑 63 //if(Input.GetKeyDown(KeyCode.LeftShift)) 64 //{ 65 // anim.SetBool(isSpeedUPID, true); 66 //} 67 //if (Input.GetKeyUp(KeyCode.LeftShift)) 68 //{ 69 // anim.SetBool(isSpeedUPID, false); 70 //} 71 72 73 } 74 75 //FQ 76 private void ProcessVault() 77 { 78 //FQ 79 bool isVault = false; 80 //当Animator状态机在混合树“Motion”时判断,节省性能 81 if (anim.GetFloat(speedZID) > 3 && anim.GetCurrentAnimatorStateInfo(0).IsName("Motion")) 82 { 83 RaycastHit hit; 84 if (Physics.Raycast(transform.position + Vector3.up * 0.3f, transform.forward, out hit, 4f)) 85 { 86 if (hit.collider.tag == "Obstacle") 87 { 88 if (hit.distance > 3) 89 { 90 Vector3 point = hit.point; 91 //设定匹配位置 92 point.y = hit.collider.transform.position.y + hit.collider.bounds.size.y + 0.05f; 93 matchTarget = point; 94 isVault = true; 95 } 96 97 } 98 } 99 } 100 anim.SetBool(vaultID, isVault); 101 102 //匹配跳跃过程中左手与墙面的位置 103 if (anim.GetCurrentAnimatorStateInfo(0).IsName("Vault")) 104 { 105 anim.MatchTarget(matchTarget, Quaternion.identity, AvatarTarget.LeftHand, new MatchTargetWeightMask(Vector3.one, 0), 0.32f, 0.4f); 106 } 107 108 } 109 110 //滑 111 private void ProcessSlide() 112 { 113 bool isSlide = false; 114 if (anim.GetFloat(speedZID) > 3 && anim.GetCurrentAnimatorStateInfo(0).IsName("Motion")) 115 { 116 RaycastHit hit; 117 if (Physics.Raycast(transform.position + Vector3.up * 1.5f, transform.forward, out hit, 3f)) 118 { 119 if (hit.collider.tag == "Obstacle") 120 { 121 if (hit.distance > 2) 122 { 123 Vector3 point = hit.point; 124 point.y = 0; 125 matchTarget = point + transform.forward * 2; 126 isSlide = true; 127 } 128 } 129 } 130 } 131 anim.SetBool(slideID,isSlide); 132 if (anim.GetCurrentAnimatorStateInfo(0).IsName("Slide")) 133 { 134 anim.MatchTarget(matchTarget, Quaternion.identity, AvatarTarget.Root, new MatchTargetWeightMask(new Vector3(1,0,1), 0), 0.17f, 0.67f); 135 } 136 } 137 138 //检测碰撞 139 private void OnTriggerEnter(Collider other) 140 { 141 //木头 142 if(other.tag=="Log") 143 { 144 Destroy(other.gameObject); 145 CarryWood(); 146 } 147 //镜头 148 if(other.tag=="Playable") 149 { 150 playable.Play(); 151 } 152 } 153 154 //扛木头 155 void CarryWood() 156 { 157 unityLog.SetActive(true); 158 anim.SetBool(isHoldLogID, true); 159 } 160 161 //设置左右手IK到相应节点 162 //每帧都调用 163 private void OnAnimatorIK(int layerIndex) 164 { 165 //当layer层级为HoldLog 166 if(layerIndex==1) 167 { 168 int weight = anim.GetBool(isHoldLogID) ? 1 : 0; 169 //左手 170 anim.SetIKPosition(AvatarIKGoal.LeftHand, leftHand.position); 171 anim.SetIKRotation(AvatarIKGoal.LeftHand, leftHand.rotation); 172 anim.SetIKPositionWeight(AvatarIKGoal.LeftHand, weight); //IK权重 173 anim.SetIKRotationWeight(AvatarIKGoal.LeftHand, weight); 174 175 //右手 176 anim.SetIKPosition(AvatarIKGoal.RightHand, rightHand.position); 177 anim.SetIKRotation(AvatarIKGoal.RightHand, rightHand.rotation); 178 anim.SetIKPositionWeight(AvatarIKGoal.RightHand, weight); 179 anim.SetIKRotationWeight(AvatarIKGoal.RightHand, weight); 180 } 181 } 182 }
Rig:
动画类型分为三类
1.Legacy:老版本的动画系统,一般都是单独做好的
2.Generic:骨骼动画,一般用在非人型生物上
3.Humanoid:骨骼动画,一般可通用在人形模型上面,只要骨骼节点设置相同
如果有些人物模型带有骨骼但是无法通用可选择:Create Form This Model -> Apply一下
->点击configure进行编辑确认后保存退出看下能不能用
Animation:
可进行动画的剪切与播放设置
1.Loop Pose让动画循环播放时衔接更顺滑(猜测是通过动画曲线开始与结束时的的陡峭程度进行插值运算)
2.Root Transform 下面的Bake into Pose勾选后动画播放后的位置就会被固定(有些动画播放时会有位移和转向)
3.Curves:设置曲线值,并且可以在Animator编辑器中添加相同名称的Parameters来控制触发条件
Animator状态机:
1.可以把动画拖进去设置然后通过相应的状态连接起来(点击连接箭头后如右边Inspector显示)
(1)Has Exit Time是否等当前动画播放完才跳转到下一个
(2)Conditions里可以设置Parameter里添加的各种条件参数
Blend Tree混合树:
在Animator里的BaseLayer层右键单击选择Creat State -> From New Blend Tree
如右边面板所示 (1)可选择1D/2D等混合树类型
(2)可以添加各个动画然后在图中拖动摆放各个动画并观察相互间的影响范围,也可以通过Compute Positions来按照特定条件计算摆放
AvatorMask:
通过Project中的Create -> AvatorMask创建
如图可以设置各个部位与Ik的禁用
通过新建一个Layer层设置Weight权重,Mask,Blending混合类型等可以在主动画播放时控制另一个动画也播放
如图中设置就能使第一个Layers里的动画播放时,第二个Layers动画中手部的动画状态覆盖掉第一个动画
(也就是说原本第一层动画是跑动时的动作(手会摆动),而第二层动画是原地站立举手的动作,如图中设置后就变成跑动时举手的动作了)
Timeline:
功能有点类似于视频编辑软件,主要通过Playable Director组件来控制
把相应的动画,物体,声音等直接拖入会显示创建类型,或者右键单击也可以看到有哪些类型可创建
1.可通过点击红色圆点进行动画的录制(改变position与rotation等)
2.右键单击相应轨道选择Add From Animation Clip可以生成模块,然后就能随意的拖动摆放或缩放播放内容了
点击相应的模块后可在inspector面板进行设置
1.Pre/Post - Extrapolate可以设置动画播放前/后的状态(暂时未发现这些设置对Post有何作用,因此那个“结束后”待定)
(1)None:在开始前/结束后,无,物体原始位置都会被设置为(0,0,0),动画开始的默认状态也不会有(以带有骨骼动画的人物为例,不会站立等,而是变成骨骼动画设置里的Muscle&Setting状态(苟起来)),直到播放动画为止
(2)Hold:在开始前/结束后,保持动画起始时的状态,直到播放动画为止
(3)Loop:同上,循环播放(起点 -> 终点, 起点 -> 终点。。这样一个状态),同上
(4)PingPong:同上,和循环对比的区别就是(起点 -> 终点 ->起点这一过程,不会瞬移),同上
(5)Continue:同上,在播放前会把动画播放一边然后一直等待到动画播放为止,如果动画前面部分被缩减掉一点,当放到此动画时依然会播放完整