一、动画状态机控制
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、效果如图