add helpers on camera boundary

This commit is contained in:
Nilton Constantino 2026-06-08 22:13:44 +01:00
parent 775dfd8ad2
commit 052f88c46d
No known key found for this signature in database
2 changed files with 778 additions and 338 deletions

File diff suppressed because it is too large Load Diff

View File

@ -2,6 +2,7 @@ using System;
using Intrepid.Core.Camera.Events;
using Intrepid.GameManagers;
using Intrepid.Utilities;
using Sirenix.OdinInspector;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
@ -9,14 +10,39 @@ using UnityEditor;
namespace Intrepid.Core.Camera
{
[ExecuteAlways]
[DisallowMultipleComponent]
[RequireComponent(typeof(BoxCollider))]
public sealed class CameraBoundary : MonoBehaviour
{
[GroupInjections, SerializeField] private BoxCollider boxCollider;
[GroupConfigurations, SerializeField, Min(0f)] private float cameraPadding = 0.5f;
[GroupConfigurations, SerializeField, Min(0.1f)] private float triggerHeight = 5f;
public Bounds WorldBounds => boxCollider.bounds;
private void Reset()
{
boxCollider = GetComponent<BoxCollider>();
ConfigureAsTrigger();
}
private void OnValidate()
{
if (boxCollider.IsNull())
boxCollider = GetComponent<BoxCollider>();
ConfigureAsTrigger();
}
private void ConfigureAsTrigger()
{
if (boxCollider.IsNull())
return;
boxCollider.isTrigger = true;
}
private void OnTriggerEnter(Collider other)
{
Proxy.Instance.EventBus.Raise(new CameraBoundaryEnterEvent
@ -33,10 +59,148 @@ namespace Intrepid.Core.Camera
});
}
[GroupDebug, Button(ButtonSizes.Medium)]
private void SetToCameraMinimumSize()
{
if (!TryGetCameraFootprintLocalBounds(out var localBounds))
return;
var size = boxCollider.size;
size.x = localBounds.size.x + cameraPadding * 2f;
size.y = triggerHeight;
size.z = localBounds.size.z + cameraPadding * 2f;
boxCollider.size = size;
}
[GroupDebug, Button(ButtonSizes.Medium)]
private void ClampToCameraMinimumSize()
{
if (!TryGetCameraFootprintLocalBounds(out var localBounds))
return;
var size = boxCollider.size;
size.x = Mathf.Max(size.x, localBounds.size.x + cameraPadding * 2f);
size.y = triggerHeight;
size.z = Mathf.Max(size.z, localBounds.size.z + cameraPadding * 2f);
boxCollider.size = size;
}
[GroupDebug, Button(ButtonSizes.Medium)]
private void FitToCurrentCameraView()
{
if (!TryGetCameraFootprintLocalBounds(out var localBounds))
return;
boxCollider.center = new Vector3(
localBounds.center.x,
0f,
localBounds.center.z
);
boxCollider.size = new Vector3(
localBounds.size.x + cameraPadding * 2f,
triggerHeight,
localBounds.size.z + cameraPadding * 2f
);
}
[GroupDebug, Button(ButtonSizes.Medium)]
private void ApplyTriggerHeight()
{
var size = boxCollider.size;
size.y = triggerHeight;
boxCollider.size = size;
}
[GroupDebug, Button(ButtonSizes.Medium)]
private void ResetColliderCenter()
{
boxCollider.center = Vector3.zero;
}
private bool TryGetCameraFootprintLocalBounds(out Bounds localBounds)
{
localBounds = default;
if (!TryGetReferenceCamera(out var cam))
return false;
if (!cam.orthographic)
{
Debug.LogWarning($"{nameof(CameraBoundary)} only supports orthographic cameras for boundary utilities.", this);
return false;
}
var planeY = boxCollider.transform.TransformPoint(boxCollider.center).y;
var groundPlane = new Plane(Vector3.up, new Vector3(0f, planeY, 0f));
var viewportCorners = new[]
{
new Vector3(0f, 0f, 0f),
new Vector3(0f, 1f, 0f),
new Vector3(1f, 1f, 0f),
new Vector3(1f, 0f, 0f),
};
var hasPoint = false;
foreach (var viewportCorner in viewportCorners)
{
var ray = cam.ViewportPointToRay(viewportCorner);
if (!groundPlane.Raycast(ray, out var distance))
continue;
var worldPoint = ray.GetPoint(distance);
var localPoint = boxCollider.transform.InverseTransformPoint(worldPoint);
if (!hasPoint)
{
localBounds = new Bounds(localPoint, Vector3.zero);
hasPoint = true;
}
else
{
localBounds.Encapsulate(localPoint);
}
}
return hasPoint;
}
private bool TryGetReferenceCamera(out UnityEngine.Camera cam)
{
cam = CameraSystem.Instance?.MainCamera;
if (cam.IsNotNull())
return true;
cam = UnityEngine.Camera.main;
if (cam.IsNotNull())
return true;
#if UNITY_EDITOR
if (SceneView.lastActiveSceneView.IsNotNull())
{
cam = SceneView.lastActiveSceneView.camera;
return cam.IsNotNull();
}
#endif
Debug.LogWarning($"{nameof(CameraBoundary)} could not find a reference camera.", this);
return false;
}
#if UNITY_EDITOR
private void OnDrawGizmosSelected()
{
if (boxCollider.IsNull()) return;
DrawBoxFill();
DrawHatchedBoxXZ();
DrawBoxWire();
@ -46,7 +210,7 @@ namespace Intrepid.Core.Camera
{
var b = boxCollider.bounds;
Gizmos.color = new Color(1f, 0f, 1f, 0.10f); // alpha
Gizmos.color = new Color(1f, 0f, 1f, 0.10f);
Gizmos.DrawCube(b.center, b.size);
}
@ -62,7 +226,7 @@ namespace Intrepid.Core.Camera
{
const float hatchSpacing = .5f;
Handles.color = new Color(1f, 0f, 1f, 0.65f); // alpha
Handles.color = new Color(1f, 0f, 1f, 0.65f);
var size = boxCollider.size;
var center = boxCollider.center;
@ -113,27 +277,19 @@ namespace Intrepid.Core.Camera
var xAtMinZ = c + minZ;
if (xAtMinZ >= minX && xAtMinZ <= maxX)
{
points[count++] = new Vector3(xAtMinZ, y, minZ);
}
var xAtMaxZ = c + maxZ;
if (xAtMaxZ >= minX && xAtMaxZ <= maxX)
{
points[count++] = new Vector3(xAtMaxZ, y, maxZ);
}
var zAtMinX = minX - c;
if (zAtMinX >= minZ && zAtMinX <= maxZ)
{
points[count++] = new Vector3(minX, y, zAtMinX);
}
var zAtMaxX = maxX - c;
if (zAtMaxX >= minZ && zAtMaxX <= maxZ)
{
points[count++] = new Vector3(maxX, y, zAtMaxX);
}
if (count < 2)
{