fix:代码提交

This commit is contained in:
zhangjiajia
2026-03-03 11:30:53 +08:00
parent adf60cc8df
commit 21ebd4c951
2520 changed files with 178964 additions and 0 deletions

View File

@@ -0,0 +1,388 @@
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; // 射线检测提前量
[SerializeField] private LayerMask collisionLayers; // 可碰撞的图层
[SerializeField] private string[] obstacleLayerNames = new string[] { "ObstacleLayer" }; // 障碍物图层名称数组
public float minMoveSpeed = 5f; // 最小移动速度,根据需求设置
// 高度阈值数组 (按升序排列)
[SerializeField] private float[] thresholds = { 27f, 50f, 100f, 150f, 200f };
// 对应速度值数组 (与阈值一一对应)
[SerializeField] private float[] speeds = { 3f, 15f, 30f, 50f, 80f };
//控制变量
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;
if (collisionLayers == 0 && obstacleLayerNames.Length > 0)
{
collisionLayers = LayerMask.GetMask(obstacleLayerNames);
}
}
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(1) || Input.GetMouseButtonDown(2))
{
viewPos_0 = mainCamera.ScreenToViewportPoint(Input.mousePosition);
startCameraPos = transform.position;
startCameraEuler = transform.eulerAngles;
}
if (Input.GetMouseButton(1) || 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;
// Debug.Log("targetCameraPos" + targetCameraPos);
}
//旋转控制
if (Input.GetMouseButtonDown(0))
{
viewPos_1 = mainCamera.ScreenToViewportPoint(Input.mousePosition);
startCameraPos = transform.position;
startCameraEuler = transform.eulerAngles;
}
if (Input.GetMouseButton(0))
{
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() * zoomSpeed;
targetCameraPos = transform.position + transform.forward * moveSpeed * Input.mouseScrollDelta.y;
// Vector3 newTargetPos = targetCameraPos + transform.forward * moveSpeed * Input.mouseScrollDelta.y;
// newTargetPos = CheckCollisionOnMove(transform.position, newTargetPos);
// targetCameraPos = newTargetPos;
}
//相机运动
LimitCamera();
// CheckCollision(); // 检查碰撞
//控制相机运动
// 控制相机运动
if (!isCheckCollisionOnMove(transform.position, targetCameraPos)) // 无碰撞时执行移动
{
if (Vector3.Distance(transform.position, targetCameraPos) > 0.1f)
{
transform.position = Vector3.Lerp(transform.position, targetCameraPos, 5f * Time.deltaTime);
}
// 控制相机旋转
if (Quaternion.Angle(transform.rotation, Quaternion.Euler(targetCameraEuler)) > 0.1f)
{
transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.Euler(targetCameraEuler), 5f * Time.deltaTime);
}
}
// if (Vector3.Distance(transform.position, targetCameraPos) > 0.1f)
// {
// transform.position = Vector3.Lerp(transform.position, targetCameraPos, 5f * Time.deltaTime);
// }
// // 控制相机旋转
// if (Quaternion.Angle(transform.rotation, Quaternion.Euler(targetCameraEuler)) > 0.1f)
// {
// transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.Euler(targetCameraEuler), 5f * Time.deltaTime);
// }
}
}
}
public bool isCheckCollisionOnMove(Vector3 position, Vector3 targetCameraPos)
{
Vector3 newPosition = CheckCollisionOnMove(position, targetCameraPos);
// 手动判断是否发生碰撞
bool hasCollision = newPosition != targetCameraPos;
return hasCollision;
}
//开启相机控制
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()
{
// // 计算高度差确保不小于0避免出现负速度
// float highDis = Mathf.Max(transform.position.y - minHeight, 0f);
// // 计算基础速度(基于高度的动态速度)
// float dynamicSpeed = moveSpeed + moveSpeed * highDis;
// // 确保速度不低于最小值,同时保留向上浮动的可能性
// float finalSpeed = Mathf.Max(dynamicSpeed, minMoveSpeed);
// // 可选:限制最大速度,防止过高高度下速度过快
// // finalSpeed = Mathf.Min(finalSpeed, maxMoveSpeed);
// // 保留整数化处理(如果需要)
// finalSpeed = Mathf.RoundToInt(finalSpeed);
// return finalSpeed;
// return transform.position.y > 80 ? 80f : transform.position.y > 30 ? 40f : 5f;
// // 高度阈值数组 (按升序排列)
float yPosition = transform.position.y;
// 检查每个阈值,返回对应速度
for (int i = 0; i < thresholds.Length; i++)
{
if (yPosition < thresholds[i])
{
return speeds[i];
}
}
Debug.Log("Speed: " + speeds[speeds.Length - 1]);
// 超过最高阈值,返回最高速度
return speeds[speeds.Length - 1];
}
//限制相机位置,角度
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);
}
// 修改CheckCollisionOnMove方法增加垂直方向检测
Vector3 CheckCollisionOnMove(Vector3 startPos, Vector3 targetPos)
{
Vector3 direction = targetPos - startPos;
float distance = direction.magnitude;
Vector3 safePosition = targetPos;
// 确保射线检测始终有足够的距离
if (distance < 0.01f)
return ApplyGroundCheck(safePosition);
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, collisionLayers))
{
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, collisionLayers))
{
float verticalSafeDistance = hit.distance - raycastOffset - sphereRadius;
safePosition.y = startPos.y + verticalSafeDistance;
collisionDetected = true;
}
}
// 底部检测(防止向下穿透)
if (direction.y < -0.1f)
{
Vector3 bottomStart = startPos - Vector3.up * sphereRadius;
Vector3 bottomDirection = Vector3.down * Mathf.Abs(direction.y);
if (Physics.SphereCast(bottomStart, sphereRadius, bottomDirection.normalized, out hit,
bottomDirection.magnitude + raycastOffset, collisionLayers))
{
float verticalSafeDistance = hit.distance - raycastOffset - sphereRadius;
safePosition.y = startPos.y - verticalSafeDistance;
collisionDetected = true;
}
}
if (collisionDetected)
{
// 应用地面检测并确保最小高度
safePosition = ApplyGroundCheck(safePosition);
return safePosition;
}
// 无碰撞时仍需确保地面高度
return ApplyGroundCheck(targetPos);
}
// 地面检测辅助方法
Vector3 ApplyGroundCheck(Vector3 position)
{
// 执行多次射线检测以提高精度
float groundDistance = float.MaxValue;
bool groundFound = false;
// 中心射线
Ray centerRay = new Ray(position + Vector3.up, Vector3.down);
if (Physics.Raycast(centerRay, out RaycastHit centerHit, 10f, collisionLayers))
{
groundDistance = centerHit.distance;
groundFound = true;
}
// 四角射线检测(提高边缘精度)
float checkRadius = 0.2f;
Vector3[] checkDirections = new Vector3[]
{
Vector3.forward * checkRadius + Vector3.right * checkRadius,
Vector3.forward * checkRadius - Vector3.right * checkRadius,
-Vector3.forward * checkRadius + Vector3.right * checkRadius,
-Vector3.forward * checkRadius - Vector3.right * checkRadius
};
foreach (Vector3 dir in checkDirections)
{
Ray cornerRay = new Ray(position + Vector3.up + dir, Vector3.down);
if (Physics.Raycast(cornerRay, out RaycastHit cornerHit, 10f, collisionLayers))
{
if (cornerHit.distance < groundDistance)
{
groundDistance = cornerHit.distance;
groundFound = true;
}
}
}
// 应用地面高度
if (groundFound)
{
float minSafeHeight = centerHit.point.y + minHeight;
if (position.y < minSafeHeight)
{
position.y = minSafeHeight;
}
}
return position;
}
}