# Unity第三人称视角解决方案

##### 镜头跟随

• 脚本实现太繁琐，有几个属性目前根本就用不到。
• 人物旋转时不能控制摄像机跟着旋转，也就是说，不能让镜头一直跟在人物身后。

```	public class SmoothFollow : MonoBehaviour
{

// The target we are following
[SerializeField]
private Transform target;
// The distance in the x-z plane to the target
[SerializeField]
private float distance = 10.0f;
// the height we want the camera to be above the target
[SerializeField]
private float height = 5.0f;

[SerializeField]
private float rotationDamping;
[SerializeField]
private float heightDamping;

// Use this for initialization
void Start() { }

// Update is called once per frame
void LateUpdate()
{
// Early out if we don't have a target
if (!target)
return;

// Calculate the current rotation angles
var wantedRotationAngle = target.eulerAngles.y;
var wantedHeight = target.position.y + height;

var currentRotationAngle = transform.eulerAngles.y;
var currentHeight = transform.position.y;

// Damp the rotation around the y-axis
currentRotationAngle = Mathf.LerpAngle(currentRotationAngle, wantedRotationAngle, rotationDamping * Time.deltaTime);

// Damp the height
currentHeight = Mathf.Lerp(currentHeight, wantedHeight, heightDamping * Time.deltaTime);

// Convert the angle into a rotation
var currentRotation = Quaternion.Euler(0, currentRotationAngle, 0);

// Set the position of the camera on the x-z plane to:
// distance meters behind the target
transform.position = target.position;
transform.position -= currentRotation * Vector3.forward * distance;

// Set the height of the camera
transform.position = new Vector3(transform.position.x ,currentHeight , transform.position.z);

// Always look at the target
transform.LookAt(target);
}
}```

```		[SerializeField]
private Transform lookAtTarget;
//transfrom.lookAt的距离差
[SerializeField]
private Vector3 lookAtOffset;
//初始向量差 用来保持距离不变
private Vector3 originVector;```

inspect面板是这样的：

`start`方法里设置`originVector`:

`			originVector =new Vector3(target.position.x-transform.position.x,target.position.y-transform.position.y,target.position.z-transform.position.z);`

Update方法里实现：

```			transform.position = target.position - originVector;
transform.LookAt (target.position+lookAtOffset);```

• 对originVector做旋转：重新规划坐标，获得每一次旋转以后的坐标点，而不是直接使用两个向量的向量差。
• 先正常旋转，然后利用`RotateAround`方法完成绕人物旋转。

```		//记录上一frame的旋转角度
private Vector3 lastFrameTargetRoation;```

start方法里：

`			lastFrameTargetRoation = target.rotation.eulerAngles;`

update方法的完整代码：

```			transform.position = target.position - originVector;
transform.RotateAround(target.position,Vector3.up,target.rotation.eulerAngles.y -  lastFrameTargetRoation.y);

lastFrameTargetRoation = target.rotation.eulerAngles;
originVector =new Vector3(target.position.x-transform.position.x,target.position.y-transform.position.y,target.position.z-transform.position.z);```

##### 鼠标右键控制镜头

```		//鼠标旋转视野的速度
[SerializeField]
private float mouseTurnedSpeed = 0.3f;
//鼠标右键控制镜头旋转的代码
private bool rightButtonDonwed;```

```			//记录鼠标右键是否按下的状态
if (Input.GetMouseButton (1) && Input.GetMouseButtonDown (1)) {
rightButtonDonwed = true;
}
if (Input.GetMouseButtonUp (1)) {
rightButtonDonwed = false;
}```

```				//获取鼠标旋转的度数 横轴
float rotationAmount = Input.GetAxis ("Mouse X") * mouseTurnedSpeed * Time.deltaTime;
//最终的旋转读书
transform.RotateAround (target.position, Vector3.up, rotationAmount*360);
//人物也旋转 保证镜头始终对着人物背面
target.RotateAround(target.position, Vector3.up, rotationAmount*360);```

X轴的旋转十分简单，接下来是Y轴的上下镜头旋转，参考了第一人称视角的解决方案，发现第三人称跟第一人称完全不一样，需要获取一个旋转轴，也就是平行于当前平面，垂直于Y轴的向量，如下图。

```				//纵轴
float rotationAmountY = Input.GetAxis ("Mouse Y") * mouseTurnedSpeed * Time.deltaTime;
Vector3 yCenter = new Vector3 (-originVector.z / originVector.x, target.position.y, 1);
transform.RotateAround (target.position,yCenter,rotationAmountY*360);```
##### 鼠标滚轮拉近/远

```				//变动的距离
float changeDistance = Input.GetAxis ("Mouse ScrollWheel") ;
//单前的距离
float currentDistance = originVector.magnitude;
//单位向量
Vector3 miniVector = originVector.normalized;
//获取新的向量
originVector = miniVector*(currentDistance-changeDistance*Time.deltaTime*100);```

```using UnityEngine;

namespace UnityStandardAssets.Utility
{
public class SmoothFollow : MonoBehaviour
{

// The target we are following
[SerializeField]
private Transform target;
// The distance in the x-z plane to the target

[SerializeField]
private Transform lookAtTarget;
[SerializeField]
private Vector3 lookAtOffset;
//初始向量差 用来保持距离不变
private Vector3 originVector;
//记录上一frame的旋转叫
private Vector3 lastFrameTargetRoation;
//鼠标旋转视野的速度
[SerializeField]
private float mouseTurnedSpeed = 0.3f;
//鼠标右键控制镜头旋转的代码
private bool rightButtonDonwed;

// Use this for initialization
void Start() {
//获取当前的distance和height
originVector =new Vector3(target.position.x-transform.position.x,target.position.y-transform.position.y,target.position.z-transform.position.z);
rightButtonDonwed = false;
lastFrameTargetRoation = target.rotation.eulerAngles;
}

// Update is called once per frame
void Update()
{

//变动的距离
float changeDistance = Input.GetAxis ("Mouse ScrollWheel") ;
//单前的距离
float currentDistance = originVector.magnitude;
//单位向量
Vector3 miniVector = originVector.normalized;
//获取新的向量
originVector = miniVector*(currentDistance-changeDistance*Time.deltaTime*100);

//记录鼠标右键是否按下的状态
if (Input.GetMouseButton (1) && Input.GetMouseButtonDown (1)) {
rightButtonDonwed = true;
}
if (Input.GetMouseButtonUp (1)) {
rightButtonDonwed = false;
}
transform.position = target.position - originVector;
print (rightButtonDonwed);
if (rightButtonDonwed) {
//获取鼠标旋转的度数 横轴
float rotationAmount = Input.GetAxis ("Mouse X") * mouseTurnedSpeed * Time.deltaTime;
//最终的旋转读书
transform.RotateAround (target.position, Vector3.up, rotationAmount*360);
//人物也旋转 保证镜头始终对着人物背面
target.RotateAround(target.position, Vector3.up, rotationAmount*360);

//纵轴
float rotationAmountY = Input.GetAxis ("Mouse Y") * mouseTurnedSpeed * Time.deltaTime;
Vector3 yCenter = new Vector3 (-originVector.z / originVector.x, target.position.y, 1);
transform.RotateAround (target.position,yCenter,rotationAmountY*360);
} else {
transform.RotateAround(target.position,Vector3.up,target.rotation.eulerAngles.y -  lastFrameTargetRoation.y);

}

lastFrameTargetRoation = target.rotation.eulerAngles;
originVector =new Vector3(target.position.x-transform.position.x,target.position.y-transform.position.y,target.position.z-transform.position.z);

}
}
}```

14 篇文章25 人订阅

0 条评论

## 相关文章

### 使用三阶贝塞尔曲线实现直播中点赞效果

CSDN: http://blog.csdn.net/jiashuai94

2043

1935

3739

2.1K2

### 3.1.3 绘制三维Contour图的思路

2007年秋，开始接触数值计算，看到Contour图形，我觉得很神奇，很好看。强烈的好奇心驱使下，零零碎碎看了相关文献，都看不懂。大约2009年深秋，我读到的最...

1140

1.5K10

4233

7735

4191

2187