1
This commit is contained in:
122
unity/Assets/camera/CameraBounds.cs
Normal file
122
unity/Assets/camera/CameraBounds.cs
Normal file
@@ -0,0 +1,122 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace IndianOceanAssets.Engine2_5D
|
||||
{
|
||||
/// <summary>
|
||||
/// 摄像机边界(空气墙)—— 框定摄像机可移动的矩形范围。
|
||||
/// 摄像机碰到边界后停下,玩家仍可继续走。
|
||||
///
|
||||
/// 原理:在 LateUpdate(晚于 CameraFollow 的 Update)把摄像机位置钳制到
|
||||
/// 以本物体为中心、size 为尺寸的矩形内(仅 XZ 平面,Y 不限制)。
|
||||
/// [DefaultExecutionOrder(10000)] 保证本脚本在其它 LateUpdate 之后执行,
|
||||
/// 即使以后把 CameraFollow 改成 LateUpdate 也能正确钳制。
|
||||
///
|
||||
/// 为什么不会抖:
|
||||
/// CameraFollow 每帧用 Lerp 把摄像机往目标推(可能推出边界),
|
||||
/// 本脚本随后把它钳回边界。边界是固定直线,钳制结果每帧一致 → 稳定不抖。
|
||||
///
|
||||
/// 用法:
|
||||
/// 1. 场景中创建空物体,挂上此脚本
|
||||
/// 2. 把空物体放到摄像机活动范围的中心点
|
||||
/// 3. 设置 size(X=宽度,Y=深度,以本物体位置为中心)
|
||||
/// 4. targetCamera 留空则自动用 Camera.main
|
||||
/// 5. Scene 视图会显示青色线框,方便对齐
|
||||
/// </summary>
|
||||
[DefaultExecutionOrder(10000)]
|
||||
public class CameraBounds : MonoBehaviour
|
||||
{
|
||||
[Tooltip("要约束的摄像机(留空则使用 Camera.main)")]
|
||||
[SerializeField] private Camera targetCamera;
|
||||
|
||||
[Tooltip("边界尺寸(X=宽度,Y=深度,以本物体位置为中心)")]
|
||||
[SerializeField] private Vector2 size = new Vector2(30f, 30f);
|
||||
|
||||
[Tooltip("Scene 视图是否显示边界线框")]
|
||||
[SerializeField] private bool drawGizmo = true;
|
||||
|
||||
[Tooltip("线框颜色")]
|
||||
[SerializeField] private Color gizmoColor = Color.cyan;
|
||||
|
||||
private Transform _camTransform;
|
||||
private bool _resolved;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
ResolveCamera();
|
||||
}
|
||||
|
||||
private void ResolveCamera()
|
||||
{
|
||||
var cam = targetCamera != null ? targetCamera : Camera.main;
|
||||
if (cam != null)
|
||||
{
|
||||
_camTransform = cam.transform;
|
||||
_resolved = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_resolved = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
if (!_resolved || _camTransform == null)
|
||||
{
|
||||
ResolveCamera();
|
||||
if (_camTransform == null) return;
|
||||
}
|
||||
|
||||
Vector3 pos = _camTransform.position;
|
||||
Vector3 center = transform.position;
|
||||
float minX = center.x - size.x * 0.5f;
|
||||
float maxX = center.x + size.x * 0.5f;
|
||||
float minZ = center.z - size.y * 0.5f;
|
||||
float maxZ = center.z + size.y * 0.5f;
|
||||
|
||||
_camTransform.position = new Vector3(
|
||||
Mathf.Clamp(pos.x, minX, maxX),
|
||||
pos.y,
|
||||
Mathf.Clamp(pos.z, minZ, maxZ)
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 把世界坐标钳制到边界内(仅 XZ,Y 不变)。供外部调用。
|
||||
/// </summary>
|
||||
public Vector3 ClampPosition(Vector3 pos)
|
||||
{
|
||||
Vector3 center = transform.position;
|
||||
return new Vector3(
|
||||
Mathf.Clamp(pos.x, center.x - size.x * 0.5f, center.x + size.x * 0.5f),
|
||||
pos.y,
|
||||
Mathf.Clamp(pos.z, center.z - size.y * 0.5f, center.z + size.y * 0.5f)
|
||||
);
|
||||
}
|
||||
|
||||
private void OnDrawGizmos()
|
||||
{
|
||||
if (!drawGizmo) return;
|
||||
|
||||
Vector3 c = transform.position;
|
||||
float hx = size.x * 0.5f;
|
||||
float hz = size.y * 0.5f;
|
||||
Vector3 p1 = new Vector3(c.x - hx, c.y, c.z - hz);
|
||||
Vector3 p2 = new Vector3(c.x + hx, c.y, c.z - hz);
|
||||
Vector3 p3 = new Vector3(c.x + hx, c.y, c.z + hz);
|
||||
Vector3 p4 = new Vector3(c.x - hx, c.y, c.z + hz);
|
||||
|
||||
Gizmos.color = gizmoColor;
|
||||
Gizmos.DrawLine(p1, p2);
|
||||
Gizmos.DrawLine(p2, p3);
|
||||
Gizmos.DrawLine(p3, p4);
|
||||
Gizmos.DrawLine(p4, p1);
|
||||
|
||||
// 中心十字
|
||||
Gizmos.color = new Color(gizmoColor.r, gizmoColor.g, gizmoColor.b, 0.6f);
|
||||
const float k = 0.5f;
|
||||
Gizmos.DrawLine(c - new Vector3(k, 0, 0), c + new Vector3(k, 0, 0));
|
||||
Gizmos.DrawLine(c - new Vector3(0, 0, k), c + new Vector3(0, 0, k));
|
||||
}
|
||||
}
|
||||
}
|
||||
11
unity/Assets/camera/CameraBounds.cs.meta
Normal file
11
unity/Assets/camera/CameraBounds.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: DylKsyylBn7lcA2y8oKcMWusHhL4i0Lo5tk6EFfHLt0CelquVgviXtA=
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user