设置扩展
This commit is contained in:
@@ -213,7 +213,7 @@ Material:
|
||||
- _Dst: 10
|
||||
- _DstBlend: 0
|
||||
- _DstBlendAlpha: 0
|
||||
- _EdgeValue: 0.5578781
|
||||
- _EdgeValue: 0.99275833
|
||||
- _EnvironmentReflections: 1
|
||||
- _FNLfanxiangkaiguan: 0
|
||||
- _Face: 1
|
||||
@@ -258,7 +258,7 @@ Material:
|
||||
- _Mask_scale: 1
|
||||
- _Metallic: 0
|
||||
- _OcclusionStrength: 1
|
||||
- _Opacity: 0.44212192
|
||||
- _Opacity: 0.0072416663
|
||||
- _Parallax: 0.005
|
||||
- _Pass: 0
|
||||
- _QueueOffset: 0
|
||||
|
||||
@@ -21,7 +21,6 @@ Material:
|
||||
- _CIRCLE_ON_ON
|
||||
- _CUSTOMDATA
|
||||
- _CUSTOMDATADIS_ON
|
||||
- _CUSTOMDATA_OFF
|
||||
- _DISSOLVEAR_ON
|
||||
- _DISSOLVEPLUSTEXAR_ON
|
||||
- _DISSOLVEPLUSTEXUVCLIP_ON
|
||||
@@ -336,8 +335,8 @@ Material:
|
||||
- _BaseMapFoldOut: 0
|
||||
- _BaseMapUVRotation: 0
|
||||
- _BaseMapUVRotationSpeed: 0
|
||||
- _BaseOptionBigBlockItemFoldOut: 0
|
||||
- _BigBlockModeSettingFoldOut: 0
|
||||
- _BaseOptionBigBlockItemFoldOut: 1
|
||||
- _BigBlockModeSettingFoldOut: 1
|
||||
- _Blend: 0
|
||||
- _BlendMode: 0
|
||||
- _BlendModePreserveSpecular: 1
|
||||
@@ -374,7 +373,7 @@ Material:
|
||||
- _Contrast: 1
|
||||
- _ContrastFoldOut: 0
|
||||
- _Contrast_Toggle: 0
|
||||
- _Cull: 2
|
||||
- _Cull: 0
|
||||
- _CullMode: 0
|
||||
- _Cullmode: 0
|
||||
- _CustomData: 1
|
||||
|
||||
Binary file not shown.
Binary file not shown.
8
Assets/AddressableAssetsData/Windows.meta
Normal file
8
Assets/AddressableAssetsData/Windows.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0116a7bc799e0ef48b8adfaffa13c043
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 039e11588f40d8c4b83e546855d509fc
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
28
Assets/AddressableAssetsData/link.xml
Normal file
28
Assets/AddressableAssetsData/link.xml
Normal file
@@ -0,0 +1,28 @@
|
||||
<linker>
|
||||
<assembly fullname="Unity.Addressables, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null" preserve="all">
|
||||
<type fullname="UnityEngine.AddressableAssets.Addressables" preserve="all" />
|
||||
</assembly>
|
||||
<assembly fullname="Unity.Localization, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
|
||||
<type fullname="UnityEngine.Localization.Locale" preserve="all" />
|
||||
<type fullname="UnityEngine.Localization.Tables.SharedTableData" preserve="all" />
|
||||
<type fullname="UnityEngine.Localization.Tables.StringTable" preserve="all" />
|
||||
<type fullname="UnityEngine.Localization.LocaleIdentifier" preserve="nothing" serialized="true" />
|
||||
<type fullname="UnityEngine.Localization.Metadata.MetadataCollection" preserve="nothing" serialized="true" />
|
||||
<type fullname="UnityEngine.Localization.Tables.TableEntryData" preserve="nothing" serialized="true" />
|
||||
<type fullname="UnityEngine.Localization.Tables.DistributedUIDGenerator" preserve="nothing" serialized="true" />
|
||||
<type fullname="UnityEngine.Localization.Tables.SharedTableData/SharedTableEntry" preserve="nothing" serialized="true" />
|
||||
<type fullname="UnityEngine.Localization.Metadata.FallbackLocale" preserve="nothing" serialized="true" />
|
||||
</assembly>
|
||||
<assembly fullname="Unity.ResourceManager, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null" preserve="all">
|
||||
<type fullname="UnityEngine.ResourceManagement.ResourceProviders.AssetBundleProvider" preserve="all" />
|
||||
<type fullname="UnityEngine.ResourceManagement.ResourceProviders.BundledAssetProvider" preserve="all" />
|
||||
<type fullname="UnityEngine.ResourceManagement.ResourceProviders.InstanceProvider" preserve="all" />
|
||||
<type fullname="UnityEngine.ResourceManagement.ResourceProviders.SceneProvider" preserve="all" />
|
||||
</assembly>
|
||||
<assembly fullname="UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
|
||||
<type fullname="UnityEngine.Object" preserve="all" />
|
||||
</assembly>
|
||||
<assembly fullname="YarnSpinner.Unity">
|
||||
<type fullname="Yarn.Unity.UnityLocalization.LineMetadata" preserve="nothing" serialized="true" />
|
||||
</assembly>
|
||||
</linker>
|
||||
7
Assets/AddressableAssetsData/link.xml.meta
Normal file
7
Assets/AddressableAssetsData/link.xml.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5f22cc995c7cc9348ba8e089a0f4193c
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Assets/FR2_Cache.asset
LFS
BIN
Assets/FR2_Cache.asset
LFS
Binary file not shown.
1905
Assets/Prefabs/Menu/UI Elements/MessageBox.prefab
Normal file
1905
Assets/Prefabs/Menu/UI Elements/MessageBox.prefab
Normal file
File diff suppressed because it is too large
Load Diff
1848
Assets/Prefabs/Menu/UI Elements/SelectionBox.prefab
Normal file
1848
Assets/Prefabs/Menu/UI Elements/SelectionBox.prefab
Normal file
File diff suppressed because it is too large
Load Diff
7
Assets/Prefabs/Menu/UI Elements/SelectionBox.prefab.meta
Normal file
7
Assets/Prefabs/Menu/UI Elements/SelectionBox.prefab.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0f8134d47a03bfe4184e2d4ccafe0e03
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
276
Assets/Prefabs/Menu/UI Elements/SelectionBoxButton.prefab
Normal file
276
Assets/Prefabs/Menu/UI Elements/SelectionBoxButton.prefab
Normal file
@@ -0,0 +1,276 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &4028587832294944382
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 4844063139079138537}
|
||||
- component: {fileID: 2675052568297457887}
|
||||
- component: {fileID: 314392640301343753}
|
||||
m_Layer: 5
|
||||
m_Name: Text (TMP)
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &4844063139079138537
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4028587832294944382}
|
||||
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: 3372188176019791897}
|
||||
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 &2675052568297457887
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4028587832294944382}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &314392640301343753
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4028587832294944382}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Unity.TextMeshPro::TMPro.TextMeshProUGUI
|
||||
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_text: Button
|
||||
m_isRightToLeft: 0
|
||||
m_fontAsset: {fileID: 11400000, guid: 87c1b020037c81841b3d98dd497cbdeb, type: 2}
|
||||
m_sharedMaterial: {fileID: -5812992765432063453, guid: 87c1b020037c81841b3d98dd497cbdeb,
|
||||
type: 2}
|
||||
m_fontSharedMaterials: []
|
||||
m_fontMaterial: {fileID: 0}
|
||||
m_fontMaterials: []
|
||||
m_fontColor32:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_enableVertexGradient: 0
|
||||
m_colorMode: 3
|
||||
m_fontColorGradient:
|
||||
topLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||
topRight: {r: 1, g: 1, b: 1, a: 1}
|
||||
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||
bottomRight: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_fontColorGradientPreset: {fileID: 0}
|
||||
m_spriteAsset: {fileID: 0}
|
||||
m_tintAllSprites: 0
|
||||
m_StyleSheet: {fileID: 0}
|
||||
m_TextStyleHashCode: -1183493901
|
||||
m_overrideHtmlColors: 0
|
||||
m_faceColor:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontSize: 30
|
||||
m_fontSizeBase: 30
|
||||
m_fontWeight: 400
|
||||
m_enableAutoSizing: 1
|
||||
m_fontSizeMin: 18
|
||||
m_fontSizeMax: 30
|
||||
m_fontStyle: 0
|
||||
m_HorizontalAlignment: 2
|
||||
m_VerticalAlignment: 512
|
||||
m_textAlignment: 65535
|
||||
m_characterSpacing: 0
|
||||
m_characterHorizontalScale: 1
|
||||
m_wordSpacing: 0
|
||||
m_lineSpacing: 0
|
||||
m_lineSpacingMax: 0
|
||||
m_paragraphSpacing: 0
|
||||
m_charWidthMaxAdj: 0
|
||||
m_TextWrappingMode: 1
|
||||
m_wordWrappingRatios: 0.4
|
||||
m_overflowMode: 0
|
||||
m_linkedTextComponent: {fileID: 0}
|
||||
parentLinkedComponent: {fileID: 0}
|
||||
m_enableKerning: 0
|
||||
m_ActiveFontFeatures: 6e72656b
|
||||
m_enableExtraPadding: 0
|
||||
checkPaddingRequired: 0
|
||||
m_isRichText: 1
|
||||
m_EmojiFallbackSupport: 1
|
||||
m_parseCtrlCharacters: 1
|
||||
m_isOrthographic: 1
|
||||
m_isCullingEnabled: 0
|
||||
m_horizontalMapping: 0
|
||||
m_verticalMapping: 0
|
||||
m_uvLineOffset: 0
|
||||
m_geometrySortingOrder: 0
|
||||
m_IsTextObjectScaleStatic: 0
|
||||
m_VertexBufferAutoSizeReduction: 0
|
||||
m_useMaxVisibleDescender: 1
|
||||
m_pageToDisplay: 1
|
||||
m_margin: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_isUsingLegacyAnimationComponent: 0
|
||||
m_isVolumetricText: 0
|
||||
m_hasFontAssetChanged: 0
|
||||
m_baseMaterial: {fileID: 0}
|
||||
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
|
||||
--- !u!1 &8350981944019684425
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 3372188176019791897}
|
||||
- component: {fileID: 2182965281669324128}
|
||||
- component: {fileID: 1480504358368706369}
|
||||
- component: {fileID: 3951511035263236737}
|
||||
- component: {fileID: 449795761659242553}
|
||||
m_Layer: 5
|
||||
m_Name: SelectionBoxButton
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &3372188176019791897
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 8350981944019684425}
|
||||
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: 4844063139079138537}
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 250, y: 50}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &2182965281669324128
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 8350981944019684425}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &1480504358368706369
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 8350981944019684425}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Image
|
||||
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: a42035fa13ca6c849afeedc8abcf13a7, 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!114 &3951511035263236737
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 8350981944019684425}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Button
|
||||
m_Navigation:
|
||||
m_Mode: 3
|
||||
m_WrapAround: 0
|
||||
m_SelectOnUp: {fileID: 0}
|
||||
m_SelectOnDown: {fileID: 0}
|
||||
m_SelectOnLeft: {fileID: 0}
|
||||
m_SelectOnRight: {fileID: 0}
|
||||
m_Transition: 1
|
||||
m_Colors:
|
||||
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
|
||||
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
|
||||
m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
|
||||
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
|
||||
m_ColorMultiplier: 1
|
||||
m_FadeDuration: 0.1
|
||||
m_SpriteState:
|
||||
m_HighlightedSprite: {fileID: 0}
|
||||
m_PressedSprite: {fileID: 0}
|
||||
m_SelectedSprite: {fileID: 0}
|
||||
m_DisabledSprite: {fileID: 0}
|
||||
m_AnimationTriggers:
|
||||
m_NormalTrigger: Normal
|
||||
m_HighlightedTrigger: Highlighted
|
||||
m_PressedTrigger: Pressed
|
||||
m_SelectedTrigger: Selected
|
||||
m_DisabledTrigger: Disabled
|
||||
m_Interactable: 1
|
||||
m_TargetGraphic: {fileID: 1480504358368706369}
|
||||
m_OnClick:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
--- !u!114 &449795761659242553
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 8350981944019684425}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: b2c45ae5390d4a4aa16e62b5704dbf0a, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::Ichni.Menu.UI.SelectionBoxButton
|
||||
button: {fileID: 3951511035263236737}
|
||||
labelText: {fileID: 314392640301343753}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5b3427e100cf597448a79c121640e3d5
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -10124,7 +10124,7 @@ MonoBehaviour:
|
||||
PrefabModifications: []
|
||||
SerializationNodes: []
|
||||
isLoading: 1
|
||||
isStarting: 1
|
||||
isStarting: 0
|
||||
isDelaying: 0
|
||||
isPlaying: 0
|
||||
isPausing: 0
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -21,7 +21,7 @@ namespace Ichni.RhythmGame.Beatmap
|
||||
#if UNITY_STANDALONE
|
||||
return new FullScreenNearTimeJudgeUnit(attachedNote);
|
||||
#elif UNITY_ANDROID || UNITY_IOS
|
||||
if (SettingsManager.instance.gameSettings.ShouldUseFullScreenJudge())
|
||||
if (SettingsManager.instance.ShouldUseFullScreenJudge())
|
||||
{
|
||||
return new FullScreenNearTimeJudgeUnit(attachedNote);
|
||||
}
|
||||
@@ -30,7 +30,7 @@ namespace Ichni.RhythmGame.Beatmap
|
||||
return new TouchAreaJudgeUnit(attachedNote, areaRadius);
|
||||
}
|
||||
#else
|
||||
return SettingsManager.instance.gameSettings.ShouldUseFullScreenJudge()
|
||||
return SettingsManager.instance.ShouldUseFullScreenJudge()
|
||||
? new FullScreenNearTimeJudgeUnit(attachedNote)
|
||||
: new TouchAreaJudgeUnit(attachedNote, areaRadius);
|
||||
#endif
|
||||
|
||||
@@ -32,6 +32,47 @@ namespace Ichni.RhythmGame
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rebuilds the list of elements whose active state is driven by a finite time duration.
|
||||
/// This preserves the existing runtime filter, while avoiding a LINQ allocation during
|
||||
/// every project load.
|
||||
/// </summary>
|
||||
public void RebuildRuntimeTimeDurations()
|
||||
{
|
||||
List<TimeDurationSubmodule> runtimeTimeDurations = GameManager.Instance.timeDurations;
|
||||
runtimeTimeDurations.Clear();
|
||||
|
||||
float songLength = GameManager.Instance.songInformation.songLength;
|
||||
for (int i = 0; i < gameElementList.Count; i++)
|
||||
{
|
||||
if (gameElementList[i] is not IHaveTimeDurationSubmodule timeDurationHost)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
TimeDurationSubmodule timeDuration = timeDurationHost.timeDurationSubmodule;
|
||||
if (timeDuration != null &&
|
||||
(timeDuration.startTime > 0f || timeDuration.endTime < songLength))
|
||||
{
|
||||
runtimeTimeDurations.Add(timeDuration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Immediately applies the active state for the registered time-duration elements.
|
||||
/// Used at loading-state boundaries so the first rendered frame already matches the
|
||||
/// current song timeline.
|
||||
/// </summary>
|
||||
public void SyncRuntimeTimeDurationStates(float songTime)
|
||||
{
|
||||
List<TimeDurationSubmodule> runtimeTimeDurations = GameManager.Instance.timeDurations;
|
||||
for (int i = 0; i < runtimeTimeDurations.Count; i++)
|
||||
{
|
||||
runtimeTimeDurations[i]?.DetectAndSwitchActiveState(songTime);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetUpInspector()
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
@@ -43,4 +84,4 @@ namespace Ichni.RhythmGame
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
113
Assets/Scripts/Game/Base/VFXObject.cs
Normal file
113
Assets/Scripts/Game/Base/VFXObject.cs
Normal file
@@ -0,0 +1,113 @@
|
||||
using System.Collections.Generic;
|
||||
using Sirenix.OdinInspector;
|
||||
using SLSUtilities.LeanPoolAssistance;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Ichni
|
||||
{
|
||||
/// <summary>
|
||||
/// 面向对象池特效的通用质量控制组件。
|
||||
///
|
||||
/// 挂载在由 LeanPool 生成与回收的 VFX 根节点上。每次 <see cref="OnSpawn"/> 时会先恢复受管理子对象的
|
||||
/// Prefab 初始激活状态,再依据当前 <see cref="VfxQuality"/> 关闭非必要的视觉子树。
|
||||
/// 设置切换仅影响之后新生成的 VFX,不会中断正在播放的效果。
|
||||
/// </summary>
|
||||
public class VFXObject : PooledObject
|
||||
{
|
||||
[Title("VFX Quality")]
|
||||
[Tooltip("Medium 与 Low 都会关闭的次要视觉子树。应放入高频、长寿命或大面积覆盖的装饰层。")]
|
||||
public List<GameObject> disableAtMediumAndLower = new List<GameObject>();
|
||||
|
||||
[Tooltip("仅 Low 会额外关闭的视觉子树。Medium 仍保留这些效果以维持基本演出层次。")]
|
||||
public List<GameObject> disableAtLowOnly = new List<GameObject>();
|
||||
|
||||
// 仅缓存两个质量列表中出现过的对象。没有被列出的子对象永远不受本组件控制。
|
||||
private readonly Dictionary<GameObject, bool> originalActiveStates = new Dictionary<GameObject, bool>();
|
||||
private bool qualityObjectsCached;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
CacheOriginalActiveStates();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 对象从 LeanPool 取出时执行一次质量裁剪。
|
||||
/// 先恢复原始状态可避免同一个对象先以 Low 生成、回收后再以 High 生成时仍错误保持隐藏。
|
||||
/// </summary>
|
||||
public override void OnSpawn()
|
||||
{
|
||||
// LeanPool 的 Broadcast IPoolable 模式或错误的重复通知不应重新裁剪一个已播放的效果。
|
||||
if (spawnExecuted)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CacheOriginalActiveStates();
|
||||
RestoreOriginalActiveStates();
|
||||
ApplyCurrentQuality();
|
||||
base.OnSpawn();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取生成瞬间的 VFX Quality 并关闭对应的完整视觉子树。
|
||||
/// 未初始化 SettingsManager 的编辑器预览或独立加载流程默认使用 High,保持作者配置的完整视觉。
|
||||
/// </summary>
|
||||
private void ApplyCurrentQuality()
|
||||
{
|
||||
VfxQuality currentQuality = SettingsManager.instance?.settingsSaveData?.vfxQuality ?? VfxQuality.High;
|
||||
|
||||
if (currentQuality <= VfxQuality.Medium)
|
||||
{
|
||||
SetObjectsActive(disableAtMediumAndLower, false);
|
||||
}
|
||||
|
||||
if (currentQuality == VfxQuality.Low)
|
||||
{
|
||||
SetObjectsActive(disableAtLowOnly, false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 记录 Quality 列表对象在 Prefab 中的初始激活状态。
|
||||
/// 这样即使某个对象本来就由作者设为 inactive,也不会在下一次 Spawn 时被强制打开。
|
||||
/// </summary>
|
||||
private void CacheOriginalActiveStates()
|
||||
{
|
||||
if (qualityObjectsCached)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CacheOriginalActiveStates(disableAtMediumAndLower);
|
||||
CacheOriginalActiveStates(disableAtLowOnly);
|
||||
qualityObjectsCached = true;
|
||||
}
|
||||
|
||||
private void CacheOriginalActiveStates(List<GameObject> qualityObjects)
|
||||
{
|
||||
foreach (GameObject qualityObject in qualityObjects)
|
||||
{
|
||||
if (!originalActiveStates.ContainsKey(qualityObject))
|
||||
{
|
||||
originalActiveStates.Add(qualityObject, qualityObject.activeSelf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RestoreOriginalActiveStates()
|
||||
{
|
||||
foreach (KeyValuePair<GameObject, bool> originalState in originalActiveStates)
|
||||
{
|
||||
originalState.Key.SetActive(originalState.Value);
|
||||
}
|
||||
}
|
||||
|
||||
private static void SetObjectsActive(List<GameObject> qualityObjects, bool isActive)
|
||||
{
|
||||
foreach (GameObject qualityObject in qualityObjects)
|
||||
{
|
||||
qualityObject.SetActive(isActive);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/Game/Base/VFXObject.cs.meta
Normal file
2
Assets/Scripts/Game/Base/VFXObject.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 922e341faf5784c41b3b0466e0468972
|
||||
@@ -68,6 +68,12 @@ namespace Ichni.RhythmGame
|
||||
|
||||
public override void Execute()
|
||||
{
|
||||
// 玩家关闭游戏内音乐特效时,不再覆盖 SettingsManager 已归零的 RTPC。
|
||||
if (!SettingsManager.instance.settingsSaveData.enableInGameAudioEffects)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 在 10Hz(无效果)与 peak Hz(最强截止)之间基于曲线插值
|
||||
float intensity = intensityCurve != null ? intensityCurve.Evaluate(effectProgressPercent) : 0f;
|
||||
float currentFreq = Mathf.Lerp(MinFrequency, peak, intensity);
|
||||
|
||||
@@ -66,6 +66,12 @@ namespace Ichni.RhythmGame
|
||||
|
||||
public override void Execute()
|
||||
{
|
||||
// 玩家关闭游戏内音乐特效时,不再覆盖 SettingsManager 已归零的 RTPC。
|
||||
if (!SettingsManager.instance.settingsSaveData.enableInGameAudioEffects)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 在 22000Hz(无效果)与 bottom Hz(最强截止)之间基于曲线插值
|
||||
float intensity = intensityCurve != null ? intensityCurve.Evaluate(effectProgressPercent) : 0f;
|
||||
float currentFreq = Mathf.Lerp(MaxFrequency, bottom, intensity);
|
||||
|
||||
@@ -87,7 +87,7 @@ namespace Ichni.RhythmGame
|
||||
|
||||
if (!GameManager.Instance.songPlayer.isUpdating || isFinalJudged) return true;
|
||||
|
||||
if (SettingsManager.instance.gameSettings.autoPlay && isFirstJudged) ExecuteProcessJudge();
|
||||
if (SettingsManager.instance.settingsSaveData.autoPlay && isFirstJudged) ExecuteProcessJudge();
|
||||
|
||||
if (isHolding)
|
||||
{
|
||||
@@ -109,7 +109,7 @@ namespace Ichni.RhythmGame
|
||||
|
||||
UpdateHoldEffects();
|
||||
|
||||
if (SettingsManager.instance.gameSettings.autoPlay && !isFirstJudged && currentSongTime >= exactJudgeTime)
|
||||
if (SettingsManager.instance.settingsSaveData.autoPlay && !isFirstJudged && currentSongTime >= exactJudgeTime)
|
||||
{
|
||||
ExecuteStartJudge(currentSongTime);
|
||||
}
|
||||
@@ -227,7 +227,7 @@ namespace Ichni.RhythmGame
|
||||
|
||||
protected override void SetJudgeArea()
|
||||
{
|
||||
if (!SettingsManager.instance.gameSettings.debugMode || NoteJudgeSubmodule == null) return;
|
||||
if (!SettingsManager.instance.settingsSaveData.debugMode || NoteJudgeSubmodule == null) return;
|
||||
|
||||
if (isDuringJudging && !isFirstJudged)
|
||||
{
|
||||
|
||||
@@ -201,7 +201,7 @@ namespace Ichni.RhythmGame
|
||||
}
|
||||
|
||||
// AutoPlay
|
||||
if (SettingsManager.instance.gameSettings.autoPlay && !isFirstJudged && currentSongTime >= exactJudgeTime)
|
||||
if (SettingsManager.instance.settingsSaveData.autoPlay && !isFirstJudged && currentSongTime >= exactJudgeTime)
|
||||
{
|
||||
ExecuteStartJudge(currentSongTime);
|
||||
}
|
||||
@@ -239,7 +239,7 @@ namespace Ichni.RhythmGame
|
||||
|
||||
protected virtual void SetJudgeArea()
|
||||
{
|
||||
if (!SettingsManager.instance.gameSettings.debugMode || NoteJudgeSubmodule?.judgeUnitList == null) return;
|
||||
if (!SettingsManager.instance.settingsSaveData.debugMode || NoteJudgeSubmodule?.judgeUnitList == null) return;
|
||||
|
||||
if (isDuringJudging && !isFirstJudged)
|
||||
{
|
||||
|
||||
@@ -63,7 +63,7 @@ namespace Ichni.RhythmGame
|
||||
|
||||
if(trackRendererSubmodule != null)
|
||||
{
|
||||
trackRendererSubmodule.meshGenerator.autoUpdate = false;
|
||||
trackRendererSubmodule.meshGenerator.autoUpdate = true;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
@@ -83,7 +83,7 @@ namespace Ichni.RhythmGame
|
||||
}
|
||||
|
||||
#region [IScheduledElement] Scheduler Interface
|
||||
public void ScheduledUpdate(UpdatePhase phase, float songTime)
|
||||
public override void ScheduledUpdate(UpdatePhase phase, float songTime)
|
||||
{
|
||||
ManualUpdate(songTime);
|
||||
}
|
||||
|
||||
@@ -89,10 +89,10 @@ namespace Ichni.RhythmGame
|
||||
return;
|
||||
}
|
||||
|
||||
if (forceImmediateRebuild)
|
||||
/*if (forceImmediateRebuild)
|
||||
{
|
||||
meshGenerator.RebuildImmediate();
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
public void RequestMeshRebuild()
|
||||
|
||||
@@ -100,7 +100,7 @@ namespace Ichni.RhythmGame
|
||||
|
||||
private void OnTap(int id, Vector2 position)
|
||||
{
|
||||
if (SettingsManager.instance.gameSettings.debugMode)
|
||||
if (SettingsManager.instance.settingsSaveData.debugMode)
|
||||
{
|
||||
GenerateTapMark(id, position);
|
||||
}
|
||||
@@ -110,7 +110,7 @@ namespace Ichni.RhythmGame
|
||||
|
||||
private void OnTouch(int id, Vector2 position)
|
||||
{
|
||||
if (SettingsManager.instance.gameSettings.debugMode)
|
||||
if (SettingsManager.instance.settingsSaveData.debugMode)
|
||||
{
|
||||
GenerateTouchMark(id, position);
|
||||
}
|
||||
@@ -120,7 +120,7 @@ namespace Ichni.RhythmGame
|
||||
|
||||
private void OnSwipe(int id, Vector2 position, bool isGeneric, bool isFirst, Vector2 direction)
|
||||
{
|
||||
if (SettingsManager.instance.gameSettings.debugMode)
|
||||
if (SettingsManager.instance.settingsSaveData.debugMode)
|
||||
{
|
||||
GenerateSwipeMark(id, position, isGeneric, isFirst, direction);
|
||||
|
||||
@@ -378,7 +378,7 @@ namespace Ichni.RhythmGame
|
||||
if (_activeTouches.ContainsKey(touchId))
|
||||
{
|
||||
_activeTouches.Remove(touchId);
|
||||
if (SettingsManager.instance.gameSettings.debugMode)
|
||||
if (SettingsManager.instance.settingsSaveData.debugMode)
|
||||
{
|
||||
GenerateEndMark(position);
|
||||
}
|
||||
@@ -390,7 +390,7 @@ namespace Ichni.RhythmGame
|
||||
if (_activeTouches.ContainsKey(touchId))
|
||||
{
|
||||
_activeTouches.Remove(touchId);
|
||||
if (SettingsManager.instance.gameSettings.debugMode)
|
||||
if (SettingsManager.instance.settingsSaveData.debugMode)
|
||||
{
|
||||
GenerateCanceledMark(position);
|
||||
}
|
||||
@@ -540,4 +540,4 @@ namespace Ichni.RhythmGame
|
||||
ss.Play();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ namespace Ichni
|
||||
public SummaryPageCanvas summaryPageCanvas;
|
||||
|
||||
public float SongTime => songPlayer.isStarting ? 0 :
|
||||
songPlayer.songTimeSegment - songInformation.offset - (SettingsManager.instance.gameSettings.beatmapOffset / 1000f);
|
||||
songPlayer.songTimeSegment - songInformation.offset - (SettingsManager.instance.settingsSaveData.beatmapOffset / 1000f);
|
||||
public bool IsPlaying => songPlayer != null && songPlayer.isPlaying;
|
||||
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Linq;
|
||||
using System.Reflection;
|
||||
using Sirenix.OdinInspector;
|
||||
using SLSUtilities.General;
|
||||
using SLSUtilities.Rendering.PostProcessing;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
using UnityEngine.Rendering.Universal;
|
||||
@@ -13,6 +14,11 @@ namespace Ichni
|
||||
{
|
||||
public class PostProcessingManager : Singleton<PostProcessingManager>
|
||||
{
|
||||
/// <summary>
|
||||
/// 当前已加载的 GameScene 后处理管理器。MenuScene 等未创建该对象的场景会返回 <c>null</c>。
|
||||
/// </summary>
|
||||
public static PostProcessingManager Instance => instance;
|
||||
|
||||
public static Volume GlobalVolume => instance.globalVolume;
|
||||
|
||||
[ShowInInspector]
|
||||
@@ -26,6 +32,29 @@ namespace Ichni
|
||||
// Force instantiate the volume profile on awake so it doesn't happen mid-game
|
||||
_ = globalVolume.profile;
|
||||
}
|
||||
|
||||
// GameScene 的 Global Volume 创建时,重新应用已加载的玩家设置,覆盖场景切换时的默认值。
|
||||
SettingsManager.instance?.ApplyPostProcessingSettings();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将全局后处理状态与 Anime Bloom 档位写入 GameScene 的运行时 Profile。
|
||||
/// Volume.profile 会提供运行时实例,因此不会修改磁盘上的 SampleSceneProfile 资产。
|
||||
/// </summary>
|
||||
public void ApplySettings(bool enablePostProcessing, BloomQuality bloomQuality)
|
||||
{
|
||||
globalVolume.enabled = enablePostProcessing;
|
||||
|
||||
if (!enablePostProcessing || !globalVolume.profile.TryGet(out AnimeBloom animeBloom))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
animeBloom.active = bloomQuality != BloomQuality.Off;
|
||||
if (animeBloom.active)
|
||||
{
|
||||
animeBloom.diffusion.value = bloomQuality == BloomQuality.Performance ? 5 : 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using DG.Tweening;
|
||||
using Ichni.RhythmGame;
|
||||
using Ichni.RhythmGame.Beatmap;
|
||||
@@ -51,8 +50,7 @@ namespace Ichni
|
||||
fakeLoadPercent = 0f;
|
||||
|
||||
Observable.EveryUpdate()
|
||||
.Where(_ => ThemeBundleManager.instance.waitingBundleAmount.Value == 0 &&
|
||||
GameManager.Instance.gameLoadingCanvas.allPartsSet)
|
||||
.Where(_ => ThemeBundleManager.instance.waitingBundleAmount.Value == 0 && GameManager.Instance.gameLoadingCanvas.allPartsSet)
|
||||
.First()
|
||||
.Subscribe(_ =>
|
||||
{
|
||||
@@ -72,6 +70,8 @@ namespace Ichni
|
||||
{
|
||||
fakeLoadObserver.Dispose();
|
||||
|
||||
GameManager.Instance.beatmapContainer.RebuildRuntimeTimeDurations();
|
||||
|
||||
Observable.Timer(TimeSpan.FromSeconds(1f)).First().Subscribe(_ =>
|
||||
{
|
||||
GameManager.Instance.gameLoadingCanvas.FadeOut();
|
||||
@@ -79,33 +79,27 @@ namespace Ichni
|
||||
GameManager.Instance.songPlayer.isStarting = true;
|
||||
|
||||
GameManager.Instance.beatmapContainer.gameElementList.ForEach(element => element.BeforeStart());
|
||||
|
||||
GameManager.Instance.gameUICanvas.readyText.DOFade(1, 0.5f)
|
||||
.SetLoops(4, LoopType.Yoyo).SetEase(Ease.InOutFlash).Play();
|
||||
// isStarting maps the Ready screen to song time zero. Apply the
|
||||
// duration-controlled active states before that screen becomes visible.
|
||||
GameManager.Instance.beatmapContainer.SyncRuntimeTimeDurationStates(GameManager.Instance.SongTime);
|
||||
GameManager.Instance.gameUICanvas.readyText.DOFade(1, 0.5f).SetLoops(4, LoopType.Yoyo).SetEase(Ease.InOutFlash).Play();
|
||||
|
||||
Observable.Timer(TimeSpan.FromSeconds(2)).First().Subscribe(_ =>
|
||||
{
|
||||
GameManager.Instance.songPlayer.isDelaying = true;
|
||||
GameManager.Instance.songPlayer.isStarting = false;
|
||||
// SongInformation.delay can make this timeline position negative.
|
||||
// Re-sync immediately after the state switch so negative-time
|
||||
// elements are correct before the first scheduler tick.
|
||||
GameManager.Instance.beatmapContainer.SyncRuntimeTimeDurationStates(GameManager.Instance.SongTime);
|
||||
Observable.NextFrame().Subscribe(_ =>
|
||||
{
|
||||
GameManager.Instance.timeDurations = GameManager.Instance.beatmapContainer.gameElementList
|
||||
.Select(x => (x as IHaveTimeDurationSubmodule)?.timeDurationSubmodule)
|
||||
.Where(x => x != null && (x.startTime > 0 || x.endTime < GameManager.Instance.songInformation.songLength)).ToList();
|
||||
GameManager.Instance.beatmapContainer.gameElementList.ForEach(element => element.WhenStart());
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
/*Observable.EveryUpdate()
|
||||
.Where(_ => !GameManager.Instance.audioManager.isStarting)
|
||||
.First()
|
||||
.Subscribe(_ =>
|
||||
{
|
||||
|
||||
});*/
|
||||
});
|
||||
}
|
||||
|
||||
public void Load(string chapterName, string musicName, string difficultyName)
|
||||
@@ -143,4 +137,4 @@ namespace Ichni
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,6 +154,16 @@ namespace Ichni
|
||||
StopMusicEvent.Post(gameObject);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清除由谱面音乐特效写入的滤波 RTPC。
|
||||
/// SettingsManager 在玩家关闭游戏内音乐特效时调用此方法,确保设置立即生效。
|
||||
/// </summary>
|
||||
public void ResetInGameAudioEffects()
|
||||
{
|
||||
HighPassFilter.SetValue(gameObject, 0f);
|
||||
LowPassFilter.SetValue(gameObject, 0f);
|
||||
}
|
||||
|
||||
private void OnMusicEvent(object in_cookie, AkCallbackType in_type, AkCallbackInfo in_info)
|
||||
{
|
||||
Debug.Log(in_type + " " + in_info);
|
||||
|
||||
@@ -3,7 +3,6 @@ using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using AK.Wwise;
|
||||
using Ichni.Menu;
|
||||
using Ichni.Menu.UI;
|
||||
using Ichni.Story;
|
||||
using Ichni.Story.UI;
|
||||
using Ichni.UI;
|
||||
@@ -24,7 +23,6 @@ namespace Ichni
|
||||
public LoginPage loginPage;
|
||||
public ChapterSelectionUIPage chapterSelectionUIPage;
|
||||
public StoryUIPage storyUIPage;
|
||||
public SelectionBoxUIPage selectionBoxUIPage;
|
||||
// dialogUIPage 已随旧对话系统移除;阶段 3 将接入新的 VN 对话页面引用
|
||||
public SongSelectionUIPage songSelectionUIPage;
|
||||
public TransitionUIPage transitionUIPage;
|
||||
@@ -88,7 +86,7 @@ namespace Ichni
|
||||
// 返回目标是一次性运行态信息。无论是否能恢复页面,都不能让它在下次重进菜单时重复生效。
|
||||
information?.ClearMenuReturnDestination();
|
||||
|
||||
Application.targetFrameRate = SettingsManager.instance.gameSettings.targetFrame;
|
||||
Application.targetFrameRate = SettingsManager.instance.settingsSaveData.targetFrame;
|
||||
asyncOperation = SceneManager.LoadSceneAsync("GameScene");
|
||||
asyncOperation.allowSceneActivation = false;
|
||||
}
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
using System.Collections.Generic;
|
||||
using Ichni.Menu.UI;
|
||||
using Ichni.UI;
|
||||
using Sirenix.OdinInspector;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Ichni.Story.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// 用于在剧情系统中管理并顺序展示 MessageBox 的独立 UI 页面。
|
||||
/// 支持动态实例化给定的 MessageBox Prefab,并在所有消息展示完毕后进行大页面的 FadeOut。
|
||||
/// 剧情与菜单共用的弹窗页面。
|
||||
/// MessageBox 与 SelectionBox 共用同一遮罩、容器和显示队列:两者不会重叠,
|
||||
/// 后续系统只需向本页提交“消息”或“选项”请求,无需再创建平行的 UIPage。
|
||||
/// </summary>
|
||||
public class MessageUIPage : UIPageBase
|
||||
{
|
||||
@@ -20,16 +22,28 @@ namespace Ichni.Story.UI
|
||||
[Tooltip("生成的 MessageBox 挂载在哪?如果不填,默认挂载在自己身上")]
|
||||
public Transform messageContainer;
|
||||
|
||||
// 用于排队的内部消息数据结构
|
||||
private struct PendingMessage
|
||||
[Tooltip("通用多选弹窗预制体。TutorialBlock、奖励选择等系统都通过本页动态生成它。")]
|
||||
public SelectionBox defaultSelectionBoxPrefab;
|
||||
|
||||
private enum PopupType
|
||||
{
|
||||
public string title;
|
||||
public string content;
|
||||
public MessageBox customPrefab; // 支持未来传入不同种类的 Prefab
|
||||
Message,
|
||||
Selection
|
||||
}
|
||||
|
||||
private Queue<PendingMessage> _messageQueue = new Queue<PendingMessage>();
|
||||
private MessageBox _currentActiveBox;
|
||||
// 用于统一排队的内部弹窗数据结构。
|
||||
private struct PendingPopup
|
||||
{
|
||||
public PopupType type;
|
||||
public string title;
|
||||
public string content;
|
||||
public MessageBox messagePrefab;
|
||||
public List<SelectionBoxOption> selectionOptions;
|
||||
}
|
||||
|
||||
private readonly Queue<PendingPopup> _popupQueue = new();
|
||||
private MessageBox _currentMessageBox;
|
||||
private SelectionBox _currentSelectionBox;
|
||||
private bool _isPageActive = false;
|
||||
|
||||
protected override void Awake()
|
||||
@@ -71,6 +85,83 @@ namespace Ichni.Story.UI
|
||||
EnqueueMessage(title, content, defaultMessageBoxPrefab);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inspector 专用的运行时调试入口。
|
||||
/// 通过正常队列创建一条基础测试文本,因此可以同时验证新 Prefab 的布局、
|
||||
/// 入退场动画、输入拦截与队列收尾,而不会绕过正式流程或污染剧情数据。
|
||||
/// </summary>
|
||||
[Button("调试:创建空 MessageBox", ButtonSizes.Medium)]
|
||||
private void DebugCreateEmptyMessageBox()
|
||||
{
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
Debug.LogWarning("[MessageUIPage] 空 MessageBox 调试按钮只能在 Play Mode 中使用。", this);
|
||||
return;
|
||||
}
|
||||
|
||||
ShowCustomMessage(
|
||||
"MessageBox Debug",
|
||||
"这是一条用于检查基础布局、文本换行与 Rail 动效的测试文本。\n\n" +
|
||||
"This is a basic MessageBox test message.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inspector 专用的运行时调试入口。
|
||||
/// 通过正常队列创建一条基础测试文本,因此可以同时验证新 Prefab 的布局、
|
||||
/// 入退场动画、输入拦截与队列收尾,而不会绕过正式流程或污染剧情数据。
|
||||
/// </summary>
|
||||
[Button("调试:创建空 SelectionBox", ButtonSizes.Medium)]
|
||||
private void DebugCreateEmptySelectionBox()
|
||||
{
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
Debug.LogWarning("[MessageUIPage] 空 SelectionBox 调试按钮只能在 Play Mode 中使用。", this);
|
||||
return;
|
||||
}
|
||||
|
||||
ShowSelectionBox(
|
||||
"SelectionBox Debug",
|
||||
"这是一条用于检查基础布局、文本换行与 Rail 动效的测试文本。\n\n" +
|
||||
"This is a basic SelectionBox test message.",
|
||||
new List<SelectionBoxOption>
|
||||
{
|
||||
new SelectionBoxOption("Option 1", () => Debug.Log("Option 1 selected")),
|
||||
new SelectionBoxOption("Option 2", () => Debug.Log("Option 2 selected")),
|
||||
new SelectionBoxOption("Option 3", () => Debug.Log("Option 3 selected"))
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将一组运行时选项加入通用弹窗队列。
|
||||
/// 若 MessageBox 或其它 SelectionBox 正在显示,选项会按提交顺序等待,而不会叠在同一遮罩上。
|
||||
/// </summary>
|
||||
public bool ShowSelectionBox(string title, string content, IReadOnlyList<SelectionBoxOption> options)
|
||||
{
|
||||
if (defaultSelectionBoxPrefab == null)
|
||||
{
|
||||
Debug.LogError("[MessageUIPage] 未配置 defaultSelectionBoxPrefab,无法显示选项框。");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (options == null || options.Count == 0)
|
||||
{
|
||||
Debug.LogWarning("[MessageUIPage] 未提供任何 SelectionBoxOption,忽略空选项框。");
|
||||
return false;
|
||||
}
|
||||
|
||||
_popupQueue.Enqueue(new PendingPopup
|
||||
{
|
||||
type = PopupType.Selection,
|
||||
title = title,
|
||||
content = content,
|
||||
// 复制调用方传入的列表,防止调用方随后改动集合而改变已排队的玩家选择。
|
||||
selectionOptions = new List<SelectionBoxOption>(options)
|
||||
});
|
||||
|
||||
BeginQueueIfNeeded();
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将指定消息入队。如果是空闲状态,则唤醒大页面并开始处理队列。
|
||||
/// </summary>
|
||||
@@ -82,22 +173,30 @@ namespace Ichni.Story.UI
|
||||
return;
|
||||
}
|
||||
|
||||
_messageQueue.Enqueue(new PendingMessage
|
||||
_popupQueue.Enqueue(new PendingPopup
|
||||
{
|
||||
type = PopupType.Message,
|
||||
title = title,
|
||||
content = content,
|
||||
customPrefab = prefab
|
||||
messagePrefab = prefab
|
||||
});
|
||||
|
||||
// 如果当前页面没有在显示中,则开始整体流程
|
||||
if (!_isPageActive)
|
||||
{
|
||||
_isPageActive = true;
|
||||
|
||||
// 唤醒大页面(执行 UIPageBase 的渐入并拦截底层射线)
|
||||
this.FadeIn(0.5f, false, ShowNextInQueue);
|
||||
}
|
||||
|
||||
BeginQueueIfNeeded();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 若当前没有弹窗,激活共享遮罩后开始依次显示队列。遮罩从出现瞬间拦截输入,
|
||||
/// 避免 UIPageBase 默认淡入结束前的短暂底层点击窗口。
|
||||
/// </summary>
|
||||
private void BeginQueueIfNeeded()
|
||||
{
|
||||
if (_isPageActive) return;
|
||||
|
||||
_isPageActive = true;
|
||||
mainCanvasGroup.gameObject.SetActive(true);
|
||||
mainCanvasGroup.interactable = true;
|
||||
mainCanvasGroup.blocksRaycasts = true;
|
||||
FadeIn(0f, false, ShowNextInQueue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -105,40 +204,85 @@ namespace Ichni.Story.UI
|
||||
/// </summary>
|
||||
private void ShowNextInQueue()
|
||||
{
|
||||
if (_messageQueue.Count == 0)
|
||||
if (_popupQueue.Count == 0)
|
||||
{
|
||||
// 队列处理完毕,大页面整体退场
|
||||
_currentActiveBox = null;
|
||||
// 队列处理完毕,大页面整体退场。
|
||||
_currentMessageBox = null;
|
||||
_currentSelectionBox = null;
|
||||
_isPageActive = false;
|
||||
this.FadeOut();
|
||||
FadeOut(0f);
|
||||
return;
|
||||
}
|
||||
|
||||
PendingMessage msg = _messageQueue.Dequeue();
|
||||
|
||||
// 实例化预制体
|
||||
_currentActiveBox = Instantiate(msg.customPrefab, messageContainer);
|
||||
|
||||
// 订阅“当这个消息框彻底结束关闭时”的事件
|
||||
_currentActiveBox.onAllMessagesClosed.AddListener(() =>
|
||||
PendingPopup popup = _popupQueue.Dequeue();
|
||||
if (popup.type == PopupType.Selection)
|
||||
{
|
||||
// 销毁旧实例
|
||||
if (_currentActiveBox != null)
|
||||
{
|
||||
Destroy(_currentActiveBox.gameObject);
|
||||
}
|
||||
|
||||
// 检查并显示下一个
|
||||
ShowNextInQueue();
|
||||
});
|
||||
ShowSelectionPopup(popup);
|
||||
return;
|
||||
}
|
||||
|
||||
// 配置并启动 MessageBox
|
||||
_currentActiveBox.Clear();
|
||||
_currentActiveBox.AddInfo(msg.title, msg.content, null);
|
||||
|
||||
// MessageBox.SetUp() 内部会激活自己并执行自己的 FadeIn
|
||||
_currentActiveBox.gameObject.SetActive(true);
|
||||
_currentActiveBox.SetUp();
|
||||
ShowMessagePopup(popup);
|
||||
}
|
||||
|
||||
private void ShowMessagePopup(PendingPopup popup)
|
||||
{
|
||||
if (popup.messagePrefab == null)
|
||||
{
|
||||
Debug.LogError("[MessageUIPage] 队列中的 MessageBox Prefab 已丢失,跳过该消息。");
|
||||
ShowNextInQueue();
|
||||
return;
|
||||
}
|
||||
|
||||
MessageBox messageBox = Instantiate(popup.messagePrefab, messageContainer);
|
||||
_currentMessageBox = messageBox;
|
||||
|
||||
// MessageBox 只显示一条消息;队列顺序始终由本页统一管理。
|
||||
messageBox.Closed += HandleMessageBoxClosed;
|
||||
messageBox.gameObject.SetActive(true);
|
||||
messageBox.SetUp(popup.title, popup.content);
|
||||
}
|
||||
|
||||
private void HandleMessageBoxClosed(MessageBox messageBox)
|
||||
{
|
||||
messageBox.Closed -= HandleMessageBoxClosed;
|
||||
Destroy(messageBox.gameObject);
|
||||
|
||||
if (_currentMessageBox == messageBox)
|
||||
_currentMessageBox = null;
|
||||
|
||||
ShowNextInQueue();
|
||||
}
|
||||
|
||||
private void ShowSelectionPopup(PendingPopup popup)
|
||||
{
|
||||
if (defaultSelectionBoxPrefab == null)
|
||||
{
|
||||
Debug.LogError("[MessageUIPage] 队列中的 SelectionBox Prefab 已丢失,跳过该选项框。");
|
||||
ShowNextInQueue();
|
||||
return;
|
||||
}
|
||||
|
||||
SelectionBox selectionBox = Instantiate(defaultSelectionBoxPrefab, messageContainer);
|
||||
_currentSelectionBox = selectionBox;
|
||||
selectionBox.Closed += HandleSelectionBoxClosed;
|
||||
|
||||
if (!selectionBox.SetUp(popup.title, popup.content, popup.selectionOptions))
|
||||
{
|
||||
selectionBox.Closed -= HandleSelectionBoxClosed;
|
||||
Destroy(selectionBox.gameObject);
|
||||
_currentSelectionBox = null;
|
||||
ShowNextInQueue();
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleSelectionBoxClosed(SelectionBox selectionBox)
|
||||
{
|
||||
if (selectionBox != _currentSelectionBox) return;
|
||||
|
||||
selectionBox.Closed -= HandleSelectionBoxClosed;
|
||||
Destroy(selectionBox.gameObject);
|
||||
_currentSelectionBox = null;
|
||||
ShowNextInQueue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,8 +156,8 @@ namespace Ichni.Story.Dialogue
|
||||
{
|
||||
action?.Invoke();
|
||||
}
|
||||
|
||||
MessageUIPage.instance.FadeIn();
|
||||
// MessageUIPage 会在收到第一项消息/选项请求时自行开启统一队列与淡入,
|
||||
// 此处不能再次直接 FadeIn,否则会与当前弹窗流程重复播放页面动画。
|
||||
}
|
||||
|
||||
if (storyUIPage != null)
|
||||
|
||||
@@ -55,7 +55,8 @@ namespace Ichni.Story
|
||||
if (!TrySetBoolAndSave(tutorialBlock.tutorialProgressVariable, true))
|
||||
return false;
|
||||
|
||||
// completedBlockIds 只负责教程节点自身的 Completed 外观与不可重复点击;
|
||||
// completedBlockIds 只负责教程节点自身的 Completed 外观;
|
||||
// Completed TutorialBlock 仍可点击,以便玩家重复进入教程。
|
||||
// 后续节点应在 StoryData 中以 VariableCondition 读取上面的剧情变量。
|
||||
treeController.OnBlockCompleted(tutorialBlock.blockId);
|
||||
return true;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Ichni.Menu;
|
||||
using Ichni.Menu.UI;
|
||||
using Ichni.Story.UI;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -13,7 +14,7 @@ namespace Ichni.Story
|
||||
public static class TutorialFlowController
|
||||
{
|
||||
/// <summary>
|
||||
/// 由 <see cref="UI.TutorialBlockView"/> 点击时调用。配置无效或 SelectionBox 页面未配置时只报错,不修改剧情进度。
|
||||
/// 由 <see cref="UI.TutorialBlockView"/> 点击时调用。配置无效或 MessageUIPage 未配置时只报错,不修改剧情进度。
|
||||
/// </summary>
|
||||
public static void RequestTutorial(StoryBlockDefinition tutorialBlock)
|
||||
{
|
||||
@@ -23,17 +24,16 @@ namespace Ichni.Story
|
||||
return;
|
||||
}
|
||||
|
||||
MenuManager menuManager = MenuManager.instance;
|
||||
SelectionBoxUIPage selectionBoxPage = menuManager?.selectionBoxUIPage;
|
||||
if (selectionBoxPage == null)
|
||||
MessageUIPage messageUIPage = MessageUIPage.instance;
|
||||
if (messageUIPage == null)
|
||||
{
|
||||
Debug.LogWarning("[TutorialFlowController] MenuManager 未配置 SelectionBoxUIPage,教程不会被解锁。");
|
||||
Debug.LogWarning("[TutorialFlowController] MessageUIPage 未就绪,教程不会被解锁。");
|
||||
return;
|
||||
}
|
||||
|
||||
// TutorialFlowController 只描述“有哪些选择、各自触发什么效果”;
|
||||
// 具体按钮由通用 SelectionBox 在运行时生成,后续其它系统可复用同一 UI。
|
||||
selectionBoxPage.Show(
|
||||
messageUIPage.ShowSelectionBox(
|
||||
tutorialBlock.tutorialName,
|
||||
string.Empty,
|
||||
new List<SelectionBoxOption>
|
||||
@@ -105,7 +105,8 @@ namespace Ichni.Story
|
||||
string.IsNullOrWhiteSpace(tutorialBlock.tutorialProgressVariable) ||
|
||||
tutorialBlock.tutorialDifficultySaveId < 0)
|
||||
{
|
||||
Debug.LogWarning($"[TutorialFlowController] TutorialBlock '{tutorialBlock?.blockId}' 的 Tutorial Key、Progress Variable 或 Difficulty Save ID 未配置完整。");
|
||||
Debug.LogWarning($"[TutorialFlowController] TutorialBlock '{tutorialBlock?.blockId}' 的 Tutorial Key、Progress Variable 或 Difficulty Save ID 未配置完整。\n" +
|
||||
$"Tutorial Key:{tutorialBlock.tutorialKey}, Progress Variable:{tutorialBlock.tutorialProgressVariable}, Difficulty Save ID:{tutorialBlock.tutorialDifficultySaveId}");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,8 +4,9 @@ using UnityEngine;
|
||||
namespace Ichni.Story.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// 教程块视图。点击后由 <see cref="TutorialFlowController"/> 显示确认窗口,
|
||||
/// 教程块视图。点击后由 <see cref="TutorialFlowController"/> 请求通用 SelectionBox,
|
||||
/// 玩家选择游玩或跳过时都会写入教程剧情变量并刷新故事树。
|
||||
/// 节点处于 Completed 时仍保持可点击,方便玩家随时回顾教程。
|
||||
/// </summary>
|
||||
public class TutorialBlockView : StoryBlockView
|
||||
{
|
||||
@@ -25,16 +26,5 @@ namespace Ichni.Story.UI
|
||||
TutorialFlowController.RequestTutorial(definition);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 已处理的教程不再重复弹出“游玩 / 跳过”确认窗口。
|
||||
/// 教程重玩将来应由独立的教程入口提供,不复用剧情进度节点。
|
||||
/// </summary>
|
||||
public override void ApplyState(StoryBlockState newState)
|
||||
{
|
||||
base.ApplyState(newState);
|
||||
|
||||
if (button != null && newState == StoryBlockState.Completed)
|
||||
button.interactable = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Localization.Settings;
|
||||
using UnityEngine.Rendering;
|
||||
using UnityEngine.Rendering.Universal;
|
||||
|
||||
namespace Ichni
|
||||
{
|
||||
public class GameSettings
|
||||
{
|
||||
public int masterVolume = 50;
|
||||
public int musicVolume = 50;
|
||||
public int soundEffectVolume = 50;
|
||||
public int uiVolume = 50;
|
||||
|
||||
public int targetFrame = 60;
|
||||
public int resolutionLevel = 3;
|
||||
|
||||
public int beatmapOffset = 0;
|
||||
|
||||
public int languageIndex = 0;
|
||||
|
||||
public bool debugMode = false;
|
||||
public bool judgeType = false;
|
||||
public bool autoPlay = false;
|
||||
|
||||
public bool ShouldUseFullScreenJudge()
|
||||
{
|
||||
return judgeType || InformationTransistor.instance?.difficulty?.ForceFullScreenJudge == true;
|
||||
}
|
||||
|
||||
public GameSettings()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public GameSettings(int masterVolume, int musicVolume, int soundEffectVolume, int uiVolume,
|
||||
int beatmapOffset, int targetFrame, int resolutionLevel, int languageIndex, bool debugMode,
|
||||
bool judgeType, bool autoPlay)
|
||||
{
|
||||
this.masterVolume = masterVolume;
|
||||
this.musicVolume = musicVolume;
|
||||
this.soundEffectVolume = soundEffectVolume;
|
||||
this.uiVolume = uiVolume;
|
||||
this.beatmapOffset = beatmapOffset;
|
||||
this.targetFrame = targetFrame;
|
||||
this.resolutionLevel = resolutionLevel;
|
||||
this.languageIndex = languageIndex;
|
||||
this.debugMode = debugMode;
|
||||
this.judgeType = judgeType;
|
||||
this.autoPlay = autoPlay;
|
||||
}
|
||||
|
||||
public void ApplyVolume()
|
||||
{
|
||||
AkSoundEngine.SetRTPCValue("MasterVolume", masterVolume);
|
||||
AkSoundEngine.SetRTPCValue("MusicVolume", musicVolume);
|
||||
AkSoundEngine.SetRTPCValue("SoundFXVolume", soundEffectVolume);
|
||||
AkSoundEngine.SetRTPCValue("UIVolume", uiVolume);
|
||||
}
|
||||
|
||||
public void ApplyGraphic()
|
||||
{
|
||||
Application.targetFrameRate = targetFrame;
|
||||
UniversalRenderPipelineAsset currentUrpAsset = GraphicsSettings.defaultRenderPipeline as UniversalRenderPipelineAsset;
|
||||
currentUrpAsset.renderScale = 0.5f + 0.1f * resolutionLevel;
|
||||
}
|
||||
|
||||
public void ApplyLanguage()
|
||||
{
|
||||
I2.Loc.LocalizationManager.CurrentLanguage = MenuManager.instance.languageList[languageIndex];
|
||||
LocalizationSettings.SelectedLocale = LocalizationSettings.AvailableLocales.Locales[languageIndex];
|
||||
I2.Loc.LocalizationManager.UpdateSources();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,34 @@
|
||||
using Ichni.Menu;
|
||||
using System.Collections.Generic;
|
||||
using Sirenix.OdinInspector;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Localization.Settings;
|
||||
using UnityEngine.Rendering;
|
||||
using UnityEngine.Rendering.Universal;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace Ichni
|
||||
{
|
||||
public class SettingsManager : SerializedMonoBehaviour
|
||||
{
|
||||
private const string SettingsSaveFileName = "SettingsSave.json";
|
||||
private const string SettingsSaveKey = "SettingsSave";
|
||||
|
||||
private const string PerformantQualityName = "Performant";
|
||||
private const string BalancedQualityName = "Balanced";
|
||||
private const string HighFidelityQualityName = "High Fidelity";
|
||||
|
||||
public static SettingsManager instance;
|
||||
|
||||
[FormerlySerializedAs("settingsPage")]
|
||||
public SettingsUIPage settingsUIPage;
|
||||
public GameSettings gameSettings;
|
||||
|
||||
[FormerlySerializedAs("gameSettings")]
|
||||
public SettingsSaveData settingsSaveData;
|
||||
|
||||
// 记录相机在玩家关闭后处理前的原始状态。重新开启时必须恢复原始值,不能无条件将所有相机改为开启。
|
||||
private readonly Dictionary<int, bool> postProcessingCameraStates = new Dictionary<int, bool>();
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
@@ -19,6 +36,8 @@ namespace Ichni
|
||||
{
|
||||
instance = this;
|
||||
DontDestroyOnLoad(gameObject);
|
||||
SceneManager.sceneLoaded += OnSceneLoaded;
|
||||
RenderPipelineManager.beginCameraRendering += ApplyPostProcessingSettingBeforeCameraRender;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -26,6 +45,18 @@ namespace Ichni
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (instance != this)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SceneManager.sceneLoaded -= OnSceneLoaded;
|
||||
RenderPipelineManager.beginCameraRendering -= ApplyPostProcessingSettingBeforeCameraRender;
|
||||
instance = null;
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
LoadGameSettings();
|
||||
@@ -34,27 +65,269 @@ namespace Ichni
|
||||
[Button]
|
||||
public void SaveGameSettings()
|
||||
{
|
||||
string savePath = Application.persistentDataPath + "/GameData/GameSettings.json";
|
||||
ES3.Save("GameSettings", gameSettings, savePath);
|
||||
string savePath = Application.persistentDataPath + "/GameData/" + SettingsSaveFileName;
|
||||
ES3.Save(SettingsSaveKey, settingsSaveData, savePath);
|
||||
}
|
||||
|
||||
[Button]
|
||||
public void LoadGameSettings()
|
||||
{
|
||||
string savePath = Application.persistentDataPath + "/GameData/GameSettings.json";
|
||||
string savePath = Application.persistentDataPath + "/GameData/" + SettingsSaveFileName;
|
||||
if (ES3.FileExists(savePath))
|
||||
{
|
||||
gameSettings = ES3.Load<GameSettings>("GameSettings", savePath);
|
||||
// 保留原有 ES3 Key,确保本次数据模型重命名不会让已有本地设置失效。
|
||||
settingsSaveData = ES3.Load<SettingsSaveData>(SettingsSaveKey, savePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
gameSettings = new GameSettings(
|
||||
50, 50, 50, 50,
|
||||
0, 60, 3, 0, false, false, false);
|
||||
settingsSaveData = CreateDefaultSettingsSaveData();
|
||||
}
|
||||
|
||||
gameSettings.ApplyVolume();
|
||||
gameSettings.ApplyGraphic();
|
||||
|
||||
ApplyAudioSettings();
|
||||
ApplyGraphicSettings();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将音频分类的当前设置写入 Wwise RTPC。
|
||||
/// </summary>
|
||||
public void ApplyAudioSettings()
|
||||
{
|
||||
AkSoundEngine.SetRTPCValue("MasterVolume", settingsSaveData.masterVolume);
|
||||
AkSoundEngine.SetRTPCValue("MusicVolume", settingsSaveData.musicVolume);
|
||||
AkSoundEngine.SetRTPCValue("SoundFXVolume", settingsSaveData.soundEffectVolume);
|
||||
AkSoundEngine.SetRTPCValue("UIVolume", settingsSaveData.uiVolume);
|
||||
ApplyInGameAudioEffectsSettings();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 应用游戏内音乐特效开关。关闭时立即清除歌曲正在使用的高通与低通滤波,
|
||||
/// 防止设置变更后残留上一帧的 RTPC 值。
|
||||
/// </summary>
|
||||
public void ApplyInGameAudioEffectsSettings()
|
||||
{
|
||||
if (settingsSaveData.enableInGameAudioEffects)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GameManager.Instance?.songPlayer?.ResetInGameAudioEffects();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将现有图形设置应用到运行时。更细的 Quality、VSync 与平台策略会在 Graphics 分类重构时接入。
|
||||
/// </summary>
|
||||
public void ApplyGraphicSettings()
|
||||
{
|
||||
int qualityLevelIndex = GetQualityLevelIndex(settingsSaveData.graphicsQualityPreset);
|
||||
if (QualitySettings.GetQualityLevel() != qualityLevelIndex)
|
||||
{
|
||||
QualitySettings.SetQualityLevel(qualityLevelIndex, true);
|
||||
}
|
||||
|
||||
Application.targetFrameRate = settingsSaveData.targetFrame;
|
||||
UniversalRenderPipelineAsset currentUrpAsset = GraphicsSettings.currentRenderPipeline as UniversalRenderPipelineAsset;
|
||||
currentUrpAsset.renderScale = 0.5f + 0.1f * settingsSaveData.renderScaleLevel;
|
||||
ApplyDisplaySettings();
|
||||
ApplyPostProcessingSettings();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 应用后处理总开关与 Bloom 档位。
|
||||
/// 关闭总开关时,已存在的 URP 相机会直接关闭 <c>renderPostProcessing</c>,并关闭 GameScene 的 Global Volume。
|
||||
/// 这样既不会执行原生后处理,也不会执行 ScriptablePostProcessor 的自定义 Render Pass。
|
||||
/// </summary>
|
||||
public void ApplyPostProcessingSettings()
|
||||
{
|
||||
bool enablePostProcessing = settingsSaveData.enablePostProcessing;
|
||||
UniversalAdditionalCameraData[] cameraDataList =
|
||||
FindObjectsByType<UniversalAdditionalCameraData>(FindObjectsInactive.Exclude, FindObjectsSortMode.None);
|
||||
|
||||
foreach (UniversalAdditionalCameraData cameraData in cameraDataList)
|
||||
{
|
||||
int instanceId = cameraData.GetInstanceID();
|
||||
if (!postProcessingCameraStates.ContainsKey(instanceId))
|
||||
{
|
||||
postProcessingCameraStates.Add(instanceId, cameraData.renderPostProcessing);
|
||||
}
|
||||
|
||||
cameraData.renderPostProcessing = enablePostProcessing && postProcessingCameraStates[instanceId];
|
||||
}
|
||||
|
||||
if (PostProcessingManager.Instance != null)
|
||||
{
|
||||
PostProcessingManager.Instance.ApplySettings(enablePostProcessing, settingsSaveData.bloomQuality);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理场景切换后新加载的相机与 Global Volume。SettingsManager 会跨场景保留,
|
||||
/// 因此不能只在首次读取存档时应用一次图形设置。
|
||||
/// </summary>
|
||||
private void OnSceneLoaded(Scene scene, LoadSceneMode loadSceneMode)
|
||||
{
|
||||
if (settingsSaveData != null)
|
||||
{
|
||||
ApplyPostProcessingSettings();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 兜底处理运行时晚于场景加载创建的相机(例如 Theme 或演出对象中的相机)。
|
||||
/// 仅在玩家关闭后处理时执行,保证该相机在首次渲染前也不会运行后处理。
|
||||
/// </summary>
|
||||
private void ApplyPostProcessingSettingBeforeCameraRender(ScriptableRenderContext context, Camera camera)
|
||||
{
|
||||
if (settingsSaveData == null || settingsSaveData.enablePostProcessing ||
|
||||
!camera.TryGetComponent(out UniversalAdditionalCameraData cameraData))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int instanceId = cameraData.GetInstanceID();
|
||||
if (!postProcessingCameraStates.ContainsKey(instanceId))
|
||||
{
|
||||
postProcessingCameraStates.Add(instanceId, cameraData.renderPostProcessing);
|
||||
}
|
||||
|
||||
cameraData.renderPostProcessing = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将 VSync、窗口模式和分辨率立即应用到 Standalone / Unity Editor。
|
||||
/// 移动端由系统管理显示模式与分辨率,因此不执行这些设置。
|
||||
/// </summary>
|
||||
public void ApplyDisplaySettings()
|
||||
{
|
||||
#if UNITY_STANDALONE || UNITY_EDITOR
|
||||
QualitySettings.vSyncCount = settingsSaveData.vSyncEnabled ? 1 : 0;
|
||||
|
||||
if (settingsSaveData.displayResolutionWidth <= 0 || settingsSaveData.displayResolutionHeight <= 0)
|
||||
{
|
||||
settingsSaveData.displayResolutionWidth = Screen.width;
|
||||
settingsSaveData.displayResolutionHeight = Screen.height;
|
||||
}
|
||||
|
||||
Screen.SetResolution(settingsSaveData.displayResolutionWidth, settingsSaveData.displayResolutionHeight,
|
||||
GetFullScreenMode(settingsSaveData.displayMode));
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 首次创建设置存档时,继承 Project Settings 为当前平台指定的默认 Quality Level。
|
||||
/// 之后玩家的选择由 SettingsSaveData 持久化,不会在下次启动时被平台默认值覆盖。
|
||||
/// </summary>
|
||||
private SettingsSaveData CreateDefaultSettingsSaveData()
|
||||
{
|
||||
SettingsSaveData defaultSettings = new SettingsSaveData();
|
||||
defaultSettings.graphicsQualityPreset = GetGraphicsQualityPreset(QualitySettings.GetQualityLevel());
|
||||
#if UNITY_STANDALONE || UNITY_EDITOR
|
||||
defaultSettings.displayMode = GetGraphicsDisplayMode(Screen.fullScreenMode);
|
||||
defaultSettings.displayResolutionWidth = Screen.width;
|
||||
defaultSettings.displayResolutionHeight = Screen.height;
|
||||
#endif
|
||||
return defaultSettings;
|
||||
}
|
||||
|
||||
private FullScreenMode GetFullScreenMode(GraphicsDisplayMode displayMode)
|
||||
{
|
||||
return displayMode switch
|
||||
{
|
||||
GraphicsDisplayMode.Fullscreen => FullScreenMode.ExclusiveFullScreen,
|
||||
GraphicsDisplayMode.Windowed => FullScreenMode.Windowed,
|
||||
_ => FullScreenMode.FullScreenWindow
|
||||
};
|
||||
}
|
||||
|
||||
private GraphicsDisplayMode GetGraphicsDisplayMode(FullScreenMode fullScreenMode)
|
||||
{
|
||||
return fullScreenMode switch
|
||||
{
|
||||
FullScreenMode.ExclusiveFullScreen => GraphicsDisplayMode.Fullscreen,
|
||||
FullScreenMode.Windowed => GraphicsDisplayMode.Windowed,
|
||||
_ => GraphicsDisplayMode.BorderlessFullscreen
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将存档枚举映射到 Project Settings 中同名的 Quality Level。
|
||||
/// 若配置缺失,回退到 Balanced;这是移动端的首发默认档位。
|
||||
/// </summary>
|
||||
private int GetQualityLevelIndex(GraphicsQualityPreset qualityPreset)
|
||||
{
|
||||
string qualityName = GetQualityName(qualityPreset);
|
||||
string[] qualityNames = QualitySettings.names;
|
||||
for (int index = 0; index < qualityNames.Length; index++)
|
||||
{
|
||||
if (qualityNames[index] == qualityName)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
Debug.LogWarning($"[SettingsManager] 未找到 Quality Level '{qualityName}',回退至 Balanced。");
|
||||
return FindQualityLevelOrFallback(BalancedQualityName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将当前 Quality Level 索引转换为可保存的枚举。未知的自定义档位统一按 Balanced 保存。
|
||||
/// </summary>
|
||||
private GraphicsQualityPreset GetGraphicsQualityPreset(int qualityLevelIndex)
|
||||
{
|
||||
string[] qualityNames = QualitySettings.names;
|
||||
if (qualityLevelIndex < 0 || qualityLevelIndex >= qualityNames.Length)
|
||||
{
|
||||
return GraphicsQualityPreset.Balanced;
|
||||
}
|
||||
|
||||
return qualityNames[qualityLevelIndex] switch
|
||||
{
|
||||
PerformantQualityName => GraphicsQualityPreset.Performant,
|
||||
HighFidelityQualityName => GraphicsQualityPreset.HighFidelity,
|
||||
_ => GraphicsQualityPreset.Balanced
|
||||
};
|
||||
}
|
||||
|
||||
private int FindQualityLevelOrFallback(string qualityName)
|
||||
{
|
||||
string[] qualityNames = QualitySettings.names;
|
||||
for (int index = 0; index < qualityNames.Length; index++)
|
||||
{
|
||||
if (qualityNames[index] == qualityName)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
return Mathf.Clamp(QualitySettings.GetQualityLevel(), 0, qualityNames.Length - 1);
|
||||
}
|
||||
|
||||
private string GetQualityName(GraphicsQualityPreset qualityPreset)
|
||||
{
|
||||
return qualityPreset switch
|
||||
{
|
||||
GraphicsQualityPreset.Performant => PerformantQualityName,
|
||||
GraphicsQualityPreset.HighFidelity => HighFidelityQualityName,
|
||||
_ => BalancedQualityName
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将当前语言索引应用到既有的 I2 与 Unity Localization 管线。
|
||||
/// 语言将于 Localization 重构时改为稳定的 Locale ID;本阶段只迁移数据承载方式。
|
||||
/// </summary>
|
||||
public void ApplyLanguageSettings()
|
||||
{
|
||||
I2.Loc.LocalizationManager.CurrentLanguage = MenuManager.instance.languageList[settingsSaveData.languageIndex];
|
||||
LocalizationSettings.SelectedLocale = LocalizationSettings.AvailableLocales.Locales[settingsSaveData.languageIndex];
|
||||
I2.Loc.LocalizationManager.UpdateSources();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断本谱面是否启用全屏判定。谱面强制要求的配置优先于玩家开关。
|
||||
/// </summary>
|
||||
public bool ShouldUseFullScreenJudge()
|
||||
{
|
||||
return settingsSaveData.judgeType || InformationTransistor.instance?.difficulty?.ForceFullScreenJudge == true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
129
Assets/Scripts/Settings/SettingsSaveData.cs
Normal file
129
Assets/Scripts/Settings/SettingsSaveData.cs
Normal file
@@ -0,0 +1,129 @@
|
||||
using System;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace Ichni
|
||||
{
|
||||
/// <summary>
|
||||
/// 与 Project Settings 中同名 Quality Level 对应的玩家图形档位。
|
||||
/// 枚举值仅用于设置存档与 UI 顺序;实际应用时由 SettingsManager 按名称查找 Quality Level,
|
||||
/// 因此调整 Project Settings 的档位顺序不会错误切换到其他渲染 Asset。
|
||||
/// </summary>
|
||||
public enum GraphicsQualityPreset
|
||||
{
|
||||
Performant = 0,
|
||||
Balanced = 1,
|
||||
HighFidelity = 2
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// PC 显示模式。移动端不使用此设置,相关 UI 也不会显示。
|
||||
/// </summary>
|
||||
public enum GraphicsDisplayMode
|
||||
{
|
||||
Fullscreen = 0,
|
||||
BorderlessFullscreen = 1,
|
||||
Windowed = 2
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Anime Bloom 的质量档位。
|
||||
/// Off 会保持其他后处理可用,但不执行 Bloom;Performance 与 Standard 分别使用预先确定的
|
||||
/// Diffusion 值。具体数值由 <see cref="PostProcessingManager"/> 统一应用,避免散落在 UI 或谱面代码中。
|
||||
/// </summary>
|
||||
public enum BloomQuality
|
||||
{
|
||||
Off = 0,
|
||||
Performance = 1,
|
||||
Standard = 2
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Note 与其他演出特效将使用的全局质量档位。
|
||||
/// 本阶段先完成存档、UI 与运行时读取入口;各特效物体后续按自身开销实现 Low / Medium / High 的实际降级策略。
|
||||
/// </summary>
|
||||
public enum VfxQuality
|
||||
{
|
||||
Low = 0,
|
||||
Medium = 1,
|
||||
High = 2
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 玩家设置的唯一持久化数据模型。
|
||||
///
|
||||
/// 此类只保存设置值,不负责将音量、图形或语言应用到运行时;
|
||||
/// 运行时应用逻辑统一由 <see cref="SettingsManager"/> 处理。
|
||||
/// 后续按 Audio、Gameplay、Graphics 等类别拆分字段时,必须保留
|
||||
/// <see cref="schemaVersion"/>,并在 SettingsManager 中补充对应的迁移逻辑。
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class SettingsSaveData
|
||||
{
|
||||
/// <summary>
|
||||
/// 设置存档结构版本。当前为首次建立 SettingsSaveData 的 V1。
|
||||
/// </summary>
|
||||
public const int CurrentSchemaVersion = 1;
|
||||
|
||||
public int schemaVersion = CurrentSchemaVersion;
|
||||
|
||||
// Audio
|
||||
public int masterVolume = 50;
|
||||
public int musicVolume = 50;
|
||||
public int soundEffectVolume = 50;
|
||||
public int uiVolume = 50;
|
||||
|
||||
/// <summary>
|
||||
/// 是否启用游戏内音乐特效。当前控制 HighPassFilterEffect 与 LowPassFilterEffect;
|
||||
/// 关闭时会立即清除正在歌曲上的滤波 RTPC,后续同类特效也应复用此开关。
|
||||
/// </summary>
|
||||
public bool enableInGameAudioEffects = true;
|
||||
|
||||
// Graphics
|
||||
/// <summary>
|
||||
/// 玩家选择的 Quality Preset。新存档会读取当前平台在 Project Settings 中配置的默认档位。
|
||||
/// </summary>
|
||||
public GraphicsQualityPreset graphicsQualityPreset = GraphicsQualityPreset.Balanced;
|
||||
|
||||
public int targetFrame = 60;
|
||||
|
||||
/// <summary>
|
||||
/// URP Render Scale 档位,0–5 分别对应 0.5–1.0。
|
||||
/// 保留 FormerlySerializedAs 以兼容场景中旧的字段名;预发布 ES3 存档可直接重置。
|
||||
/// </summary>
|
||||
[FormerlySerializedAs("resolutionLevel")]
|
||||
public int renderScaleLevel = 3;
|
||||
|
||||
/// <summary>
|
||||
/// 后处理总开关。关闭后,所有 URP 相机都会停用 post-processing,Global Volume 也不会参与计算;
|
||||
/// 因此原生与自定义后处理都不会产生渲染开销。
|
||||
/// </summary>
|
||||
public bool enablePostProcessing = true;
|
||||
|
||||
/// <summary>
|
||||
/// Anime Bloom 的质量档位。默认 Standard,对应 Diffusion 8。
|
||||
/// </summary>
|
||||
public BloomQuality bloomQuality = BloomQuality.Standard;
|
||||
|
||||
/// <summary>
|
||||
/// 后续 Note / 演出特效读取的质量档位。默认 High,以保持当前未分级特效的视觉基线。
|
||||
/// </summary>
|
||||
public VfxQuality vfxQuality = VfxQuality.High;
|
||||
|
||||
// Desktop display settings. These values are saved on every platform but only applied on PC and in the Unity Editor.
|
||||
public bool vSyncEnabled = false;
|
||||
public GraphicsDisplayMode displayMode = GraphicsDisplayMode.BorderlessFullscreen;
|
||||
public int displayResolutionWidth = 0;
|
||||
public int displayResolutionHeight = 0;
|
||||
|
||||
// Gameplay
|
||||
public int beatmapOffset = 0;
|
||||
|
||||
// Localization
|
||||
public int languageIndex = 0;
|
||||
|
||||
// Developer settings. 这些字段会在后续分类重构时迁出正式 Release 设置。
|
||||
public bool debugMode = false;
|
||||
public bool judgeType = false;
|
||||
public bool autoPlay = false;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c2ca67619927cac4a91d5b0612d6f7eb
|
||||
guid: a52b8dd62f9e43b69cd3fa97ad8ed71c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
@@ -12,9 +12,9 @@ namespace Ichni.UI
|
||||
public int selectedIndex;
|
||||
public string selectedOption;
|
||||
|
||||
public void SetUp(int initialValue, List<string> options, string title = "")
|
||||
public void SetUp(int initialValue, List<string> options, string title = "", bool preservePrefabTitle = false)
|
||||
{
|
||||
base.SetUp(title);
|
||||
base.SetUp(title, preservePrefabTitle: preservePrefabTitle);
|
||||
|
||||
this.options = options;
|
||||
this.dropdown.items = new List<CustomDropdown.Item>();
|
||||
@@ -45,4 +45,4 @@ namespace Ichni.UI
|
||||
dropdown.UpdateItemLayout();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,8 +19,18 @@ namespace Ichni.UI
|
||||
|
||||
public UnityAction updateValueAction;
|
||||
|
||||
public virtual void SetUp(string title = "", string subTitle = "")
|
||||
/// <summary>
|
||||
/// 初始化设置控件的标题区域。
|
||||
/// <paramref name="preservePrefabTitle"/> 用于已经由 Unity Localization 直接驱动标题的控件:
|
||||
/// 运行时代码不会覆盖或隐藏 Prefab 中的本地化标题。
|
||||
/// </summary>
|
||||
public virtual void SetUp(string title = "", string subTitle = "", bool preservePrefabTitle = false)
|
||||
{
|
||||
if (preservePrefabTitle)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (title != "")
|
||||
{
|
||||
SetTitle(title, subTitle);
|
||||
@@ -51,4 +61,4 @@ namespace Ichni.UI
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,9 +7,9 @@ namespace Ichni.UI
|
||||
public bool value;
|
||||
public SwitchManager switchManager;
|
||||
|
||||
public void SetUp(bool initialValue, string title = "")
|
||||
public void SetUp(bool initialValue, string title = "", bool preservePrefabTitle = false)
|
||||
{
|
||||
base.SetUp(title);
|
||||
base.SetUp(title, preservePrefabTitle: preservePrefabTitle);
|
||||
|
||||
switchManager.onValueChanged.AddListener(isOn =>
|
||||
{
|
||||
@@ -34,4 +34,4 @@ namespace Ichni.UI
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,158 +1,323 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using DG.Tweening;
|
||||
using Sirenix.OdinInspector;
|
||||
using SLSUtilities.WwiseAssistance;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.Serialization;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Ichni.Menu.UI
|
||||
{
|
||||
public partial class MessageBox : SerializedMonoBehaviour
|
||||
/// <summary>
|
||||
/// 单条文本提示框。
|
||||
/// 多条弹窗的 FIFO 顺序由 MessageUIPage 统一管理;本类只负责当前一条消息的布局、
|
||||
/// 入退场视觉和确认输入,避免与 UIPage 的队列职责重复。
|
||||
/// </summary>
|
||||
public sealed class MessageBox : MonoBehaviour
|
||||
{
|
||||
public CanvasGroup canvasGroup;
|
||||
[Header("Base")]
|
||||
[SerializeField] private CanvasGroup canvasGroup;
|
||||
[SerializeField] private Button receiveButton;
|
||||
|
||||
[Tooltip("当该消息框结束所有消息并彻底淡出消失时触发。")]
|
||||
public UnityEvent onAllMessagesClosed = new UnityEvent();
|
||||
[Header("Text")]
|
||||
[SerializeField] private TMP_Text titleText;
|
||||
[SerializeField] private TMP_Text contentText;
|
||||
|
||||
public int infoIndex;
|
||||
public List<MessageBoxInfo> infos;
|
||||
|
||||
public Sprite defaultIcon;
|
||||
public Image iconImage;
|
||||
public TMP_Text titleText;
|
||||
public TMP_Text contentText;
|
||||
|
||||
public Button receiveButton;
|
||||
|
||||
public Tweener fadeTweener;
|
||||
[Header("Layout References")]
|
||||
[Tooltip("可变高度的最终布局节点。动画期间不会修改它、Title 或 Content 的 RectTransform。")]
|
||||
[SerializeField] private RectTransform messageBody;
|
||||
[SerializeField] private RectTransform backgroundVisual;
|
||||
[SerializeField] private RectMask2D titleTextMask;
|
||||
[SerializeField] private RectTransform contentLayoutRoot;
|
||||
[SerializeField] private RectMask2D contentTextMask;
|
||||
[SerializeField] private RectTransform railRoot;
|
||||
[SerializeField] private RectTransform leftRail;
|
||||
[SerializeField] private RectTransform rightRail;
|
||||
|
||||
private void Start()
|
||||
[Header("Content Height Limit")]
|
||||
[SerializeField, Min(0f)] private float maximumBodyHeight = 600f;
|
||||
[SerializeField, Min(1f)] private float minimumContentFontSize = 18f;
|
||||
|
||||
[Header("Animation")]
|
||||
[Tooltip("背景与文本 Mask 从中心展开前的延迟;Rail 的默认延迟为 0,因此会先行动。")]
|
||||
[SerializeField, Min(0f)] private float bodyOpenDelay = 0.1f;
|
||||
[SerializeField, Min(0f)] private float bodyOpenDuration = 0.5f;
|
||||
[SerializeField, Min(0f)] private float railOpenDelay;
|
||||
[SerializeField, Min(0f)] private float railOpenDuration = 0.5f;
|
||||
[SerializeField, Min(0f)] private float bodyCloseDelay;
|
||||
[SerializeField, Min(0f)] private float bodyCloseDuration = 0.5f;
|
||||
[SerializeField, Min(0f)] private float railCloseDelay = 0.1f;
|
||||
[SerializeField, Min(0f)] private float railCloseDuration = 0.5f;
|
||||
[SerializeField, Min(0f)] private float closedMaskHorizontalPadding = 520f;
|
||||
[SerializeField] private Ease bodyEase = Ease.OutCubic;
|
||||
[SerializeField] private Ease railEase = Ease.OutQuart;
|
||||
|
||||
/// <summary>
|
||||
/// 退场动画结束后触发。MessageUIPage 订阅它以销毁当前实例并继续 FIFO 队列。
|
||||
/// </summary>
|
||||
public event Action<MessageBox> Closed;
|
||||
|
||||
private Sequence transitionSequence;
|
||||
private CanvasGroup leftRailCanvasGroup;
|
||||
private CanvasGroup rightRailCanvasGroup;
|
||||
private Vector2 backgroundOpenSizeDelta;
|
||||
private Vector2 leftRailOpenPosition;
|
||||
private Vector2 rightRailOpenPosition;
|
||||
private float contentMaximumFontSize;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
receiveButton.onClick.AddListener(()=>PlayNextMessage(true));
|
||||
receiveButton.GetComponent<RectTransform>().sizeDelta = new Vector2(Screen.width, Screen.height);
|
||||
backgroundOpenSizeDelta = backgroundVisual.sizeDelta;
|
||||
leftRailOpenPosition = leftRail.anchoredPosition;
|
||||
rightRailOpenPosition = rightRail.anchoredPosition;
|
||||
leftRailCanvasGroup = leftRail.GetComponent<CanvasGroup>();
|
||||
rightRailCanvasGroup = rightRail.GetComponent<CanvasGroup>();
|
||||
contentMaximumFontSize = contentText.fontSize;
|
||||
|
||||
receiveButton.onClick.AddListener(HandleReceiveButtonClicked);
|
||||
}
|
||||
|
||||
public void SetUp()
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (infos.Count == 0)
|
||||
transitionSequence?.Kill();
|
||||
receiveButton.onClick.RemoveListener(HandleReceiveButtonClicked);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入唯一一条待显示文本,并播放入场动画。
|
||||
/// 多条提示请分别提交给 MessageUIPage,而不要在一个 MessageBox 中追加消息。
|
||||
/// </summary>
|
||||
public void SetUp(string title, string content)
|
||||
{
|
||||
titleText.text = title ?? string.Empty;
|
||||
contentText.text = content ?? string.Empty;
|
||||
|
||||
RefreshLayoutAndFitContentText();
|
||||
Open();
|
||||
}
|
||||
|
||||
private void HandleReceiveButtonClicked()
|
||||
{
|
||||
AudioManager.Post(AK.EVENTS.CONFIRM);
|
||||
Close();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用最终宽度计算文字换行与内容高度。正文超过 maximumBodyHeight 时,
|
||||
/// 通过二分查找缩小至可容纳的最大字号;不会引入滚动或截断内容。
|
||||
/// </summary>
|
||||
private void RefreshLayoutAndFitContentText()
|
||||
{
|
||||
SetOpenVisualState();
|
||||
ForceRebuildLayout();
|
||||
|
||||
if (maximumBodyHeight <= 0f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
infoIndex = 0;
|
||||
PlayNextMessage();
|
||||
FadeIn();
|
||||
}
|
||||
|
||||
public void SetUpIcon(Sprite icon)
|
||||
{
|
||||
iconImage.sprite = icon;
|
||||
}
|
||||
|
||||
public void AddInfo(string title, string content, UnityAction action = null, Sprite icon = null)
|
||||
{
|
||||
MessageBoxInfo info = new MessageBoxInfo(icon, title, content, action);
|
||||
infos.Add(info);
|
||||
}
|
||||
contentText.enableAutoSizing = false;
|
||||
contentText.fontSize = contentMaximumFontSize;
|
||||
ForceRebuildLayout();
|
||||
|
||||
public void PlayNextMessage(bool playAudio = false)
|
||||
{
|
||||
if (playAudio)
|
||||
if (messageBody.rect.height <= maximumBodyHeight)
|
||||
{
|
||||
AudioManager.Post(AK.EVENTS.CONFIRM);
|
||||
}
|
||||
|
||||
if (infoIndex >= infos.Count)
|
||||
{
|
||||
FadeOut();
|
||||
return;
|
||||
}
|
||||
|
||||
infos[infoIndex].action?.Invoke();
|
||||
|
||||
if (titleText != null) titleText.text = infos[infoIndex].title;
|
||||
if (contentText != null) contentText.text = infos[infoIndex].content;
|
||||
|
||||
this.iconImage.sprite = infos[infoIndex].icon != null ? infos[infoIndex].icon : defaultIcon;
|
||||
infoIndex++;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
infos = new List<MessageBoxInfo>();
|
||||
infoIndex = 0;
|
||||
iconImage.sprite = defaultIcon;
|
||||
titleText.text = string.Empty;
|
||||
contentText.text = string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
public partial class MessageBox
|
||||
{
|
||||
// 废弃对 I2.Loc 参数化功能的支持
|
||||
// public void SetParameter(string paramName, string paramValue, bool localize = false)
|
||||
// {
|
||||
// }
|
||||
}
|
||||
float minimumFontSize = Mathf.Min(minimumContentFontSize, contentMaximumFontSize);
|
||||
float lowerBound = minimumFontSize;
|
||||
float upperBound = contentMaximumFontSize;
|
||||
float bestFontSize = minimumFontSize;
|
||||
|
||||
public partial class MessageBox
|
||||
{
|
||||
public void FadeIn(float duration = 0.5f, bool ignoreTimeScale = false)
|
||||
// 字号与内容高度单调相关;六次二分已足够平滑且只在弹窗创建时执行。
|
||||
for (int iteration = 0; iteration < 6; iteration++)
|
||||
{
|
||||
float candidate = (lowerBound + upperBound) * 0.5f;
|
||||
contentText.fontSize = candidate;
|
||||
ForceRebuildLayout();
|
||||
|
||||
if (messageBody.rect.height <= maximumBodyHeight)
|
||||
{
|
||||
bestFontSize = candidate;
|
||||
lowerBound = candidate;
|
||||
}
|
||||
else
|
||||
{
|
||||
upperBound = candidate;
|
||||
}
|
||||
}
|
||||
|
||||
contentText.fontSize = bestFontSize;
|
||||
ForceRebuildLayout();
|
||||
|
||||
if (messageBody.rect.height > maximumBodyHeight)
|
||||
{
|
||||
Debug.LogWarning(
|
||||
$"[MessageBox] 正文在最小字号 {minimumFontSize:F1} 下仍超过最大高度 {maximumBodyHeight:F1};" +
|
||||
"已保留完整内容并允许消息框继续增高。",
|
||||
this);
|
||||
}
|
||||
}
|
||||
|
||||
private void ForceRebuildLayout()
|
||||
{
|
||||
Canvas.ForceUpdateCanvases();
|
||||
LayoutRebuilder.ForceRebuildLayoutImmediate(contentLayoutRoot);
|
||||
LayoutRebuilder.ForceRebuildLayoutImmediate(messageBody);
|
||||
Canvas.ForceUpdateCanvases();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 恢复最终视觉尺寸以完成布局。这里不会改变 MessageBox、Title 或 Content 的尺寸,
|
||||
/// 因此 TMP 在展开和收拢全过程都不会重新换行。
|
||||
/// </summary>
|
||||
private void SetOpenVisualState()
|
||||
{
|
||||
backgroundVisual.sizeDelta = backgroundOpenSizeDelta;
|
||||
titleTextMask.padding = Vector4.zero;
|
||||
contentTextMask.padding = Vector4.zero;
|
||||
leftRail.anchoredPosition = leftRailOpenPosition;
|
||||
rightRail.anchoredPosition = rightRailOpenPosition;
|
||||
leftRailCanvasGroup.alpha = 1f;
|
||||
rightRailCanvasGroup.alpha = 1f;
|
||||
}
|
||||
|
||||
private void SetClosedVisualState()
|
||||
{
|
||||
backgroundVisual.sizeDelta = GetClosedBackgroundSizeDelta();
|
||||
titleTextMask.padding = ClosedMaskPadding;
|
||||
contentTextMask.padding = ClosedMaskPadding;
|
||||
|
||||
float halfRootWidth = railRoot.rect.width * 0.5f;
|
||||
leftRail.anchoredPosition = new Vector2(halfRootWidth, leftRailOpenPosition.y);
|
||||
rightRail.anchoredPosition = new Vector2(-halfRootWidth, rightRailOpenPosition.y);
|
||||
leftRailCanvasGroup.alpha = 0f;
|
||||
rightRailCanvasGroup.alpha = 0f;
|
||||
}
|
||||
|
||||
private Vector4 ClosedMaskPadding =>
|
||||
new(closedMaskHorizontalPadding, 0f, closedMaskHorizontalPadding, 0f);
|
||||
|
||||
/// <summary>
|
||||
/// Background 使用左右 Stretch 锚点。以最终实际宽度抵消它的 SizeDelta X,
|
||||
/// 可将图像视觉收拢到中心而不改变 MessageBox 的布局宽度。
|
||||
/// </summary>
|
||||
private Vector2 GetClosedBackgroundSizeDelta() =>
|
||||
new(backgroundOpenSizeDelta.x - backgroundVisual.rect.width, backgroundOpenSizeDelta.y);
|
||||
|
||||
private static Tween CreateMaskPaddingTween(RectMask2D mask, Vector4 targetPadding, float duration, Ease ease) =>
|
||||
DOTween.To(() => mask.padding, value => mask.padding = value, targetPadding, duration).SetEase(ease);
|
||||
|
||||
private static void AddRailTransition(
|
||||
Sequence sequence,
|
||||
RectTransform rail,
|
||||
CanvasGroup railCanvasGroup,
|
||||
Vector2 targetPosition,
|
||||
float targetAlpha,
|
||||
float delay,
|
||||
float duration,
|
||||
Ease positionEase)
|
||||
{
|
||||
sequence.Insert(delay, rail.DOAnchorPos(targetPosition, duration).SetEase(positionEase));
|
||||
sequence.Insert(delay, railCanvasGroup.DOFade(targetAlpha, duration).SetEase(Ease.Linear));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 只展开 Background 与两个文字 Mask;MessageBox、标题、正文均已是最终布局尺寸。
|
||||
/// 每个 Sequence 都先 Pause,再在结尾显式调用 Play,符合项目的 DOTween 使用约定。
|
||||
/// </summary>
|
||||
private void Open()
|
||||
{
|
||||
transitionSequence?.Kill();
|
||||
|
||||
canvasGroup.gameObject.SetActive(true);
|
||||
|
||||
fadeTweener = canvasGroup.DOFade(1f, duration).OnComplete(() =>
|
||||
canvasGroup.alpha = 1f;
|
||||
canvasGroup.interactable = false;
|
||||
canvasGroup.blocksRaycasts = false;
|
||||
SetClosedVisualState();
|
||||
|
||||
transitionSequence = DOTween.Sequence().SetAutoKill(true).Pause();
|
||||
transitionSequence.Insert(
|
||||
bodyOpenDelay,
|
||||
backgroundVisual.DOSizeDelta(backgroundOpenSizeDelta, bodyOpenDuration).SetEase(bodyEase));
|
||||
transitionSequence.Insert(
|
||||
bodyOpenDelay,
|
||||
CreateMaskPaddingTween(titleTextMask, Vector4.zero, bodyOpenDuration, bodyEase));
|
||||
transitionSequence.Insert(
|
||||
bodyOpenDelay,
|
||||
CreateMaskPaddingTween(contentTextMask, Vector4.zero, bodyOpenDuration, bodyEase));
|
||||
AddRailTransition(
|
||||
transitionSequence,
|
||||
leftRail,
|
||||
leftRailCanvasGroup,
|
||||
leftRailOpenPosition,
|
||||
1f,
|
||||
railOpenDelay,
|
||||
railOpenDuration,
|
||||
railEase);
|
||||
AddRailTransition(
|
||||
transitionSequence,
|
||||
rightRail,
|
||||
rightRailCanvasGroup,
|
||||
rightRailOpenPosition,
|
||||
1f,
|
||||
railOpenDelay,
|
||||
railOpenDuration,
|
||||
railEase);
|
||||
|
||||
transitionSequence.OnComplete(() =>
|
||||
{
|
||||
canvasGroup.interactable = true;
|
||||
canvasGroup.blocksRaycasts = true;
|
||||
});
|
||||
|
||||
if (ignoreTimeScale)
|
||||
{
|
||||
fadeTweener.SetUpdate(true);
|
||||
}
|
||||
|
||||
fadeTweener.Play();
|
||||
transitionSequence.Play();
|
||||
}
|
||||
|
||||
public void FadeOut(float duration = 0.5f, bool ignoreTimeScale = false)
|
||||
|
||||
/// <summary>
|
||||
/// 反向收拢 Background、文字 Mask 和两侧 Rail;完成后通知 MessageUIPage 显示下一项。
|
||||
/// </summary>
|
||||
private void Close()
|
||||
{
|
||||
transitionSequence?.Kill();
|
||||
canvasGroup.interactable = false;
|
||||
canvasGroup.blocksRaycasts = false;
|
||||
|
||||
fadeTweener = canvasGroup.DOFade(0f, duration).OnComplete(() =>
|
||||
|
||||
float halfRootWidth = railRoot.rect.width * 0.5f;
|
||||
transitionSequence = DOTween.Sequence().SetAutoKill(true).Pause();
|
||||
transitionSequence.Insert(
|
||||
bodyCloseDelay,
|
||||
backgroundVisual.DOSizeDelta(GetClosedBackgroundSizeDelta(), bodyCloseDuration).SetEase(Ease.InCubic));
|
||||
transitionSequence.Insert(
|
||||
bodyCloseDelay,
|
||||
CreateMaskPaddingTween(titleTextMask, ClosedMaskPadding, bodyCloseDuration, Ease.InCubic));
|
||||
transitionSequence.Insert(
|
||||
bodyCloseDelay,
|
||||
CreateMaskPaddingTween(contentTextMask, ClosedMaskPadding, bodyCloseDuration, Ease.InCubic));
|
||||
AddRailTransition(
|
||||
transitionSequence,
|
||||
leftRail,
|
||||
leftRailCanvasGroup,
|
||||
new Vector2(halfRootWidth, leftRailOpenPosition.y),
|
||||
0f,
|
||||
railCloseDelay,
|
||||
railCloseDuration,
|
||||
Ease.InQuart);
|
||||
AddRailTransition(
|
||||
transitionSequence,
|
||||
rightRail,
|
||||
rightRailCanvasGroup,
|
||||
new Vector2(-halfRootWidth, rightRailOpenPosition.y),
|
||||
0f,
|
||||
railCloseDelay,
|
||||
railCloseDuration,
|
||||
Ease.InQuart);
|
||||
|
||||
transitionSequence.OnComplete(() =>
|
||||
{
|
||||
canvasGroup.gameObject.SetActive(false);
|
||||
onAllMessagesClosed?.Invoke();
|
||||
Closed?.Invoke(this);
|
||||
});
|
||||
|
||||
if (ignoreTimeScale)
|
||||
{
|
||||
fadeTweener.SetUpdate(true);
|
||||
}
|
||||
|
||||
fadeTweener.Play();
|
||||
transitionSequence.Play();
|
||||
}
|
||||
}
|
||||
|
||||
public struct MessageBoxInfo
|
||||
{
|
||||
public Sprite icon;
|
||||
public string title;
|
||||
public string content;
|
||||
public UnityAction action;
|
||||
|
||||
public MessageBoxInfo(Sprite icon, string title, string content, UnityAction action)
|
||||
{
|
||||
this.icon = icon;
|
||||
this.title = title;
|
||||
this.content = content;
|
||||
this.action = action;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,96 +4,306 @@ using DG.Tweening;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Ichni.Menu.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// 可复用的多选弹窗元素。调用方提供标题、内容与任意数量的 <see cref="SelectionBoxOption"/>,
|
||||
/// 本类动态实例化对应按钮,并确保一次显示最多只会执行一个选项回调。
|
||||
/// 通用多选弹窗。
|
||||
/// 标题、正文与按钮均在播放前完成最终布局;入退场只改变 Background、两处文本 Mask 和 Rail,
|
||||
/// 因而不会在动画期间触发 TMP 重新换行或按钮布局抖动。
|
||||
/// </summary>
|
||||
public class SelectionBox : MonoBehaviour
|
||||
public sealed class SelectionBox : MonoBehaviour
|
||||
{
|
||||
[Header("Selection Box")]
|
||||
public CanvasGroup canvasGroup;
|
||||
public TMP_Text titleText;
|
||||
public TMP_Text contentText;
|
||||
public RectTransform optionContainer;
|
||||
public SelectionBoxButton optionButtonPrefab;
|
||||
[Header("Base")]
|
||||
[SerializeField] private CanvasGroup canvasGroup;
|
||||
[SerializeField] private CanvasGroup optionCanvasGroup;
|
||||
|
||||
private readonly List<SelectionBoxButton> _generatedButtons = new();
|
||||
private bool _isResolved;
|
||||
[Header("Text & Options")]
|
||||
[SerializeField] private TMP_Text titleText;
|
||||
[SerializeField] private TMP_Text contentText;
|
||||
[SerializeField] private RectTransform optionContainer;
|
||||
[SerializeField] private SelectionBoxButton optionButtonPrefab;
|
||||
|
||||
[Header("Layout References")]
|
||||
[SerializeField] private RectTransform messageBody;
|
||||
[SerializeField] private RectTransform backgroundVisual;
|
||||
[SerializeField] private RectMask2D titleTextMask;
|
||||
[SerializeField] private RectTransform contentLayoutRoot;
|
||||
[SerializeField] private RectMask2D contentTextMask;
|
||||
[SerializeField] private RectTransform railRoot;
|
||||
[SerializeField] private RectTransform leftRail;
|
||||
[SerializeField] private RectTransform rightRail;
|
||||
|
||||
[Header("Animation")]
|
||||
[SerializeField, Min(0f)] private float bodyOpenDelay = 0.1f;
|
||||
[SerializeField, Min(0f)] private float bodyOpenDuration = 0.5f;
|
||||
[SerializeField, Min(0f)] private float railOpenDelay;
|
||||
[SerializeField, Min(0f)] private float railOpenDuration = 0.5f;
|
||||
[SerializeField, Min(0f)] private float bodyCloseDelay;
|
||||
[SerializeField, Min(0f)] private float bodyCloseDuration = 0.5f;
|
||||
[SerializeField, Min(0f)] private float railCloseDelay = 0.1f;
|
||||
[SerializeField, Min(0f)] private float railCloseDuration = 0.5f;
|
||||
[SerializeField, Min(0f)] private float closedMaskHorizontalPadding = 600f;
|
||||
[SerializeField] private Ease bodyEase = Ease.OutCubic;
|
||||
[SerializeField] private Ease railEase = Ease.OutQuart;
|
||||
|
||||
/// <summary>
|
||||
/// 选项被选择并且自身淡出结束后触发。页面容器使用它销毁本次生成的 SelectionBox。
|
||||
/// 玩家选择任一选项、弹窗完成退场后触发。MessageUIPage 使用它继续共享 FIFO 队列。
|
||||
/// </summary>
|
||||
public event Action<SelectionBox> Closed;
|
||||
|
||||
private readonly List<SelectionBoxButton> generatedButtons = new();
|
||||
private Sequence transitionSequence;
|
||||
private CanvasGroup leftRailCanvasGroup;
|
||||
private CanvasGroup rightRailCanvasGroup;
|
||||
private Vector2 backgroundOpenSizeDelta;
|
||||
private Vector2 leftRailOpenPosition;
|
||||
private Vector2 rightRailOpenPosition;
|
||||
private bool isResolved;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
canvasGroup ??= GetComponent<CanvasGroup>();
|
||||
backgroundOpenSizeDelta = backgroundVisual.sizeDelta;
|
||||
leftRailOpenPosition = leftRail.anchoredPosition;
|
||||
rightRailOpenPosition = rightRail.anchoredPosition;
|
||||
leftRailCanvasGroup = leftRail.GetComponent<CanvasGroup>();
|
||||
rightRailCanvasGroup = rightRail.GetComponent<CanvasGroup>();
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
transitionSequence?.Kill();
|
||||
ClearGeneratedButtons();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据运行时选项初始化弹窗。至少需要一个选项;失败时返回 false,且不会显示半配置的弹窗。
|
||||
/// 创建本次选择所需的按钮并播放入场动画。空选项没有可执行的玩家选择,因此返回 false。
|
||||
/// </summary>
|
||||
public bool SetUp(string title, string content, IReadOnlyList<SelectionBoxOption> options)
|
||||
{
|
||||
if (canvasGroup == null || optionContainer == null || optionButtonPrefab == null ||
|
||||
options == null || options.Count == 0)
|
||||
if (options == null || options.Count == 0)
|
||||
{
|
||||
Debug.LogWarning("[SelectionBox] 缺少 CanvasGroup、选项容器、选项按钮预制体,或未提供任何选项。");
|
||||
Debug.LogWarning("[SelectionBox] 未提供任何 SelectionBoxOption,忽略空选项框。", this);
|
||||
return false;
|
||||
}
|
||||
|
||||
ClearGeneratedButtons();
|
||||
_isResolved = false;
|
||||
|
||||
if (titleText != null) titleText.text = title ?? string.Empty;
|
||||
if (contentText != null) contentText.text = content ?? string.Empty;
|
||||
isResolved = false;
|
||||
titleText.text = title ?? string.Empty;
|
||||
contentText.text = content ?? string.Empty;
|
||||
|
||||
foreach (SelectionBoxOption option in options)
|
||||
{
|
||||
SelectionBoxButton button = Instantiate(optionButtonPrefab, optionContainer);
|
||||
_generatedButtons.Add(button);
|
||||
generatedButtons.Add(button);
|
||||
button.SetUp(option.label, () => Select(option.action));
|
||||
}
|
||||
|
||||
gameObject.SetActive(true);
|
||||
canvasGroup.alpha = 0f;
|
||||
canvasGroup.interactable = true;
|
||||
canvasGroup.blocksRaycasts = true;
|
||||
canvasGroup.DOFade(1f, 0.2f).Play();
|
||||
RefreshFinalLayout();
|
||||
Open();
|
||||
return true;
|
||||
}
|
||||
|
||||
private void Select(UnityAction action)
|
||||
{
|
||||
if (_isResolved) return;
|
||||
_isResolved = true;
|
||||
if (isResolved) return;
|
||||
isResolved = true;
|
||||
|
||||
// 先禁用所有输入,再执行回调。回调可以触发存档、场景切换或打开下一层 UI,
|
||||
// 因而不能让同一帧内的其它按钮再次触发。
|
||||
// 先阻断输入,再执行可能触发存档、跳转或新 UI 的业务回调。
|
||||
canvasGroup.interactable = false;
|
||||
canvasGroup.blocksRaycasts = false;
|
||||
foreach (SelectionBoxButton button in _generatedButtons)
|
||||
foreach (SelectionBoxButton button in generatedButtons)
|
||||
{
|
||||
if (button?.button != null)
|
||||
button.button.interactable = false;
|
||||
button.button.interactable = false;
|
||||
}
|
||||
|
||||
action?.Invoke();
|
||||
canvasGroup.DOFade(0f, 0.2f).OnComplete(() => Closed?.Invoke(this)).Play();
|
||||
Close();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 在最终尺寸下重建正文、主体和按钮行的布局。后续动画不再改变这些布局节点的尺寸。
|
||||
/// </summary>
|
||||
private void RefreshFinalLayout()
|
||||
{
|
||||
SetOpenVisualState();
|
||||
Canvas.ForceUpdateCanvases();
|
||||
LayoutRebuilder.ForceRebuildLayoutImmediate(contentLayoutRoot);
|
||||
LayoutRebuilder.ForceRebuildLayoutImmediate(messageBody);
|
||||
LayoutRebuilder.ForceRebuildLayoutImmediate(optionContainer);
|
||||
Canvas.ForceUpdateCanvases();
|
||||
}
|
||||
|
||||
private void SetOpenVisualState()
|
||||
{
|
||||
backgroundVisual.sizeDelta = backgroundOpenSizeDelta;
|
||||
titleTextMask.padding = Vector4.zero;
|
||||
contentTextMask.padding = Vector4.zero;
|
||||
optionContainer.localScale = new Vector3(1f, optionContainer.localScale.y, optionContainer.localScale.z);
|
||||
optionCanvasGroup.alpha = 1f;
|
||||
optionCanvasGroup.interactable = true;
|
||||
optionCanvasGroup.blocksRaycasts = true;
|
||||
leftRail.anchoredPosition = leftRailOpenPosition;
|
||||
rightRail.anchoredPosition = rightRailOpenPosition;
|
||||
leftRailCanvasGroup.alpha = 1f;
|
||||
rightRailCanvasGroup.alpha = 1f;
|
||||
}
|
||||
|
||||
private void SetClosedVisualState()
|
||||
{
|
||||
backgroundVisual.sizeDelta = GetClosedBackgroundSizeDelta();
|
||||
titleTextMask.padding = ClosedMaskPadding;
|
||||
contentTextMask.padding = ClosedMaskPadding;
|
||||
optionCanvasGroup.alpha = 0f;
|
||||
optionCanvasGroup.interactable = false;
|
||||
optionCanvasGroup.blocksRaycasts = false;
|
||||
|
||||
float halfRootWidth = railRoot.rect.width * 0.5f;
|
||||
leftRail.anchoredPosition = new Vector2(halfRootWidth, leftRailOpenPosition.y);
|
||||
rightRail.anchoredPosition = new Vector2(-halfRootWidth, rightRailOpenPosition.y);
|
||||
leftRailCanvasGroup.alpha = 0f;
|
||||
rightRailCanvasGroup.alpha = 0f;
|
||||
}
|
||||
|
||||
private Vector4 ClosedMaskPadding =>
|
||||
new(closedMaskHorizontalPadding, 0f, closedMaskHorizontalPadding, 0f);
|
||||
|
||||
private Vector2 GetClosedBackgroundSizeDelta() =>
|
||||
new(backgroundOpenSizeDelta.x - backgroundVisual.rect.width, backgroundOpenSizeDelta.y);
|
||||
|
||||
private static Tween CreateMaskPaddingTween(RectMask2D mask, Vector4 targetPadding, float duration, Ease ease) =>
|
||||
DOTween.To(() => mask.padding, value => mask.padding = value, targetPadding, duration).SetEase(ease);
|
||||
|
||||
private static void AddRailTransition(
|
||||
Sequence sequence,
|
||||
RectTransform rail,
|
||||
CanvasGroup railCanvasGroup,
|
||||
Vector2 targetPosition,
|
||||
float targetAlpha,
|
||||
float delay,
|
||||
float duration,
|
||||
Ease positionEase)
|
||||
{
|
||||
sequence.Insert(delay, rail.DOAnchorPos(targetPosition, duration).SetEase(positionEase));
|
||||
sequence.Insert(delay, railCanvasGroup.DOFade(targetAlpha, duration).SetEase(Ease.Linear));
|
||||
}
|
||||
|
||||
private void Open()
|
||||
{
|
||||
transitionSequence?.Kill();
|
||||
canvasGroup.gameObject.SetActive(true);
|
||||
canvasGroup.alpha = 1f;
|
||||
canvasGroup.interactable = false;
|
||||
canvasGroup.blocksRaycasts = false;
|
||||
SetClosedVisualState();
|
||||
|
||||
transitionSequence = DOTween.Sequence().SetAutoKill(true).Pause();
|
||||
transitionSequence.Insert(
|
||||
bodyOpenDelay,
|
||||
backgroundVisual.DOSizeDelta(backgroundOpenSizeDelta, bodyOpenDuration).SetEase(bodyEase));
|
||||
transitionSequence.Insert(
|
||||
bodyOpenDelay,
|
||||
CreateMaskPaddingTween(titleTextMask, Vector4.zero, bodyOpenDuration, bodyEase));
|
||||
transitionSequence.Insert(
|
||||
bodyOpenDelay,
|
||||
CreateMaskPaddingTween(contentTextMask, Vector4.zero, bodyOpenDuration, bodyEase));
|
||||
AddRailTransition(
|
||||
transitionSequence,
|
||||
leftRail,
|
||||
leftRailCanvasGroup,
|
||||
leftRailOpenPosition,
|
||||
1f,
|
||||
railOpenDelay,
|
||||
railOpenDuration,
|
||||
railEase);
|
||||
AddRailTransition(
|
||||
transitionSequence,
|
||||
rightRail,
|
||||
rightRailCanvasGroup,
|
||||
rightRailOpenPosition,
|
||||
1f,
|
||||
railOpenDelay,
|
||||
railOpenDuration,
|
||||
railEase);
|
||||
|
||||
float optionRevealTime = bodyOpenDelay + bodyOpenDuration;
|
||||
transitionSequence.Insert(
|
||||
optionRevealTime,
|
||||
optionCanvasGroup.DOFade(1f, 0.4f).From(0f).SetEase(Ease.Linear));
|
||||
transitionSequence.Insert(
|
||||
optionRevealTime,
|
||||
optionContainer.DOAnchorPos(Vector2.zero, 0.4f).From(new Vector2(0f, 100f)).SetEase(Ease.OutQuad));
|
||||
transitionSequence.OnComplete(() =>
|
||||
{
|
||||
canvasGroup.interactable = true;
|
||||
canvasGroup.blocksRaycasts = true;
|
||||
optionCanvasGroup.interactable = true;
|
||||
optionCanvasGroup.blocksRaycasts = true;
|
||||
});
|
||||
// 项目约定:DOTween 动画必须由代码显式触发 Play。
|
||||
transitionSequence.Play();
|
||||
}
|
||||
|
||||
private void Close()
|
||||
{
|
||||
transitionSequence?.Kill();
|
||||
canvasGroup.interactable = false;
|
||||
canvasGroup.blocksRaycasts = false;
|
||||
optionCanvasGroup.interactable = false;
|
||||
optionCanvasGroup.blocksRaycasts = false;
|
||||
|
||||
float halfRootWidth = railRoot.rect.width * 0.5f;
|
||||
transitionSequence = DOTween.Sequence().SetAutoKill(true).Pause();
|
||||
transitionSequence.Insert(
|
||||
bodyCloseDelay,
|
||||
backgroundVisual.DOSizeDelta(GetClosedBackgroundSizeDelta(), bodyCloseDuration).SetEase(Ease.InCubic));
|
||||
transitionSequence.Insert(
|
||||
bodyCloseDelay,
|
||||
CreateMaskPaddingTween(titleTextMask, ClosedMaskPadding, bodyCloseDuration, Ease.InCubic));
|
||||
transitionSequence.Insert(
|
||||
bodyCloseDelay,
|
||||
CreateMaskPaddingTween(contentTextMask, ClosedMaskPadding, bodyCloseDuration, Ease.InCubic));
|
||||
transitionSequence.Insert(
|
||||
bodyCloseDelay,
|
||||
optionContainer.DOScaleX(0f, bodyCloseDuration).SetEase(Ease.InCubic));
|
||||
AddRailTransition(
|
||||
transitionSequence,
|
||||
leftRail,
|
||||
leftRailCanvasGroup,
|
||||
new Vector2(halfRootWidth, leftRailOpenPosition.y),
|
||||
0f,
|
||||
railCloseDelay,
|
||||
railCloseDuration,
|
||||
Ease.InQuart);
|
||||
AddRailTransition(
|
||||
transitionSequence,
|
||||
rightRail,
|
||||
rightRailCanvasGroup,
|
||||
new Vector2(-halfRootWidth, rightRailOpenPosition.y),
|
||||
0f,
|
||||
railCloseDelay,
|
||||
railCloseDuration,
|
||||
Ease.InQuart);
|
||||
|
||||
transitionSequence.OnComplete(() =>
|
||||
{
|
||||
canvasGroup.gameObject.SetActive(false);
|
||||
Closed?.Invoke(this);
|
||||
});
|
||||
// 项目约定:DOTween 动画必须由代码显式触发 Play。
|
||||
transitionSequence.Play();
|
||||
}
|
||||
|
||||
private void ClearGeneratedButtons()
|
||||
{
|
||||
foreach (SelectionBoxButton button in _generatedButtons)
|
||||
foreach (SelectionBoxButton button in generatedButtons)
|
||||
{
|
||||
if (button != null)
|
||||
Destroy(button.gameObject);
|
||||
Destroy(button.gameObject);
|
||||
}
|
||||
|
||||
_generatedButtons.Clear();
|
||||
generatedButtons.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using Ichni.UI;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Ichni.Menu.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// 通用 SelectionBox 的页面宿主,职责等同于 MessageBox 的页面容器:
|
||||
/// 显示时动态生成一个 SelectionBox,选择完成后统一淡出并销毁本次实例。
|
||||
/// </summary>
|
||||
public class SelectionBoxUIPage : UIPageBase
|
||||
{
|
||||
[Header("Selection Box Page")]
|
||||
public SelectionBox selectionBoxPrefab;
|
||||
public RectTransform selectionBoxContainer;
|
||||
|
||||
private SelectionBox _currentSelectionBox;
|
||||
private bool _isShowing;
|
||||
|
||||
/// <summary>当前是否已有一个 SelectionBox 等待玩家选择。</summary>
|
||||
public bool IsShowing => _isShowing;
|
||||
|
||||
/// <summary>
|
||||
/// 生成并显示一组运行时选项。页面显示期间拒绝重复请求,避免两个弹窗争夺输入。
|
||||
/// </summary>
|
||||
public bool Show(string title, string content, IReadOnlyList<SelectionBoxOption> options)
|
||||
{
|
||||
if (_isShowing)
|
||||
{
|
||||
Debug.LogWarning("[SelectionBoxUIPage] 已有 SelectionBox 显示中,忽略重复请求。");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mainCanvasGroup == null || selectionBoxPrefab == null || selectionBoxContainer == null)
|
||||
{
|
||||
Debug.LogWarning("[SelectionBoxUIPage] 缺少 CanvasGroup、SelectionBox Prefab 或容器,无法显示选项框。");
|
||||
return false;
|
||||
}
|
||||
|
||||
_currentSelectionBox = Instantiate(selectionBoxPrefab, selectionBoxContainer);
|
||||
_currentSelectionBox.Closed += HandleSelectionBoxClosed;
|
||||
if (!_currentSelectionBox.SetUp(title, content, options))
|
||||
{
|
||||
Destroy(_currentSelectionBox.gameObject);
|
||||
_currentSelectionBox = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
_isShowing = true;
|
||||
|
||||
// UIPageBase 默认淡入完成后才开启射线;选择框从出现瞬间就必须阻断底层输入。
|
||||
mainCanvasGroup.gameObject.SetActive(true);
|
||||
mainCanvasGroup.interactable = true;
|
||||
mainCanvasGroup.blocksRaycasts = true;
|
||||
FadeIn();
|
||||
return true;
|
||||
}
|
||||
|
||||
private void HandleSelectionBoxClosed(SelectionBox selectionBox)
|
||||
{
|
||||
if (selectionBox != _currentSelectionBox) return;
|
||||
|
||||
FadeOut(0.2f, false, () =>
|
||||
{
|
||||
if (_currentSelectionBox != null)
|
||||
Destroy(_currentSelectionBox.gameObject);
|
||||
|
||||
_currentSelectionBox = null;
|
||||
_isShowing = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e8b607f8c5654e1eb3bf1f7ca33fd3a4
|
||||
@@ -11,6 +11,7 @@ namespace Ichni.Menu
|
||||
public ValueModifier musicVolumeModifier;
|
||||
public ValueModifier sfxVolumeModifier;
|
||||
public ValueModifier uiVolumeModifier;
|
||||
public Switch inGameAudioEffectsSwitch;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -19,7 +20,7 @@ namespace Ichni.Menu
|
||||
mainVolumeModifier.updateValueAction = () =>
|
||||
{
|
||||
gameSettings.masterVolume = mainVolumeModifier.GetValue();
|
||||
gameSettings.ApplyVolume();
|
||||
SettingsManager.instance.ApplyAudioSettings();
|
||||
};
|
||||
|
||||
musicVolumeModifier.SetUp(gameSettings.musicVolume, 10, "Menu UI/Settings_Music_Volume");
|
||||
@@ -27,7 +28,7 @@ namespace Ichni.Menu
|
||||
musicVolumeModifier.updateValueAction = () =>
|
||||
{
|
||||
gameSettings.musicVolume = musicVolumeModifier.GetValue();
|
||||
gameSettings.ApplyVolume();
|
||||
SettingsManager.instance.ApplyAudioSettings();
|
||||
};
|
||||
|
||||
sfxVolumeModifier.SetUp(gameSettings.soundEffectVolume, 10, "Menu UI/Settings_SFX_Volume");
|
||||
@@ -35,7 +36,7 @@ namespace Ichni.Menu
|
||||
sfxVolumeModifier.updateValueAction = () =>
|
||||
{
|
||||
gameSettings.soundEffectVolume = sfxVolumeModifier.GetValue();
|
||||
gameSettings.ApplyVolume();
|
||||
SettingsManager.instance.ApplyAudioSettings();
|
||||
};
|
||||
|
||||
uiVolumeModifier.SetUp(gameSettings.uiVolume, 10, "Menu UI/Settings_UI_Volume");
|
||||
@@ -43,7 +44,15 @@ namespace Ichni.Menu
|
||||
uiVolumeModifier.updateValueAction = () =>
|
||||
{
|
||||
gameSettings.uiVolume = uiVolumeModifier.GetValue();
|
||||
gameSettings.ApplyVolume();
|
||||
SettingsManager.instance.ApplyAudioSettings();
|
||||
};
|
||||
|
||||
inGameAudioEffectsSwitch.SetUp(gameSettings.enableInGameAudioEffects,
|
||||
"Menu UI/Settings_InGame_Audio_Effects");
|
||||
inGameAudioEffectsSwitch.updateValueAction = () =>
|
||||
{
|
||||
gameSettings.enableInGameAudioEffects = inGameAudioEffectsSwitch.GetValue();
|
||||
SettingsManager.instance.ApplyInGameAudioEffectsSettings();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -53,6 +62,7 @@ namespace Ichni.Menu
|
||||
musicVolumeModifier.SetValue(gameSettings.musicVolume);
|
||||
sfxVolumeModifier.SetValue(gameSettings.soundEffectVolume);
|
||||
uiVolumeModifier.SetValue(gameSettings.uiVolume);
|
||||
inGameAudioEffectsSwitch.SetValue(gameSettings.enableInGameAudioEffects);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace Ichni.UI
|
||||
languageDropdown.updateValueAction = () =>
|
||||
{
|
||||
gameSettings.languageIndex = languageDropdown.selectedIndex;
|
||||
gameSettings.ApplyLanguage();
|
||||
SettingsManager.instance.ApplyLanguageSettings();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -34,4 +34,4 @@ namespace Ichni.UI
|
||||
languageDropdown.SetValue(gameSettings.languageIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,22 +2,70 @@ using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Ichni.UI;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace Ichni.Menu
|
||||
{
|
||||
public class GraphicsSettingsWindow : SettingsWindow
|
||||
{
|
||||
public ValueModifier resolutionLevelModifier;
|
||||
private static readonly List<string> QualityPresetOptions = new List<string>
|
||||
{
|
||||
"Performant",
|
||||
"Balanced",
|
||||
"High Fidelity"
|
||||
};
|
||||
|
||||
private static readonly List<string> DisplayModeOptions = new List<string>
|
||||
{
|
||||
"Fullscreen",
|
||||
"Borderless Fullscreen",
|
||||
"Windowed"
|
||||
};
|
||||
|
||||
private static readonly List<string> BloomQualityOptions = new List<string>
|
||||
{
|
||||
"Off",
|
||||
"Performance",
|
||||
"Standard"
|
||||
};
|
||||
|
||||
private static readonly List<string> VfxQualityOptions = new List<string>
|
||||
{
|
||||
"Low",
|
||||
"Medium",
|
||||
"High"
|
||||
};
|
||||
|
||||
private readonly List<Vector2Int> _availableDisplayResolutions = new List<Vector2Int>();
|
||||
private readonly List<string> _displayResolutionOptions = new List<string>();
|
||||
|
||||
public Dropdown qualityPresetDropdown;
|
||||
[FormerlySerializedAs("resolutionLevelModifier")]
|
||||
public ValueModifier renderScaleModifier;
|
||||
public ValueModifier targetFrameModifier;
|
||||
public Switch postProcessingSwitch;
|
||||
public Dropdown bloomQualityDropdown;
|
||||
public Dropdown vfxQualityDropdown;
|
||||
public Switch vSyncSwitch;
|
||||
public Dropdown displayModeDropdown;
|
||||
public Dropdown displayResolutionDropdown;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
resolutionLevelModifier.SetUp(gameSettings.resolutionLevel, 1, "Menu UI/Settings_Resolution_Level");
|
||||
resolutionLevelModifier.SetMinMax(0, 5);
|
||||
resolutionLevelModifier.updateValueAction = () =>
|
||||
qualityPresetDropdown.SetUp((int)gameSettings.graphicsQualityPreset, QualityPresetOptions,
|
||||
"Menu UI/Settings_Quality_Preset");
|
||||
qualityPresetDropdown.updateValueAction = () =>
|
||||
{
|
||||
gameSettings.resolutionLevel = resolutionLevelModifier.GetValue();
|
||||
gameSettings.ApplyGraphic();
|
||||
gameSettings.graphicsQualityPreset = (GraphicsQualityPreset)qualityPresetDropdown.selectedIndex;
|
||||
SettingsManager.instance.ApplyGraphicSettings();
|
||||
};
|
||||
|
||||
renderScaleModifier.SetUp(gameSettings.renderScaleLevel, 1, "Menu UI/Settings_Render_Scale");
|
||||
renderScaleModifier.SetMinMax(0, 5);
|
||||
renderScaleModifier.updateValueAction = () =>
|
||||
{
|
||||
gameSettings.renderScaleLevel = renderScaleModifier.GetValue();
|
||||
SettingsManager.instance.ApplyGraphicSettings();
|
||||
};
|
||||
|
||||
targetFrameModifier.SetUp(gameSettings.targetFrame, 30, "Menu UI/Settings_Target_Frame");
|
||||
@@ -25,14 +73,148 @@ namespace Ichni.Menu
|
||||
targetFrameModifier.updateValueAction = () =>
|
||||
{
|
||||
gameSettings.targetFrame = targetFrameModifier.GetValue();
|
||||
gameSettings.ApplyGraphic();
|
||||
SettingsManager.instance.ApplyGraphicSettings();
|
||||
};
|
||||
|
||||
InitializePostProcessingSettings();
|
||||
|
||||
#if UNITY_STANDALONE || UNITY_EDITOR
|
||||
InitializeDesktopDisplaySettings();
|
||||
#else
|
||||
vSyncSwitch.gameObject.SetActive(false);
|
||||
displayModeDropdown.gameObject.SetActive(false);
|
||||
displayResolutionDropdown.gameObject.SetActive(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
public override void SetValuesFromSettings()
|
||||
{
|
||||
resolutionLevelModifier.SetValue(gameSettings.resolutionLevel);
|
||||
qualityPresetDropdown.SetValue((int)gameSettings.graphicsQualityPreset);
|
||||
renderScaleModifier.SetValue(gameSettings.renderScaleLevel);
|
||||
targetFrameModifier.SetValue(gameSettings.targetFrame);
|
||||
|
||||
if (postProcessingSwitch != null)
|
||||
{
|
||||
postProcessingSwitch.SetValue(gameSettings.enablePostProcessing);
|
||||
bloomQualityDropdown.SetValue((int)gameSettings.bloomQuality);
|
||||
vfxQualityDropdown.SetValue((int)gameSettings.vfxQuality);
|
||||
}
|
||||
|
||||
#if UNITY_STANDALONE || UNITY_EDITOR
|
||||
vSyncSwitch.SetValue(gameSettings.vSyncEnabled);
|
||||
displayModeDropdown.SetValue((int)gameSettings.displayMode);
|
||||
displayResolutionDropdown.SetValue(GetDisplayResolutionIndex());
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化后处理、Bloom 与 VFX 档位。
|
||||
/// 三个标题由 Prefab 上的 Unity Localization 组件管理,因此这里保留原有标题显示,不再由脚本写入本地化 Key。
|
||||
/// 在旧 Prefab 尚未布置这些控件前保留兼容分支,避免更新脚本后立即破坏既有设置页。
|
||||
/// </summary>
|
||||
private void InitializePostProcessingSettings()
|
||||
{
|
||||
if (postProcessingSwitch == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
postProcessingSwitch.SetUp(gameSettings.enablePostProcessing, preservePrefabTitle: true);
|
||||
postProcessingSwitch.updateValueAction = () =>
|
||||
{
|
||||
gameSettings.enablePostProcessing = postProcessingSwitch.GetValue();
|
||||
SettingsManager.instance.ApplyPostProcessingSettings();
|
||||
};
|
||||
|
||||
bloomQualityDropdown.SetUp((int)gameSettings.bloomQuality, BloomQualityOptions, preservePrefabTitle: true);
|
||||
bloomQualityDropdown.updateValueAction = () =>
|
||||
{
|
||||
gameSettings.bloomQuality = (BloomQuality)bloomQualityDropdown.selectedIndex;
|
||||
SettingsManager.instance.ApplyPostProcessingSettings();
|
||||
};
|
||||
|
||||
vfxQualityDropdown.SetUp((int)gameSettings.vfxQuality, VfxQualityOptions, preservePrefabTitle: true);
|
||||
vfxQualityDropdown.updateValueAction = () =>
|
||||
{
|
||||
gameSettings.vfxQuality = (VfxQuality)vfxQualityDropdown.selectedIndex;
|
||||
};
|
||||
}
|
||||
|
||||
#if UNITY_STANDALONE || UNITY_EDITOR
|
||||
private void InitializeDesktopDisplaySettings()
|
||||
{
|
||||
BuildDisplayResolutionOptions();
|
||||
|
||||
vSyncSwitch.SetUp(gameSettings.vSyncEnabled, "Menu UI/Settings_VSync");
|
||||
vSyncSwitch.updateValueAction = () =>
|
||||
{
|
||||
gameSettings.vSyncEnabled = vSyncSwitch.GetValue();
|
||||
SettingsManager.instance.ApplyDisplaySettings();
|
||||
};
|
||||
|
||||
displayModeDropdown.SetUp((int)gameSettings.displayMode, DisplayModeOptions,
|
||||
"Menu UI/Settings_Display_Mode");
|
||||
displayModeDropdown.updateValueAction = () =>
|
||||
{
|
||||
gameSettings.displayMode = (GraphicsDisplayMode)displayModeDropdown.selectedIndex;
|
||||
SettingsManager.instance.ApplyDisplaySettings();
|
||||
};
|
||||
|
||||
displayResolutionDropdown.SetUp(GetDisplayResolutionIndex(), _displayResolutionOptions,
|
||||
"Menu UI/Settings_Display_Resolution");
|
||||
displayResolutionDropdown.updateValueAction = () =>
|
||||
{
|
||||
Vector2Int resolution = _availableDisplayResolutions[displayResolutionDropdown.selectedIndex];
|
||||
gameSettings.displayResolutionWidth = resolution.x;
|
||||
gameSettings.displayResolutionHeight = resolution.y;
|
||||
SettingsManager.instance.ApplyDisplaySettings();
|
||||
};
|
||||
}
|
||||
|
||||
private void BuildDisplayResolutionOptions()
|
||||
{
|
||||
_availableDisplayResolutions.Clear();
|
||||
_displayResolutionOptions.Clear();
|
||||
|
||||
AddDisplayResolution(Screen.width, Screen.height);
|
||||
foreach (Resolution resolution in Screen.resolutions)
|
||||
{
|
||||
AddDisplayResolution(resolution.width, resolution.height);
|
||||
}
|
||||
|
||||
_availableDisplayResolutions.Sort((left, right) =>
|
||||
{
|
||||
int pixelCountComparison = (left.x * left.y).CompareTo(right.x * right.y);
|
||||
return pixelCountComparison != 0 ? pixelCountComparison : left.x.CompareTo(right.x);
|
||||
});
|
||||
|
||||
foreach (Vector2Int resolution in _availableDisplayResolutions)
|
||||
{
|
||||
_displayResolutionOptions.Add($"{resolution.x} x {resolution.y}");
|
||||
}
|
||||
}
|
||||
|
||||
private void AddDisplayResolution(int width, int height)
|
||||
{
|
||||
Vector2Int resolution = new Vector2Int(width, height);
|
||||
if (!_availableDisplayResolutions.Contains(resolution))
|
||||
{
|
||||
_availableDisplayResolutions.Add(resolution);
|
||||
}
|
||||
}
|
||||
|
||||
private int GetDisplayResolutionIndex()
|
||||
{
|
||||
Vector2Int savedResolution = new Vector2Int(gameSettings.displayResolutionWidth,
|
||||
gameSettings.displayResolutionHeight);
|
||||
int savedResolutionIndex = _availableDisplayResolutions.IndexOf(savedResolution);
|
||||
if (savedResolutionIndex >= 0)
|
||||
{
|
||||
return savedResolutionIndex;
|
||||
}
|
||||
|
||||
return _availableDisplayResolutions.IndexOf(new Vector2Int(Screen.width, Screen.height));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace Ichni.Menu
|
||||
offsetModifier.SetPrefixAndSuffix("", " ms", true);
|
||||
offsetModifier.updateValueAction = () =>
|
||||
{
|
||||
offset = SettingsManager.instance.gameSettings.beatmapOffset = offsetModifier.GetValue();
|
||||
offset = SettingsManager.instance.settingsSaveData.beatmapOffset = offsetModifier.GetValue();
|
||||
largeOffsetHintText.gameObject.SetActive(Mathf.Abs(offset) > 50);
|
||||
};
|
||||
|
||||
@@ -71,7 +71,7 @@ namespace Ichni.Menu
|
||||
(uint)AkCallbackType.AK_EnableGetMusicPlayPosition | (uint)AkCallbackType.AK_MusicSyncEntry,
|
||||
OnMusicEvent, null);
|
||||
|
||||
offsetModifier.SetValue(SettingsManager.instance.gameSettings.beatmapOffset);
|
||||
offsetModifier.SetValue(SettingsManager.instance.settingsSaveData.beatmapOffset);
|
||||
}
|
||||
|
||||
void Update()
|
||||
@@ -141,4 +141,4 @@ namespace Ichni.Menu
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace Ichni.Menu
|
||||
{
|
||||
public class SettingsUIPage : UIPageBase
|
||||
{
|
||||
GameSettings gameSettings => SettingsManager.instance.gameSettings;
|
||||
SettingsSaveData gameSettings => SettingsManager.instance.settingsSaveData;
|
||||
|
||||
public Button backButton;
|
||||
public SettingsWindowController settingsWindowController;
|
||||
@@ -23,4 +23,4 @@ namespace Ichni.Menu
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace Ichni.Menu
|
||||
{
|
||||
public abstract class SettingsWindow : SerializedMonoBehaviour
|
||||
{
|
||||
public GameSettings gameSettings => SettingsManager.instance.gameSettings;
|
||||
public SettingsSaveData gameSettings => SettingsManager.instance.settingsSaveData;
|
||||
|
||||
public abstract void Initialize();
|
||||
|
||||
@@ -18,4 +18,4 @@ namespace Ichni.Menu
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Ichni.Menu
|
||||
{
|
||||
public partial class SettingsWindowController : MonoBehaviour
|
||||
{
|
||||
public GameSettings gameSettings => SettingsManager.instance.gameSettings;
|
||||
public SettingsSaveData gameSettings => SettingsManager.instance.settingsSaveData;
|
||||
|
||||
public CanvasGroup canvasGroup;
|
||||
|
||||
@@ -70,4 +70,4 @@ namespace Ichni.Menu
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
8
Assets/Sprites/UITextures/General.meta
Normal file
8
Assets/Sprites/UITextures/General.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c826ec81b4d62334697e4620a4cb2474
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Assets/Sprites/UITextures/General/BoxBG.png
LFS
Normal file
BIN
Assets/Sprites/UITextures/General/BoxBG.png
LFS
Normal file
Binary file not shown.
143
Assets/Sprites/UITextures/General/BoxBG.png.meta
Normal file
143
Assets/Sprites/UITextures/General/BoxBG.png.meta
Normal file
@@ -0,0 +1,143 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 49526de8ef0d7374696f0e4fd4533142
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 13
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 0
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 25, y: 20, z: 25, w: 20}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 4
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 4
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 4
|
||||
buildTarget: Android
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 4
|
||||
buildTarget: iOS
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
customData:
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: 5e97eb03825dee720800000000000000
|
||||
internalID: 1537655665
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spriteCustomMetadata:
|
||||
entries: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Assets/Sprites/UITextures/General/BoxBorder.png
LFS
Normal file
BIN
Assets/Sprites/UITextures/General/BoxBorder.png
LFS
Normal file
Binary file not shown.
143
Assets/Sprites/UITextures/General/BoxBorder.png.meta
Normal file
143
Assets/Sprites/UITextures/General/BoxBorder.png.meta
Normal file
@@ -0,0 +1,143 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 19ac3b816ac249d42962b597b4a5b9d5
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 13
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 0
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 42, z: 0, w: 42}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 4
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 4
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 4
|
||||
buildTarget: Android
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 4
|
||||
buildTarget: iOS
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
customData:
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: 5e97eb03825dee720800000000000000
|
||||
internalID: 1537655665
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spriteCustomMetadata:
|
||||
entries: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Assets/Sprites/UITextures/General/BoxSquares.png
LFS
Normal file
BIN
Assets/Sprites/UITextures/General/BoxSquares.png
LFS
Normal file
Binary file not shown.
143
Assets/Sprites/UITextures/General/BoxSquares.png.meta
Normal file
143
Assets/Sprites/UITextures/General/BoxSquares.png.meta
Normal file
@@ -0,0 +1,143 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6fa105ce9ef516d46879783dbfeb0e88
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 13
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 0
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 4
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 4
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 4
|
||||
buildTarget: Android
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 4
|
||||
buildTarget: iOS
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
customData:
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spriteCustomMetadata:
|
||||
entries: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,21 +1,21 @@
|
||||
ManifestFileVersion: 0
|
||||
UnityVersion: 6000.3.7f1
|
||||
CRC: 3502675414
|
||||
CRC: 4053260153
|
||||
HashAppended: 0
|
||||
AssetBundleManifest:
|
||||
AssetBundleInfos:
|
||||
Info_0:
|
||||
Name: shapes
|
||||
Name: unifiedraytracing
|
||||
Dependencies: {}
|
||||
Info_1:
|
||||
Name: basic
|
||||
Dependencies: {}
|
||||
Info_2:
|
||||
Name: metropolis_on_orbit
|
||||
Dependencies: {}
|
||||
Info_3:
|
||||
Name: departure_to_multiverse
|
||||
Dependencies: {}
|
||||
Info_4:
|
||||
Name: unifiedraytracing
|
||||
Info_3:
|
||||
Name: metropolis_on_orbit
|
||||
Dependencies: {}
|
||||
Info_4:
|
||||
Name: shapes
|
||||
Dependencies: {}
|
||||
|
||||
Binary file not shown.
@@ -1,16 +1,16 @@
|
||||
ManifestFileVersion: 0
|
||||
UnityVersion: 6000.3.7f1
|
||||
CRC: 1054575820
|
||||
CRC: 4187162310
|
||||
Hashes:
|
||||
AssetFileHash:
|
||||
serializedVersion: 2
|
||||
Hash: 007f20ee8efa9449fd672739395d8b8b
|
||||
Hash: 041639c891c497f5cda773d76795250a
|
||||
TypeTreeHash:
|
||||
serializedVersion: 2
|
||||
Hash: dfed41e3b38758e5f34df30221d719dc
|
||||
IncrementalBuildHash:
|
||||
serializedVersion: 2
|
||||
Hash: 2fc84aafa10273fada9abacc94cc0ec8
|
||||
Hash: 1175efd1b6efe2bebf239ab190c42566
|
||||
HashAppended: 0
|
||||
ClassTypes:
|
||||
- Class: 1
|
||||
|
||||
Binary file not shown.
@@ -1,16 +1,16 @@
|
||||
ManifestFileVersion: 0
|
||||
UnityVersion: 6000.3.7f1
|
||||
CRC: 3814763255
|
||||
CRC: 12343729
|
||||
Hashes:
|
||||
AssetFileHash:
|
||||
serializedVersion: 2
|
||||
Hash: b67223887fe2f824117e4b27a9358f9c
|
||||
Hash: 95c6613dec434b5e157eab1de94cfdfc
|
||||
TypeTreeHash:
|
||||
serializedVersion: 2
|
||||
Hash: 8111ab10d600eaa1a60bd178b1bcf4cf
|
||||
Hash: 6d9f9b8bc1074349261a0dbbf7f0f9f8
|
||||
IncrementalBuildHash:
|
||||
serializedVersion: 2
|
||||
Hash: 85f89324f6067e3b6b212baf51e9b101
|
||||
Hash: 0f6768f5833370c99987c209c7f083f1
|
||||
HashAppended: 0
|
||||
ClassTypes:
|
||||
- Class: 1
|
||||
@@ -57,6 +57,8 @@ ClassTypes:
|
||||
Script: {fileID: 11500000, guid: 638fbd0e919667f47a93485dd230c71f, type: 3}
|
||||
- Class: 114
|
||||
Script: {fileID: 11500000, guid: eb907071d10d7324995ff3aefbc2f1df, type: 3}
|
||||
- Class: 114
|
||||
Script: {fileID: 11500000, guid: 922e341faf5784c41b3b0466e0468972, type: 3}
|
||||
- Class: 115
|
||||
Script: {instanceID: 0}
|
||||
- Class: 135
|
||||
|
||||
@@ -10,7 +10,7 @@ Hashes:
|
||||
Hash: 8ab77e54d824a64c30bc20496c5f5926
|
||||
IncrementalBuildHash:
|
||||
serializedVersion: 2
|
||||
Hash: cb0fdc66431f09d69236a0e556b74895
|
||||
Hash: 204f3b93fddc5bbe213f57aa05799cdd
|
||||
HashAppended: 0
|
||||
ClassTypes:
|
||||
- Class: 1
|
||||
|
||||
@@ -10,7 +10,7 @@ Hashes:
|
||||
Hash: bc9f87c7e64ff656997db0f2b2a91703
|
||||
IncrementalBuildHash:
|
||||
serializedVersion: 2
|
||||
Hash: 612a23b0b40c16e3e1e3cbbf90636bd0
|
||||
Hash: 98313c8eb74f89178044a9a994c30a81
|
||||
HashAppended: 0
|
||||
ClassTypes:
|
||||
- Class: 28
|
||||
|
||||
Binary file not shown.
@@ -1,6 +1,6 @@
|
||||
ManifestFileVersion: 0
|
||||
UnityVersion: 6000.3.7f1
|
||||
CRC: 803255327
|
||||
CRC: 3304633615
|
||||
HashAppended: 0
|
||||
AssetBundleManifest:
|
||||
AssetBundleInfos:
|
||||
|
||||
Binary file not shown.
@@ -1,16 +1,16 @@
|
||||
ManifestFileVersion: 0
|
||||
UnityVersion: 6000.3.7f1
|
||||
CRC: 3067715901
|
||||
CRC: 1012070008
|
||||
Hashes:
|
||||
AssetFileHash:
|
||||
serializedVersion: 2
|
||||
Hash: 6abcdfd9cae8dff022735fc0aa0fb26c
|
||||
Hash: f038c8737dccdbbb922785ad13defdbe
|
||||
TypeTreeHash:
|
||||
serializedVersion: 2
|
||||
Hash: dfed41e3b38758e5f34df30221d719dc
|
||||
IncrementalBuildHash:
|
||||
serializedVersion: 2
|
||||
Hash: 5137fd1deb792cb6f62602cd7823e6fb
|
||||
Hash: daff94e5b2902357c1b4f50d325b0bb4
|
||||
HashAppended: 0
|
||||
ClassTypes:
|
||||
- Class: 1
|
||||
|
||||
Binary file not shown.
@@ -1,16 +1,16 @@
|
||||
ManifestFileVersion: 0
|
||||
UnityVersion: 6000.3.7f1
|
||||
CRC: 1851616411
|
||||
CRC: 3176997596
|
||||
Hashes:
|
||||
AssetFileHash:
|
||||
serializedVersion: 2
|
||||
Hash: e222936565bcc8f611c0cecb46e4de21
|
||||
Hash: 2739e7db8a5127e5f4e38ed26a5dab24
|
||||
TypeTreeHash:
|
||||
serializedVersion: 2
|
||||
Hash: 8111ab10d600eaa1a60bd178b1bcf4cf
|
||||
Hash: 6d9f9b8bc1074349261a0dbbf7f0f9f8
|
||||
IncrementalBuildHash:
|
||||
serializedVersion: 2
|
||||
Hash: 67609888e0ca1cd25ae3c8a70c9cc423
|
||||
Hash: 087cd007fe584b08e6ef217eeaede36a
|
||||
HashAppended: 0
|
||||
ClassTypes:
|
||||
- Class: 1
|
||||
@@ -57,6 +57,8 @@ ClassTypes:
|
||||
Script: {fileID: 11500000, guid: 638fbd0e919667f47a93485dd230c71f, type: 3}
|
||||
- Class: 114
|
||||
Script: {fileID: 11500000, guid: eb907071d10d7324995ff3aefbc2f1df, type: 3}
|
||||
- Class: 114
|
||||
Script: {fileID: 11500000, guid: 922e341faf5784c41b3b0466e0468972, type: 3}
|
||||
- Class: 115
|
||||
Script: {instanceID: 0}
|
||||
- Class: 135
|
||||
|
||||
@@ -10,7 +10,7 @@ Hashes:
|
||||
Hash: 8ab77e54d824a64c30bc20496c5f5926
|
||||
IncrementalBuildHash:
|
||||
serializedVersion: 2
|
||||
Hash: d112fcb376deb19d16966ce67cc858fe
|
||||
Hash: 2b9d1caa8b3c01da7365d30bd4e1e291
|
||||
HashAppended: 0
|
||||
ClassTypes:
|
||||
- Class: 1
|
||||
|
||||
@@ -34636,6 +34636,7 @@ GameObject:
|
||||
- component: {fileID: 6374922826736626084}
|
||||
- component: {fileID: 8731137484130123864}
|
||||
- component: {fileID: 6411650891525449585}
|
||||
- component: {fileID: 7677400993941291652}
|
||||
m_Layer: 0
|
||||
m_Name: Flick_HitFX
|
||||
m_TagString: Untagged
|
||||
@@ -39468,3 +39469,38 @@ ParticleSystemRenderer:
|
||||
m_MeshWeighting1: 1
|
||||
m_MeshWeighting2: 1
|
||||
m_MeshWeighting3: 1
|
||||
--- !u!114 &7677400993941291652
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 7916584198410465453}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 922e341faf5784c41b3b0466e0468972, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::Ichni.VFXObject
|
||||
serializationData:
|
||||
SerializedFormat: 2
|
||||
SerializedBytes:
|
||||
ReferencedUnityObjects: []
|
||||
SerializedBytesString:
|
||||
Prefab: {fileID: 0}
|
||||
PrefabModificationsReferencedUnityObjects: []
|
||||
PrefabModifications: []
|
||||
SerializationNodes:
|
||||
- Name: onSpawnAction
|
||||
Entry: 6
|
||||
Data:
|
||||
- Name: onDespawnAction
|
||||
Entry: 6
|
||||
Data:
|
||||
isAutoDespawn: 1
|
||||
autoDespawnTime: 0.4
|
||||
despawnTimer: 0
|
||||
disableAtMediumAndLower:
|
||||
- {fileID: 4315719500094685406}
|
||||
- {fileID: 7653901243468862591}
|
||||
disableAtLowOnly:
|
||||
- {fileID: 218248303542728390}
|
||||
|
||||
@@ -19422,6 +19422,7 @@ GameObject:
|
||||
- component: {fileID: 1036169766419486204}
|
||||
- component: {fileID: 3711062127305343447}
|
||||
- component: {fileID: 4188768693027638627}
|
||||
- component: {fileID: 380390184437325210}
|
||||
m_Layer: 0
|
||||
m_Name: Hold_HitFX_B
|
||||
m_TagString: Untagged
|
||||
@@ -24253,6 +24254,41 @@ ParticleSystemRenderer:
|
||||
m_MeshWeighting1: 1
|
||||
m_MeshWeighting2: 1
|
||||
m_MeshWeighting3: 1
|
||||
--- !u!114 &380390184437325210
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2943020494385716766}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 922e341faf5784c41b3b0466e0468972, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::Ichni.VFXObject
|
||||
serializationData:
|
||||
SerializedFormat: 2
|
||||
SerializedBytes:
|
||||
ReferencedUnityObjects: []
|
||||
SerializedBytesString:
|
||||
Prefab: {fileID: 0}
|
||||
PrefabModificationsReferencedUnityObjects: []
|
||||
PrefabModifications: []
|
||||
SerializationNodes:
|
||||
- Name: onSpawnAction
|
||||
Entry: 6
|
||||
Data:
|
||||
- Name: onDespawnAction
|
||||
Entry: 6
|
||||
Data:
|
||||
isAutoDespawn: 0
|
||||
autoDespawnTime: 1
|
||||
despawnTimer: 0
|
||||
disableAtMediumAndLower:
|
||||
- {fileID: 6573924625455929684}
|
||||
disableAtLowOnly:
|
||||
- {fileID: 6651680105352939543}
|
||||
- {fileID: 2070592205952932412}
|
||||
--- !u!1 &6573924625455929684
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
||||
@@ -4847,6 +4847,7 @@ GameObject:
|
||||
- component: {fileID: 6795338915013005225}
|
||||
- component: {fileID: 7686838569397045560}
|
||||
- component: {fileID: 8644577418426854476}
|
||||
- component: {fileID: 786338997556789770}
|
||||
m_Layer: 0
|
||||
m_Name: Hold_HitFX_G
|
||||
m_TagString: Untagged
|
||||
@@ -9678,6 +9679,41 @@ ParticleSystemRenderer:
|
||||
m_MeshWeighting1: 1
|
||||
m_MeshWeighting2: 1
|
||||
m_MeshWeighting3: 1
|
||||
--- !u!114 &786338997556789770
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5199942171001745879}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 922e341faf5784c41b3b0466e0468972, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::Ichni.VFXObject
|
||||
serializationData:
|
||||
SerializedFormat: 2
|
||||
SerializedBytes:
|
||||
ReferencedUnityObjects: []
|
||||
SerializedBytesString:
|
||||
Prefab: {fileID: 0}
|
||||
PrefabModificationsReferencedUnityObjects: []
|
||||
PrefabModifications: []
|
||||
SerializationNodes:
|
||||
- Name: onSpawnAction
|
||||
Entry: 6
|
||||
Data:
|
||||
- Name: onDespawnAction
|
||||
Entry: 6
|
||||
Data:
|
||||
isAutoDespawn: 0
|
||||
autoDespawnTime: 1
|
||||
despawnTimer: 0
|
||||
disableAtMediumAndLower:
|
||||
- {fileID: 8145642094151385667}
|
||||
disableAtLowOnly:
|
||||
- {fileID: 7142595897816035270}
|
||||
- {fileID: 6969281223192018514}
|
||||
--- !u!1 &6422879766326712376
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
||||
@@ -29152,6 +29152,7 @@ GameObject:
|
||||
- component: {fileID: 8304709085130353050}
|
||||
- component: {fileID: 8543824802591545481}
|
||||
- component: {fileID: 8940303714819021693}
|
||||
- component: {fileID: 7045525186860897399}
|
||||
m_Layer: 0
|
||||
m_Name: Hold_HitFX_P
|
||||
m_TagString: Untagged
|
||||
@@ -33983,3 +33984,38 @@ ParticleSystemRenderer:
|
||||
m_MeshWeighting1: 1
|
||||
m_MeshWeighting2: 1
|
||||
m_MeshWeighting3: 1
|
||||
--- !u!114 &7045525186860897399
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 8837549430712806196}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 922e341faf5784c41b3b0466e0468972, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::Ichni.VFXObject
|
||||
serializationData:
|
||||
SerializedFormat: 2
|
||||
SerializedBytes:
|
||||
ReferencedUnityObjects: []
|
||||
SerializedBytesString:
|
||||
Prefab: {fileID: 0}
|
||||
PrefabModificationsReferencedUnityObjects: []
|
||||
PrefabModifications: []
|
||||
SerializationNodes:
|
||||
- Name: onSpawnAction
|
||||
Entry: 6
|
||||
Data:
|
||||
- Name: onDespawnAction
|
||||
Entry: 6
|
||||
Data:
|
||||
isAutoDespawn: 0
|
||||
autoDespawnTime: 1
|
||||
despawnTimer: 0
|
||||
disableAtMediumAndLower:
|
||||
- {fileID: 1807912427671244093}
|
||||
disableAtLowOnly:
|
||||
- {fileID: 4690891593166535979}
|
||||
- {fileID: 5194171103924125613}
|
||||
|
||||
@@ -4905,6 +4905,7 @@ GameObject:
|
||||
- component: {fileID: 3798029571758690913}
|
||||
- component: {fileID: 6512331645267871761}
|
||||
- component: {fileID: 4138720391616017682}
|
||||
- component: {fileID: 5571405091865508458}
|
||||
m_Layer: 0
|
||||
m_Name: Stay_HitFX
|
||||
m_TagString: Untagged
|
||||
@@ -9733,6 +9734,39 @@ ParticleSystemRenderer:
|
||||
m_MeshWeighting1: 1
|
||||
m_MeshWeighting2: 1
|
||||
m_MeshWeighting3: 1
|
||||
--- !u!114 &5571405091865508458
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5249990677744981946}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 922e341faf5784c41b3b0466e0468972, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::Ichni.VFXObject
|
||||
serializationData:
|
||||
SerializedFormat: 2
|
||||
SerializedBytes:
|
||||
ReferencedUnityObjects: []
|
||||
SerializedBytesString:
|
||||
Prefab: {fileID: 0}
|
||||
PrefabModificationsReferencedUnityObjects: []
|
||||
PrefabModifications: []
|
||||
SerializationNodes:
|
||||
- Name: onSpawnAction
|
||||
Entry: 6
|
||||
Data:
|
||||
- Name: onDespawnAction
|
||||
Entry: 6
|
||||
Data:
|
||||
isAutoDespawn: 1
|
||||
autoDespawnTime: 1
|
||||
despawnTimer: 0
|
||||
disableAtMediumAndLower:
|
||||
- {fileID: 481741008711077494}
|
||||
disableAtLowOnly: []
|
||||
--- !u!1 &5931878544904699336
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
||||
@@ -9826,6 +9826,7 @@ GameObject:
|
||||
- component: {fileID: 8544422724010775666}
|
||||
- component: {fileID: 8082031638419169081}
|
||||
- component: {fileID: 1014060429300395170}
|
||||
- component: {fileID: 4889441942532997180}
|
||||
m_Layer: 0
|
||||
m_Name: Tap_HiEffect_B
|
||||
m_TagString: Untagged
|
||||
@@ -14653,3 +14654,35 @@ ParticleSystemRenderer:
|
||||
m_MeshWeighting1: 1
|
||||
m_MeshWeighting2: 1
|
||||
m_MeshWeighting3: 1
|
||||
--- !u!114 &4889441942532997180
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 8754511166712621810}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 922e341faf5784c41b3b0466e0468972, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::Ichni.VFXObject
|
||||
serializationData:
|
||||
SerializedFormat: 2
|
||||
SerializedBytes:
|
||||
ReferencedUnityObjects: []
|
||||
SerializedBytesString:
|
||||
Prefab: {fileID: 0}
|
||||
PrefabModificationsReferencedUnityObjects: []
|
||||
PrefabModifications: []
|
||||
SerializationNodes:
|
||||
- Name: onSpawnAction
|
||||
Entry: 6
|
||||
Data:
|
||||
- Name: onDespawnAction
|
||||
Entry: 6
|
||||
Data:
|
||||
isAutoDespawn: 1
|
||||
autoDespawnTime: 0.4
|
||||
despawnTimer: 0
|
||||
disableAtMediumAndLower: []
|
||||
disableAtLowOnly: []
|
||||
|
||||
@@ -9844,6 +9844,7 @@ GameObject:
|
||||
- component: {fileID: 3263924656594740668}
|
||||
- component: {fileID: 7038272264455304515}
|
||||
- component: {fileID: 8700396741641032723}
|
||||
- component: {fileID: 987397096316892202}
|
||||
m_Layer: 0
|
||||
m_Name: Tap_HitEffect_G
|
||||
m_TagString: Untagged
|
||||
@@ -14672,6 +14673,39 @@ ParticleSystemRenderer:
|
||||
m_MeshWeighting1: 1
|
||||
m_MeshWeighting2: 1
|
||||
m_MeshWeighting3: 1
|
||||
--- !u!114 &987397096316892202
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 7671123070809976812}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 922e341faf5784c41b3b0466e0468972, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::Ichni.VFXObject
|
||||
serializationData:
|
||||
SerializedFormat: 2
|
||||
SerializedBytes:
|
||||
ReferencedUnityObjects: []
|
||||
SerializedBytesString:
|
||||
Prefab: {fileID: 0}
|
||||
PrefabModificationsReferencedUnityObjects: []
|
||||
PrefabModifications: []
|
||||
SerializationNodes:
|
||||
- Name: onSpawnAction
|
||||
Entry: 6
|
||||
Data:
|
||||
- Name: onDespawnAction
|
||||
Entry: 6
|
||||
Data:
|
||||
isAutoDespawn: 1
|
||||
autoDespawnTime: 0.4
|
||||
despawnTimer: 0
|
||||
disableAtMediumAndLower:
|
||||
- {fileID: 7986537471941685033}
|
||||
disableAtLowOnly: []
|
||||
--- !u!1 &7986537471941685033
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
||||
@@ -4923,6 +4923,7 @@ GameObject:
|
||||
- component: {fileID: 5040270902117431550}
|
||||
- component: {fileID: 447330800752594519}
|
||||
- component: {fileID: 1390550520963138891}
|
||||
- component: {fileID: 4762391414571929359}
|
||||
m_Layer: 0
|
||||
m_Name: Tap_HitEffect_P
|
||||
m_TagString: Untagged
|
||||
@@ -9753,6 +9754,41 @@ ParticleSystemRenderer:
|
||||
m_MeshWeighting1: 1
|
||||
m_MeshWeighting2: 1
|
||||
m_MeshWeighting3: 1
|
||||
--- !u!114 &4762391414571929359
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 976141841207214558}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 922e341faf5784c41b3b0466e0468972, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::SLSUtilities.LeanPoolAssistance.VFXObject
|
||||
serializationData:
|
||||
SerializedFormat: 2
|
||||
SerializedBytes:
|
||||
ReferencedUnityObjects: []
|
||||
SerializedBytesString:
|
||||
Prefab: {fileID: 0}
|
||||
PrefabModificationsReferencedUnityObjects: []
|
||||
PrefabModifications: []
|
||||
SerializationNodes:
|
||||
- Name: onSpawnAction
|
||||
Entry: 6
|
||||
Data:
|
||||
- Name: onDespawnAction
|
||||
Entry: 6
|
||||
Data:
|
||||
isAutoDespawn: 1
|
||||
autoDespawnTime: 0.4
|
||||
despawnTimer: 0
|
||||
disableAtMediumAndLower:
|
||||
- {fileID: 7286007667833831019}
|
||||
- {fileID: 1526589185383174293}
|
||||
disableAtLowOnly:
|
||||
- {fileID: 587594120215132903}
|
||||
--- !u!1 &1526589185383174293
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
||||
@@ -35,8 +35,6 @@ namespace Ichni.RhythmGame.ThemeBundles.DepartureToMultiverse
|
||||
{
|
||||
noteVisual.extraPartList[0].gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
LeanPool.Despawn(effectParticle.gameObject, 1);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user