动画之人物移动旋转
一、动画状态机控制
1、导入人物动画,调整为人形动画,做好前期准备工作(修改动画是否循环,动画范围,动画旋转锁定,Y轴,XZ轴锁定等)
2、添加Animator组件,创建动画状态机
3、打开动画状态机,把人物待机、走路、跑步、向左跑、向右跑的动画添加到状态机中。
4、添加参数Speed、ISRun、TurnRun/移动速度、是否跑步、转向速度
二、混合树Blend Tree
1、1D混合树控制一个方向运动
在Animator面板下创建BlendTree,双击BlendTree进入编辑界面
2、2D混合树通过两个变量控制,一个使用速度控制PosY,另一个是用角度控制PosX
三、功能代码
1.相机跟随移动
1 public Transform playerTran;//目标人物 2 Vector3 offset; 3 float smoothing=2; 4 private void Start() 5 { 6 offset = transform.position - playerTran.position;//相机位置与人的位置差 7 } 8 private void Update() 9 { 10 Vector3 targetPosition = playerTran.position + playerTran.TransformDirection(offset); 11 transform.position = Vector3.Lerp(transform.position, targetPosition, Time.deltaTime * smoothing); 12 transform.LookAt(playerTran.position); 13 }
public class PlayerAnimationController : MonoBehaviour { public Animator playerAni; int speedID = Animator.StringToHash("Speed"); int IsRunID = Animator.StringToHash("IsRun"); int turnRun = Animator.StringToHash("TurnRun"); void Update() { playerAni.SetFloat(speedID, Input.GetAxis("Vertical"));//控制移动 playerAni.SetFloat(turnRun, Input.GetAxis("Horizontal"));//控制转向 if (Input.GetKeyDown(KeyCode.LeftShift))//控制是否加速 { playerAni.SetBool(IsRunID, true); } else if (Input.GetKeyUp(KeyCode.LeftShift)) { playerAni.SetBool(IsRunID, false); } } }
四、控制人物FQ
1、将修改完的FQ动画添加到状态机中,新添加变量SpeedX、SpeedY、IsOverTheWall
2、添加功能
int speedX = Animator.StringToHash("SpeedX");//转向的速度
int speedY = Animator.StringToHash("SpeedY");//前进的速度
int IsOverTheWall = Animator.StringToHash("IsOverTheWall");//FQ bool isOverTheWall = false;//是否FQ private Vector3 margetPosition=Vector3.zero;//FQ匹配的位置 //FQ void PlayerVault() { isOverTheWall = false; playerAni.SetFloat(speedX, Input.GetAxis("Horizontal") * 126); playerAni.SetFloat(speedY, Input.GetAxis("Vertical") * 3.6f); if (playerAni.GetFloat(speedY) > 2 && playerAni.GetCurrentAnimatorStateInfo(0).IsName("Locomotion")) { RaycastHit hit; if (Physics.Raycast(transform.position + Vector3.up * 0.3f, transform.forward, out hit, 4)) { if (hit.collider.tag == "Obstacle") { if (hit.distance > 3) { Vector3 point = hit.point; point.y = hit.collider.transform.position.y + hit.collider.bounds.size.y + 0.1f; margetPosition = point;//目标位置 isOverTheWall = true; } } } } playerAni.SetBool(IsOverTheWall, isOverTheWall); if (playerAni.GetCurrentAnimatorStateInfo(0).IsName("Vault") && playerAni.IsInTransition(0) == false) { //指定了匹配的位置、角度、身体的具体部位、权重、匹配开始时间和结束时间 playerAni.MatchTarget(margetPosition, Quaternion.identity, AvatarTarget.LeftHand, new MatchTargetWeightMask(Vector3.one, 0), 0.32f, 0.4f); } }
3、给人物添加CharacterController,在动画状态机中新添加变量Collider来控制播放FQ动画是角色控制器与墙不发生碰撞
4、设置FQ动画下Curves,先确定两帧(开始FQ和结束FQ),编辑两个点大于0.5,并把设置的Collider变量放置在Curves上
5、效果展示
五、控制人物滑动
1、将修改完的滑动动画添加到状态机中,新添加变量Slider控制是否滑动
2、动画状态机连接情况如图
3、添加功能代码
int slider = Animator.StringToHash("Slider");//滑动 int playcollider = Animator.StringToHash("Collider"); void Update() { PlayerSlider(); PlayerVault(); playerCharacterController.enabled = playerAni.GetFloat(playcollider) < 0.45f; } //滑动 void PlayerSlider() { bool IsSlider = false; if (playerAni.GetFloat(speedY) > 2 && playerAni.GetCurrentAnimatorStateInfo(0).IsName("Locomotion")) { RaycastHit hit; if (Physics.Raycast(transform.position + Vector3.up * 1.5f, transform.forward, out hit, 3)) { if (hit.collider.tag == "Obstacle") { if (hit.distance > 2) { Vector3 point = hit.point; point.y = -10; margetPosition = point + transform.forward * 2; IsSlider = true; } } } } playerAni.SetBool(slider, IsSlider); if (playerAni.GetCurrentAnimatorStateInfo(0).IsName("Slide") && playerAni.IsInTransition(0) == false) { Debug.Log("滑动"); playerAni.MatchTarget(margetPosition, Quaternion.identity, AvatarTarget.Root, new MatchTargetWeightMask(new Vector3(1, 0, 1), 0), 0.17f, 0.67f); } }
4、同样也给滑动动画下Curves添加Collider,在播放动画时关闭角色控制器
5、效果展示
六、动画状态机Layers层设置
Weight:1(对其他层的动画的影响权重值,1:完全影响(如果Blending为Additive的话,那么会将所有层的Additive的Weight的值进行同时计算),0:完全不影响)
Mask:HandWaveLMask(下面有图,我们只要保留左手绿色即可)
Blending:Override(该层的动画将会覆盖其他的)
1、举木头动画切换
2、由于举木头动画与移动动画有影响,创骨骼遮罩在Projects——>Avatar Mask设置骨骼遮罩
3、通过IK设置左右手位置,与木头更加吻合
勾选上图中IK Pass,添加两个点是左右手位置
代码如下:
1 public Transform leftHandPos;//左手位置 2 public Transform rightHandPos;//右手位置 3 int holdLog = Animator.StringToHash("IsHoldLog");//是否举起 4 private void OnTriggerEnter(Collider other) 5 { 6 if (other.tag=="Wood") 7 { 8 Destroy(other.gameObject); 9 CreateWood(); 10 } 11 } 12 //显示木头 13 void CreateWood() 14 { 15 newWood.SetActive(true); 16 playerAni.SetBool(holdLog, true); 17 } 18 //通过IK动画设置举木头手的位置 19 private void OnAnimatorIK(int layerIndex) 20 { 21 float Weight = playerAni.GetBool(holdLog) ? 1 : 0; 22 if (layerIndex == 1) 23 { 24 //左手 25 playerAni.SetIKPosition(AvatarIKGoal.LeftHand, leftHandPos.position);//设置左手位置 26 playerAni.SetIKPositionWeight(AvatarIKGoal.LeftHand, Weight);//设置左手权重 27 playerAni.SetIKRotation(AvatarIKGoal.LeftHand, leftHandPos.rotation);//设置左手旋转 28 playerAni.SetIKRotationWeight(AvatarIKGoal.LeftHand, Weight); 29 //右手 30 playerAni.SetIKPosition(AvatarIKGoal.RightHand, rightHandPos.position); 31 playerAni.SetIKPositionWeight(AvatarIKGoal.RightHand, Weight); 32 playerAni.SetIKRotation(AvatarIKGoal.RightHand, rightHandPos.rotation); 33 playerAni.SetIKRotationWeight(AvatarIKGoal.RightHand, Weight); 34 35 } 36 }
4、效果如图