add camera boundary

This commit is contained in:
Nilton Constantino 2026-05-26 16:58:01 +01:00
parent fec6eaffa0
commit 8a299eea99
No known key found for this signature in database
14 changed files with 1086 additions and 15 deletions

View File

@ -1379,6 +1379,7 @@ GameObject:
- component: {fileID: 744497487}
- component: {fileID: 744497486}
- component: {fileID: 744497485}
- component: {fileID: 744497488}
m_Layer: 0
m_Name: Cube (28)
m_TagString: Untagged
@ -1447,7 +1448,7 @@ MeshRenderer:
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:
- {fileID: 2100000, guid: 9452ae1262a74094f8a68013fbcd1834, type: 2}
- {fileID: 2100000, guid: 31321ba15b8f8eb4c954353edc038b1d, type: 2}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
@ -1479,6 +1480,20 @@ MeshFilter:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 744497483}
m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
--- !u!114 &744497488
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 744497483}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 0a0ba32e2ebe4f2eb4f2e18c11be758d, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::__Prototype.Scripts.MeshColorSetter
meshRenderer: {fileID: 744497486}
color: {r: 0.6156997, g: 0.2946778, b: 0.8113208, a: 1}
--- !u!1 &783026646
GameObject:
m_ObjectHideFlags: 0
@ -1842,13 +1857,13 @@ Transform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 873481847}
serializedVersion: 2
m_LocalRotation: {x: 0.38268343, y: 0, z: 0, w: 0.92387956}
m_LocalPosition: {x: 0, y: 12, z: -5}
m_LocalRotation: {x: 0.38268346, y: 0, z: 0, w: 0.9238795}
m_LocalPosition: {x: 0, y: 10.606603, z: -10.606601}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1761661293}
m_LocalEulerAnglesHint: {x: 45, y: 0, z: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &873481849
MonoBehaviour:
m_ObjectHideFlags: 0
@ -1952,15 +1967,15 @@ Camera:
m_LensShift: {x: 0, y: 0}
m_NormalizedViewPortRect:
serializedVersion: 2
x: 0.123447776
x: 0
y: 0
width: 1.0609529
height: 1.061039
near clip plane: 0.3
far clip plane: 1000
field of view: 60
width: 1
height: 1
near clip plane: 0.1
far clip plane: 5000
field of view: 40
orthographic: 1
orthographic size: 6.5
orthographic size: 7
m_Depth: 0
m_CullingMask:
serializedVersion: 2
@ -2360,6 +2375,167 @@ Transform:
- {fileID: 1809909214}
m_Father: {fileID: 2054429927}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &1223120086
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1223120087}
- component: {fileID: 1223120090}
- component: {fileID: 1223120092}
- component: {fileID: 1223120091}
- component: {fileID: 1223120093}
m_Layer: 0
m_Name: Follow
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &1223120087
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1223120086}
serializedVersion: 2
m_LocalRotation: {x: 0.38268346, y: 0, z: 0, w: 0.9238795}
m_LocalPosition: {x: 0, y: 10.606603, z: -10.606601}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1710245337}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &1223120090
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1223120086}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: f9dfa5b682dcd46bda6128250e975f58, type: 3}
m_Name:
m_EditorClassIdentifier: Unity.Cinemachine::Unity.Cinemachine.CinemachineCamera
Priority:
Enabled: 1
m_Value: 10
OutputChannel: 1
StandbyUpdate: 2
m_StreamingVersion: 20241001
m_LegacyPriority: 0
Target:
TrackingTarget: {fileID: 1478155984}
LookAtTarget: {fileID: 0}
CustomLookAtTarget: 0
Lens:
FieldOfView: 40
OrthographicSize: 7
NearClipPlane: 0.1
FarClipPlane: 5000
Dutch: 0
ModeOverride: 0
PhysicalProperties:
GateFit: 2
SensorSize: {x: 21.946, y: 16.002}
LensShift: {x: 0, y: 0}
FocusDistance: 10
Iso: 200
ShutterSpeed: 0.005
Aperture: 16
BladeCount: 5
Curvature: {x: 2, y: 11}
BarrelClipping: 0.25
Anamorphism: 0
BlendHint: 0
--- !u!114 &1223120091
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1223120086}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 62d54399b04b4fa48a73e121d4937dd4, type: 3}
m_Name:
m_EditorClassIdentifier: Unity.Cinemachine::Unity.Cinemachine.CinemachinePanTilt
ReferenceFrame: 0
RecenterTarget: 0
PanAxis:
Value: 0
Center: 0
Range: {x: -180, y: 180}
Wrap: 1
Recentering:
Enabled: 0
Wait: 1
Time: 2
Restrictions: 0
TiltAxis:
Value: 45
Center: 0
Range: {x: -70, y: 70}
Wrap: 0
Recentering:
Enabled: 0
Wait: 1
Time: 2
Restrictions: 0
--- !u!114 &1223120092
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1223120086}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 886251e9a18ece04ea8e61686c173e1b, type: 3}
m_Name:
m_EditorClassIdentifier: Unity.Cinemachine::Unity.Cinemachine.CinemachinePositionComposer
CameraDistance: 15
DeadZoneDepth: 0
Composition:
ScreenPosition: {x: 0, y: 0}
DeadZone:
Enabled: 0
Size: {x: 0.2, y: 0.2}
HardLimits:
Enabled: 0
Size: {x: 0.8, y: 0.8}
Offset: {x: 0, y: 0}
CenterOnActivate: 1
TargetOffset: {x: 0, y: 0, z: 0}
Damping: {x: 1, y: 0, z: 1}
Lookahead:
Enabled: 1
Time: 0.5
Smoothing: 15
IgnoreY: 1
--- !u!114 &1223120093
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1223120086}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: c34046a3bb0046209d0489e839c1f8ba, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::Intrepid.Core.Camera.CameraGroundProjectionConfinerExtension
confineX: 1
confineZ: 1
fallbackProjectionY: 0
useFollowTargetY: 1
projectionYSmoothTime: 0.08
drawDebugProjection: 1
--- !u!1 &1264271869
GameObject:
m_ObjectHideFlags: 0
@ -2632,6 +2808,87 @@ MeshFilter:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1286810257}
m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
--- !u!1 &1372692861
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1372692862}
- component: {fileID: 1372692865}
- component: {fileID: 1372692864}
- component: {fileID: 1372692863}
m_Layer: 0
m_Name: BoundaryA
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &1372692862
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1372692861}
serializedVersion: 2
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1943926653}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &1372692863
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1372692861}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 8141d03c55254ee5a7409fbf76ddff16, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::Intrepid.Core.Camera.CameraBoundaryTrigger
boundary: {fileID: 1372692864}
--- !u!114 &1372692864
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1372692861}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 0b288204b12348cbbba504fb13d2a8c1, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::Intrepid.Core.Camera.CameraBoundary
boxCollider: {fileID: 1372692865}
--- !u!65 &1372692865
BoxCollider:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1372692861}
m_Material: {fileID: 0}
m_IncludeLayers:
serializedVersion: 2
m_Bits: 0
m_ExcludeLayers:
serializedVersion: 2
m_Bits: 0
m_LayerOverridePriority: 0
m_IsTrigger: 1
m_ProvidesContacts: 0
m_Enabled: 1
serializedVersion: 3
m_Size: {x: 24.054745, y: 1, z: 16.044468}
m_Center: {x: -0.014335632, y: 0, z: 3.9807591}
--- !u!1 &1434619732
GameObject:
m_ObjectHideFlags: 0
@ -2898,6 +3155,87 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::Intrepid.Core.Entities.EntityMotorSmoothRotation
turnSpeed: 720
--- !u!1 &1524378542
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1524378543}
- component: {fileID: 1524378546}
- component: {fileID: 1524378545}
- component: {fileID: 1524378544}
m_Layer: 0
m_Name: BoundaryA (1)
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &1524378543
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1524378542}
serializedVersion: 2
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: -18, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1943926653}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &1524378544
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1524378542}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 8141d03c55254ee5a7409fbf76ddff16, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::Intrepid.Core.Camera.CameraBoundaryTrigger
boundary: {fileID: 1524378545}
--- !u!114 &1524378545
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1524378542}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 0b288204b12348cbbba504fb13d2a8c1, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::Intrepid.Core.Camera.CameraBoundary
boxCollider: {fileID: 1524378546}
--- !u!65 &1524378546
BoxCollider:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1524378542}
m_Material: {fileID: 0}
m_IncludeLayers:
serializedVersion: 2
m_Bits: 0
m_ExcludeLayers:
serializedVersion: 2
m_Bits: 0
m_LayerOverridePriority: 0
m_IsTrigger: 1
m_ProvidesContacts: 0
m_Enabled: 1
serializedVersion: 3
m_Size: {x: 7.999547, y: 4.956458, z: 34.4506}
m_Center: {x: 17.990416, y: 1.978229, z: 13.269833}
--- !u!1 &1532299328
GameObject:
m_ObjectHideFlags: 0
@ -3262,6 +3600,10 @@ PrefabInstance:
serializedVersion: 3
m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: 1110237080051008694, guid: 774b83ee4bf84c4c9b531c2a6350b8a5, type: 3}
propertyPath: m_IsActive
value: 1
objectReference: {fileID: 0}
- target: {fileID: 6646150498868371415, guid: 774b83ee4bf84c4c9b531c2a6350b8a5, type: 3}
propertyPath: m_LocalPosition.x
value: 0
@ -3311,6 +3653,38 @@ PrefabInstance:
m_AddedGameObjects: []
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 774b83ee4bf84c4c9b531c2a6350b8a5, type: 3}
--- !u!1 &1710245336
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1710245337}
m_Layer: 0
m_Name: Cameras
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &1710245337
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1710245336}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 1223120087}
m_Father: {fileID: 2054429927}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!137 &1750149050 stripped
SkinnedMeshRenderer:
m_CorrespondingSourceObject: {fileID: -2717395650310496025, guid: 2faa610713d3b3c439473daa55e8c60a, type: 3}
@ -3346,8 +3720,9 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::Intrepid.Core.Camera.CameraSystem
subscriptionId: a1f48773fed94f9385fd09875081cc76
mainCamera: {fileID: 0}
cinemachineBrain: {fileID: 0}
mainCamera: {fileID: 873481852}
cinemachineBrain: {fileID: 873481849}
cameraBoundaryManager: {fileID: 2059090170}
--- !u!4 &1761661293
Transform:
m_ObjectHideFlags: 0
@ -3362,6 +3737,7 @@ Transform:
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 873481848}
- {fileID: 2059090169}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &1777983739
@ -3744,6 +4120,8 @@ Transform:
- {fileID: 1031327464}
- {fileID: 1552570365}
- {fileID: 744497484}
- {fileID: 1372692862}
- {fileID: 1524378543}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!54 &1943926654
@ -4410,9 +4788,58 @@ Transform:
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 1179841130}
- {fileID: 1710245337}
- {fileID: 1478155984}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &2059090168
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 2059090169}
- component: {fileID: 2059090170}
m_Layer: 0
m_Name: BoundaryManager
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &2059090169
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2059090168}
serializedVersion: 2
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1761661293}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &2059090170
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2059090168}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: f46a8ced4ba84673b632d5ab60e27d51, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::Intrepid.Core.Camera.CameraBoundaryManager
subscriptionId: 1053a94ff61f4bbab2371b708c5725b4
enterBlendTime: 1
boundsBlendTime: 0.75
exitBlendTime: 0.5
--- !u!1660057539 &9223372036854775807
SceneRoots:
m_ObjectHideFlags: 0

View File

@ -0,0 +1,36 @@
using Intrepid.Core.Camera.Events;
using Intrepid.GameManagers;
using Intrepid.Utilities;
using UnityEngine;
namespace Intrepid.Core.Camera
{
[RequireComponent(typeof(Collider))]
public sealed class CameraBoundaryTrigger : MonoBehaviour
{
[GroupInjections, SerializeField] private CameraBoundary boundary;
private void Reset()
{
boundary = GetComponentInParent<CameraBoundary>();
var col = GetComponent<Collider>();
col.isTrigger = true;
}
private void OnTriggerEnter(Collider other)
{
Proxy.Instance.EventBus.Raise(new CameraBoundaryEnterEvent
{
Boundary = boundary
});
}
private void OnTriggerExit(Collider other)
{
Proxy.Instance.EventBus.Raise(new CameraBoundaryExitEvent
{
Boundary = boundary
});
}
}}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 8141d03c55254ee5a7409fbf76ddff16
timeCreated: 1779803052

View File

@ -0,0 +1,27 @@
using Intrepid.Utilities;
using UnityEngine;
namespace Intrepid.Core.Camera
{
[DisallowMultipleComponent]
[RequireComponent(typeof(BoxCollider))]
public sealed class CameraBoundary : MonoBehaviour
{
[GroupInjections, SerializeField] private BoxCollider boxCollider;
public Bounds WorldBounds => boxCollider.bounds;
#if UNITY_EDITOR
private void OnDrawGizmos()
{
var b = boxCollider.bounds;
Gizmos.color = new Color(0f, 1f, 1f, 0.25f);
Gizmos.DrawCube(b.center, b.size);
Gizmos.color = Color.cyan;
Gizmos.DrawWireCube(b.center, b.size);
}
#endif
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0b288204b12348cbbba504fb13d2a8c1
timeCreated: 1779802832

View File

@ -0,0 +1,289 @@
using System;
using System.Collections.Generic;
using Intrepid.Core.Camera.Events;
using Intrepid.SimpleEvents;
using Intrepid.Utilities;
using UnityEngine;
namespace Intrepid.Core.Camera
{
public class CameraBoundaryManager : EventListener
{
[GroupConfigurations, SerializeField] private float enterBlendTime = 1f;
[GroupConfigurations, SerializeField] private float boundsBlendTime = 0.75f;
[GroupConfigurations, SerializeField] private float exitBlendTime = 0.5f;
private readonly List<CameraBoundary> activeBoundaries = new();
private Bounds currentBounds;
private Bounds targetBounds;
private Bounds blendStartBounds;
private Bounds fadingOutBounds;
private bool hasCurrentBounds;
private bool hasTargetBounds;
private bool hasFadingOutBounds;
private float targetWeight;
private float boundsBlend = 1f;
public float BoundaryWeight { get; private set; }
public float SmoothBoundaryWeight => SmoothStep(BoundaryWeight);
public bool HasActiveBoundary => activeBoundaries.Count > 0;
protected override void InitializeVariables()
{
}
protected override void OnBootstrap()
{
}
protected override void Subscriptions()
{
Subscribe<CameraBoundaryEnterEvent>(e => Enter(e.Boundary));
Subscribe<CameraBoundaryExitEvent>(e => Exit(e.Boundary));
}
private void Enter(CameraBoundary boundary)
{
if (boundary.IsNull())
{
return;
}
if (activeBoundaries.Contains(boundary))
{
return;
}
activeBoundaries.Add(boundary);
hasFadingOutBounds = false;
targetWeight = 1f;
RefreshTargetBounds();
}
private void Exit(CameraBoundary boundary)
{
if (boundary.IsNull())
{
return;
}
if (!activeBoundaries.Contains(boundary))
{
return;
}
var hadCameraBounds = TryGetCameraBounds(out var previousCameraBounds);
activeBoundaries.Remove(boundary);
if (activeBoundaries.Count == 0)
{
if (hadCameraBounds)
{
fadingOutBounds = previousCameraBounds;
hasFadingOutBounds = true;
}
hasTargetBounds = false;
hasCurrentBounds = false;
targetWeight = 0f;
return;
}
hasFadingOutBounds = false;
targetWeight = 1f;
RefreshTargetBounds();
}
private void Update()
{
UpdateWeight();
UpdateBoundsBlend();
}
private void UpdateWeight()
{
var blendTime = targetWeight > BoundaryWeight
? enterBlendTime
: exitBlendTime;
if (blendTime <= 0f)
{
BoundaryWeight = targetWeight;
if (BoundaryWeight <= 0f)
{
hasFadingOutBounds = false;
}
return;
}
var speed = 1f / blendTime;
BoundaryWeight = Mathf.MoveTowards(
BoundaryWeight,
targetWeight,
speed * Time.deltaTime
);
if (BoundaryWeight <= 0f && targetWeight <= 0f)
{
BoundaryWeight = 0f;
hasFadingOutBounds = false;
}
}
private void UpdateBoundsBlend()
{
if (!hasTargetBounds)
{
return;
}
if (boundsBlend >= 1f)
{
currentBounds = targetBounds;
hasCurrentBounds = true;
return;
}
if (boundsBlendTime <= 0f)
{
boundsBlend = 1f;
currentBounds = targetBounds;
hasCurrentBounds = true;
return;
}
boundsBlend += Time.deltaTime / boundsBlendTime;
boundsBlend = Mathf.Clamp01(boundsBlend);
var t = SmoothStep(boundsBlend);
currentBounds = LerpBounds(blendStartBounds, targetBounds, t);
hasCurrentBounds = true;
}
public bool TryGetCameraBounds(out Bounds bounds)
{
if (hasCurrentBounds)
{
bounds = currentBounds;
return true;
}
if (hasFadingOutBounds)
{
bounds = fadingOutBounds;
return true;
}
bounds = default;
return false;
}
private void RefreshTargetBounds()
{
if (!TryCalculateEffectiveBounds(out var newTargetBounds))
{
hasTargetBounds = false;
return;
}
if (!hasCurrentBounds)
{
currentBounds = newTargetBounds;
targetBounds = newTargetBounds;
blendStartBounds = newTargetBounds;
hasCurrentBounds = true;
hasTargetBounds = true;
boundsBlend = 1f;
return;
}
blendStartBounds = currentBounds;
targetBounds = newTargetBounds;
hasTargetBounds = true;
boundsBlend = 0f;
}
private bool TryCalculateEffectiveBounds(out Bounds bounds)
{
if (activeBoundaries.Count == 0)
{
bounds = default;
return false;
}
bounds = activeBoundaries[0].WorldBounds;
for (var i = 1; i < activeBoundaries.Count; i++)
{
bounds = Intersect(bounds, activeBoundaries[i].WorldBounds);
}
return true;
}
private static Bounds Intersect(Bounds a, Bounds b)
{
var min = Vector3.Max(a.min, b.min);
var max = Vector3.Min(a.max, b.max);
if (min.x > max.x)
{
var x = (min.x + max.x) * 0.5f;
min.x = x;
max.x = x;
}
if (min.y > max.y)
{
var y = (min.y + max.y) * 0.5f;
min.y = y;
max.y = y;
}
if (min.z > max.z)
{
var z = (min.z + max.z) * 0.5f;
min.z = z;
max.z = z;
}
var result = new Bounds();
result.SetMinMax(min, max);
return result;
}
private static Bounds LerpBounds(Bounds from, Bounds to, float t)
{
var min = Vector3.Lerp(from.min, to.min, t);
var max = Vector3.Lerp(from.max, to.max, t);
var result = new Bounds();
result.SetMinMax(min, max);
return result;
}
private static float SmoothStep(float t)
{
t = Mathf.Clamp01(t);
return t * t * (3f - 2f * t);
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f46a8ced4ba84673b632d5ab60e27d51
timeCreated: 1779802949

View File

@ -0,0 +1,254 @@
using Intrepid.Utilities;
using Unity.Cinemachine;
using UnityEngine;
namespace Intrepid.Core.Camera
{
[DisallowMultipleComponent]
public sealed class CameraGroundProjectionConfinerExtension : CinemachineExtension
{
//[GroupConfigurations, SerializeField] private float groundY;
[GroupConfigurations, SerializeField] private bool confineX = true;
[GroupConfigurations, SerializeField] private bool confineZ = true;
[GroupConfigurations, SerializeField] private float fallbackProjectionY;
[GroupConfigurations, SerializeField] private bool useFollowTargetY = true;
[GroupConfigurations, SerializeField] private float projectionYSmoothTime = 0.08f;
[GroupDebug, SerializeField] private bool drawDebugProjection = true;
private float currentProjectionY;
private float projectionYVelocity;
private bool hasProjectionY;
private readonly Vector3[] groundCorners = new Vector3[4];
protected override void PostPipelineStageCallback(
CinemachineVirtualCameraBase vcam,
CinemachineCore.Stage stage,
ref CameraState state,
float deltaTime)
{
// Use Finalize so Body, Aim and Noise have already done their work.
if (stage != CinemachineCore.Stage.Finalize) return;
var lens = state.Lens;
if (!lens.Orthographic) return;
var manager = CameraSystem.Instance?.CameraBoundaryManager;
if (manager is null) return;
if (!manager.TryGetCameraBounds(out var bounds)) return;
var weight = manager.SmoothBoundaryWeight;
if (weight <= 0f) return;
var cameraPosition = state.RawPosition + state.PositionCorrection;
var cameraRotation = state.RawOrientation;
var projectionY = GetProjectionY(vcam, deltaTime);
CalculateOrthographicGroundCorners(cameraPosition, cameraRotation, lens, projectionY, groundCorners);
var correction = CalculateCorrection(groundCorners, bounds);
state.PositionCorrection += correction * weight;
}
private float GetProjectionY(CinemachineVirtualCameraBase vcam, float deltaTime)
{
var targetY = fallbackProjectionY;
if (useFollowTargetY && vcam.Follow is not null)
{
targetY = vcam.Follow.position.y;
}
if (!hasProjectionY || deltaTime < 0f || projectionYSmoothTime <= 0f)
{
currentProjectionY = targetY;
projectionYVelocity = 0f;
hasProjectionY = true;
return currentProjectionY;
}
currentProjectionY = Mathf.SmoothDamp(
currentProjectionY,
targetY,
ref projectionYVelocity,
projectionYSmoothTime,
Mathf.Infinity,
deltaTime
);
return currentProjectionY;
}
private static void CalculateOrthographicGroundCorners(
Vector3 cameraPosition,
Quaternion cameraRotation,
LensSettings lens,
float groundY,
Vector3[] results)
{
var halfHeight = lens.OrthographicSize;
var halfWidth = lens.OrthographicSize * lens.Aspect;
var right = cameraRotation * Vector3.right;
var up = cameraRotation * Vector3.up;
var forward = cameraRotation * Vector3.forward;
// Ordem:
// 0 = bottom-left
// 1 = bottom-right
// 2 = top-right
// 3 = top-left
Vector3[] localCorners =
{
(-right * halfWidth) + (-up * halfHeight),
(right * halfWidth) + (-up * halfHeight),
(right * halfWidth) + (up * halfHeight),
(-right * halfWidth) + (up * halfHeight),
};
var groundPlane = new Plane(Vector3.up, new Vector3(0f, groundY, 0f));
for (var i = 0; i < 4; i++)
{
var rayOrigin = cameraPosition + localCorners[i];
var ray = new Ray(rayOrigin, forward);
if (groundPlane.Raycast(ray, out float distance))
{
results[i] = ray.GetPoint(distance);
}
else
{
results[i] = rayOrigin;
}
}
}
private Vector3 CalculateCorrection(Vector3[] corners, Bounds bounds)
{
var minX = corners[0].x;
var maxX = corners[0].x;
var minZ = corners[0].z;
var maxZ = corners[0].z;
for (var i = 1; i < corners.Length; i++)
{
minX = Mathf.Min(minX, corners[i].x);
maxX = Mathf.Max(maxX, corners[i].x);
minZ = Mathf.Min(minZ, corners[i].z);
maxZ = Mathf.Max(maxZ, corners[i].z);
}
var correction = Vector3.zero;
var footprintWidth = maxX - minX;
var footprintDepth = maxZ - minZ;
var boundsWidth = bounds.max.x - bounds.min.x;
var boundsDepth = bounds.max.z - bounds.min.z;
// if camera is able to see more than the boundary,
// center it to avoid fighting between min/max.
if (footprintWidth > boundsWidth)
{
var footprintCenterX = (minX + maxX) * 0.5f;
correction.x = bounds.center.x - footprintCenterX;
}
else
{
if (minX < bounds.min.x)
{
correction.x += bounds.min.x - minX;
}
if (maxX > bounds.max.x)
{
correction.x -= maxX - bounds.max.x;
}
}
if (footprintDepth > boundsDepth)
{
var footprintCenterZ = (minZ + maxZ) * 0.5f;
correction.z = bounds.center.z - footprintCenterZ;
}
else
{
if (minZ < bounds.min.z)
{
correction.z += bounds.min.z - minZ;
}
if (maxZ > bounds.max.z)
{
correction.z -= maxZ - bounds.max.z;
}
}
if (!confineX)
{
correction.x = 0f;
}
if (!confineZ)
{
correction.z = 0f;
}
correction.y = 0f;
return correction;
}
#if UNITY_EDITOR
private void OnDrawGizmos()
{
if (!drawDebugProjection) return;
var outputCamera = CameraSystem.Instance?.MainCamera;
if (outputCamera is null) return;
Gizmos.color = Color.yellow;
var corners = new Vector3[4];
if (!TryGetCameraGroundProjection(outputCamera, currentProjectionY, corners))
{
return;
}
for (var i = 0; i < 4; i++)
{
var a = corners[i];
var b = corners[(i + 1) % 4];
Gizmos.DrawLine(a, b);
Gizmos.DrawSphere(a, 0.15f);
}
}
private static bool TryGetCameraGroundProjection(
UnityEngine.Camera camera,
float groundY,
Vector3[] results)
{
var groundPlane = new Plane(Vector3.up, new Vector3(0f, groundY, 0f));
Vector3[] viewportCorners =
{
new(0f, 0f, 0f), // bottom-left
new(1f, 0f, 0f), // bottom-right
new(1f, 1f, 0f), // top-right
new(0f, 1f, 0f), // top-left
};
for (var i = 0; i < 4; i++)
{
var ray = camera.ViewportPointToRay(viewportCorners[i]);
if (!groundPlane.Raycast(ray, out var distance))
{
return false;
}
results[i] = ray.GetPoint(distance);
}
return true;
}
#endif
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c34046a3bb0046209d0489e839c1f8ba
timeCreated: 1779802276

View File

@ -11,13 +11,15 @@ namespace Intrepid.Core.Camera
{
[GroupInjections, SerializeField] private UnityEngine.Camera mainCamera;
[GroupInjections, SerializeField] private CinemachineBrain cinemachineBrain;
[GroupInjections, SerializeField] private CameraBoundaryManager cameraBoundaryManager;
private bool IsBlendClearing { get; set; }
private CameraStreamStack CurrentCameraStreamStack { get; set; }
public bool IsCameraBlending => cinemachineBrain.IsBlending;
public float NormalAngle => mainCamera.transform.rotation.eulerAngles.z;
public UnityEngine.Camera MainCamera => mainCamera;
public Vector2 CameraTargetPosition => CurrentCameraStreamStack?.TopCameraStream?.VCamera.Follow.position ?? Vector2.zero;
// public Vector2 CameraTargetPosition => CurrentCameraStreamStack?.TopCameraStream?.VCamera.Follow.position ?? Vector2.zero;
public CameraBoundaryManager CameraBoundaryManager => cameraBoundaryManager;
protected override void InitializeVariables()
{

View File

@ -0,0 +1,9 @@
using Intrepid.SimpleEvents;
namespace Intrepid.Core.Camera.Events
{
public class CameraBoundaryEnterEvent : IEventBase
{
public CameraBoundary Boundary { get; set; }
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 5116ac60fac54e48849057a7ddc55849
timeCreated: 1779808201

View File

@ -0,0 +1,9 @@
using Intrepid.SimpleEvents;
namespace Intrepid.Core.Camera.Events
{
public class CameraBoundaryExitEvent : IEventBase
{
public CameraBoundary Boundary { get; set; }
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b2e7155437804591b2f1d188808645e0
timeCreated: 1779808216