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 updatevoid Start() {}public void SetPolarDeg(float degree) {currentHorizontal = degree;cameraFollow.polarDeg = degree;}private bool IsPointerOverUIObject() {//判断是否点击的是UI,有效应对安卓没有反应的情况,true为UIif (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 framevoid 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 {}}}