using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.EventSystems; public class CameraControl : MonoBehaviour { [Header("移动速度")] public float moveSpeed = 1.2f; [Header("旋转速度")] public float rotateSpeed = 45f; [Header("缩放速度")] public float zoomSpeed = 0.2f; [Header("最小高度")] public float minHeight = 0.1f; [Header("最大高度")] public float maxHeight = 100f; [Header("地图中心")] public Vector3 mapCenter = Vector3.zero; [Header("最大距离")] public float maxDistance = 3000f; [Header("最小角度")] public float minAngleX = -60f; [Header("最大角度")] public float maxAngleX = 88f; [Header("射线检测提前量")] public float raycastOffset = 0.1f; // 射线检测提前量 //控制变量 private Vector3 viewPos_0; //鼠标左键初始坐标 private Vector3 viewPos_1; //鼠标右键初始坐标 private Vector3 startCameraPos; //相机初始位置 private Vector3 targetCameraPos; //相机目标位置 private Vector2 startCameraEuler; //初始角度 private Vector2 targetCameraEuler; //目标角度 //相机控制 private Camera mainCamera; private bool isCameraCtrl = true; //相机是否可控制 private float screenAdapter = 1f; //屏幕长度比 //相机操作有效性判断 private bool isClickUI = false; private void Awake() { mainCamera = Camera.main; screenAdapter = Screen.width / (float)Screen.height; targetCameraPos = transform.position; targetCameraEuler = transform.eulerAngles; } void Update() { //相机控制 if (isCameraCtrl) { //操作有效性判断 if (EventSystem.current != null) { if (Input.GetMouseButtonDown(0) || Input.GetMouseButtonDown(1) || Input.GetMouseButtonDown(2)) { isClickUI = EventSystem.current.IsPointerOverGameObject(); } if (Input.GetMouseButtonUp(0) || Input.GetMouseButtonUp(1) || Input.GetMouseButtonUp(2)) { isClickUI = false; } } if (!isClickUI) { //平移控制 if (Input.GetMouseButtonDown(0) || Input.GetMouseButtonDown(2)) { viewPos_0 = mainCamera.ScreenToViewportPoint(Input.mousePosition); startCameraPos = transform.position; startCameraEuler = transform.eulerAngles; } if (Input.GetMouseButton(0) || Input.GetMouseButton(2)) { Vector3 currentViewPos = mainCamera.ScreenToViewportPoint(Input.mousePosition); Vector3 dis = currentViewPos - viewPos_0; dis = dis * GetMoveSpeed(); // 获取相机的右向量和上向量 Vector3 right = transform.right; Vector3 up = transform.up; // 分别计算水平和垂直方向的位移 float horizontalDis = -dis.x * screenAdapter; float verticalDis = -dis.y * screenAdapter; // 根据相机的右向量和上向量计算最终位移 Vector3 finalDis = right * horizontalDis + up * verticalDis; // targetCameraPos = startCameraPos + finalDis; Vector3 newTargetPos = startCameraPos + finalDis; newTargetPos = CheckCollisionOnMove(transform.position, newTargetPos); targetCameraPos = newTargetPos; } //旋转控制 if (Input.GetMouseButtonDown(1)) { viewPos_1 = mainCamera.ScreenToViewportPoint(Input.mousePosition); startCameraPos = transform.position; startCameraEuler = transform.eulerAngles; } if (Input.GetMouseButton(1)) { Vector2 angle = (mainCamera.ScreenToViewportPoint(Input.mousePosition) - viewPos_1) * rotateSpeed; angle = new Vector3(-angle.y, angle.x * screenAdapter); targetCameraEuler = startCameraEuler + angle; } //缩进控制 if (Input.mouseScrollDelta != Vector2.zero) { // float moveSpeed = GetMoveSpeed() * 0.2f; // targetCameraPos += transform.forward * moveSpeed * Input.mouseScrollDelta.y; float moveSpeed = GetMoveSpeed() * zoomSpeed; Vector3 newTargetPos = targetCameraPos + transform.forward * moveSpeed * Input.mouseScrollDelta.y; newTargetPos = CheckCollisionOnMove(transform.position, newTargetPos); targetCameraPos = newTargetPos; } //相机运动 LimitCamera(); // CheckCollision(); // 检查碰撞 //控制相机运动 // 控制相机运动 if (Vector3.Distance(transform.position, targetCameraPos) > 0.1f) { transform.position = Vector3.Lerp(transform.position, targetCameraPos, 5f * Time.deltaTime); // Debug.Log("position"+transform.position); } // 控制相机旋转 if (Quaternion.Angle(transform.rotation, Quaternion.Euler(targetCameraEuler)) > 0.1f) { transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.Euler(targetCameraEuler), 5f * Time.deltaTime); // Debug.Log("rotation"+transform.eulerAngles); } } } } //开启相机控制 // public void StartCameraControl() // { // isCameraCtrl = true; // isClickUI = false; // viewPos_0 = mainCamera.ScreenToViewportPoint(Input.mousePosition); // viewPos_1 = mainCamera.ScreenToViewportPoint(Input.mousePosition); // startCameraPos = transform.position; // startCameraEuler = transform.eulerAngles; // targetCameraPos = transform.position; // targetCameraEuler = transform.eulerAngles; // } //停止相机控制 // public void StopCameraControl() // { // isCameraCtrl = false; // } //获取相机移动速度 float GetMoveSpeed() { float highDis = (transform.position.y - minHeight); float speed = moveSpeed + moveSpeed * highDis; speed = Mathf.RoundToInt(speed); return speed; } //限制相机位置,角度 void LimitCamera() { //位置限制 targetCameraPos.y = Mathf.Clamp(targetCameraPos.y, minHeight, maxHeight); float dis = Vector3.Distance(targetCameraPos, mapCenter); if (dis > maxDistance) { Vector3 dir = (targetCameraPos - mapCenter).normalized; targetCameraPos = mapCenter + dir * maxDistance; } //角度限制 if (targetCameraEuler.x > 180) { targetCameraEuler.x -= 360f; } if (targetCameraEuler.x < -180) { targetCameraEuler.x += 360; } if (targetCameraEuler.y > 180) { targetCameraEuler.y -= 360f; } if (targetCameraEuler.y < -180) { targetCameraEuler.y += 360; } targetCameraEuler.x = Mathf.Clamp(targetCameraEuler.x, minAngleX, maxAngleX); } // // 检查碰撞 // void CheckCollisionOnMove(Vector3 startPos, Vector3 targetPos) // { // RaycastHit hit; // Vector3 direction = targetCameraPos - transform.position; // float distance = direction.magnitude; // if (Physics.Raycast(transform.position, direction.normalized, out hit, distance)) // { // targetCameraPos = hit.point; // } // } // 修改CheckCollisionOnMove方法,增加垂直方向检测 Vector3 CheckCollisionOnMove(Vector3 startPos, Vector3 targetPos) { Vector3 direction = targetPos - startPos; float distance = direction.magnitude; // 存储最终的安全位置 Vector3 safePosition = targetPos; // 1. 检测移动路径上的障碍物(包括水平和垂直方向) if (distance > 0) { float sphereRadius = 0.1f; // 根据相机碰撞体大小调整 // 计算起点和终点的包围盒 Bounds startBounds = new Bounds(startPos, Vector3.one * sphereRadius * 2); Bounds endBounds = new Bounds(targetPos, Vector3.one * sphereRadius * 2); // 创建从起点到终点的包围盒移动路径 Bounds movementBounds = new Bounds(); movementBounds.Encapsulate(startBounds); movementBounds.Encapsulate(endBounds); // 使用多个方向的射线检测全方位碰撞 bool collisionDetected = false; // 主方向检测 if (Physics.SphereCast(startPos, sphereRadius, direction.normalized, out RaycastHit hit, distance + raycastOffset)) { float safeDistance = hit.distance - raycastOffset - sphereRadius; safePosition = startPos + direction.normalized * Mathf.Max(safeDistance, 0); collisionDetected = true; } // 如果是向上移动,增加顶部检测 if (direction.y > 0.1f) // 设置一个阈值,只在明显向上移动时检测 { Vector3 topStart = startPos + Vector3.up * sphereRadius; Vector3 topDirection = Vector3.up * (endBounds.max.y - startBounds.max.y); if (Physics.SphereCast(topStart, sphereRadius, topDirection.normalized, out hit, topDirection.magnitude + raycastOffset)) { float verticalSafeDistance = hit.distance - raycastOffset - sphereRadius; safePosition.y = startPos.y + verticalSafeDistance; collisionDetected = true; } } if (collisionDetected) { // 声明地面检测变量(移到这里避免作用域冲突) Ray groundRay1; float maxGroundDistance1; RaycastHit groundHit1; // 如果检测到碰撞,进行地面高度验证 groundRay1 = new Ray(safePosition + Vector3.up, Vector3.down); maxGroundDistance1 = 0.5f; if (Physics.Raycast(groundRay1, out groundHit1, maxGroundDistance1)) { float minSafeHeight = groundHit1.point.y + minHeight; if (safePosition.y < minSafeHeight) { safePosition.y = minSafeHeight; } } return safePosition; } } // 2. 如果没有检测到碰撞,只进行地面高度验证 // 重用之前声明的变量 Ray groundRay = new Ray(targetPos + Vector3.up, Vector3.down); float maxGroundDistance = 0.5f; if (Physics.Raycast(groundRay, out RaycastHit groundHit, maxGroundDistance)) { float minSafeHeight = groundHit.point.y + minHeight; if (targetPos.y < minSafeHeight) { targetPos.y = minSafeHeight; } } return targetPos; } }