chore: initial commit
This commit is contained in:
0
Assets/Scripts/Camera/.gitkeep
Normal file
0
Assets/Scripts/Camera/.gitkeep
Normal file
17
Assets/Scripts/Camera/BaseGames.Camera.asmdef
Normal file
17
Assets/Scripts/Camera/BaseGames.Camera.asmdef
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"precompiledReferences": [],
|
||||
"name": "BaseGames.Camera",
|
||||
"defineConstraints": [],
|
||||
"noEngineReferences": false,
|
||||
"versionDefines": [],
|
||||
"rootNamespace": "BaseGames.Camera",
|
||||
"references": [
|
||||
"BaseGames.Core.Events",
|
||||
"Unity.Cinemachine"
|
||||
],
|
||||
"autoReferenced": true,
|
||||
"overrideReferences": false,
|
||||
"includePlatforms": []
|
||||
}
|
||||
7
Assets/Scripts/Camera/BaseGames.Camera.asmdef.meta
Normal file
7
Assets/Scripts/Camera/BaseGames.Camera.asmdef.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5b9cbc0f2e569d64a862f3b7f417c7b6
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
25
Assets/Scripts/Camera/CameraBlendProfileSO.cs
Normal file
25
Assets/Scripts/Camera/CameraBlendProfileSO.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using UnityEngine;
|
||||
using Unity.Cinemachine;
|
||||
|
||||
namespace BaseGames.Camera
|
||||
{
|
||||
[CreateAssetMenu(menuName = "Camera/BlendProfile")]
|
||||
public class CameraBlendProfileSO : ScriptableObject
|
||||
{
|
||||
public CinemachineBlendDefinition.Styles Style = CinemachineBlendDefinition.Styles.EaseInOut;
|
||||
public float BlendTime = 0.5f;
|
||||
[Tooltip("Style = Custom 时使用")]
|
||||
public AnimationCurve CustomCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f);
|
||||
|
||||
/// <summary>转换为 Cinemachine 混合定义。</summary>
|
||||
public CinemachineBlendDefinition ToBlendDefinition()
|
||||
{
|
||||
return new CinemachineBlendDefinition
|
||||
{
|
||||
Style = this.Style,
|
||||
Time = this.BlendTime,
|
||||
CustomCurve = this.Style == CinemachineBlendDefinition.Styles.Custom ? CustomCurve : null
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Camera/CameraBlendProfileSO.cs.meta
Normal file
11
Assets/Scripts/Camera/CameraBlendProfileSO.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 04f7b183b6d364d4ea85283d30339db7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
22
Assets/Scripts/Camera/CameraConfigSO.cs
Normal file
22
Assets/Scripts/Camera/CameraConfigSO.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace BaseGames.Camera
|
||||
{
|
||||
[CreateAssetMenu(menuName = "Camera/CameraConfig")]
|
||||
public class CameraConfigSO : ScriptableObject
|
||||
{
|
||||
[Header("跟随")]
|
||||
public float FollowDamping = 0.15f;
|
||||
public float LookAheadTime = 0.3f;
|
||||
public float LookAheadSmoothing = 0.1f;
|
||||
public Vector2 DeadZoneSize = new Vector2(1f, 0.5f);
|
||||
public Vector2 SoftZoneSize = new Vector2(2.5f, 2f);
|
||||
|
||||
[Header("偏移")]
|
||||
public float LookDownOffset = -1.5f;
|
||||
public float LookUpOffset = 1.5f;
|
||||
|
||||
[Header("画面抖动默认强度")]
|
||||
public float DefaultImpulseStrength = 0.3f;
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Camera/CameraConfigSO.cs.meta
Normal file
11
Assets/Scripts/Camera/CameraConfigSO.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b358a30ac16c6a34fb673ede0a288e48
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
87
Assets/Scripts/Camera/CameraStateController.cs
Normal file
87
Assets/Scripts/Camera/CameraStateController.cs
Normal file
@@ -0,0 +1,87 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using Unity.Cinemachine;
|
||||
|
||||
namespace BaseGames.Camera
|
||||
{
|
||||
/// <summary>
|
||||
/// 相机状态单例控制器。管理房间相机切换、限位器更新与屏幕抖动。
|
||||
/// 须放置在持久化场景中。
|
||||
/// </summary>
|
||||
[DefaultExecutionOrder(-100)]
|
||||
public class CameraStateController : MonoBehaviour
|
||||
{
|
||||
public static CameraStateController Instance { get; private set; }
|
||||
|
||||
[Header("引用")]
|
||||
[SerializeField] private CinemachineBrain _brain;
|
||||
[SerializeField] private CinemachineImpulseSource _impulseSource;
|
||||
|
||||
[Header("默认混合配置")]
|
||||
[SerializeField] private CameraBlendProfileSO _defaultBlendProfile;
|
||||
|
||||
// ── 注册表 ────────────────────────────────────────────────────────────
|
||||
private readonly HashSet<RoomCamera> _registeredCameras = new HashSet<RoomCamera>();
|
||||
private RoomCamera _activeCamera;
|
||||
|
||||
// ── Unity Lifecycle ───────────────────────────────────────────────────
|
||||
private void Awake()
|
||||
{
|
||||
if (Instance != null && Instance != this)
|
||||
{
|
||||
Destroy(gameObject);
|
||||
return;
|
||||
}
|
||||
Instance = this;
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (Instance == this) Instance = null;
|
||||
}
|
||||
|
||||
// ── 公开 API ──────────────────────────────────────────────────────────
|
||||
|
||||
/// <summary>向控制器注册一个房间相机(可选,也可由触发器直接调用 SwitchRoom)。</summary>
|
||||
public void RegisterRoomCamera(RoomCamera camera)
|
||||
{
|
||||
if (camera != null) _registeredCameras.Add(camera);
|
||||
}
|
||||
|
||||
/// <summary>注销房间相机。</summary>
|
||||
public void UnregisterRoomCamera(RoomCamera camera)
|
||||
{
|
||||
if (camera != null) _registeredCameras.Remove(camera);
|
||||
}
|
||||
|
||||
/// <summary>切换到目标房间相机,并应用对应的混合配置。</summary>
|
||||
public void SwitchRoom(RoomCamera targetCamera)
|
||||
{
|
||||
if (targetCamera == null || targetCamera == _activeCamera) return;
|
||||
|
||||
// 应用混合配置到 Brain
|
||||
if (_brain != null)
|
||||
{
|
||||
var profile = targetCamera.BlendProfile ?? _defaultBlendProfile;
|
||||
if (profile != null)
|
||||
_brain.DefaultBlend = profile.ToBlendDefinition();
|
||||
}
|
||||
|
||||
// 禁用旧相机、启用新相机
|
||||
_activeCamera?.Deactivate();
|
||||
_activeCamera = targetCamera;
|
||||
_activeCamera.Activate();
|
||||
}
|
||||
|
||||
/// <summary>触发屏幕抖动。</summary>
|
||||
public void TriggerImpulse(Vector3 velocity)
|
||||
{
|
||||
if (_impulseSource != null)
|
||||
_impulseSource.GenerateImpulse(velocity);
|
||||
}
|
||||
|
||||
/// <summary>以默认强度触发屏幕抖动。</summary>
|
||||
public void TriggerImpulse(float strength = 0.3f)
|
||||
=> TriggerImpulse(Vector3.down * strength);
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Camera/CameraStateController.cs.meta
Normal file
11
Assets/Scripts/Camera/CameraStateController.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 49f718c655d71394ea13e312a2dd9eed
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
42
Assets/Scripts/Camera/CameraTriggerZone.cs
Normal file
42
Assets/Scripts/Camera/CameraTriggerZone.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace BaseGames.Camera
|
||||
{
|
||||
/// <summary>
|
||||
/// 相机区域切换触发器。玩家进入时通知 CameraStateController 切换到目标房间相机。
|
||||
/// [ExecuteAlways] 确保编辑器中 Gizmo 立即更新。
|
||||
/// </summary>
|
||||
[ExecuteAlways]
|
||||
[RequireComponent(typeof(BoxCollider2D))]
|
||||
public class CameraTriggerZone : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private RoomCamera _targetCamera;
|
||||
[SerializeField] private string _playerTag = "Player";
|
||||
|
||||
private BoxCollider2D _collider;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_collider = GetComponent<BoxCollider2D>();
|
||||
_collider.isTrigger = true;
|
||||
}
|
||||
|
||||
private void OnTriggerEnter2D(Collider2D other)
|
||||
{
|
||||
if (!Application.isPlaying) return;
|
||||
if (!other.CompareTag(_playerTag)) return;
|
||||
if (_targetCamera != null)
|
||||
CameraStateController.Instance?.SwitchRoom(_targetCamera);
|
||||
}
|
||||
|
||||
private void OnDrawGizmos()
|
||||
{
|
||||
if (_collider == null) _collider = GetComponent<BoxCollider2D>();
|
||||
Gizmos.color = new Color(0.2f, 0.8f, 1f, 0.25f);
|
||||
Gizmos.matrix = transform.localToWorldMatrix;
|
||||
Gizmos.DrawCube(_collider.offset, _collider.size);
|
||||
Gizmos.color = new Color(0.2f, 0.8f, 1f, 0.8f);
|
||||
Gizmos.DrawWireCube(_collider.offset, _collider.size);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Camera/CameraTriggerZone.cs.meta
Normal file
11
Assets/Scripts/Camera/CameraTriggerZone.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 108d2b73047255f44a823dbcdea4a7fa
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
33
Assets/Scripts/Camera/RoomCamera.cs
Normal file
33
Assets/Scripts/Camera/RoomCamera.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using UnityEngine;
|
||||
using Unity.Cinemachine;
|
||||
|
||||
namespace BaseGames.Camera
|
||||
{
|
||||
/// <summary>
|
||||
/// 单房间虚拟相机。激活时提升优先级,停用时降为 0。
|
||||
/// 挂载在每个房间的 CinemachineCamera GameObject 上。
|
||||
/// </summary>
|
||||
[RequireComponent(typeof(CinemachineCamera))]
|
||||
public class RoomCamera : MonoBehaviour
|
||||
{
|
||||
[Header("房间设置")]
|
||||
[SerializeField] private RoomVisibleArea _visibleArea;
|
||||
[SerializeField] private Vector2 _cameraOffset = Vector2.zero;
|
||||
[SerializeField] private CameraBlendProfileSO _blendProfile;
|
||||
[SerializeField] private int _activePriority = 15;
|
||||
|
||||
private CinemachineCamera _vcam;
|
||||
|
||||
private void Awake() => _vcam = GetComponent<CinemachineCamera>();
|
||||
private void OnEnable() => _vcam.Priority = _activePriority;
|
||||
private void OnDisable() => _vcam.Priority = 0;
|
||||
|
||||
public PolygonCollider2D ConfinerCollider => _visibleArea?.Collider;
|
||||
public Vector2 CameraOffset => _cameraOffset;
|
||||
public CameraBlendProfileSO BlendProfile => _blendProfile;
|
||||
|
||||
/// <summary>在 CameraStateController 管理的激活流程中调用。</summary>
|
||||
public void Activate() => gameObject.SetActive(true);
|
||||
public void Deactivate() => gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Camera/RoomCamera.cs.meta
Normal file
11
Assets/Scripts/Camera/RoomCamera.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: af7e12583264b8c4da8dcd69df274793
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
30
Assets/Scripts/Camera/RoomVisibleArea.cs
Normal file
30
Assets/Scripts/Camera/RoomVisibleArea.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace BaseGames.Camera
|
||||
{
|
||||
/// <summary>
|
||||
/// 标记房间的可见区域(多边形)。供 CinemachineConfiner2D 使用。
|
||||
/// [ExecuteAlways] 确保编辑器中碰撞体立即更新。
|
||||
/// </summary>
|
||||
[ExecuteAlways]
|
||||
[RequireComponent(typeof(PolygonCollider2D))]
|
||||
public class RoomVisibleArea : MonoBehaviour
|
||||
{
|
||||
private PolygonCollider2D _collider;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_collider = GetComponent<PolygonCollider2D>();
|
||||
_collider.isTrigger = true;
|
||||
}
|
||||
|
||||
public PolygonCollider2D Collider
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_collider == null) _collider = GetComponent<PolygonCollider2D>();
|
||||
return _collider;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Camera/RoomVisibleArea.cs.meta
Normal file
11
Assets/Scripts/Camera/RoomVisibleArea.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 38af2eabab7039c4a919181e4c507d12
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
3
Assets/Scripts/Camera/_Placeholder.cs
Normal file
3
Assets/Scripts/Camera/_Placeholder.cs
Normal file
@@ -0,0 +1,3 @@
|
||||
// Placeholder to prevent asmdef-no-scripts warning.
|
||||
namespace BaseGames.Camera { }
|
||||
|
||||
11
Assets/Scripts/Camera/_Placeholder.cs.meta
Normal file
11
Assets/Scripts/Camera/_Placeholder.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5097f44608b602a46a8b8304e2edf090
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user