diff --git a/Assets/GameContent/Feature_MainUI/Prefabs/Old/Play Tool Panel.prefab b/Assets/GameContent/Feature_MainUI/Prefabs/Old/Play Tool Panel.prefab index b7703b005..8584806b3 100644 --- a/Assets/GameContent/Feature_MainUI/Prefabs/Old/Play Tool Panel.prefab +++ b/Assets/GameContent/Feature_MainUI/Prefabs/Old/Play Tool Panel.prefab @@ -598,7 +598,6 @@ RectTransform: - {fileID: 2435851631326673332} - {fileID: 3369822658199011853} - {fileID: 1952989201910221321} - - {fileID: 7001172210609801577} - {fileID: 3098988001922718290} - {fileID: 5986227694117348860} - {fileID: 4753076094804246705} @@ -631,81 +630,6 @@ MonoBehaviour: m_EditorClassIdentifier: objWidth: 700 objHeight: 550 ---- !u!1 &7868860406131582412 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 7001172210609801577} - - component: {fileID: 5984596302561387657} - - component: {fileID: 756790148796958745} - m_Layer: 5 - m_Name: Fade Image - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 0 ---- !u!224 &7001172210609801577 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 7868860406131582412} - 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: 5358297362873264388} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 0, y: 0} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!222 &5984596302561387657 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 7868860406131582412} - m_CullTransparentMesh: 1 ---- !u!114 &756790148796958745 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 7868860406131582412} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_Sprite: {fileID: 21300000, guid: 217208fd7d83b3c4a8e9a8e08baec32c, type: 3} - m_Type: 0 - m_PreserveAspect: 0 - m_FillCenter: 1 - m_FillMethod: 4 - m_FillAmount: 1 - m_FillClockwise: 1 - m_FillOrigin: 0 - m_UseSpriteMesh: 0 - m_PixelsPerUnitMultiplier: 1 --- !u!1001 &5111124973336394898 PrefabInstance: m_ObjectHideFlags: 0 diff --git a/Assets/GameContent/Feature_MainUI/Prefabs/Screen Transition Panel.prefab b/Assets/GameContent/Feature_MainUI/Prefabs/Screen Transition Panel.prefab new file mode 100644 index 000000000..60f49686b --- /dev/null +++ b/Assets/GameContent/Feature_MainUI/Prefabs/Screen Transition Panel.prefab @@ -0,0 +1,395 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &100100 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 100101} + - component: {fileID: 100102} + m_Layer: 5 + m_Name: Screen Transition Panel + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &100101 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 100100} + 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: 200101} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &100102 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 100100} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6b517be3c5ca46bdad6d13b94cb1b179, type: 3} + m_Name: + m_EditorClassIdentifier: + transitionVisualRoot: {fileID: 200100} + overlayImage: {fileID: 300103} + shutterRoot: {fileID: 400101} + shutterTop: {fileID: 500103} + shutterBottom: {fileID: 600103} +--- !u!1 &200100 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 200101} + - component: {fileID: 200102} + - component: {fileID: 200103} + m_Layer: 5 + m_Name: Transition Visual Root + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &200101 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 200100} + 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: 300101} + - {fileID: 400101} + m_Father: {fileID: 100101} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &200102 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 200100} + m_CullTransparentMesh: 1 +--- !u!114 &200103 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 200100} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 0, b: 0, a: 0} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &300100 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 300101} + - component: {fileID: 300102} + - component: {fileID: 300103} + m_Layer: 5 + m_Name: Overlay Image + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &300101 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 300100} + 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: 200101} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &300102 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 300100} + m_CullTransparentMesh: 1 +--- !u!114 &300103 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 300100} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 0, b: 0, a: 0} + m_RaycastTarget: 0 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &400100 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 400101} + m_Layer: 5 + m_Name: Shutter Root + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &400101 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 400100} + 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: 500101} + - {fileID: 600101} + m_Father: {fileID: 200101} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &500100 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 500101} + - component: {fileID: 500102} + - component: {fileID: 500103} + m_Layer: 5 + m_Name: Shutter Top + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &500101 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 500100} + 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: 400101} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.5} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 1} + m_Pivot: {x: 0.5, y: 1} +--- !u!222 &500102 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 500100} + m_CullTransparentMesh: 1 +--- !u!114 &500103 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 500100} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 0, b: 0, a: 1} + m_RaycastTarget: 0 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &600100 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 600101} + - component: {fileID: 600102} + - component: {fileID: 600103} + m_Layer: 5 + m_Name: Shutter Bottom + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &600101 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 600100} + 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: 400101} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 1} + m_Pivot: {x: 0.5, y: 0} +--- !u!222 &600102 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 600100} + m_CullTransparentMesh: 1 +--- !u!114 &600103 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 600100} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 0, b: 0, a: 1} + m_RaycastTarget: 0 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 diff --git a/Assets/GameContent/Feature_MainUI/Prefabs/Screen Transition Panel.prefab.meta b/Assets/GameContent/Feature_MainUI/Prefabs/Screen Transition Panel.prefab.meta new file mode 100644 index 000000000..1815e9974 --- /dev/null +++ b/Assets/GameContent/Feature_MainUI/Prefabs/Screen Transition Panel.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 3923593479c745bdb809777da8333e7e +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scenes/Persistence.unity b/Assets/Scenes/Persistence.unity index 41c4b0066..f6a8e81dc 100644 --- a/Assets/Scenes/Persistence.unity +++ b/Assets/Scenes/Persistence.unity @@ -8393,6 +8393,7 @@ RectTransform: - {fileID: 923998313} - {fileID: 1867622714} - {fileID: 3100100002} + - {fileID: 3100101002} m_Father: {fileID: 1110722291} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} @@ -9695,6 +9696,24 @@ PrefabInstance: m_AddedGameObjects: [] m_AddedComponents: [] m_SourcePrefab: {fileID: 100100000, guid: 0bd336c33b9dc77498582232b543e604, type: 3} +--- !u!1001 &3100101000 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + serializedVersion: 3 + m_TransformParent: {fileID: 2091451641} + m_Modifications: [] + m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 3923593479c745bdb809777da8333e7e, type: 3} +--- !u!224 &3100101002 stripped +RectTransform: + m_CorrespondingSourceObject: {fileID: 100101, guid: 3923593479c745bdb809777da8333e7e, type: 3} + m_PrefabInstance: {fileID: 3100101000} + m_PrefabAsset: {fileID: 0} --- !u!1660057539 &9223372036854775807 SceneRoots: m_ObjectHideFlags: 0 diff --git a/Assets/Scripts/Dialog System/BaseYarnCommand.cs b/Assets/Scripts/Dialog System/BaseYarnCommand.cs index 4f4c24820..ba9fca2ba 100644 --- a/Assets/Scripts/Dialog System/BaseYarnCommand.cs +++ b/Assets/Scripts/Dialog System/BaseYarnCommand.cs @@ -47,31 +47,73 @@ namespace AibisDream [YarnCommand("fade_in")] public static IEnumerator FadeIn(float duration = 1) { - var panel = UIManager.Instance.GetPanel(); + var panel = UIManager.Instance.GetPanel(); return panel.FadeInAsync(duration); } [YarnCommand("fade_out")] public static IEnumerator FadeOut(float duration = 1) { - var panel = UIManager.Instance.GetPanel(); + var panel = UIManager.Instance.GetPanel(); return panel.FadeOutAsync(duration); } [YarnCommand("fade_in_sync")] public static void FadeInSync(float duration = 1) { - var panel = UIManager.Instance.GetPanel(); + var panel = UIManager.Instance.GetPanel(); panel.FadeInSync(duration); } [YarnCommand("fade_out_sync")] public static void FadeOutSync(float duration = 1) { - var panel = UIManager.Instance.GetPanel(); + var panel = UIManager.Instance.GetPanel(); panel.FadeOutSync(duration); } + [YarnCommand("fade_in_white")] + public static IEnumerator FadeInWhite(float duration = 1) + { + var panel = UIManager.Instance.GetPanel(); + return panel.FadeInWhiteAsync(duration); + } + + [YarnCommand("flash_white")] + public static IEnumerator FlashWhite(float duration = 0.2f) + { + var panel = UIManager.Instance.GetPanel(); + return panel.FlashWhite(duration); + } + + [YarnCommand("wipe_in")] + public static IEnumerator WipeIn(float duration = 0.6f) + { + var panel = UIManager.Instance.GetPanel(); + return panel.WipeInAsync(duration); + } + + [YarnCommand("wipe_out")] + public static IEnumerator WipeOut(float duration = 0.6f) + { + var panel = UIManager.Instance.GetPanel(); + return panel.WipeOutAsync(duration); + } + + [YarnCommand("shutter_in")] + public static IEnumerator ShutterIn(float duration = 0.6f) + { + var panel = UIManager.Instance.GetPanel(); + return panel.ShutterInAsync(duration); + } + + [YarnCommand("shutter_out")] + public static IEnumerator ShutterOut(float duration = 0.6f) + { + var panel = UIManager.Instance.GetPanel(); + return panel.ShutterOutAsync(duration); + } + [YarnCommand("show_obj")] public static IEnumerator ShowObj(string picName, float duration = 1) { diff --git a/Assets/Scripts/FixSystemNew/States/CoreFixCues.cs b/Assets/Scripts/FixSystemNew/States/CoreFixCues.cs index 475c08bbb..ae0a3a799 100644 --- a/Assets/Scripts/FixSystemNew/States/CoreFixCues.cs +++ b/Assets/Scripts/FixSystemNew/States/CoreFixCues.cs @@ -74,7 +74,7 @@ namespace AibisDream.FixSystem { // 切换相机 yield return CameraKit.Instance.SwitchCamera(CameraEnum.BodyModuleCenter); - yield return UIManager.Instance.GetPanel().FadeOutAsync(0.5f); + yield return UIManager.Instance.GetPanel().FadeOutAsync(0.5f); yield return new WaitForSeconds(0.5f); yield return CameraKit.Instance.SwitchCamera(CameraEnum.BodyModule); if (FixPanelSystem.Instance.ShouldAutoStartOnHeadEntry) diff --git a/Assets/Scripts/FixSystemNew/States/CutFixCues.cs b/Assets/Scripts/FixSystemNew/States/CutFixCues.cs index aa69181bf..fb5a7953b 100644 --- a/Assets/Scripts/FixSystemNew/States/CutFixCues.cs +++ b/Assets/Scripts/FixSystemNew/States/CutFixCues.cs @@ -35,20 +35,20 @@ namespace AibisDream.FixSystem } yield return CameraKit.Instance.SwitchCamera(CameraEnum.CutEmo); - yield return UIManager.Instance.GetPanel().FadeInAsync(0.1f); + yield return UIManager.Instance.GetPanel().FadeInAsync(0.1f); yield return CameraKit.Instance.SwitchCamera(CameraEnum.CutEmoDeep); - yield return UIManager.Instance.GetPanel().FadeOutAsync(0.1f); + yield return UIManager.Instance.GetPanel().FadeOutAsync(0.1f); yield return cuttingManager.StartCutting(bodyModule); } public IEnumerator Exit(FixTransition transition) { // 无 - yield return UIManager.Instance.GetPanel().FadeInAsync(0.1f); + yield return UIManager.Instance.GetPanel().FadeInAsync(0.1f); var cuttingManager = FixSystemCenter.SystemDic.Get(); cuttingManager.ClearCutLine(); yield return CameraKit.Instance.SwitchCamera(CameraEnum.CutEmo); - yield return UIManager.Instance.GetPanel().FadeOutAsync(0.1f); + yield return UIManager.Instance.GetPanel().FadeOutAsync(0.1f); } } @@ -80,20 +80,20 @@ namespace AibisDream.FixSystem } yield return CameraKit.Instance.SwitchCamera(CameraEnum.CutMemory); - yield return UIManager.Instance.GetPanel().FadeInAsync(0.1f); + yield return UIManager.Instance.GetPanel().FadeInAsync(0.1f); yield return CameraKit.Instance.SwitchCamera(CameraEnum.CutMemoryDeep); - yield return UIManager.Instance.GetPanel().FadeOutAsync(0.1f); + yield return UIManager.Instance.GetPanel().FadeOutAsync(0.1f); yield return cuttingManager.StartCutting(bodyModule); } public IEnumerator Exit(FixTransition transition) { - yield return UIManager.Instance.GetPanel().FadeInAsync(0.1f); + yield return UIManager.Instance.GetPanel().FadeInAsync(0.1f); var cuttingManager = FixSystemCenter.SystemDic.Get(); cuttingManager.ClearCutLine(); yield return CameraKit.Instance.SwitchCamera(CameraEnum.CutMemory); - yield return UIManager.Instance.GetPanel().FadeOutAsync(0.1f); + yield return UIManager.Instance.GetPanel().FadeOutAsync(0.1f); } } @@ -124,19 +124,19 @@ namespace AibisDream.FixSystem } yield return CameraKit.Instance.SwitchCamera(CameraEnum.CutLogic); - yield return UIManager.Instance.GetPanel().FadeInAsync(0.1f); + yield return UIManager.Instance.GetPanel().FadeInAsync(0.1f); yield return CameraKit.Instance.SwitchCamera(CameraEnum.CutLogicDeep); - yield return UIManager.Instance.GetPanel().FadeOutAsync(0.1f); + yield return UIManager.Instance.GetPanel().FadeOutAsync(0.1f); yield return cuttingManager.StartCutting(bodyModule); } public IEnumerator Exit(FixTransition transition) { - yield return UIManager.Instance.GetPanel().FadeInAsync(0.1f); + yield return UIManager.Instance.GetPanel().FadeInAsync(0.1f); var cuttingManager = FixSystemCenter.SystemDic.Get(); cuttingManager.ClearCutLine(); yield return CameraKit.Instance.SwitchCamera(CameraEnum.CutLogic); - yield return UIManager.Instance.GetPanel().FadeOutAsync(0.1f); + yield return UIManager.Instance.GetPanel().FadeOutAsync(0.1f); } } } diff --git a/Assets/Scripts/FixSystemNew/States/HuoShanFixCues.cs b/Assets/Scripts/FixSystemNew/States/HuoShanFixCues.cs index 20c6dd11a..8ebe2186b 100644 --- a/Assets/Scripts/FixSystemNew/States/HuoShanFixCues.cs +++ b/Assets/Scripts/FixSystemNew/States/HuoShanFixCues.cs @@ -27,11 +27,11 @@ namespace AibisDream.FixSystem // 切换到表达相机 yield return TimelineCenter.Instance.PlayTimelineAsync("透镜/透镜in"); yield return CameraKit.Instance.SwitchCamera(CameraEnum.Expression); - yield return UIManager.Instance.GetPanel().FadeInAsync(0.5f); + yield return UIManager.Instance.GetPanel().FadeInAsync(0.5f); expressionManager.OpenView(); // 切换到深度表达相机 yield return CameraKit.Instance.SwitchCamera(CameraEnum.ExpressionDeep); - yield return UIManager.Instance.GetPanel().FadeOutAsync(0.5f); + yield return UIManager.Instance.GetPanel().FadeOutAsync(0.5f); yield return TimelineCenter.Instance.PlayTimelineAsync("火山表达模块/火山表达深入"); } @@ -39,7 +39,7 @@ namespace AibisDream.FixSystem { var expressionManager = FixSystemCenter.SystemDic.Get(); var bodyModuleSystem = FixSystemCenter.SystemDic.Get(); - yield return UIManager.Instance.GetPanel().FadeInAsync(0.5f); + yield return UIManager.Instance.GetPanel().FadeInAsync(0.5f); // 重置身体模块 FixPanelSystem.GetRepairPanel().ResetPlug(); @@ -47,7 +47,7 @@ namespace AibisDream.FixSystem // 关闭表达系统视图 expressionManager.CloseView(); yield return CameraKit.Instance.SwitchCamera(CameraEnum.Expression); - yield return UIManager.Instance.GetPanel().FadeOutAsync(0.5f); + yield return UIManager.Instance.GetPanel().FadeOutAsync(0.5f); yield return CameraKit.Instance.SwitchCamera(CameraEnum.BodyModule); yield return TimelineCenter.Instance.PlayTimelineAsync("透镜/透镜out"); yield break; @@ -69,10 +69,10 @@ namespace AibisDream.FixSystem } yield return CameraKit.Instance.SwitchCamera(CameraEnum.Emo); - yield return UIManager.Instance.GetPanel().FadeInAsync(0.5f); + yield return UIManager.Instance.GetPanel().FadeInAsync(0.5f); //emoManager.OpenView(); yield return CameraKit.Instance.SwitchCamera(CameraEnum.EmoDeep); - yield return UIManager.Instance.GetPanel().FadeOutAsync(0.5f); + yield return UIManager.Instance.GetPanel().FadeOutAsync(0.5f); } public IEnumerator Exit(FixTransition transition) @@ -102,14 +102,14 @@ namespace AibisDream.FixSystem FixPanelSystem.GetRepairPanel().ResetPlug(); // 切换到分析模式相机 - yield return UIManager.Instance.GetPanel().FadeInAsync(0.5f); + yield return UIManager.Instance.GetPanel().FadeInAsync(0.5f); yield return CameraKit.Instance.SwitchCamera(CameraEnum.AnalysisMode); // 进入分析模式 if (analysisModeManager != null) { analysisModeManager.OnEnter(); } - yield return UIManager.Instance.GetPanel().FadeOutAsync(0.5f); + yield return UIManager.Instance.GetPanel().FadeOutAsync(0.5f); } public IEnumerator Exit(FixTransition transition) @@ -117,7 +117,7 @@ namespace AibisDream.FixSystem float duration = 0.5f; var analysisModeManager = FixSystemCenter.SystemDic.Get(); - yield return UIManager.Instance.GetPanel().FadeInAsync(duration); + yield return UIManager.Instance.GetPanel().FadeInAsync(duration); // 退出分析模式 if (analysisModeManager != null) @@ -125,7 +125,7 @@ namespace AibisDream.FixSystem analysisModeManager.OnExit(); } - yield return UIManager.Instance.GetPanel().FadeOutAsync(duration); + yield return UIManager.Instance.GetPanel().FadeOutAsync(duration); } } @@ -150,13 +150,13 @@ namespace AibisDream.FixSystem if (salesManager != null) { // FadeIn - yield return UIManager.Instance.GetPanel().FadeInAsync(0.5f); + yield return UIManager.Instance.GetPanel().FadeInAsync(0.5f); // 打开销售系统视图,传入systemView参数 salesManager.OpenView(); // FadeOut - yield return UIManager.Instance.GetPanel().FadeOutAsync(0.5f); + yield return UIManager.Instance.GetPanel().FadeOutAsync(0.5f); // 销售模块使用自身的气泡槽位;缺失时再回退到 ScreenSystem,避免读到错误的槽位配置 if (BubbleSlotKit.Instance.TryGet(BubbleSlotEnum.Sales, out _)) @@ -177,7 +177,7 @@ namespace AibisDream.FixSystem float duration = 0.5f; var salesManager = FixSystemCenter.SystemDic.Get(); - yield return UIManager.Instance.GetPanel().FadeInAsync(duration); + yield return UIManager.Instance.GetPanel().FadeInAsync(duration); // 关闭销售系统视图 if (salesManager != null) @@ -185,7 +185,7 @@ namespace AibisDream.FixSystem salesManager.CloseView(); } // 关闭前先播放钳子放下盖子,完成后再结 - yield return UIManager.Instance.GetPanel().FadeOutAsync(duration); + yield return UIManager.Instance.GetPanel().FadeOutAsync(duration); yield return TimelineCenter.Instance.PlayTimelineAsync("钳子/放下盖子"); yield return null; } diff --git a/Assets/Scripts/FixSystemNew/States/PeipeiFixCues.cs b/Assets/Scripts/FixSystemNew/States/PeipeiFixCues.cs index bd2a04df1..81dd78c2f 100644 --- a/Assets/Scripts/FixSystemNew/States/PeipeiFixCues.cs +++ b/Assets/Scripts/FixSystemNew/States/PeipeiFixCues.cs @@ -25,12 +25,12 @@ namespace AibisDream.FixSystem FixPanelSystem.GetRepairPanel().ResetPlug(); // 切换相机 yield return CameraKit.Instance.SwitchCamera(CameraEnum.UF); - yield return UIManager.Instance.GetPanel().FadeInAsync(0.5f); + yield return UIManager.Instance.GetPanel().FadeInAsync(0.5f); ufSystem.OpenUFView(); yield return CameraKit.Instance.SwitchCamera(CameraEnum.EyeDeep); eyeSystem.OnEnter(); BubbleSlotKit.Instance.LoadBubbles(BubbleSlotEnum.Eye); - yield return UIManager.Instance.GetPanel().FadeOutAsync(0.5f); + yield return UIManager.Instance.GetPanel().FadeOutAsync(0.5f); } public IEnumerator Exit(FixTransition transition) @@ -38,11 +38,11 @@ namespace AibisDream.FixSystem float duration = 0.5f; var ufSystem = FixSystemCenter.SystemDic.Get(); var eyeSystem = FixSystemCenter.SystemDic.Get(); - yield return UIManager.Instance.GetPanel().FadeInAsync(duration); + yield return UIManager.Instance.GetPanel().FadeInAsync(duration); eyeSystem.OnExit(); ufSystem.CloseUFView(); yield return CameraKit.Instance.SwitchCamera(CameraEnum.UF); - yield return UIManager.Instance.GetPanel().FadeOutAsync(duration); + yield return UIManager.Instance.GetPanel().FadeOutAsync(duration); } } @@ -69,11 +69,11 @@ namespace AibisDream.FixSystem FixPanelSystem.GetRepairPanel().ResetPlug(); // 切换相机 yield return CameraKit.Instance.SwitchCamera(CameraEnum.Eye); - yield return UIManager.Instance.GetPanel().FadeInAsync(0.5f); + yield return UIManager.Instance.GetPanel().FadeInAsync(0.5f); yield return CameraKit.Instance.SwitchCamera(CameraEnum.EyeDeep); eyeSystem.OnEnter(); BubbleSlotKit.Instance.LoadBubbles(BubbleSlotEnum.Eye); - yield return UIManager.Instance.GetPanel().FadeOutAsync(0.5f); + yield return UIManager.Instance.GetPanel().FadeOutAsync(0.5f); } public IEnumerator EnterImmediate(FixTransition transition) @@ -89,11 +89,11 @@ namespace AibisDream.FixSystem var bodyModuleSystem = FixSystemCenter.SystemDic.Get(); float duration = 0.5f; var eyeSystem = FixSystemCenter.SystemDic.Get(); - yield return UIManager.Instance.GetPanel().FadeInAsync(duration); + yield return UIManager.Instance.GetPanel().FadeInAsync(duration); yield return CameraKit.Instance.SwitchCamera(CameraEnum.Eye); eyeSystem.OnExit(); yield return new WaitForSeconds(0.1f); - yield return UIManager.Instance.GetPanel().FadeOutAsync(duration); + yield return UIManager.Instance.GetPanel().FadeOutAsync(duration); //关上 var eyeModule = bodyModuleSystem.FindBodyModuleByType(); yield return eyeModule.CloseEye(); @@ -120,9 +120,9 @@ namespace AibisDream.FixSystem FixPanelSystem.GetRepairPanel().ResetPlug(); // 相机聚焦到目标位 yield return CameraKit.Instance.SwitchCamera(CameraEnum.Memory); - yield return UIManager.Instance.GetPanel().FadeInAsync(duration); + yield return UIManager.Instance.GetPanel().FadeInAsync(duration); memorySystem.OnEnter(); - yield return UIManager.Instance.GetPanel().FadeOutAsync(duration); + yield return UIManager.Instance.GetPanel().FadeOutAsync(duration); BubbleSlotKit.Instance.LoadBubbles(BubbleSlotEnum.Memory); } @@ -141,10 +141,10 @@ namespace AibisDream.FixSystem { float duration = 0.5f; var memorySystem = FixSystemCenter.SystemDic.Get(); - yield return UIManager.Instance.GetPanel().FadeInAsync(duration); + yield return UIManager.Instance.GetPanel().FadeInAsync(duration); memorySystem.OnExit(); memorySystem.CloseMemoryView(); - yield return UIManager.Instance.GetPanel().FadeOutAsync(duration); + yield return UIManager.Instance.GetPanel().FadeOutAsync(duration); yield return CameraKit.Instance.SwitchCamera(CameraEnum.BodyModule); memorySystem.PullMemoryProjector(); } diff --git a/Assets/Scripts/Framework/OtherKit/FadeKit.cs b/Assets/Scripts/Framework/OtherKit/FadeKit.cs index 7de1574e4..5449fb880 100644 --- a/Assets/Scripts/Framework/OtherKit/FadeKit.cs +++ b/Assets/Scripts/Framework/OtherKit/FadeKit.cs @@ -9,42 +9,74 @@ namespace AibisDream.Framework { public static IEnumerator FadeInAsync(this Image image, float duration, bool useUnscaledTime = false) { - image.gameObject.SetActive(true); - var tweener = image.DOBlendableColor(Color.white, duration); - if (useUnscaledTime) + var tweener = StartFade(image, 1f, duration, useUnscaledTime); + if (tweener != null) { - tweener.SetUpdate(true); + yield return tweener.WaitForCompletion(); } - - yield return tweener.WaitForCompletion(); } public static void FadeIn(this Image image, float duration) { - image.gameObject.SetActive(true); - var tweener = image.DOBlendableColor(Color.white, duration); + StartFade(image, 1f, duration, false); } public static IEnumerator FadeOutAsync(this Image image, float duration, bool useUnscaledTime = false) { - image.gameObject.SetActive(true); - var tweener = image.DOBlendableColor(Color.clear, duration); - if (useUnscaledTime) + var completed = false; + var tweener = StartFade(image, 0f, duration, useUnscaledTime); + if (tweener == null) { - tweener.SetUpdate(true); + image?.gameObject.SetActive(false); + yield break; } + tweener.OnComplete(() => completed = true); yield return tweener.WaitForCompletion(); - image.gameObject.SetActive(false); + if (completed && image != null) + { + image.gameObject.SetActive(false); + } } public static void FadeOut(this Image image, float duration) { - image.gameObject.SetActive(true); - image.DOBlendableColor(Color.clear, duration).onComplete += () => + var tweener = StartFade(image, 0f, duration, false); + if (tweener == null) { - image.gameObject.SetActive(false); - }; + image?.gameObject.SetActive(false); + return; + } + + tweener.OnComplete(() => + { + if (image != null) + { + image.gameObject.SetActive(false); + } + }); + } + + private static Tweener StartFade(Image image, float targetAlpha, float duration, bool useUnscaledTime) + { + if (image == null) + { + return null; + } + + image.DOKill(false); + image.gameObject.SetActive(true); + + duration = Mathf.Max(0f, duration); + if (duration <= 0f) + { + var color = image.color; + color.a = targetAlpha; + image.color = color; + return null; + } + + return image.DOFade(targetAlpha, duration).SetUpdate(useUnscaledTime); } } -} \ No newline at end of file +} diff --git a/Assets/Scripts/Game Loop/GameManager.cs b/Assets/Scripts/Game Loop/GameManager.cs index 589964708..e0c66dbfa 100644 --- a/Assets/Scripts/Game Loop/GameManager.cs +++ b/Assets/Scripts/Game Loop/GameManager.cs @@ -50,9 +50,9 @@ namespace AibisDream /// private IEnumerator AppBootstrapCoroutine() { - var playTool = UIManager.Instance.GetPanel(); - UIManager.Instance.ShowPanel(); - playTool?.ApplyFadeScreenCovered(true); + var transitionPanel = UIManager.Instance.GetPanel(); + UIManager.Instance.ShowPanel(); + transitionPanel?.ApplyScreenCovered(true); yield return LocalizationKit.WaitUntilReady(); @@ -60,9 +60,9 @@ namespace AibisDream yield return LocalizationKit.WaitForUIRefresh(); - if (playTool != null) + if (transitionPanel != null) { - yield return playTool.FadeOutAsync(MainMenuFadeDuration); + yield return transitionPanel.FadeOutAsync(MainMenuFadeDuration); } } @@ -133,7 +133,7 @@ namespace AibisDream private IEnumerator LoadFirstScene() { ChapterController.Instance.UnlockChapter(_currentTalkSceneSo.Value); - yield return UIManager.Instance.GetPanel().FadeInAsync(0.5f); + yield return UIManager.Instance.GetPanel().FadeInAsync(0.5f); yield return SceneLoader.Instance.LoadSceneAsync(_currentTalkSceneSo.Value.firstSceneName); yield return WaitForSceneDialogueReady(); DialogController.Instance.StartDialog(_currentTalkSceneSo.Value.yarnProject); @@ -238,10 +238,12 @@ namespace AibisDream private IEnumerator RestartCoroutine() { var playTool = UIManager.Instance.GetPanel(); + var transitionPanel = UIManager.Instance.GetPanel(); UIManager.Instance.ShowPanel(); - if (playTool != null) + UIManager.Instance.ShowPanel(); + if (transitionPanel != null) { - yield return playTool.FadeInAsync(MainMenuFadeDuration); + yield return transitionPanel.FadeInAsync(MainMenuFadeDuration); } // 清理所有系统注册 @@ -269,9 +271,9 @@ namespace AibisDream yield return LocalizationKit.WaitForUIRefresh(); - if (playTool != null) + if (transitionPanel != null) { - yield return playTool.FadeOutAsync(MainMenuFadeDuration); + yield return transitionPanel.FadeOutAsync(MainMenuFadeDuration); } EventSystem.current?.SetSelectedGameObject(null); @@ -332,7 +334,7 @@ namespace AibisDream { _currentTalkSceneSo.Value = next; ChapterController.Instance.UnlockChapter(_currentTalkSceneSo.Value); - yield return UIManager.Instance.GetPanel().FadeInAsync(); + yield return UIManager.Instance.GetPanel().FadeInAsync(); yield return SceneLoader.Instance.LoadSceneAsync(_currentTalkSceneSo.Value.firstSceneName); yield return WaitForSceneDialogueReady(); DialogController.Instance.StartDialog(_currentTalkSceneSo.Value.yarnProject); diff --git a/Assets/Scripts/SaveSystem/SaveRestoreOrchestrator.cs b/Assets/Scripts/SaveSystem/SaveRestoreOrchestrator.cs index 3d382b18c..f181215a4 100644 --- a/Assets/Scripts/SaveSystem/SaveRestoreOrchestrator.cs +++ b/Assets/Scripts/SaveSystem/SaveRestoreOrchestrator.cs @@ -472,7 +472,7 @@ namespace AibisDream.SaveSystem private static IEnumerator FadeInForRestore() { AddRestoreLog("Begin restore fade in"); - var panel = UIManager.Instance?.GetPanel(); + var panel = UIManager.Instance?.GetPanel(); if (panel != null) { yield return panel.FadeInAsync(RestoreFadeDuration, useUnscaledTime: true); @@ -482,7 +482,7 @@ namespace AibisDream.SaveSystem private static IEnumerator FadeOutForRestore() { AddRestoreLog("End restore fade out"); - var panel = UIManager.Instance?.GetPanel(); + var panel = UIManager.Instance?.GetPanel(); if (panel != null) { yield return panel.FadeOutAsync(RestoreFadeDuration, useUnscaledTime: true); diff --git a/Assets/Scripts/SaveSystem/SaveSnapshot.cs b/Assets/Scripts/SaveSystem/SaveSnapshot.cs index 4312b9195..6d86c8830 100644 --- a/Assets/Scripts/SaveSystem/SaveSnapshot.cs +++ b/Assets/Scripts/SaveSystem/SaveSnapshot.cs @@ -174,7 +174,7 @@ namespace AibisDream.SaveSystem public float saturationWeight; /// - /// 演出遮罩终态:true = 黑屏盖住(FadeIn 完成); + /// 全局遮罩终态:true = 画面被完全盖住; /// false = 画面可见(FadeOut 完成或遮罩未启用)。不记录转场中间 alpha。 /// public bool isFadeScreenCovered; diff --git a/Assets/Scripts/SaveSystem/ScreenSnapshotHelper.cs b/Assets/Scripts/SaveSystem/ScreenSnapshotHelper.cs index c7d0a073c..bfd6e395b 100644 --- a/Assets/Scripts/SaveSystem/ScreenSnapshotHelper.cs +++ b/Assets/Scripts/SaveSystem/ScreenSnapshotHelper.cs @@ -4,8 +4,8 @@ using UnityEngine; namespace AibisDream.SaveSystem { /// - /// screen section 的捕获/还原实现:屏幕后处理饱和度 + PlayToolPanel 遮罩终态(黑屏盖住 / 画面可见)。 - /// screen section:饱和度 + PlayToolPanel 遮罩终态()。 + /// screen section 的捕获/还原实现:屏幕后处理饱和度 + ScreenTransitionPanel 遮罩终态。 + /// screen section:饱和度 + 全局遮罩终态()。 /// 供 委托,避免 Provider 直接依赖 UI 细节。 /// public static class ScreenSnapshotHelper @@ -24,10 +24,10 @@ namespace AibisDream.SaveSystem if (UIManager.Instance != null) { - var panel = UIManager.Instance.GetPanel(); + var panel = UIManager.Instance.GetPanel(); if (panel != null) { - dto.isFadeScreenCovered = panel.CaptureFadeScreenCovered(); + dto.isFadeScreenCovered = panel.CaptureScreenCovered(); } } @@ -52,8 +52,8 @@ namespace AibisDream.SaveSystem return; } - var panel = UIManager.Instance.GetPanel(); - panel?.ApplyFadeScreenCovered(dto.isFadeScreenCovered); + var panel = UIManager.Instance.GetPanel(); + panel?.ApplyScreenCovered(dto.isFadeScreenCovered); } } @@ -66,8 +66,8 @@ namespace AibisDream.SaveSystem } _hasDeferredFadeScreenCovered = false; - var panel = UIManager.Instance?.GetPanel(); - panel?.ApplyFadeScreenCovered(_deferredFadeScreenCovered); + var panel = UIManager.Instance?.GetPanel(); + panel?.ApplyScreenCovered(_deferredFadeScreenCovered); } } } diff --git a/Assets/Scripts/UI/Panel/PlayToolPanel.cs b/Assets/Scripts/UI/Panel/PlayToolPanel.cs index 8b2077f24..4aeabbe03 100644 --- a/Assets/Scripts/UI/Panel/PlayToolPanel.cs +++ b/Assets/Scripts/UI/Panel/PlayToolPanel.cs @@ -11,7 +11,7 @@ using UnityEngine.UI; namespace AibisDream.UI { /// - /// 主要用来放置淡入淡出,图片展示等演出工具 + /// 主要用来放置图片展示、窗口和时间流转等演出工具 /// public class PlayToolPanel : MonoBehaviour, IUIPanel { @@ -26,7 +26,6 @@ namespace AibisDream.UI #region 索引 - private Image _fadeImage; private GameObject _showObjPanel; private Image _showObjImage; private Image _fullScreenImage; @@ -46,7 +45,6 @@ namespace AibisDream.UI private void InitRefs() { - _fadeImage = transform.Find("Fade Image").GetComponent(); _showObjPanel = transform.Find("Show Obj").gameObject; _showObjImage = _showObjPanel.transform.Find("Obj").GetComponent(); _fullScreenImage = transform.Find("Full Screen Image").GetComponent(); @@ -65,56 +63,6 @@ namespace AibisDream.UI : picName; } - public IEnumerator FadeInAsync(float duration = 1, bool useUnscaledTime = false) - { - return _fadeImage.FadeInAsync(duration, useUnscaledTime); - } - - public IEnumerator FadeOutAsync(float duration = 1, bool useUnscaledTime = false) - { - return _fadeImage.FadeOutAsync(duration, useUnscaledTime); - } - - public void FadeInSync(float duration = 1) - { - StartCoroutine(FadeInAsync(duration)); - } - - public void FadeOutSync(float duration = 1) - { - StartCoroutine(FadeOutAsync(duration)); - } - - /// - /// 捕获遮罩终态:黑屏盖住(FadeIn 完成) vs 画面可见(FadeOut 完成 / HideAll)。 - /// 与 一致——终态以 gameObject.activeSelf 为准(FadeOut 结束会 SetActive(false))。 - /// - public bool CaptureFadeScreenCovered() - { - if (_fadeImage == null) return false; - return _fadeImage.gameObject.activeSelf; - } - - /// - /// 按快照终态还原遮罩(同步设置 active 与颜色,与 终态一致)。 - /// - public void ApplyFadeScreenCovered(bool isCovered) - { - if (_fadeImage == null) return; - - _fadeImage.DOKill(); - if (isCovered) - { - _fadeImage.gameObject.SetActive(true); - _fadeImage.color = Color.white; - } - else - { - _fadeImage.color = Color.clear; - _fadeImage.gameObject.SetActive(false); - } - } - /// /// 显示物体 /// @@ -240,7 +188,7 @@ namespace AibisDream.UI } /// - /// 清理演出层内容,但不影响黑屏遮罩(用于返回主界面时在遮罩下重置状态)。 + /// 清理演出层内容,但不影响全局转场面板(用于返回主界面时在遮罩下重置状态)。 /// public void ClearPresentationEffects() { @@ -265,8 +213,13 @@ namespace AibisDream.UI { var version = ++_timeFlowsVersion; + var transitionPanel = UIManager.Instance.GetPanel(); + // 黑屏淡入 - yield return _fadeImage.FadeInAsync(0.5f); + if (transitionPanel != null) + { + yield return transitionPanel.FadeInAsync(0.5f); + } if (version != _timeFlowsVersion) yield break; // 时间流转 @@ -274,7 +227,10 @@ namespace AibisDream.UI if (version != _timeFlowsVersion) yield break; // 黑屏淡出 - yield return _fadeImage.FadeOutAsync(0.5f); + if (transitionPanel != null) + { + yield return transitionPanel.FadeOutAsync(0.5f); + } } #region 感觉这个面板应该常驻 diff --git a/Assets/Scripts/UI/Panel/ScreenTransitionPanel.cs b/Assets/Scripts/UI/Panel/ScreenTransitionPanel.cs new file mode 100644 index 000000000..1db91f226 --- /dev/null +++ b/Assets/Scripts/UI/Panel/ScreenTransitionPanel.cs @@ -0,0 +1,442 @@ +using System.Collections; +using DG.Tweening; +using UnityEngine; +using UnityEngine.UI; + +namespace AibisDream.UI +{ + /// + /// 全局屏幕转场面板。In 决定遮罩颜色和盖入方式,Out 决定揭出方式。 + /// + public class ScreenTransitionPanel : MonoBehaviour, IUIPanel + { + private enum TransitionVisual + { + None, + Overlay, + Shutter + } + + private const float DefaultWipeDuration = 0.6f; + private const float DefaultShutterDuration = 0.6f; + + [SerializeField] private GameObject transitionVisualRoot; + [SerializeField] private Image overlayImage; + [SerializeField] private RectTransform shutterRoot; + [SerializeField] private Image shutterTop; + [SerializeField] private Image shutterBottom; + + private Color _coverColor = Color.black; + private TransitionVisual _currentVisual = TransitionVisual.None; + private bool _isCovered; + private int _transitionVersion; + + public bool IsOpen => gameObject.activeSelf; + public bool IsCloseable => false; + + private RectTransform OverlayRect => overlayImage.rectTransform; + + private void Awake() + { + ResetVisualsImmediate(); + } + + private void OnDisable() + { + CancelActiveTransition(); + } + + public IEnumerator FadeInAsync(float duration = 1f, bool useUnscaledTime = false) + { + return FadeInInternal(Color.black, duration, useUnscaledTime); + } + + public IEnumerator FadeInWhiteAsync(float duration = 1f, bool useUnscaledTime = false) + { + return FadeInInternal(Color.white, duration, useUnscaledTime); + } + + public IEnumerator FadeOutAsync(float duration = 1f, bool useUnscaledTime = false) + { + var version = BeginTransition(); + PrepareOverlayForFadeOut(); + + duration = Mathf.Max(0f, duration); + if (duration <= 0f) + { + if (version == _transitionVersion) + { + ResetVisualsImmediate(); + } + + yield break; + } + + var tween = overlayImage.DOFade(0f, duration) + .SetUpdate(useUnscaledTime) + .SetTarget(this); + yield return tween.WaitForCompletion(); + + if (version == _transitionVersion) + { + ResetVisualsImmediate(); + } + } + + public void FadeInSync(float duration = 1f) + { + StartCoroutine(FadeInAsync(duration)); + } + + public void FadeOutSync(float duration = 1f) + { + StartCoroutine(FadeOutAsync(duration)); + } + + public IEnumerator FlashWhite(float duration = 0.2f, bool useUnscaledTime = false) + { + var version = BeginTransition(); + PrepareVisibleOverlay(Color.white, 0f); + _isCovered = false; + + duration = Mathf.Max(0f, duration); + if (duration <= 0f) + { + if (version == _transitionVersion) + { + ResetVisualsImmediate(); + } + + yield break; + } + + var halfDuration = duration * 0.5f; + var sequence = DOTween.Sequence() + .Append(overlayImage.DOFade(1f, halfDuration)) + .Append(overlayImage.DOFade(0f, halfDuration)) + .SetUpdate(useUnscaledTime) + .SetTarget(this); + yield return sequence.WaitForCompletion(); + + if (version == _transitionVersion) + { + ResetVisualsImmediate(); + } + } + + public IEnumerator WipeInAsync(float duration = DefaultWipeDuration, bool useUnscaledTime = false) + { + var version = BeginTransition(); + PrepareVisibleOverlay(Color.black, 1f); + _isCovered = false; + + var width = GetTransitionWidth(); + OverlayRect.anchoredPosition = new Vector2(-width, 0f); + duration = Mathf.Max(0f, duration); + if (duration <= 0f) + { + OverlayRect.anchoredPosition = Vector2.zero; + CompleteCover(version); + yield break; + } + + var tween = OverlayRect.DOAnchorPosX(0f, duration) + .SetEase(Ease.InOutQuad) + .SetUpdate(useUnscaledTime) + .SetTarget(this); + yield return tween.WaitForCompletion(); + CompleteCover(version); + } + + public IEnumerator WipeOutAsync(float duration = DefaultWipeDuration, bool useUnscaledTime = false) + { + var version = BeginTransition(); + PrepareOverlayCovered(); + + var width = GetTransitionWidth(); + duration = Mathf.Max(0f, duration); + if (duration <= 0f) + { + OverlayRect.anchoredPosition = new Vector2(width, 0f); + if (version == _transitionVersion) + { + ResetVisualsImmediate(); + } + + yield break; + } + + var tween = OverlayRect.DOAnchorPosX(width, duration) + .SetEase(Ease.InOutQuad) + .SetUpdate(useUnscaledTime) + .SetTarget(this); + yield return tween.WaitForCompletion(); + + if (version == _transitionVersion) + { + ResetVisualsImmediate(); + } + } + + public IEnumerator ShutterInAsync(float duration = DefaultShutterDuration, bool useUnscaledTime = false) + { + var version = BeginTransition(); + _coverColor = Color.black; + PrepareShutter(_coverColor, 0f); + _isCovered = false; + + duration = Mathf.Max(0f, duration); + if (duration <= 0f) + { + SetShutterScale(1f); + CompleteCover(version); + yield break; + } + + var sequence = DOTween.Sequence() + .Join(shutterTop.rectTransform.DOScaleY(1f, duration)) + .Join(shutterBottom.rectTransform.DOScaleY(1f, duration)) + .SetEase(Ease.InOutQuad) + .SetUpdate(useUnscaledTime) + .SetTarget(this); + yield return sequence.WaitForCompletion(); + CompleteCover(version); + } + + public IEnumerator ShutterOutAsync(float duration = DefaultShutterDuration, bool useUnscaledTime = false) + { + var version = BeginTransition(); + if (!transitionVisualRoot.activeSelf) + { + _coverColor = Color.black; + } + + PrepareShutter(_coverColor, 1f); + duration = Mathf.Max(0f, duration); + if (duration <= 0f) + { + SetShutterScale(0f); + if (version == _transitionVersion) + { + ResetVisualsImmediate(); + } + + yield break; + } + + var sequence = DOTween.Sequence() + .Join(shutterTop.rectTransform.DOScaleY(0f, duration)) + .Join(shutterBottom.rectTransform.DOScaleY(0f, duration)) + .SetEase(Ease.InOutQuad) + .SetUpdate(useUnscaledTime) + .SetTarget(this); + yield return sequence.WaitForCompletion(); + + if (version == _transitionVersion) + { + ResetVisualsImmediate(); + } + } + + public bool CaptureScreenCovered() + { + return _isCovered; + } + + public void ApplyScreenCovered(bool isCovered) + { + BeginTransition(); + if (!isCovered) + { + ResetVisualsImmediate(); + return; + } + + PrepareVisibleOverlay(Color.black, 1f); + _isCovered = true; + } + + public void Show() + { + gameObject.SetActive(true); + } + + public void Hide() + { + BeginTransition(); + ResetVisualsImmediate(); + gameObject.SetActive(false); + } + + private IEnumerator FadeInInternal(Color color, float duration, bool useUnscaledTime) + { + var version = BeginTransition(); + var startAlpha = transitionVisualRoot.activeSelf && _currentVisual == TransitionVisual.Overlay + ? overlayImage.color.a + : 0f; + PrepareVisibleOverlay(color, startAlpha); + _isCovered = false; + + duration = Mathf.Max(0f, duration); + if (duration <= 0f) + { + SetImageAlpha(overlayImage, 1f); + CompleteCover(version); + yield break; + } + + var tween = overlayImage.DOFade(1f, duration) + .SetUpdate(useUnscaledTime) + .SetTarget(this); + yield return tween.WaitForCompletion(); + CompleteCover(version); + } + + private int BeginTransition() + { + _transitionVersion++; + CancelActiveTransition(); + return _transitionVersion; + } + + private void CancelActiveTransition() + { + DOTween.Kill(this, false); + overlayImage?.DOKill(false); + if (overlayImage != null) + { + overlayImage.rectTransform.DOKill(false); + } + + shutterTop?.rectTransform.DOKill(false); + shutterBottom?.rectTransform.DOKill(false); + } + + private void PrepareVisibleOverlay(Color color, float alpha) + { + transitionVisualRoot.SetActive(true); + _coverColor = Opaque(color); + _currentVisual = TransitionVisual.Overlay; + + shutterRoot.gameObject.SetActive(false); + overlayImage.gameObject.SetActive(true); + OverlayRect.anchoredPosition = Vector2.zero; + overlayImage.color = WithAlpha(_coverColor, alpha); + } + + private void PrepareOverlayForFadeOut() + { + if (!transitionVisualRoot.activeSelf) + { + PrepareVisibleOverlay(Color.black, 1f); + return; + } + + if (_currentVisual == TransitionVisual.Shutter) + { + PrepareVisibleOverlay(_coverColor, 1f); + return; + } + + var alpha = overlayImage.gameObject.activeSelf ? overlayImage.color.a : 1f; + PrepareVisibleOverlay(_coverColor, alpha); + } + + private void PrepareOverlayCovered() + { + if (!transitionVisualRoot.activeSelf) + { + _coverColor = Color.black; + } + + PrepareVisibleOverlay(_coverColor, 1f); + } + + private void PrepareShutter(Color color, float scaleY) + { + transitionVisualRoot.SetActive(true); + _coverColor = Opaque(color); + _currentVisual = TransitionVisual.Shutter; + + shutterRoot.gameObject.SetActive(true); + shutterTop.gameObject.SetActive(true); + shutterBottom.gameObject.SetActive(true); + shutterTop.color = _coverColor; + shutterBottom.color = _coverColor; + SetShutterScale(scaleY); + + // 完全覆盖帧先准备目标节点,再关闭来源节点,避免跨模式切换时漏出背景。 + overlayImage.gameObject.SetActive(false); + } + + private void CompleteCover(int version) + { + if (version != _transitionVersion) + { + return; + } + + _isCovered = true; + } + + private float GetTransitionWidth() + { + Canvas.ForceUpdateCanvases(); + var rectTransform = transitionVisualRoot.transform as RectTransform; + return Mathf.Max(1f, rectTransform != null ? rectTransform.rect.width : Screen.width); + } + + private void SetShutterScale(float scaleY) + { + var topScale = shutterTop.rectTransform.localScale; + topScale.y = scaleY; + shutterTop.rectTransform.localScale = topScale; + + var bottomScale = shutterBottom.rectTransform.localScale; + bottomScale.y = scaleY; + shutterBottom.rectTransform.localScale = bottomScale; + } + + private void ResetVisualsImmediate() + { + CancelActiveTransition(); + + if (overlayImage != null) + { + overlayImage.gameObject.SetActive(true); + OverlayRect.anchoredPosition = Vector2.zero; + overlayImage.color = Color.clear; + } + + if (shutterRoot != null) + { + SetShutterScale(0f); + shutterRoot.gameObject.SetActive(false); + } + + _coverColor = Color.black; + _currentVisual = TransitionVisual.None; + _isCovered = false; + transitionVisualRoot?.SetActive(false); + } + + private static Color Opaque(Color color) + { + color.a = 1f; + return color; + } + + private static Color WithAlpha(Color color, float alpha) + { + color.a = alpha; + return color; + } + + private static void SetImageAlpha(Graphic graphic, float alpha) + { + var color = graphic.color; + color.a = alpha; + graphic.color = color; + } + } +} diff --git a/Assets/Scripts/UI/Panel/ScreenTransitionPanel.cs.meta b/Assets/Scripts/UI/Panel/ScreenTransitionPanel.cs.meta new file mode 100644 index 000000000..df8887856 --- /dev/null +++ b/Assets/Scripts/UI/Panel/ScreenTransitionPanel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6b517be3c5ca46bdad6d13b94cb1b179 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/UI/UIManager.cs b/Assets/Scripts/UI/UIManager.cs index febd4aee9..62f05d44b 100644 --- a/Assets/Scripts/UI/UIManager.cs +++ b/Assets/Scripts/UI/UIManager.cs @@ -95,6 +95,7 @@ namespace AibisDream // 游戏打开 ShowPanel(); ShowPanel(); + ShowPanel(); HidePanel(); HidePanel(); diff --git a/Docs/Yarn全局转场指令表.md b/Docs/Yarn全局转场指令表.md new file mode 100644 index 000000000..bbc5ba51b --- /dev/null +++ b/Docs/Yarn全局转场指令表.md @@ -0,0 +1,56 @@ +# Yarn 全局转场指令表 + +全局转场采用“进入方式”和“退出方式”自由组合:`in` 表示盖住画面,`out` 表示揭开画面。 + +| Yarn 命令 | 默认时长 | 是否等待完成 | 用途 | +|---|---:|:---:|---| +| `<>` | 1 秒 | 是 | 黑色遮罩逐渐盖住画面 | +| `<>` | 1 秒 | 是 | 当前遮罩逐渐消失,黑幕和白幕通用 | +| `<>` | 1 秒 | 否 | 开始黑色淡入后立即继续执行后续 Yarn | +| `<>` | 1 秒 | 否 | 开始淡出后立即继续执行后续 Yarn | +| `<>` | 1 秒 | 是 | 白色遮罩逐渐盖住画面 | +| `<>` | 0.2 秒 | 是 | 完成一次白色闪光,参数表示完整总时长 | +| `<>` | 0.6 秒 | 是 | 黑色幕布从左向右盖住画面 | +| `<>` | 0.6 秒 | 是 | 当前颜色的幕布继续向右移出 | +| `<>` | 0.6 秒 | 是 | 黑色上下幕布向中心闭合 | +| `<>` | 0.6 秒 | 是 | 当前颜色的上下幕布向外打开 | + +## 使用规则 + +- 所有时长参数都可以省略,单位为秒。 +- Out 自动继承当前遮罩颜色,因此没有 `fade_out_white`。 +- 除两个旧 Sync 指令外,其他指令都会等待动画完成。 +- In 与 Out 可以自由组合,不要求同类型配对。 +- `flash_white` 是一次性效果,不需要再接 Out;应从可见画面开始使用。 + +## 常用写法 + +```yarn +// 传统黑色淡入淡出 +<> +<> +<> + +// 白色淡入,普通淡出 +<> +<> + +// 黑幕淡入,然后向右推开 +<> +<> + +// 推幕盖入,然后淡出 +<> +<> + +// 白幕淡入,然后上下打开 +<> +<> + +// 上下闭合,然后向右推开 +<> +<> + +// 单次白闪 +<> +```