diff --git a/Assets/_Game/Data/Streaming.meta b/Assets/_Game/Data/Streaming.meta
new file mode 100644
index 0000000..22e5fb7
--- /dev/null
+++ b/Assets/_Game/Data/Streaming.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 712983ef837dc2745b7c72eb346da52f
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/_Game/Data/Streaming/STR_BudgetConfig_Default.asset b/Assets/_Game/Data/Streaming/STR_BudgetConfig_Default.asset
new file mode 100644
index 0000000..8d87153
--- /dev/null
+++ b/Assets/_Game/Data/Streaming/STR_BudgetConfig_Default.asset
@@ -0,0 +1,24 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!114 &11400000
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 0}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 65e349713a81a3846a654ea9f428ef99, type: 3}
+ m_Name: STR_BudgetConfig_Default
+ m_EditorClassIdentifier:
+ MaxDormantRooms: 6
+ MaxMemoryMB: 300
+ MaxConcurrentLoads: 2
+ PreloadLookaheadHops: 2
+ CoolingDuration: 6
+ LifecycleActivatePerFrame: 8
+ AtmosphericFadeOutDuration: 0.25
+ AtmosphericFadeInDuration: 0.3
+ RegionNameDisplayDuration: 1.2
+ SeamlessWaitTimeout: 10
diff --git a/Assets/_Game/Data/Streaming/STR_BudgetConfig_Default.asset.meta b/Assets/_Game/Data/Streaming/STR_BudgetConfig_Default.asset.meta
new file mode 100644
index 0000000..021943e
--- /dev/null
+++ b/Assets/_Game/Data/Streaming/STR_BudgetConfig_Default.asset.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: cd50a6ced54f54a43bda5a4d39b7865e
+NativeFormatImporter:
+ externalObjects: {}
+ mainObjectFileID: 11400000
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/_Game/Scenes/Persistent.unity b/Assets/_Game/Scenes/Persistent.unity
index f2f12d3..117f930 100644
--- a/Assets/_Game/Scenes/Persistent.unity
+++ b/Assets/_Game/Scenes/Persistent.unity
@@ -281,6 +281,76 @@ AudioSource:
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
+--- !u!1 &157732602
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 157732603}
+ - component: {fileID: 157732605}
+ - component: {fileID: 157732604}
+ m_Layer: 0
+ m_Name: SYS_RoomStreamingManager
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!4 &157732603
+Transform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 157732602}
+ 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: 162844601}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &157732604
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 157732602}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: a6db86de2f8c90548ba7e185b9cd5df6, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ _streamingManagerRef: {fileID: 157732605}
+ _onFadeOutRequest: {fileID: 11400000, guid: a17901d6793dcf2409e2672ffb383208, type: 2}
+ _onFadeInRequest: {fileID: 11400000, guid: f8d520fe699782b4184ff72ce5200c25, type: 2}
+ _onRegionNameDisplay: {fileID: 0}
+ _onSceneWorldStateRestored: {fileID: 0}
+ _mapDatabase: {fileID: 0}
+ _budget: {fileID: 11400000, guid: cd50a6ced54f54a43bda5a4d39b7865e, type: 2}
+--- !u!114 &157732605
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 157732602}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 0c17eea5df8bd684599801eb7dd7c41f, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ _mapDatabase: {fileID: 0}
+ _budget: {fileID: 11400000, guid: cd50a6ced54f54a43bda5a4d39b7865e, type: 2}
+ _onRoomEntered: {fileID: 11400000, guid: 133c65f23b6631846ab619edb0e44708, type: 2}
+ _onRoomPreloaded: {fileID: 0}
+ _onRoomActivated: {fileID: 0}
+ _unitsPerGrid: 16
--- !u!1 &162844600
GameObject:
m_ObjectHideFlags: 0
@@ -322,6 +392,8 @@ Transform:
- {fileID: 225262501}
- {fileID: 737017261}
- {fileID: 1208346588}
+ - {fileID: 1151871939}
+ - {fileID: 157732603}
m_Father: {fileID: 1218230064}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &225262500
@@ -432,8 +504,8 @@ MonoBehaviour:
_sceneService: {fileID: 1321234353}
_eventChannelRegistry: {fileID: 750267177}
_saveManager: {fileID: 737017262}
- _checkpointService: {fileID: 1308486565}
- _primaryListener: {fileID: 0}
+ _checkpointService: {fileID: 1151871940}
+ _primaryListener: {fileID: 464414703}
--- !u!1 &307714525
GameObject:
m_ObjectHideFlags: 0
@@ -554,6 +626,176 @@ CanvasRenderer:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 307714525}
m_CullTransparentMesh: 1
+--- !u!1 &315072829
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 315072830}
+ - component: {fileID: 315072836}
+ - component: {fileID: 315072835}
+ - component: {fileID: 315072834}
+ - component: {fileID: 315072833}
+ - component: {fileID: 315072832}
+ - component: {fileID: 315072831}
+ m_Layer: 0
+ m_Name: VCamA
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!4 &315072830
+Transform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 315072829}
+ 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: 537419888}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &315072831
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 315072829}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 886251e9a18ece04ea8e61686c173e1b, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ CameraDistance: 10
+ DeadZoneDepth: 0
+ Composition:
+ ScreenPosition: {x: 0, y: -0.15}
+ DeadZone:
+ Enabled: 1
+ Size: {x: 0.15, y: 0.05}
+ 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: 0.5, y: 0, z: 0}
+ Lookahead:
+ Enabled: 1
+ Time: 0.28
+ Smoothing: 5
+ IgnoreY: 1
+--- !u!114 &315072832
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 315072829}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: a12cbb2380ff137459b7ba80d492733f, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ _restScale: 0.25
+ _speedAtFullLookahead: 12
+ _speedSmoothing: 5
+--- !u!114 &315072833
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 315072829}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: cb5a7225ab133e74b81d1f0ae22ccc77, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ _dampingDown: 0.08
+ _dampingUp: 0.65
+--- !u!114 &315072834
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 315072829}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 7e2e7849ca8d76f438c4b2899c9fb421, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ LockX: 0
+ LockY: 0
+ LockedX: 0
+ LockedY: 0
+--- !u!114 &315072835
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 315072829}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 4d75924d76b05344aa410607bc57db98, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ BoundingVolume: {fileID: 0}
+ SlowingDistance: 0
+--- !u!114 &315072836
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 315072829}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: f9dfa5b682dcd46bda6128250e975f58, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ Priority:
+ Enabled: 0
+ m_Value: 0
+ OutputChannel: 1
+ StandbyUpdate: 2
+ m_StreamingVersion: 20241001
+ m_LegacyPriority: 0
+ Target:
+ TrackingTarget: {fileID: 0}
+ LookAtTarget: {fileID: 0}
+ CustomLookAtTarget: 0
+ Lens:
+ FieldOfView: 40
+ OrthographicSize: 10
+ 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!1 &320356782
GameObject:
m_ObjectHideFlags: 0
@@ -971,7 +1213,7 @@ Camera:
height: 1
near clip plane: 0.1
far clip plane: 5000
- field of view: 10
+ field of view: 40
orthographic: 0
orthographic size: 10
m_Depth: 0
@@ -998,7 +1240,7 @@ Transform:
m_GameObject: {fileID: 464414701}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
- m_LocalPosition: {x: -18.954266, y: 5.5, z: -64}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
@@ -1080,6 +1322,8 @@ Transform:
- {fileID: 464414705}
- {fileID: 1838586610}
- {fileID: 1341315320}
+ - {fileID: 315072830}
+ - {fileID: 1852813069}
m_Father: {fileID: 1218230064}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &545025334
@@ -1255,6 +1499,54 @@ MonoBehaviour:
_onMapOpen: {fileID: 11400000, guid: b972e8c7aec9da34d80381e643d49cb2, type: 2}
_onCharmPanelOpen: {fileID: 0}
_onSpellSelectOpen: {fileID: 0}
+--- !u!1 &712830947
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 712830948}
+ - component: {fileID: 712830949}
+ m_Layer: 0
+ m_Name: SYS_SceneFade
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!4 &712830948
+Transform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 712830947}
+ 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: 1810445798}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &712830949
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 712830947}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 5e4fa87eedbe2f24db81bdf66714343f, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ _fadeOut: {fileID: 0}
+ _fadeIn: {fileID: 0}
+ _onFadeOutRequest: {fileID: 11400000, guid: a17901d6793dcf2409e2672ffb383208, type: 2}
+ _onFadeInRequest: {fileID: 11400000, guid: f8d520fe699782b4184ff72ce5200c25, type: 2}
--- !u!1 &737017260
GameObject:
m_ObjectHideFlags: 0
@@ -1728,6 +2020,51 @@ MonoBehaviour:
_onLoadingStarted: {fileID: 11400000, guid: 78de6bbfc7741ad47ad568ba0b65fde0, type: 2}
_onLoadingComplete: {fileID: 11400000, guid: 1e4580d266c4bd44c8b25a70d26608d3, type: 2}
_onLoadingProgressUpdated: {fileID: 11400000, guid: 2d366d52ee6a8214c8cd94d14e9ccd15, type: 2}
+--- !u!1 &1151871938
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 1151871939}
+ - component: {fileID: 1151871940}
+ m_Layer: 0
+ m_Name: CheckpointService
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!4 &1151871939
+Transform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1151871938}
+ 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: 162844601}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &1151871940
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1151871938}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 486e785d32d1c4c468a4eb0fd4cf1822, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ _onSceneLoaded: {fileID: 11400000, guid: ce0e5d2372599c74aabdac63c1620289, type: 2}
--- !u!1 &1189402268
GameObject:
m_ObjectHideFlags: 0
@@ -2958,6 +3295,7 @@ Transform:
- {fileID: 1758098875}
- {fileID: 1710356906}
- {fileID: 622211655}
+ - {fileID: 712830948}
m_Father: {fileID: 1218230064}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &1838586609
@@ -3065,6 +3403,176 @@ MonoBehaviour:
_lensConfig: {fileID: 11400000, guid: 12fec951ce5cc3d499b00e38b5dfa14a, type: 2}
_onPlayerSpawned: {fileID: 11400000, guid: 7e2c7e614f6627b449a244ab44443adf, type: 2}
_showDebugOverlay: 0
+--- !u!1 &1852813068
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 1852813069}
+ - component: {fileID: 1852813075}
+ - component: {fileID: 1852813074}
+ - component: {fileID: 1852813073}
+ - component: {fileID: 1852813072}
+ - component: {fileID: 1852813071}
+ - component: {fileID: 1852813070}
+ m_Layer: 0
+ m_Name: VCamB
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!4 &1852813069
+Transform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1852813068}
+ 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: 537419888}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &1852813070
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1852813068}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 886251e9a18ece04ea8e61686c173e1b, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ CameraDistance: 10
+ DeadZoneDepth: 0
+ Composition:
+ ScreenPosition: {x: 0, y: -0.15}
+ DeadZone:
+ Enabled: 1
+ Size: {x: 0.15, y: 0.05}
+ 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: 0.5, y: 0, z: 0}
+ Lookahead:
+ Enabled: 1
+ Time: 0.28
+ Smoothing: 5
+ IgnoreY: 1
+--- !u!114 &1852813071
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1852813068}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: a12cbb2380ff137459b7ba80d492733f, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ _restScale: 0.25
+ _speedAtFullLookahead: 12
+ _speedSmoothing: 5
+--- !u!114 &1852813072
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1852813068}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: cb5a7225ab133e74b81d1f0ae22ccc77, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ _dampingDown: 0.08
+ _dampingUp: 0.65
+--- !u!114 &1852813073
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1852813068}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 7e2e7849ca8d76f438c4b2899c9fb421, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ LockX: 0
+ LockY: 0
+ LockedX: 0
+ LockedY: 0
+--- !u!114 &1852813074
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1852813068}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 4d75924d76b05344aa410607bc57db98, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ BoundingVolume: {fileID: 0}
+ SlowingDistance: 0
+--- !u!114 &1852813075
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1852813068}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: f9dfa5b682dcd46bda6128250e975f58, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ Priority:
+ Enabled: 0
+ m_Value: 0
+ OutputChannel: 1
+ StandbyUpdate: 2
+ m_StreamingVersion: 20241001
+ m_LegacyPriority: 0
+ Target:
+ TrackingTarget: {fileID: 0}
+ LookAtTarget: {fileID: 0}
+ CustomLookAtTarget: 0
+ Lens:
+ FieldOfView: 40
+ OrthographicSize: 10
+ 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!1 &1859511082
GameObject:
m_ObjectHideFlags: 0
diff --git a/Assets/_Game/Scenes/Testings/TestRoomA.unity b/Assets/_Game/Scenes/Testings/TestRoomA.unity
index e62a772..79a8d3c 100644
--- a/Assets/_Game/Scenes/Testings/TestRoomA.unity
+++ b/Assets/_Game/Scenes/Testings/TestRoomA.unity
@@ -5627,6 +5627,102 @@ MonoBehaviour:
_noiseFrequency: 1
_dedicatedCamera: {fileID: 840207430}
_dedicatedPriority: 20
+--- !u!1 &318931261
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 318931262}
+ - component: {fileID: 318931264}
+ - component: {fileID: 318931263}
+ m_Layer: 25
+ m_Name: '[Shape_Polygon]'
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!4 &318931262
+Transform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 318931261}
+ serializedVersion: 2
+ m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+ m_LocalPosition: {x: 0, y: 0.291, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children: []
+ m_Father: {fileID: 831117707}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &318931263
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 318931261}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: e11b931e351246344aec20aa35489592, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+--- !u!60 &318931264
+PolygonCollider2D:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 318931261}
+ m_Enabled: 1
+ m_Density: 1
+ m_Material: {fileID: 0}
+ m_IncludeLayers:
+ serializedVersion: 2
+ m_Bits: 0
+ m_ExcludeLayers:
+ serializedVersion: 2
+ m_Bits: 0
+ m_LayerOverridePriority: 0
+ m_ForceSendLayers:
+ serializedVersion: 2
+ m_Bits: 4294967295
+ m_ForceReceiveLayers:
+ serializedVersion: 2
+ m_Bits: 4294967295
+ m_ContactCaptureLayers:
+ serializedVersion: 2
+ m_Bits: 4294967295
+ m_CallbackLayers:
+ serializedVersion: 2
+ m_Bits: 4294967295
+ m_IsTrigger: 1
+ m_UsedByEffector: 0
+ m_UsedByComposite: 0
+ m_Offset: {x: 0, y: 0}
+ m_SpriteTilingProperty:
+ border: {x: 0, y: 0, z: 0, w: 0}
+ pivot: {x: 0, y: 0}
+ oldSize: {x: 0, y: 0}
+ newSize: {x: 0, y: 0}
+ adaptiveTilingThreshold: 0
+ drawMode: 0
+ adaptiveTiling: 0
+ m_AutoTiling: 0
+ m_Points:
+ m_Paths:
+ - - {x: 0, y: 0.3}
+ - {x: 0.6047108, y: 0.3348503}
+ - {x: 0.7406552, y: 0.12676334}
+ - {x: 0.7771857, y: -0.2715292}
+ - {x: -0.79761577, y: -0.28302938}
+ - {x: -0.78284264, y: -0.07071018}
+ m_UseDelaunayMesh: 0
--- !u!1 &320063820
GameObject:
m_ObjectHideFlags: 0
@@ -12912,7 +13008,7 @@ Transform:
m_GameObject: {fileID: 785719612}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
- m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalPosition: {x: 0, y: 0.51, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
@@ -12992,10 +13088,10 @@ SpriteRenderer:
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
- m_SortingLayerID: 0
- m_SortingLayer: 0
+ m_SortingLayerID: 652617267
+ m_SortingLayer: -6
m_SortingOrder: 0
- m_Sprite: {fileID: 7482667652216324306, guid: 311925a002f4447b3a28927169b83ea6, type: 3}
+ m_Sprite: {fileID: 1805018772, guid: 97a250d50f6857443aa7d823bbe36304, type: 3}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_FlipX: 0
m_FlipY: 0
@@ -13798,9 +13894,9 @@ GameObject:
serializedVersion: 6
m_Component:
- component: {fileID: 831117707}
- - component: {fileID: 831117706}
- component: {fileID: 831117705}
- component: {fileID: 831117704}
+ - component: {fileID: 831117708}
m_Layer: 25
m_Name: ContactDamageZone
m_TagString: Untagged
@@ -13838,9 +13934,25 @@ MonoBehaviour:
_id:
_rivalHitBoxMask:
serializedVersion: 2
- m_Bits: 0
---- !u!58 &831117706
-CircleCollider2D:
+ m_Bits: 512
+--- !u!4 &831117707
+Transform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 831117703}
+ 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: 318931262}
+ m_Father: {fileID: 1864792379}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!70 &831117708
+CapsuleCollider2D:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
@@ -13871,24 +13983,9 @@ CircleCollider2D:
m_IsTrigger: 1
m_UsedByEffector: 0
m_UsedByComposite: 0
- m_Offset: {x: 0, y: 0}
- serializedVersion: 2
- m_Radius: 0.4
---- !u!4 &831117707
-Transform:
- m_ObjectHideFlags: 0
- m_CorrespondingSourceObject: {fileID: 0}
- m_PrefabInstance: {fileID: 0}
- m_PrefabAsset: {fileID: 0}
- m_GameObject: {fileID: 831117703}
- 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: 1864792379}
- m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_Offset: {x: 0.40729484, y: 0.32778132}
+ m_Size: {x: 0.7284849, y: 0.65556294}
+ m_Direction: 1
--- !u!1 &837279661
GameObject:
m_ObjectHideFlags: 0
@@ -210626,8 +210723,8 @@ GameObject:
serializedVersion: 6
m_Component:
- component: {fileID: 1758953875}
- - component: {fileID: 1758953874}
- component: {fileID: 1758953873}
+ - component: {fileID: 1758953876}
m_Layer: 27
m_Name: HurtBox
m_TagString: Untagged
@@ -210649,8 +210746,23 @@ MonoBehaviour:
m_EditorClassIdentifier:
_onDamageDealt: {fileID: 0}
_onHitConfirmed: {fileID: 11400000, guid: a67d56f5124e0db4f98f326c74be8091, type: 2}
---- !u!70 &1758953874
-CapsuleCollider2D:
+--- !u!4 &1758953875
+Transform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1758953872}
+ 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: 1864792379}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!61 &1758953876
+BoxCollider2D:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
@@ -210681,24 +210793,19 @@ CapsuleCollider2D:
m_IsTrigger: 1
m_UsedByEffector: 0
m_UsedByComposite: 0
- m_Offset: {x: 0, y: 0}
- m_Size: {x: 0.55, y: 0.75}
- m_Direction: 0
---- !u!4 &1758953875
-Transform:
- m_ObjectHideFlags: 0
- m_CorrespondingSourceObject: {fileID: 0}
- m_PrefabInstance: {fileID: 0}
- m_PrefabAsset: {fileID: 0}
- m_GameObject: {fileID: 1758953872}
+ m_Offset: {x: -0.01498282, y: 0.4}
+ m_SpriteTilingProperty:
+ border: {x: 0, y: 0, z: 0, w: 0}
+ pivot: {x: 0, y: 0}
+ oldSize: {x: 0, y: 0}
+ newSize: {x: 0, y: 0}
+ adaptiveTilingThreshold: 0
+ drawMode: 0
+ adaptiveTiling: 0
+ m_AutoTiling: 0
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: 1864792379}
- m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_Size: {x: 1.5648925, y: 0.8}
+ m_EdgeRadius: 0
--- !u!1 &1766894770
GameObject:
m_ObjectHideFlags: 0
@@ -212034,6 +212141,7 @@ GameObject:
- component: {fileID: 1864792372}
- component: {fileID: 1864792371}
- component: {fileID: 1864792370}
+ - component: {fileID: 1864792380}
m_Layer: 13
m_Name: ENM_CaoZhi
m_TagString: Untagged
@@ -212282,7 +212390,7 @@ BoxCollider2D:
m_IsTrigger: 0
m_UsedByEffector: 0
m_UsedByComposite: 0
- m_Offset: {x: 0, y: 0}
+ m_Offset: {x: -0.01498282, y: 0.4}
m_SpriteTilingProperty:
border: {x: 0, y: 0, z: 0, w: 0}
pivot: {x: 0, y: 0}
@@ -212293,7 +212401,7 @@ BoxCollider2D:
adaptiveTiling: 0
m_AutoTiling: 0
serializedVersion: 2
- m_Size: {x: 0.6, y: 0.8}
+ m_Size: {x: 1.5648925, y: 0.8}
m_EdgeRadius: 0
--- !u!50 &1864792378
Rigidbody2D:
@@ -212341,6 +212449,67 @@ Transform:
- {fileID: 1650269713}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &1864792380
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1864792369}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 0cdaa3305fa954c45a80c9662aa6f425, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_GraphName: Behavior Tree
+ m_Index: 0
+ m_Data:
+ m_TaskData:
+ - m_ObjectType: Opsive.BehaviorDesigner.Runtime.Tasks.Actions.StackedAction
+ m_ValueHashes:
+ m_LongValueHashes: 30b77c28f48d1b2966cb3cf98c4bd96480f6501333363a66622a4da7e5588b5847627e5c3afba34af262c60c48f0bccad0ed2caea3f34ac163eb2caea3f34ac1a8724a1098fa102319cb31fdb78bb19fc8fad5b29007ef3a396f2e031315f24fe4a06bb554569d8946fff10c773614c9
+ m_ValuePositions: 000000000200000004000000060000000a0000003100000035000000390000003d0000004100000045000000460000004a0000004a000000
+ m_Values: 0000ffffffff010000004261736547616d65732e456e656d6965732e41492e42445f506174726f6c576179706f696e7473020000000000000001000000000000009a99993e000000000000000000
+ m_UnityObjects:
+ - {fileID: 5705765}
+ - {fileID: 1398696825}
+ m_Version: 3.4
+ m_EventTaskData:
+ - m_ObjectType: Opsive.BehaviorDesigner.Runtime.Tasks.Events.Start
+ m_ValueHashes:
+ m_LongValueHashes: 59405171878141b1
+ m_ValuePositions: 00000000
+ m_Values: 0000
+ m_UnityObjects: []
+ m_Version: 3.4
+ m_SharedVariableData: []
+ m_DisabledEventNodesData: []
+ m_DisabledLogicNodesData: []
+ m_UniqueID: 206339031
+ m_LogicNodePropertiesData:
+ - m_ObjectType: Opsive.GraphDesigner.Runtime.LogicNodeProperties
+ m_ValueHashes:
+ m_LongValueHashes: bc124df8ef5e104cf36ca30dee0de9958dd19827f48d1b29bd8814239a1bb7642f6406e2580d1e294f869cc9196b0c27aea3bc2e18d5b803a034c7c2b541f015557e981535906112a98ff48b9e8a66b37f542abda0a249c23a7f01b1f88d1a7b
+ m_ValuePositions: 00000000240000002c000000300000003000000030000000400000004100000045000000450000004700000049000000
+ m_Values: 35363062633134302d633833632d343334312d393338392d3063396165323031616638660000a54300008c4200000043000000000000000000000000000000000000000000ffffffff00
+ m_UnityObjects: []
+ m_Version: 3.4
+ m_EventNodePropertiesData:
+ - m_ObjectType: Opsive.GraphDesigner.Runtime.NodeProperties
+ m_ValueHashes:
+ m_LongValueHashes: bc124df8ef5e104cf36ca30dee0de9958dd19827f48d1b29bd8814239a1bb7642f6406e2580d1e294f869cc9196b0c27aea3bc2e18d5b803
+ m_ValuePositions: 00000000240000002c00000030000000300000003000000040000000
+ m_Values: 31383566623665622d343438392d346266612d616463652d3434353131393731373638310000a543000000000000dc420000000000000000000000000000000000
+ m_UnityObjects: []
+ m_Version: 3.4
+ m_GroupPropertiesData: []
+ m_SharedVariableGroupsData: []
+ m_StartWhenEnabled: 1
+ m_PauseWhenDisabled: 0
+ m_UpdateMode: 0
+ m_EvaluationType: 0
+ m_MaxEvaluationCount: 1
+ m_Subtree: {fileID: 0}
--- !u!1 &1865796628
GameObject:
m_ObjectHideFlags: 0
diff --git a/Assets/_Game/Scripts/Core/SceneService.cs b/Assets/_Game/Scripts/Core/SceneService.cs
index adff7c8..aeedf4b 100644
--- a/Assets/_Game/Scripts/Core/SceneService.cs
+++ b/Assets/_Game/Scripts/Core/SceneService.cs
@@ -10,6 +10,12 @@ namespace BaseGames.Core
///
public interface ISceneService
{
+ ///
+ /// 直接触发场景过渡请求(无需 Inspector SO 引用)。
+ /// 游戏场景物体(RoomTransition、DoorTransition 等)通过 ServiceLocator 调用此方法,
+ /// 替代手动拖拽 SceneLoadRequestEventChannelSO。
+ ///
+ void RequestTransition(SceneLoadRequest request);
/// 异步加载指定场景(Additive)。
IEnumerator LoadSceneCoroutine(SceneLoadRequest request);
/// 卸载当前房间场景(保留 Persistent)。
@@ -69,6 +75,9 @@ namespace BaseGames.Core
private void OnDisable() => _subscriptions.Clear();
+ ///
+ public void RequestTransition(SceneLoadRequest request) => HandleSceneLoadRequest(request);
+
private void HandleSceneLoadRequest(SceneLoadRequest request)
{
// Seamless / AtmosphericFade 由 ITransitionDirector 处理(需要预加载支持)
diff --git a/Assets/_Game/Scripts/Editor/BaseGames.Editor.asmdef b/Assets/_Game/Scripts/Editor/BaseGames.Editor.asmdef
index 876c852..603f3f4 100644
--- a/Assets/_Game/Scripts/Editor/BaseGames.Editor.asmdef
+++ b/Assets/_Game/Scripts/Editor/BaseGames.Editor.asmdef
@@ -35,7 +35,8 @@
"BaseGames.EventChain",
"BaseGames.VFX",
"BaseGames.Localization",
- "Unity.InputSystem"
+ "Unity.InputSystem",
+ "Unity.TextMeshPro"
],
"includePlatforms": [
"Editor"
diff --git a/Assets/_Game/Scripts/Editor/Scene/SceneScaffoldTools.cs b/Assets/_Game/Scripts/Editor/Scene/SceneScaffoldTools.cs
index f100eae..279216e 100644
--- a/Assets/_Game/Scripts/Editor/Scene/SceneScaffoldTools.cs
+++ b/Assets/_Game/Scripts/Editor/Scene/SceneScaffoldTools.cs
@@ -168,8 +168,19 @@ namespace BaseGames.Editor
AssignAsset(loadingMgr, "_onLoadingProgressUpdated", report, false, "EVT_LoadingProgressUpdated");
loadingCanvasGo.SetActive(false);
+ // ── SceneFadeController(场景切换黑幕)───────────────────────────
+ // 纯逻辑节点:监听淡出/淡入事件后调用 SceneFeedback.Play()。
+ // 实际 UI 效果完全由 SceneFeedback 内部的 MMF_Player 负责。
+ GameObject fadeCtrGo = GetOrCreateChild(ui.transform, "SYS_SceneFade").gameObject;
+ SceneFadeController fadeCtr = GetOrAddComponent(fadeCtrGo);
+ AssignAsset(fadeCtr, "_onFadeOutRequest", report, false, "EVT_FadeOutRequest");
+ AssignAsset(fadeCtr, "_onFadeInRequest", report, false, "EVT_FadeInRequest");
+
report.Add("Canvas_Splash:请将工作室 Logo CanvasGroup 赋给 _studioLogoGroup,游戏标题 CanvasGroup 赋给 _gameTitleGroup。");
report.Add("Canvas_Loading:请为 LoadingScreenManager 绑定 _progressBar(Slider)和 _loadingPanel(GameObject)。");
+ report.Add("SYS_SceneFade:请创建两个带 MMF_Player 的 SceneFeedback(淡出/淡入)," +
+ "配置完毕后分别拖入 SceneFadeController._fadeOut / _fadeIn。" +
+ "MMF_Player 总时长应 ≤ SceneService._sceneFadeDuration(默认 0.4 s)。");
EnsureAudioSources(audioManagerGo, audioManager, report);
diff --git a/Assets/_Game/Scripts/Editor/UI/HUDScaffoldWizard.cs b/Assets/_Game/Scripts/Editor/UI/HUDScaffoldWizard.cs
new file mode 100644
index 0000000..ebd35ff
--- /dev/null
+++ b/Assets/_Game/Scripts/Editor/UI/HUDScaffoldWizard.cs
@@ -0,0 +1,402 @@
+using System.Collections.Generic;
+using BaseGames.UI;
+using BaseGames.UI.HUD;
+using TMPro;
+using UnityEditor;
+using UnityEditor.SceneManagement;
+using UnityEngine;
+using UnityEngine.SceneManagement;
+using UnityEngine.UI;
+
+namespace BaseGames.Editor.UI
+{
+ ///
+ /// HUD 脚手架工具(架构 10_UIModule §HUD)。
+ /// 在当前活动场景中生成完整的 HUD Canvas 层级结构并自动绑定已存在的事件频道资产。
+ /// 执行路径:BaseGames ▸ Scene ▸ Setup ▸ Scaffold HUD Canvas
+ ///
+ public static class HUDScaffoldWizard
+ {
+ [MenuItem("BaseGames/Scene/Setup/Scaffold HUD Canvas", priority = 203)]
+ public static void ScaffoldHUDCanvas()
+ {
+ var report = new List();
+ Undo.SetCurrentGroupName("Scaffold HUD Canvas");
+ int undoGroup = Undo.GetCurrentGroup();
+
+ // ── Canvas ────────────────────────────────────────────────────────
+ GameObject canvasGo = GetOrCreateRootCanvas("HUD Canvas", 0);
+
+ // ── HUDRoot ───────────────────────────────────────────────────────
+ GameObject hudRootGo = GetOrCreateChild(canvasGo.transform, "HUDRoot").gameObject;
+ HUDController hudCtrl = GetOrAddComponent(hudRootGo);
+
+ // 若场景中已存在 UIManager,自动将 _hudRoot 指向本 HUDRoot
+ UIManager uiManager = Object.FindFirstObjectByType();
+ if (uiManager != null)
+ AssignRef(uiManager, "_hudRoot", hudRootGo);
+
+ // ── HP 区域 ───────────────────────────────────────────────────────
+ GameObject hpContainerGo = GetOrCreateChild(hudRootGo.transform, "HP_Container").gameObject;
+ var hpLayout = GetOrAddComponent(hpContainerGo);
+ hpLayout.childForceExpandWidth = false;
+ hpLayout.childForceExpandHeight = false;
+ hpLayout.spacing = 4f;
+
+ // ── 魄元(Soul)量条 ──────────────────────────────────────────────
+ GameObject soulGaugeGo = GetOrCreateChild(hudRootGo.transform, "Gauge_Soul").gameObject;
+ Image soulFill = GetOrAddComponent(soulGaugeGo);
+ soulFill.type = Image.Type.Filled;
+ soulFill.fillMethod = Image.FillMethod.Horizontal;
+ soulFill.fillAmount = 1f;
+
+ // ── 灵力(Spirit)量条 ────────────────────────────────────────────
+ GameObject spiritGaugeGo = GetOrCreateChild(hudRootGo.transform, "Gauge_Spirit").gameObject;
+ Image spiritFill = GetOrAddComponent(spiritGaugeGo);
+ spiritFill.type = Image.Type.Filled;
+ spiritFill.fillMethod = Image.FillMethod.Horizontal;
+ spiritFill.fillAmount = 1f;
+
+ // ── 灵铢(LingZhu)文本 ───────────────────────────────────────────
+ GameObject lingZhuGo = GetOrCreateChild(hudRootGo.transform, "Text_LingZhu").gameObject;
+ TMP_Text lingZhuText = GetOrAddComponent(lingZhuGo);
+ lingZhuText.text = "0";
+
+ // ── 回春图标(Spring Charges)─────────────────────────────────────
+ GameObject springContainerGo = GetOrCreateChild(hudRootGo.transform, "Spring_Container").gameObject;
+ var springLayout = GetOrAddComponent(springContainerGo);
+ springLayout.childForceExpandWidth = false;
+ springLayout.childForceExpandHeight = false;
+ springLayout.spacing = 4f;
+
+ // ── 形态图标(Form Icons × 4)────────────────────────────────────
+ const int kFormIconCount = 4;
+ GameObject formIconsRoot = GetOrCreateChild(hudRootGo.transform, "FormIcons").gameObject;
+ Image[] formImages = new Image[kFormIconCount];
+ for (int i = 0; i < kFormIconCount; i++)
+ {
+ GameObject iconGo = GetOrCreateChild(formIconsRoot.transform, $"FormIcon_{i}").gameObject;
+ formImages[i] = GetOrAddComponent(iconGo);
+ }
+
+ // ── 交互提示(InteractPrompt)─────────────────────────────────────
+ GameObject interactPromptGo = GetOrCreateChild(hudRootGo.transform, "InteractPrompt").gameObject;
+ InteractPromptWidget interactWidget = GetOrAddComponent(interactPromptGo);
+
+ GameObject promptRootGo = GetOrCreateChild(interactPromptGo.transform, "Root").gameObject;
+ GameObject promptKeyIconGo = GetOrCreateChild(promptRootGo.transform, "KeyIcon").gameObject;
+ Image keyIcon = GetOrAddComponent(promptKeyIconGo);
+ GameObject promptLabelGo = GetOrCreateChild(promptRootGo.transform, "LabelText").gameObject;
+ TMP_Text promptLabel = GetOrAddComponent(promptLabelGo);
+ promptLabel.text = "互动";
+ promptRootGo.SetActive(false);
+
+ AssignRef(interactWidget, "_keyIcon", keyIcon);
+ AssignRef(interactWidget, "_labelText", promptLabel);
+ AssignRef(interactWidget, "_root", promptRootGo);
+
+ // ── 法术槽(SpellSlot)───────────────────────────────────────────
+ GameObject spellSlotGo = GetOrCreateChild(hudRootGo.transform, "SpellSlot").gameObject;
+ SpellSlotWidget spellWidget = GetOrAddComponent(spellSlotGo);
+
+ GameObject spellIconGo = GetOrCreateChild(spellSlotGo.transform, "IconImage").gameObject;
+ Image spellIcon = GetOrAddComponent(spellIconGo);
+ GameObject spellCdGo = GetOrCreateChild(spellSlotGo.transform, "CooldownFill").gameObject;
+ Image spellCd = GetOrAddComponent(spellCdGo);
+ spellCd.type = Image.Type.Filled;
+ spellCd.fillMethod = Image.FillMethod.Radial360;
+ spellCd.fillAmount = 0f;
+ GameObject spellEmptyGo = GetOrCreateChild(spellSlotGo.transform, "EmptySlot").gameObject;
+
+ AssignRef(spellWidget, "_iconImage", spellIcon);
+ AssignRef(spellWidget, "_cooldownFill", spellCd);
+ AssignRef(spellWidget, "_emptySlot", spellEmptyGo);
+
+ // ── 工具栏(ToolHUD × 2 slots)──────────────────────────────────
+ GameObject toolHUDGo = GetOrCreateChild(hudRootGo.transform, "ToolHUD").gameObject;
+ ToolHUD toolHUD = GetOrAddComponent(toolHUDGo);
+ const int kToolSlotCount = 2;
+ var toolSlots = new ToolSlotUI[kToolSlotCount];
+
+ for (int i = 0; i < kToolSlotCount; i++)
+ {
+ GameObject slotGo = GetOrCreateChild(toolHUDGo.transform, $"ToolSlot_{i}").gameObject;
+ ToolSlotUI slotUI = GetOrAddComponent(slotGo);
+
+ GameObject iconGo = GetOrCreateChild(slotGo.transform, "Icon").gameObject;
+ Image slotIcon = GetOrAddComponent(iconGo);
+ GameObject usesGo = GetOrCreateChild(slotGo.transform, "UsesText").gameObject;
+ TMP_Text usesText = GetOrAddComponent(usesGo);
+ usesText.text = "0";
+ GameObject cdGo = GetOrCreateChild(slotGo.transform, "CooldownMask").gameObject;
+ Image cdMask = GetOrAddComponent(cdGo);
+ cdMask.type = Image.Type.Filled;
+ cdMask.fillMethod = Image.FillMethod.Horizontal;
+ cdMask.fillAmount = 0f;
+
+ AssignRef(slotUI, "_icon", slotIcon);
+ AssignRef(slotUI, "_usesText", usesText);
+ AssignRef(slotUI, "_cooldownMask", cdMask);
+ toolSlots[i] = slotUI;
+ }
+
+ AssignArrayRefs(toolHUD, "_slots", toolSlots, report);
+
+ // ── Boss 血条(BossHPBar)────────────────────────────────────────
+ GameObject bossBarGo = GetOrCreateChild(hudRootGo.transform, "BossHPBar").gameObject;
+ bossBarGo.SetActive(false);
+ BossHPBar bossHPBar = GetOrAddComponent(bossBarGo);
+
+ GameObject bossNameGo = GetOrCreateChild(bossBarGo.transform, "BossName").gameObject;
+ TMP_Text bossName = GetOrAddComponent(bossNameGo);
+ bossName.text = "Boss 名称";
+ GameObject bossHPFillGo = GetOrCreateChild(bossBarGo.transform, "HPFill").gameObject;
+ Image bossHPFill = GetOrAddComponent(bossHPFillGo);
+ bossHPFill.type = Image.Type.Filled;
+ bossHPFill.fillMethod = Image.FillMethod.Horizontal;
+ bossHPFill.fillAmount = 1f;
+ GameObject phaseRootGo = GetOrCreateChild(bossBarGo.transform, "PhaseMarkersRoot").gameObject;
+
+ AssignRef(bossHPBar, "_bossNameText", bossName);
+ AssignRef(bossHPBar, "_hpFill", bossHPFill);
+ AssignRef(bossHPBar, "_phaseMarkersRoot", phaseRootGo.transform);
+
+ // ── 状态效果 HUD(StatusEffectHUD)──────────────────────────────
+ GameObject statusHUDGo = GetOrCreateChild(hudRootGo.transform, "StatusEffectHUD").gameObject;
+ StatusEffectHUD statusHUD = GetOrAddComponent(statusHUDGo);
+
+ GameObject statusTemplateGo = GetOrCreateChild(statusHUDGo.transform, "SlotTemplate").gameObject;
+ statusTemplateGo.SetActive(false);
+ GetOrAddComponent(statusTemplateGo);
+ GameObject statusContainerGo = GetOrCreateChild(statusHUDGo.transform, "Container").gameObject;
+ var statusLayout = GetOrAddComponent(statusContainerGo);
+ statusLayout.childForceExpandWidth = false;
+ statusLayout.spacing = 4f;
+
+ AssignRef(statusHUD, "_slotTemplate", statusTemplateGo);
+ AssignRef(statusHUD, "_container", statusContainerGo.transform);
+
+ // ── 任务追踪(QuestTracker)──────────────────────────────────────
+ GameObject questTrackerGo = GetOrCreateChild(hudRootGo.transform, "QuestTracker").gameObject;
+ QuestTrackerWidget questWidget = GetOrAddComponent(questTrackerGo);
+
+ GameObject questTitleGo = GetOrCreateChild(questTrackerGo.transform, "QuestTitle").gameObject;
+ TMP_Text questTitle = GetOrAddComponent(questTitleGo);
+ questTitle.text = "任务名称";
+ GameObject objTemplateGo = GetOrCreateChild(questTrackerGo.transform, "ObjectiveRowTemplate").gameObject;
+ objTemplateGo.SetActive(false);
+ GetOrAddComponent(objTemplateGo);
+ GameObject objContainerGo = GetOrCreateChild(questTrackerGo.transform, "ObjectiveContainer").gameObject;
+ var objLayout = GetOrAddComponent(objContainerGo);
+ objLayout.childForceExpandWidth = false;
+ objLayout.spacing = 2f;
+
+ AssignRef(questWidget, "_questTitleText", questTitle);
+ AssignRef(questWidget, "_objectiveRowTemplate", objTemplateGo);
+ AssignRef(questWidget, "_objectiveContainer", objContainerGo.transform);
+
+ // ── HUDController 子组件引用 ──────────────────────────────────────
+ AssignRef(hudCtrl, "_hpContainer", hpContainerGo.transform);
+ AssignRef(hudCtrl, "_soulGaugeFill", soulFill);
+ AssignRef(hudCtrl, "_spiritGaugeFill", spiritFill);
+ AssignRef(hudCtrl, "_lingZhuText", lingZhuText);
+ AssignRef(hudCtrl, "_springContainer", springContainerGo.transform);
+ AssignRef(hudCtrl, "_interactPromptWidget", interactWidget);
+ AssignArrayRefs(hudCtrl, "_formIcons", formImages, report);
+
+ // ── 事件频道 ──────────────────────────────────────────────────────
+ AssignAsset(hudCtrl, "_onHPChanged", report, true, "EVT_HPChanged", "EVT_PlayerHPChanged");
+ AssignAsset(hudCtrl, "_onMaxHPChanged", report, false, "EVT_MaxHPChanged", "EVT_PlayerMaxHPChanged");
+ AssignAsset(hudCtrl, "_onSoulPowerChanged", report, false, "EVT_SoulPowerChanged", "EVT_MagicPowerChanged");
+ AssignAsset(hudCtrl, "_onSpiritPowerChanged", report, false, "EVT_SpiritPowerChanged");
+ AssignAsset(hudCtrl, "_onLingZhuChanged", report, false, "EVT_LingZhuChanged", "EVT_CurrencyChanged");
+ AssignAsset(hudCtrl, "_onSpringChargesChanged", report, false, "EVT_SpringChargesChanged", "EVT_SpringCharges");
+ AssignAsset(hudCtrl, "_onFormChanged", report, false, "EVT_FormChanged");
+
+ AssignAsset(interactWidget, "_onShowPrompt", report, false, "EVT_ShowInteractPrompt", "EVT_InteractPromptShow");
+ AssignAsset(interactWidget, "_onHidePrompt", report, false, "EVT_HideInteractPrompt", "EVT_InteractPromptHide");
+
+ AssignAsset(bossHPBar, "_onBossFightToggled", report, false, "EVT_BossFightToggled", "EVT_BossFightStarted");
+ AssignAsset(bossHPBar, "_onBossHPChanged", report, false, "EVT_BossHPChanged");
+ AssignAsset(bossHPBar, "_onBossHPMaxSet", report, false, "EVT_BossHPMaxSet");
+ AssignAsset(bossHPBar, "_onBossNameSet", report, false, "EVT_BossNameSet");
+ AssignAsset(bossHPBar, "_onBossPhaseThreshold", report, false, "EVT_BossPhaseThreshold");
+
+ AssignAsset(statusHUD, "_onStatusEffectApplied", report, false, "EVT_StatusEffectApplied");
+ AssignAsset(statusHUD, "_onStatusEffectExpired", report, false, "EVT_StatusEffectExpired");
+
+ AssignAsset(questWidget, "_onQuestStarted", report, false, "EVT_QuestStarted");
+ AssignAsset(questWidget, "_onQuestCompleted", report, false, "EVT_QuestCompleted");
+ AssignAsset(questWidget, "_onQuestFailed", report, false, "EVT_QuestFailed");
+ AssignAsset(questWidget, "_onQuestAbandoned", report, false, "EVT_QuestAbandoned");
+ AssignAsset(questWidget, "_onQuestReadyToComplete", report, false, "EVT_QuestReadyToComplete");
+ AssignAsset(questWidget, "_onObjectiveBatchUpdated", report, false, "EVT_QuestObjectiveBatchUpdated");
+
+ AssignAsset(toolHUD, "_onToolUsed", report, false, "EVT_ToolUsed");
+
+ // ── 手工步骤说明 ──────────────────────────────────────────────────
+ report.Add("HUDController._hpCellPrefab:请将 HP 格子 Prefab 赋给该字段。");
+ report.Add("HUDController._springIconPrefab:请将回春图标 Prefab 赋给该字段。");
+ report.Add("BossHPBar._phaseMarkerPrefab:请将阶段标记点 Prefab 赋给该字段。");
+ report.Add("StatusEffectHUD._slotConfigs:请在 Inspector 中配置各状态效果的图标映射。");
+
+ Undo.CollapseUndoOperations(undoGroup);
+ MarkDirtyAndLog("HUD Canvas 脚手架", canvasGo, report);
+ }
+
+ // ─────────────────────────────────────────────────────────────────────
+ // Private helpers
+ // ─────────────────────────────────────────────────────────────────────
+
+ ///
+ /// 在活动场景中查找或创建 HUD Canvas。
+ /// 查找顺序:
+ /// 1. 遍历场景根节点中的直接同名节点
+ /// 2. 遍历各根节点下的 [UI]/UIRoot/{name} 或 UIRoot/{name} 子路径
+ /// 若均不存在则新建 Canvas,并优先挂载至 UIRoot(兼容 ScaffoldPersistentScene 层级);
+ /// 若场景中不存在 UIRoot,则回退到场景根层并发出警告。
+ ///
+ private static GameObject GetOrCreateRootCanvas(string name, int sortOrder)
+ {
+ Scene scene = SceneManager.GetActiveScene();
+
+ // ── Phase 1: 搜索已存在的 Canvas ─────────────────────────────────
+ foreach (GameObject root in scene.GetRootGameObjects())
+ {
+ if (root.name == name)
+ return root;
+
+ // 兼容 ScaffoldPersistentScene 层级:[Persistent] ▸ [UI] ▸ UIRoot ▸ HUD Canvas
+ foreach (string path in new[] { $"[UI]/UIRoot/{name}", $"UIRoot/{name}", name })
+ {
+ Transform found = root.transform.Find(path);
+ if (found != null) return found.gameObject;
+ }
+ }
+
+ // ── Phase 2: 定位 UIRoot(Canvas 的正确父节点)───────────────────
+ Transform uiRoot = null;
+ foreach (GameObject root in scene.GetRootGameObjects())
+ {
+ uiRoot = root.transform.Find("[UI]/UIRoot")
+ ?? root.transform.Find("UIRoot");
+ if (uiRoot != null) break;
+ }
+
+ if (uiRoot == null)
+ Debug.LogWarning(
+ "[HUDScaffold] 未找到 UIRoot(期望路径:[Persistent]/[UI]/UIRoot)。" +
+ "将在场景根层创建 HUD Canvas。建议先执行 BaseGames/Scene/Setup/Scaffold Persistent Scene。");
+
+ // ── Phase 3: 创建 Canvas 并挂载至正确父节点 ──────────────────────
+ GameObject canvasGo = new GameObject(name);
+ Undo.RegisterCreatedObjectUndo(canvasGo, $"Create {name}");
+
+ if (uiRoot != null)
+ canvasGo.transform.SetParent(uiRoot, false);
+
+ Canvas canvas = canvasGo.AddComponent