创建人物

思考并回答以下问题:

  • 以下代码自己实现一遍。

添加摄像机

新建一个名为ThirdPersonCam的脚本。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
using UnityEngine;
using System.Collections;

public class ThirdPersonCam : MonoBehaviour
{
// 摄像机所跟随的对象
public Transform follow;
// 摄像机在水平方向与对象的距离
public float distanceAway;
// 摄像机在垂直方向与对象的距离
public float distanceUp;
// 过渡速度
public float smooth;
// 摄像机的目标速度
private Vector3 targetPosition;

// 在LateUpdate中执行摄像机操作,确保在对象的操作完成之后
void LateUpdate ()
{
// 计算目标位置
targetPosition = follow.position + Vector3.up * distanceUp - follow.forward * distanceAway;
// 对当前位置进行插值计算
transform.position = Vector3.Lerp(transform.position, targetPosition, Time.deltaTime * smooth);
// 使摄像机观察对象
transform.LookAt(follow);
}
}

将参数进行如下设置。

  • Follow:设置为player游戏对象。
  • Distance Away:设置为5。
  • Distance Up:设置为2。
  • Smooth:设置为3。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
using UnityEngine;
using System.Collections;

public class PlayerManager_5: MonoBehaviour
{
private Animator animator;
private CharacterController charController;

void Awake()
{
//得到Animator组件
animator = GetComponent<Animator>();
charController = GetComponent<CharacterController>();
}

void Update ()
{
//得到Joystick水平轴向输入的值
float v = Input.GetAxis("Vertical");
//得到Joystick水平轴向输入的值
float h = Input.GetAxis("Horizontal");
//将该值传递至animator的Speed参数
animator.SetFloat("Speed", h*h+v*v);
//将该值传递至animator的Direction参数
animator.SetFloat("Direction", h, 0.25f, Time.deltaTime);


//得到Animator中序号为0的layer,也就是Base Layer的状态信息
AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(0);
if (stateInfo.shortNameHash == Animator.StringToHash("Run"))
{
//Base Layer为Run状态,当检测到按下开火按钮,设置Jump为true
if (Input.GetButton("Fire1")) animator.SetBool("Jump", true);
}
else
{
//当Base Layer为其他状态时,设置Jump为false
animator.SetBool("Jump", false);
}

if (stateInfo.shortNameHash == Animator.StringToHash("Jump"))
{
//当Base Layer为Jump状态,将CharController的高度设置为与ColliderHeight曲线对应
if(!animator.IsInTransition(0))
charController.height = animator.GetFloat("ColliderHeight");
}

//得到Animator中序号为1的layer,也就是RightArm Layer的状态信息
AnimatorStateInfo stateInfo2 = animator.GetCurrentAnimatorStateInfo(1);
if (stateInfo2.shortNameHash == Animator.StringToHash("Wave"))
{
//当RightArm Layer为挥手状态时
animator.SetBool("Wave", false);
}
else
{
//当RightArm Layer为其他状态时
//当按下鼠标右键时
if(Input.GetButtonDown("Fire2") )
{
animator.SetBool("Wave", true);
}
}
}
}

反向动力学

当开启iKPass后,会在每一帧里调用MonoBehaviour的OnAnimatorIK()函数。IK的处理也只能在OnAnimatorIK()函数里。

角色上绑定的IKCtrl脚本代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
using UnityEngine;
using System;
using System.Collections;

// 要求游戏对象必须有Animator组件
[RequireComponent(typeof(Animator))]
public class IKCtrl: MonoBehaviour
{
private Animator animator;
// IK的开关
public bool iKPositionActive;
public bool iKLookAtActive;
public bool iKRotationActive;

// SetIKPosition和SetLookAtPosition的对象
public Transform rightHandObj;

// SetIKRotation的对象
public Transform rightHandRotationObj;

void Start ()
{
animator = GetComponent<Animator>();
}

void OnAnimatorIK()
{
if(iKPositionActive)
{
// 当开启IK位置时
// 设置右手的IK位置权重为1
animator.SetIKPositionWeight(AvatarIKGoal.RightHand, 1.0f);
// 设置右手的IK位置为rightHandObj的位置
animator.SetIKPosition(AvatarIKGoal.RightHand, rightHandObj.position);
}else
{
// 当不开启IK位置时,重置IK位置的权重为0
animator.SetIKPositionWeight(AvatarIKGoal.RightHand, 0f);
}

if(iKLookAtActive)
{
// 当开启IK的LookAt时
// 设置IK的LookAt权重为1
animator.SetLookAtWeight(1);
// 设置头部看向rightHandObj
animator.SetLookAtPosition(rightHandObj.transform.position);
}else
{
// 当不开启IK的LookAt时,重置IK的LookAt的权重为0
animator.SetLookAtWeight(0f);
}

if(iKRotationActive)
{
// 当开启IK旋转时
// 设置右手的IK旋转权重为1
animator.SetIKRotationWeight(AvatarIKGoal.RightHand, 1.0f);
// 设置右手的IK旋转角度为rightHandObj的旋转角度
animator.SetIKRotation(AvatarIKGoal.RightHand, rightHandObj.rotation);
} else
{
// 当不开启IK旋转时,重置IK旋转的权重为0
animator.SetIKRotationWeight(AvatarIKGoal.RightHand, 0f);
}
}
}

需要注意Unity中IK的限制,AvatarIKGoal也就是IK的目标只有RightHand、LeftHand、RightFoot和LeftFoot这4种,而且IK是某个身体部分(比如右臂)的反向动力学,并不是全身的。

0%