1.相机跟随组件,节点:
2.相机跟随组件脚本:
using System;
using System.Collections;
using System.Collections.Generic;
using Unity.Burst.Intrinsics;
using UnityEngine;
using UnityEngine.UI;
public class CameraFollow : Singleton<CameraFollow> {
public Transform firstAngleTarget; //第一人称跟随的目标
public Transform threeAngleTarget; //第三人称跟随的目标
public float radius;
public float polarDeg;
public float elevationDeg;
private Transform target;
public bool isLookAt;
public float lerpSpeed = 0;
//是否第一人称视角
private bool isFirstAngle = false;
LayerMask mask;
/// <summary>
/// 极坐标转换成笛卡尔坐标
/// </summary>
/// <param name="radius"></param>
/// <param name="angle"></param>
/// <returns></returns>
///
private bool isDriven;
private void Awake() {
EventManager.Instance.AddListener(EventName.PlayerDriving, (s, e) => { //开车事件触发
var arg = e as PlayerDrivingEventArgs;
if (arg.driveObj && arg.driveObj.GetComponent<VehicleBase>() && arg.driveObj.GetComponent<VehicleBase>().driveCam) {
gameObject.SetActive(false);
}
else {
isDriven = true;
}
});
EventManager.Instance.AddListener(EventName.PlayerDown, (s, e) => { //开车事件触发
var arg = e as PlayerDrivingEventArgs; //isDriven = false;
if (arg.driveObj && arg.driveObj.GetComponent<VehicleBase>() && arg.driveObj.GetComponent<VehicleBase>().driveCam) {
gameObject.SetActive(true);
}
else {
isDriven = false;
}
});
}
private void Start()
{
mask.value = (1 << LayerMask.NameToLayer("Ground")) | (1 << LayerMask.NameToLayer("Wall"));
this.target = this.threeAngleTarget;
EventManager.Instance.AddListener(EventName.ChangeAngle, changeAngle);
var offset = SphericalToCartesian(radius, DegreeToRadian(polarDeg), DegreeToRadian(elevationDeg));
//transform.position = Vector3.Lerp(transform.position, target.position + offset, Time.deltaTime * 10);
transform.position = target.position + offset;
}
private void changeAngle(object sender, EventArgs e) {
var data = e as AngleChangeEventArgs;
if (data != null) {
if (data.angleIndex == 1) {
this.target = this.firstAngleTarget;
this.radius = 0;
isFirstAngle = true;
transform.position = target.position;
transform.forward = target.forward;
} else if (data.angleIndex == 3) {
this.target = this.threeAngleTarget;
this.radius = 6;
isFirstAngle = false;
}
}
Debug.Log("摄像机视角改变" + e);
}
public Vector2 PolarToCartesian(float radius, float angle) {
float x = radius * Mathf.Cos(angle);
float y = radius * Mathf.Sin(angle);
return new Vector2(x, y);
}
public static float DegreeToRadian(float degree) {
return degree * Mathf.Deg2Rad;
}
public static Vector3 SphericalToCartesian(float radius, float polar, float elevation) {
float a = radius * Mathf.Cos(elevation);
float x = a * Mathf.Cos(polar);
float y = radius * Mathf.Sin(elevation);
float z = a * Mathf.Sin(polar);
return new Vector3(x, y, z);
}
public static void CartesianToSpherical(Vector3 cartesian, out float radius, out float polar, out float elevation) {
radius = Mathf.Sqrt(Mathf.Pow(cartesian.x, 2) + Mathf.Pow(cartesian.y, 2) + Mathf.Pow(cartesian.z, 2));
polar = Mathf.Atan2(cartesian.z, cartesian.x);
elevation = Mathf.Asin(cartesian.y / radius);
}
void LateUpdate() {
if (isDriven) {
var offset = SphericalToCartesian(6f, DegreeToRadian(270), DegreeToRadian(-15));
transform.position = Vector3.Lerp(transform.position, target.TransformPoint(target.localPosition + offset), Time.deltaTime * 3);
//transform.position = target.TransformPoint(target.localPosition + offset);
transform.LookAt(target);
return;
}
if (isFirstAngle) {
//var offset = SphericalToCartesian(radius, DegreeToRadian(polarDeg), DegreeToRadian(elevationDeg));
target.eulerAngles = new Vector3(elevationDeg, -polarDeg, 0);
transform.forward = target.forward;
transform.position = target.position;
if (PlayerController.Instance.animator) {
var euler = PlayerController.Instance.animator.transform.eulerAngles;
PlayerController.Instance.animator.transform.eulerAngles = new Vector3(euler.x, target.eulerAngles.y, euler.z);
}
}
else {
Ctrl_Cam_Move();
CtrThird();
}
}
void CtrThird() {
var offset = SphericalToCartesian(radius, DegreeToRadian(polarDeg), DegreeToRadian(elevationDeg));
//更新相机位置
//transform.position = target.position + offset;
transform.position = target.position + offset;
//TODO:做成CAMERA NEAR OBJ,进行隐藏
if (PlayerController.Instance.animator != null) PlayerController.Instance.animator.gameObject.SetActive(true);
//计算完位置之后处理让镜头不会穿墙
Vector3 direction = transform.position - target.position;
float distance = direction.magnitude;
direction.Normalize();
RaycastHit hit;
if (Physics.Raycast(target.transform.position, direction, out hit, distance, mask.value)) {
var dstPos = hit.point - distance * distance * direction * 0.01f;
var offsetDis = target.position - dstPos;
CartesianToSpherical(offsetDis, out var compareRadius, out _, out _);
if (compareRadius < 1f) {
if (PlayerController.Instance.animator != null) PlayerController.Instance.animator.gameObject.SetActive(false);
}
transform.position = dstPos;
}
transform.eulerAngles = target.eulerAngles;
if (isLookAt) {
transform.LookAt(target);
}
}
public void Ctrl_Cam_Move()
{
if (EditorModel.Instance.CurrentUnlock != null) { //解锁其他物体的时候,镜头不动, 要前后移动的是物体
return;
}
if (Input.GetAxis("Mouse ScrollWheel") > 0)
{
//transform.Translate(Vector3.forward * 1f);//速度可调 自行调整
radius = Math.Clamp(radius - 1.0f, 2, 15);
}
if (Input.GetAxis("Mouse ScrollWheel") < 0)
{
//transform.Translate(Vector3.forward * -1f);//速度可调 自行调整
radius = Math.Clamp(radius + 1.0f, 2, 15);
}
}
}
3.相机跟随角色视角旋转:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class CameraRotate : MonoBehaviour
{
public float speedH;
//public float speedVertical;
public bool isMobile;
//[Range(0f, 1f)]
//public float damping;
CameraFollow cameraFollow;
private float currentHorizontal;
private float currentVertical;
private Vector3 lastMousePosition;
private bool isDragging;
float time;
private float velocityY;
private float velocityX;
PointerEventData eventDataCurrentPosition;
//private bool isDragging;
public static CameraRotate instance;
private void Awake() {
instance = this;
//UI交互要禁用玩家的控制
cameraFollow = Camera.main.GetComponent<CameraFollow>();
currentHorizontal = cameraFollow.polarDeg;
time = Time.realtimeSinceStartup;
}
// Start is called before the first frame update
void Start() {
}
public void SetPolarDeg(float degree) {
currentHorizontal = degree;
cameraFollow.polarDeg = degree;
}
private bool IsPointerOverUIObject() {//判断是否点击的是UI,有效应对安卓没有反应的情况,true为UI
if (eventDataCurrentPosition == null) {
eventDataCurrentPosition = new PointerEventData(EventSystem.current);
}
eventDataCurrentPosition.position = new Vector2(Input.mousePosition.x, Input.mousePosition.y);
List<RaycastResult> results = new List<RaycastResult>();
EventSystem.current.RaycastAll(eventDataCurrentPosition, results);
return results.Count > 0;
}
// Update is called once per frame
void LateUpdate() {
//if (IsPointerOverUIObject()) {
// lastMousePosition = Input.mousePosition;
// return;//点击到UI不处理
//}
// 检查鼠标左键是否按下如果按下的那一下是在UI之上,则不让其旋转
if (PlayerData.Instance.isRunningPC)
{
if (Input.GetMouseButtonDown(0) && IsPointerOverUIObject() == false)
{
// 记录鼠标点击位置
lastMousePosition = Input.mousePosition;
isDragging = true;
}
else if (Input.GetMouseButtonUp(0))
{
// 如果鼠标抬起,则需要重新按下鼠标来记录新的点击位置
isDragging = false;
}
}
else {
if (Input.GetMouseButtonDown(0))
{
// 记录鼠标点击位置
lastMousePosition = Input.mousePosition;
isDragging = true;
}
else if (Input.GetMouseButtonUp(0))
{
// 如果鼠标抬起,则需要重新按下鼠标来记录新的点击位置
isDragging = false;
}
}
if (isDragging) {
float speedHorizontal = speedH;
float speedVertical = 0.1f;
// 计算鼠标移动的增量
Vector3 deltaMousePosition = Input.mousePosition - lastMousePosition;
//Debug.Log("deltaMousePosition.x:" + deltaMousePosition.x + "deltaMousePosition.y:" + deltaMousePosition.y);
// 计算水平旋转角度
// 计算水平旋转角度
float deltaHorizontal = speedHorizontal * deltaMousePosition.x;
var newHorizontal = currentHorizontal - deltaHorizontal;
//newHorizontal = Mathf.SmoothDamp(currentHorizontal, newHorizontal,ref velocityX, Time.unscaledDeltaTime);
// 更新摄像机跟随脚本的旋转角度
cameraFollow.polarDeg = newHorizontal;
//Debug.Log("cameraFollow.polarDeg" + cameraFollow.polarDeg);
currentHorizontal = newHorizontal;
float deltaVertical = speedVertical * deltaMousePosition.y;
var newVertical = currentVertical - deltaVertical;
//newHorizontal = Mathf.SmoothDamp(currentVertical, newVertical, ref velocityY, Time.unscaledDeltaTime);
// 更新摄像机跟随脚本的旋转角度
cameraFollow.elevationDeg = Mathf.Clamp(newVertical, -90f, 89);
currentVertical = newVertical;
lastMousePosition = Input.mousePosition;
}
else {
}
}
}