游戏开发中,不可避免地会涉及摄像机的跟随和控制,摄像机的位置以及角度朝向都需要在不断的调试中,以确认出对玩家比较友好的方案。本篇中将讨论几种在Unity3D中摄像机跟随的方案。
如字面意思,将摄像机作为需要跟随的目标的子物体,在操纵目标进行移动旋转时,摄像机也会跟随父物体进行移动旋转。
优点:简单直观,不需要写代码。
不足:由于是跟随父物体一起运动,会随着父物体的旋转而旋转,当父物体的旋转不当时,摄像机的角度无法进行调整。
这里有几个参数需要介绍一下
水平偏移角度:摄像机在x轴和z轴平面中,与目标位置形成的角度
垂直偏移角度:摄像机在x轴和y轴平面中,与目标位置形成的角度
距离:摄像机与目标之间的距离
现在我们分别从水平平面和垂直平面中求得摄像机的x、y、z坐标。
height = distance * Mathf.Sin(roll)
temp= distance * Mathf.Cos(roll)
在垂直平面中,我们求得摄像机距目标的相对高度,即摄像机的y坐标,和求x、z坐标的一个中间值
cameraPos.x = targetPos.x + temp * Mathf.Cos(rot);
cameraPos.z = targetPos.z + temp * Mathf.Sin(rot);
通过中间值temp,我们便可以求得摄像机的x、z坐标
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraFollow : MonoBehaviour {
//距离
public float distance = 8;
//横向角度
public float rot = 0;
//纵向角度
private float roll = 30f * Mathf.PI * 2 / 360;
//目标物体
private GameObject target;
//横向旋转速度
public float rotSpeed = 0.2f;
//纵向角度范围
private float maxRoll = 70f * Mathf.PI * 2 / 360;
private float minRoll = -10f * Mathf.PI * 2 / 360;
//纵向旋转速度
private float rollSpeed = 0.2f;
//距离范围
public float maxDistance = 22f;
public float minDistance = 5f;
//距离变化速度
public float zoomSpeed = 0.2f;
void Start() {
//找到坦克
//SetTarget(GameObject.Find("tank"));
}
void LateUpdate() {
//一些判断
if (target == null)
return;
if (Camera.main == null)
return;
//目标的坐标
Vector3 targetPos = target.transform.position;
//用三角函数计算相机位置
Vector3 cameraPos;
float d = distance * Mathf.Cos(roll);
float height = distance * Mathf.Sin(roll);
cameraPos.x = targetPos.x + d * Mathf.Cos(rot);
cameraPos.z = targetPos.z + d * Mathf.Sin(rot);
cameraPos.y = targetPos.y + height;
Camera.main.transform.position = cameraPos;
//对准目标
Camera.main.transform.LookAt(target.transform);
//横向旋转
Rotate();
//纵向旋转
Roll();
//调整距离
Zoom();
}
//设置目标
public void SetTarget(GameObject target) {
if (target.transform.Find("cameraPoint") != null)
this.target = target.transform.Find("cameraPoint").gameObject;
else
this.target = target;
}
//横向旋转
void Rotate() {
float w = Input.GetAxis("Mouse X") * rotSpeed;
rot -= w;
}
//纵向旋转
void Roll() {
float w = Input.GetAxis("Mouse Y") * rollSpeed * 0.5f;
roll -= w;
if (roll > maxRoll)
roll = maxRoll;
if (roll < minRoll)
roll = minRoll;
}
//调整距离
void Zoom() {
if (Input.GetAxis("Mouse ScrollWheel") > 0) {
if (distance > minDistance)
distance -= zoomSpeed;
} else if (Input.GetAxis("Mouse ScrollWheel") < 0) {
if (distance < maxDistance)
distance += zoomSpeed;
}
}
}
优点:比较严谨摄像机跟随方案,可进行进一步的摄像机控制,例如视角的操控
缺点:实现过程稍麻烦,需要理解摄像机与跟随目标的三角函数关系
Vector3 TargetPos = new Vector3(0, 3f, -3f);
transform.position = Vector3.Lerp(transform.position, playerTransform.position + TargetPos, speed * Time.deltaTime);
使用Lerp函数是为了摄像机移动的更平滑些。
Quaternion TargetRotation = Quaternion.LookRotation(playerTransform.position - transform.position);
transform.rotation = Quaternion.Slerp(transform.rotation, TargetRotation, speed * Time.deltaTime);
使用Slerp函数与使用Lerp函数同理
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FollowPlayer : MonoBehaviour
{
public float speed = 2f;
private Transform playerTransform;
void Start ()
{
playerTransform = GameObject.FindGameObjectWithTag("Player").transform;
}
void Update ()
{
if (playerTransform == null)
return;
Vector3 TargetPos = new Vector3(0, 3f, -3f);
transform.position = Vector3.Lerp(transform.position, playerTransform.position + TargetPos, speed * Time.deltaTime);
Quaternion TargetRotation = Quaternion.LookRotation(playerTransform.position - transform.position);
transform.rotation = Quaternion.Slerp(transform.rotation, TargetRotation, speed * Time.deltaTime);
}
}
优点:代码实现简单,可以做出不错的摄像机跟随效果。
不足:不便于进行视角的操控
由于博主能力有限,在学习过程中,总结了这三种摄像机跟随的实现方案,实现是比较简单的,而且能满足基本的需求。