diff --git a/Assets/AddressableAssetsData/link.xml.meta b/Assets/AddressableAssetsData/link.xml.meta index 2472afd1..dd51f201 100644 --- a/Assets/AddressableAssetsData/link.xml.meta +++ b/Assets/AddressableAssetsData/link.xml.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 06c4284984209ae4184b0b412cfd93d1 +guid: b72cf0d289c3f72498b163dbcbe86dd5 TextScriptImporter: externalObjects: {} userData: diff --git a/Assets/CameraLetterBox.cs b/Assets/CameraLetterBox.cs index c7857c6e..6cf2642b 100644 --- a/Assets/CameraLetterBox.cs +++ b/Assets/CameraLetterBox.cs @@ -6,6 +6,10 @@ public class CameraLetterbox : MonoBehaviour { public float targetAspect = 16f / 9f; + // 关闭时相机填满整个屏幕(跟随用户分辨率,无黑边);开启时回退到旧的 16:9 锁定加黑边行为。 + // 透视相机填满屏幕会按 Hor+ 水平扩展视野,不会拉伸变形。 + public bool lockAspect = false; + private int lastWidth; private int lastHeight; @@ -29,6 +33,13 @@ public class CameraLetterbox : MonoBehaviour void ApplyLetterbox() { Camera cam = GetComponent(); + + if (!lockAspect) + { + cam.rect = new Rect(0f, 0f, 1f, 1f); + return; + } + float screenAspect = (float)Screen.width / Screen.height; float scaleHeight = screenAspect / targetAspect; diff --git a/Assets/Graphy - Ultimate Stats Monitor/Prefab/[Graphy].prefab b/Assets/Graphy - Ultimate Stats Monitor/Prefab/[Graphy].prefab index a7a9670c..d540017d 100644 --- a/Assets/Graphy - Ultimate Stats Monitor/Prefab/[Graphy].prefab +++ b/Assets/Graphy - Ultimate Stats Monitor/Prefab/[Graphy].prefab @@ -78,7 +78,7 @@ MonoBehaviour: m_ScaleFactor: 0.66 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 diff --git a/Assets/Prefabs/UI/Panel/GetItem.prefab b/Assets/Prefabs/UI/Panel/GetItem.prefab index f82b6f9f..16b939be 100644 --- a/Assets/Prefabs/UI/Panel/GetItem.prefab +++ b/Assets/Prefabs/UI/Panel/GetItem.prefab @@ -629,7 +629,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 1 - m_MatchWidthOrHeight: 0 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 diff --git a/Assets/Prefabs/UI/Panel/UI_Panel_Main.prefab b/Assets/Prefabs/UI/Panel/UI_Panel_Main.prefab index cc6147d5..f130996b 100644 --- a/Assets/Prefabs/UI/Panel/UI_Panel_Main.prefab +++ b/Assets/Prefabs/UI/Panel/UI_Panel_Main.prefab @@ -9759,7 +9759,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 1 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 diff --git a/Assets/Prefabs/UI/Panel/UnlockNewSkill.prefab b/Assets/Prefabs/UI/Panel/UnlockNewSkill.prefab index 707e9878..cbc6621c 100644 --- a/Assets/Prefabs/UI/Panel/UnlockNewSkill.prefab +++ b/Assets/Prefabs/UI/Panel/UnlockNewSkill.prefab @@ -1028,7 +1028,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 1 - m_MatchWidthOrHeight: 0 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 diff --git a/Assets/Prefabs/UI/Panel_Character/UI_Panel_Character.prefab b/Assets/Prefabs/UI/Panel_Character/UI_Panel_Character.prefab index de3fcaf0..ff9fb3c8 100644 --- a/Assets/Prefabs/UI/Panel_Character/UI_Panel_Character.prefab +++ b/Assets/Prefabs/UI/Panel_Character/UI_Panel_Character.prefab @@ -1316,7 +1316,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 1 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 diff --git a/Assets/Prefabs/UI/Panel_Level/UI_Panel_Level.prefab b/Assets/Prefabs/UI/Panel_Level/UI_Panel_Level.prefab index fba2c767..72edec66 100644 --- a/Assets/Prefabs/UI/Panel_Level/UI_Panel_Level.prefab +++ b/Assets/Prefabs/UI/Panel_Level/UI_Panel_Level.prefab @@ -472,7 +472,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 1 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 diff --git a/Assets/Prefabs/UI/Panel_Music/UI_Panel_Music.prefab b/Assets/Prefabs/UI/Panel_Music/UI_Panel_Music.prefab index 30c2708a..b1f400b1 100644 --- a/Assets/Prefabs/UI/Panel_Music/UI_Panel_Music.prefab +++ b/Assets/Prefabs/UI/Panel_Music/UI_Panel_Music.prefab @@ -117,7 +117,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 diff --git a/Assets/Prefabs/UI/Panel_Note/UI_Panel_Note.prefab b/Assets/Prefabs/UI/Panel_Note/UI_Panel_Note.prefab index 7a1f2db7..9385261c 100644 --- a/Assets/Prefabs/UI/Panel_Note/UI_Panel_Note.prefab +++ b/Assets/Prefabs/UI/Panel_Note/UI_Panel_Note.prefab @@ -81,7 +81,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 1 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 diff --git a/Assets/Prefabs/UI/Panel_Setting/UI_Panel_Setting.prefab b/Assets/Prefabs/UI/Panel_Setting/UI_Panel_Setting.prefab index 4f49cd5a..8efe6b73 100644 --- a/Assets/Prefabs/UI/Panel_Setting/UI_Panel_Setting.prefab +++ b/Assets/Prefabs/UI/Panel_Setting/UI_Panel_Setting.prefab @@ -2383,7 +2383,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 1 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 diff --git a/Assets/Prefabs/UI/Panel_Story/UI_Panel_Story.prefab b/Assets/Prefabs/UI/Panel_Story/UI_Panel_Story.prefab index 9a2103f5..c9e6e7ac 100644 --- a/Assets/Prefabs/UI/Panel_Story/UI_Panel_Story.prefab +++ b/Assets/Prefabs/UI/Panel_Story/UI_Panel_Story.prefab @@ -5472,7 +5472,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 diff --git a/Assets/RESULTS.prefab b/Assets/RESULTS.prefab index 7bbf1ade..b0e514f0 100644 --- a/Assets/RESULTS.prefab +++ b/Assets/RESULTS.prefab @@ -411,7 +411,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 diff --git a/Assets/Resources/GlobalNoticeSystem.prefab b/Assets/Resources/GlobalNoticeSystem.prefab index 65f67022..d7295df9 100644 --- a/Assets/Resources/GlobalNoticeSystem.prefab +++ b/Assets/Resources/GlobalNoticeSystem.prefab @@ -273,7 +273,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 diff --git a/Assets/Resources/gTransitionPrefab.prefab b/Assets/Resources/gTransitionPrefab.prefab index 16eaf800..281d276f 100644 --- a/Assets/Resources/gTransitionPrefab.prefab +++ b/Assets/Resources/gTransitionPrefab.prefab @@ -33,9 +33,9 @@ RectTransform: m_Children: [] m_Father: {fileID: 3662934241968352798} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0.5, y: 0.5} - m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: 874, y: -474} + m_AnchorMin: {x: 1, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: -86, y: -474} m_SizeDelta: {x: 0, y: 30} m_Pivot: {x: 1, y: 0.5} --- !u!222 &6547744825235139397 @@ -129,7 +129,7 @@ RectTransform: m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5} m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 1920, y: 1080} + m_SizeDelta: {x: 19200, y: 10800} m_Pivot: {x: 0.5, y: 0.5} --- !u!222 &9043655295654679034 CanvasRenderer: @@ -218,6 +218,7 @@ MonoBehaviour: b_Canvas: {fileID: 8634987774727144996} b_CG: {fileID: 7488946224478211922} nowLoadingText: {fileID: 2886771985255225193} + postSceneLoadCameraRefreshFrames: 12 --- !u!225 &7488946224478211922 CanvasGroup: m_ObjectHideFlags: 0 @@ -282,12 +283,12 @@ Canvas: m_RenderMode: 1 m_Camera: {fileID: 0} m_PlaneDistance: 100 - m_PixelPerfect: 0 + m_PixelPerfect: 1 m_ReceivesEvents: 1 m_OverrideSorting: 0 m_OverridePixelPerfect: 0 m_SortingBucketNormalizedSize: 0 - m_VertexColorAlwaysGammaSpace: 0 + m_VertexColorAlwaysGammaSpace: 1 m_AdditionalShaderChannelsFlag: 0 m_UpdateRectTransformForStandalone: 0 m_SortingLayerID: 0 @@ -310,7 +311,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 diff --git a/Assets/Resources/so/player_titles.meta b/Assets/Resources/so/player_titles.meta new file mode 100644 index 00000000..288a940e --- /dev/null +++ b/Assets/Resources/so/player_titles.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f06c2c7d0b414034a9794d19a327f8b8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/so/player_titles/PlayerTitleLibrary.asset b/Assets/Resources/so/player_titles/PlayerTitleLibrary.asset new file mode 100644 index 00000000..37b0f719 --- /dev/null +++ b/Assets/Resources/so/player_titles/PlayerTitleLibrary.asset @@ -0,0 +1,19 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a77a5d11c6274a94bb16e9d477a17301, type: 3} + m_Name: PlayerTitleLibrary + m_EditorClassIdentifier: + titles: + - titleId: 2026hzsw + titleSprite: {fileID: 21300000, guid: 4e6799a77466162499c411ec44cadde5, type: 3} + chineseName: "2026\u676D\u5DDE\u8BD5\u73A9" + englishName: 2026 Hangzhou Playtest diff --git a/Assets/Resources/so/player_titles/PlayerTitleLibrary.asset.meta b/Assets/Resources/so/player_titles/PlayerTitleLibrary.asset.meta new file mode 100644 index 00000000..0b5c1ef6 --- /dev/null +++ b/Assets/Resources/so/player_titles/PlayerTitleLibrary.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4bb250bc5a7043249a8cdb65db43745a +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scenes/BootScene.unity b/Assets/Scenes/BootScene.unity index 9ffd8b1b..e3d8ab9d 100644 --- a/Assets/Scenes/BootScene.unity +++ b/Assets/Scenes/BootScene.unity @@ -304,7 +304,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 diff --git a/Assets/Scenes/Main_main.unity b/Assets/Scenes/Main_main.unity index 36e7c4d5..ba7aec7b 100644 --- a/Assets/Scenes/Main_main.unity +++ b/Assets/Scenes/Main_main.unity @@ -1176,7 +1176,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -4412,7 +4412,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -5044,7 +5044,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -5846,7 +5846,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -6105,7 +6105,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -6344,7 +6344,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -7538,7 +7538,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -8597,14 +8597,14 @@ MonoBehaviour: m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UiScaleMode: 0 + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 1 m_ReferencePixelsPerUnit: 100 m_ScaleFactor: 1 - m_ReferenceResolution: {x: 800, y: 600} + m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -9473,7 +9473,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -9779,7 +9779,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 diff --git a/Assets/Scenes/SampleScene.unity b/Assets/Scenes/SampleScene.unity index c5b4dd85..250c2e49 100644 --- a/Assets/Scenes/SampleScene.unity +++ b/Assets/Scenes/SampleScene.unity @@ -172,7 +172,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 diff --git a/Assets/Scenes/Songs_Select.unity b/Assets/Scenes/Songs_Select.unity index aed19c53..9c8540af 100644 --- a/Assets/Scenes/Songs_Select.unity +++ b/Assets/Scenes/Songs_Select.unity @@ -1139,7 +1139,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -1980,7 +1980,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -2364,7 +2364,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -3126,7 +3126,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -5814,7 +5814,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -7205,7 +7205,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -8442,7 +8442,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -8619,7 +8619,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -8723,7 +8723,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -10876,7 +10876,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -11993,14 +11993,14 @@ MonoBehaviour: m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UiScaleMode: 0 + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 1 m_ReferencePixelsPerUnit: 100 m_ScaleFactor: 1 - m_ReferenceResolution: {x: 800, y: 600} + m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -13054,7 +13054,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -18410,7 +18410,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -18638,7 +18638,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -23128,7 +23128,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -24181,7 +24181,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -25112,7 +25112,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 diff --git a/Assets/Scenes/UI_UI.unity b/Assets/Scenes/UI_UI.unity index dc0f1545..1799a7af 100644 --- a/Assets/Scenes/UI_UI.unity +++ b/Assets/Scenes/UI_UI.unity @@ -5348,7 +5348,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -6777,14 +6777,14 @@ RectTransform: m_GameObject: {fileID: 297168935} m_LocalRotation: {x: -0, y: -0, z: 0.000004306435, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1.0000306, y: 1.0000306, z: 1.0000306} + m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 1155171500} m_LocalEulerAnglesHint: {x: 0, y: 0, z: -360} m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: 629.4, y: 205.6} + m_AnchoredPosition: {x: -24.2, y: 8.5} m_SizeDelta: {x: 660, y: 117} m_Pivot: {x: 0.5, y: 0.5} --- !u!114 &297168937 @@ -7906,6 +7906,7 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: targetAspect: 1.7777778 + lockAspect: 0 --- !u!114 &330585548 MonoBehaviour: m_ObjectHideFlags: 0 @@ -10857,12 +10858,12 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} m_Name: m_EditorClassIdentifier: - m_UiScaleMode: 0 + m_UiScaleMode: 1 m_ReferencePixelsPerUnit: 100 m_ScaleFactor: 1 - m_ReferenceResolution: {x: 800, y: 600} + m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -13011,7 +13012,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 1 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -16291,7 +16292,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -29521,7 +29522,7 @@ RectTransform: m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: 71.7, y: -0.00000071526} + m_AnchoredPosition: {x: 100, y: -0.00000071526} m_SizeDelta: {x: 30, y: 24} m_Pivot: {x: 0.5, y: 0.5} --- !u!114 &980586653 @@ -32711,11 +32712,11 @@ RectTransform: m_Children: - {fileID: 750480011} - {fileID: 980586652} - m_Father: {fileID: 1941047790} + m_Father: {fileID: 2030106541} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0.5, y: 0.5} - m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: 655.5915, y: -322.7} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} m_SizeDelta: {x: 376.529, y: 41.653} m_Pivot: {x: 0.5, y: 0.5} --- !u!114 &1069894366 @@ -34718,7 +34719,7 @@ RectTransform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1155171499} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + 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 @@ -34730,10 +34731,11 @@ RectTransform: - {fileID: 1204245234} - {fileID: 169498467} - {fileID: 2139588348} - m_Father: {fileID: 1556637616} + - {fileID: 1410585899} + m_Father: {fileID: 2030106541} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0.5, y: 0.5} - m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} m_AnchoredPosition: {x: 0, y: 0} m_SizeDelta: {x: 100, y: 100} m_Pivot: {x: 0.5, y: 0.5} @@ -41891,7 +41893,7 @@ RectTransform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1410585898} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + 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 @@ -41900,11 +41902,11 @@ RectTransform: - {fileID: 372578918} - {fileID: 237340894} - {fileID: 600355260} - m_Father: {fileID: 1941047790} + m_Father: {fileID: 1155171500} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: 0, y: 0} + m_AnchoredPosition: {x: -635.7, y: -214} m_SizeDelta: {x: 100, y: 100} m_Pivot: {x: 0.5, y: 0.5} --- !u!114 &1410585901 @@ -45437,7 +45439,6 @@ RectTransform: - {fileID: 1326341347} - {fileID: 1596671030} - {fileID: 1311485916} - - {fileID: 1155171500} - {fileID: 2030106541} - {fileID: 1615010622} - {fileID: 1284781886} @@ -56666,11 +56667,9 @@ RectTransform: - {fileID: 1362026693} - {fileID: 749472731} - {fileID: 1556637616} - - {fileID: 1410585899} - {fileID: 167119534} - {fileID: 1227675749} - {fileID: 806830622} - - {fileID: 1069894365} - {fileID: 726168683} - {fileID: 832185058} - {fileID: 2061899620} @@ -58989,14 +58988,16 @@ RectTransform: m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: + - {fileID: 1155171500} - {fileID: 992587306} - {fileID: 17691537} - {fileID: 806335508} + - {fileID: 1069894365} m_Father: {fileID: 1556637616} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 1, y: 0.5} m_AnchorMax: {x: 1, y: 0.5} - m_AnchoredPosition: {x: -101.69995, y: -76.9} + m_AnchoredPosition: {x: -101.69995, y: -35} m_SizeDelta: {x: 404, y: 0} m_Pivot: {x: 1, y: 0.5} --- !u!114 &2030106542 @@ -67131,7 +67132,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 diff --git a/Assets/Scenes/beforeEverything.unity b/Assets/Scenes/beforeEverything.unity index 8431c45e..d65e5c43 100644 --- a/Assets/Scenes/beforeEverything.unity +++ b/Assets/Scenes/beforeEverything.unity @@ -2357,7 +2357,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 diff --git a/Assets/Scenes/gamePlay_gamePlay.unity b/Assets/Scenes/gamePlay_gamePlay.unity index 255bfeb9..fe1bc1a2 100644 --- a/Assets/Scenes/gamePlay_gamePlay.unity +++ b/Assets/Scenes/gamePlay_gamePlay.unity @@ -2822,7 +2822,7 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_text: "\u58A8\u5F69\u79BB" + m_text: "\u7231\u7433\u8FBE\u96C5" m_isRightToLeft: 0 m_fontAsset: {fileID: 11400000, guid: 47babadf44fc728438ae9a924c42227e, type: 2} m_sharedMaterial: {fileID: 6312708493749940865, guid: 47babadf44fc728438ae9a924c42227e, type: 2} @@ -11041,7 +11041,7 @@ SpriteRenderer: m_LightmapParameters: {fileID: 0} m_SortingLayerID: 0 m_SortingLayer: 0 - m_SortingOrder: 668 + m_SortingOrder: 1230 m_Sprite: {fileID: 21300000, guid: e816a07ba153c4647b5544d5edd6d3c6, type: 3} m_Color: {r: 1, g: 1, b: 1, a: 0.3529412} m_FlipX: 0 @@ -11079,8 +11079,8 @@ Transform: m_GameObject: {fileID: 228531561} serializedVersion: 2 m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: -0.0457, y: 5.3, z: 0} - m_LocalScale: {x: 0.89, y: 2.3747165, z: 1} + m_LocalPosition: {x: -0.0457, y: 9.86, z: 0} + m_LocalScale: {x: 0.89, y: 2.5, z: 1} m_ConstrainProportionsScale: 0 m_Children: - {fileID: 1584828688} @@ -11221,7 +11221,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -12838,8 +12838,8 @@ Transform: m_GameObject: {fileID: 278391250} serializedVersion: 2 m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: -0.0376, y: -1.7716, z: 0} - m_LocalScale: {x: 1.0466657, y: 0.47952017, z: 1} + m_LocalPosition: {x: -0.0376, y: -3.2444, z: 0} + m_LocalScale: {x: 1.0466657, y: 0.5178007, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 228531562} @@ -12889,7 +12889,7 @@ SpriteRenderer: m_SortingLayer: 0 m_SortingOrder: 4 m_Sprite: {fileID: 21300000, guid: cc94db22637159644b2d2327eeab6fe9, type: 3} - m_Color: {r: 0.13725491, g: 0.52156866, b: 1, a: 0.14901961} + m_Color: {r: 0.13725491, g: 0.52156866, b: 1, a: 0.05882353} m_FlipX: 0 m_FlipY: 0 m_DrawMode: 0 @@ -12976,7 +12976,7 @@ SpriteRenderer: m_SortingLayer: 0 m_SortingOrder: 4 m_Sprite: {fileID: 4306421076497480165, guid: a4550097127810540bfea369dfdd9002, type: 3} - m_Color: {r: 0.21568628, g: 0.972549, b: 0.83137256, a: 0.11764706} + m_Color: {r: 0.28875935, g: 0.9716981, b: 0.5669937, a: 0.019607844} m_FlipX: 0 m_FlipY: 0 m_DrawMode: 0 @@ -14069,6 +14069,10 @@ MonoBehaviour: maxScaleMultiplier: 0.5 jumpForce: 5 gravity: -15 + horizontalDriftRange: {x: 0.25, y: 0.65} + rotationRange: 8 + scalePunch: 0.18 + scalePunchDuration: 0.18 fadeInTime: 0.25 fadeOutStartTime: 0.25 fadeOutDuration: 0.25 @@ -14672,8 +14676,8 @@ MonoBehaviour: m_ColorSpace: -1 m_NumColorKeys: 2 m_NumAlphaKeys: 2 - minParticleScale: 0.03 - maxParticleScale: 0.06 + minParticleScale: 0.015 + maxParticleScale: 0.03 enableParticles: 1 physicsLayerName: particles sortingLayerName: Particles @@ -15181,7 +15185,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -15795,11 +15799,11 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 682261594771255014, guid: 7e80d4de8ab2ff04a9bf1c54e5a064b1, type: 3} propertyPath: m_SizeDelta.x - value: 95.5 + value: 96.525 objectReference: {fileID: 0} - target: {fileID: 682261594771255014, guid: 7e80d4de8ab2ff04a9bf1c54e5a064b1, type: 3} propertyPath: m_AnchoredPosition.x - value: 96.5 + value: 95.85 objectReference: {fileID: 0} - target: {fileID: 682261594771255014, guid: 7e80d4de8ab2ff04a9bf1c54e5a064b1, type: 3} propertyPath: m_AnchoredPosition.y @@ -15815,7 +15819,7 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 4266895856353985475, guid: 7e80d4de8ab2ff04a9bf1c54e5a064b1, type: 3} propertyPath: m_SizeDelta.x - value: 88.5 + value: 87.75 objectReference: {fileID: 0} - target: {fileID: 4266895856353985475, guid: 7e80d4de8ab2ff04a9bf1c54e5a064b1, type: 3} propertyPath: m_AnchoredPosition.y @@ -15915,11 +15919,11 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 6759631360171910247, guid: 7e80d4de8ab2ff04a9bf1c54e5a064b1, type: 3} propertyPath: m_SizeDelta.x - value: 8 + value: 8.1 objectReference: {fileID: 0} - target: {fileID: 6759631360171910247, guid: 7e80d4de8ab2ff04a9bf1c54e5a064b1, type: 3} propertyPath: m_AnchoredPosition.x - value: 88.5 + value: 87.75 objectReference: {fileID: 0} - target: {fileID: 6759631360171910247, guid: 7e80d4de8ab2ff04a9bf1c54e5a064b1, type: 3} propertyPath: m_AnchoredPosition.y @@ -16952,7 +16956,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -18907,7 +18911,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -19111,7 +19115,7 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_Sprite: {fileID: 21300000, guid: 440e0141c6eb0144c9e9162f0f278d6b, type: 3} + m_Sprite: {fileID: 21300000, guid: c8f373c5ea610a345a513f33ba768314, type: 3} m_Type: 0 m_PreserveAspect: 0 m_FillCenter: 1 @@ -20281,7 +20285,7 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_text: 570/570 + m_text: 1500/1500 m_isRightToLeft: 0 m_fontAsset: {fileID: 11400000, guid: 7cad3f54ac7b53d4885f00c16f1a6929, type: 2} m_sharedMaterial: {fileID: -346136068272202111, guid: 7cad3f54ac7b53d4885f00c16f1a6929, type: 2} @@ -20697,8 +20701,8 @@ Transform: m_GameObject: {fileID: 471259273} serializedVersion: 2 m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 3.668, y: 5.297, z: 0} - m_LocalScale: {x: 0.89, y: 2.3747165, z: 1} + m_LocalPosition: {x: 3.668, y: 9.856999, z: 0} + m_LocalScale: {x: 0.89, y: 2.5, z: 1} m_ConstrainProportionsScale: 0 m_Children: - {fileID: 1155855054} @@ -21018,8 +21022,8 @@ Transform: m_GameObject: {fileID: 480679342} serializedVersion: 2 m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0.0043, y: 1.7158, z: 0} - m_LocalScale: {x: -0.7957424, y: -0.56400156, z: 1} + m_LocalPosition: {x: 0.0043, y: -0.4986, z: 0} + m_LocalScale: {x: -0.7957424, y: -0.50332755, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 1083269823} @@ -21069,7 +21073,7 @@ SpriteRenderer: m_SortingLayer: 0 m_SortingOrder: 4 m_Sprite: {fileID: 21300000, guid: 3e600073feb689a46b63b89d6b0978e1, type: 3} - m_Color: {r: 0.13725491, g: 0.52156866, b: 1, a: 0.14901961} + m_Color: {r: 0.13725491, g: 0.52156866, b: 1, a: 0.05882353} m_FlipX: 0 m_FlipY: 0 m_DrawMode: 0 @@ -21642,7 +21646,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -22576,7 +22580,7 @@ GameObject: m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 - m_IsActive: 0 + m_IsActive: 1 --- !u!4 &542344487 Transform: m_ObjectHideFlags: 0 @@ -23607,7 +23611,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -23768,8 +23772,8 @@ Transform: m_GameObject: {fileID: 614786765} serializedVersion: 2 m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: -0.0127, y: 1.777, z: 0} - m_LocalScale: {x: 0.78261685, y: 0.55610794, z: 1} + m_LocalPosition: {x: -0.0127, y: -0.4439, z: 0} + m_LocalScale: {x: 0.78261685, y: 0.49628305, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 1801052429} @@ -23819,7 +23823,7 @@ SpriteRenderer: m_SortingLayer: 0 m_SortingOrder: 4 m_Sprite: {fileID: 21300000, guid: 6191b3d03c22a7d47a6b3251b8064942, type: 3} - m_Color: {r: 0.13725491, g: 0.52156866, b: 1, a: 0.14901961} + m_Color: {r: 0.13725491, g: 0.52156866, b: 1, a: 0.05882353} m_FlipX: 0 m_FlipY: 0 m_DrawMode: 0 @@ -24224,7 +24228,7 @@ Transform: m_GameObject: {fileID: 628867848} serializedVersion: 2 m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 1.91, y: -1.5379415, z: 0.046203207} + m_LocalPosition: {x: 1.901906, y: -1.78, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 1 m_Children: [] @@ -24469,7 +24473,7 @@ SpriteRenderer: m_LightmapParameters: {fileID: 0} m_SortingLayerID: 0 m_SortingLayer: 0 - m_SortingOrder: 668 + m_SortingOrder: 1230 m_Sprite: {fileID: 21300000, guid: e816a07ba153c4647b5544d5edd6d3c6, type: 3} m_Color: {r: 1, g: 1, b: 1, a: 0.3529412} m_FlipX: 0 @@ -30976,7 +30980,7 @@ ParticleSystemRenderer: m_VertexStreams: 00010304181f m_UseCustomTrailVertexStreams: 0 m_TrailVertexStreams: 00010304 - m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} m_Mesh1: {fileID: 0} m_Mesh2: {fileID: 0} m_Mesh3: {fileID: 0} @@ -30994,7 +30998,7 @@ Transform: m_GameObject: {fileID: 675385938} serializedVersion: 2 m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: -1.766094, y: 1.75, z: 0.046203207} + m_LocalPosition: {x: -1.766094, y: 1.7, z: 0.046203207} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: @@ -31576,7 +31580,7 @@ MonoBehaviour: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 701909117} - m_Enabled: 1 + m_Enabled: 0 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: 31a19414c41e5ae4aae2af33fee712f6, type: 3} m_Name: @@ -31589,7 +31593,7 @@ MonoBehaviour: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 701909117} - m_Enabled: 1 + m_Enabled: 0 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} m_Name: @@ -32333,11 +32337,11 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 682261594771255014, guid: 7e80d4de8ab2ff04a9bf1c54e5a064b1, type: 3} propertyPath: m_SizeDelta.x - value: 95.5 + value: 96.525 objectReference: {fileID: 0} - target: {fileID: 682261594771255014, guid: 7e80d4de8ab2ff04a9bf1c54e5a064b1, type: 3} propertyPath: m_AnchoredPosition.x - value: 96.5 + value: 95.85 objectReference: {fileID: 0} - target: {fileID: 682261594771255014, guid: 7e80d4de8ab2ff04a9bf1c54e5a064b1, type: 3} propertyPath: m_AnchoredPosition.y @@ -32353,7 +32357,7 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 4266895856353985475, guid: 7e80d4de8ab2ff04a9bf1c54e5a064b1, type: 3} propertyPath: m_SizeDelta.x - value: 88.5 + value: 87.75 objectReference: {fileID: 0} - target: {fileID: 4266895856353985475, guid: 7e80d4de8ab2ff04a9bf1c54e5a064b1, type: 3} propertyPath: m_AnchoredPosition.y @@ -32453,11 +32457,11 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 6759631360171910247, guid: 7e80d4de8ab2ff04a9bf1c54e5a064b1, type: 3} propertyPath: m_SizeDelta.x - value: 8 + value: 8.1 objectReference: {fileID: 0} - target: {fileID: 6759631360171910247, guid: 7e80d4de8ab2ff04a9bf1c54e5a064b1, type: 3} propertyPath: m_AnchoredPosition.x - value: 88.5 + value: 87.75 objectReference: {fileID: 0} - target: {fileID: 6759631360171910247, guid: 7e80d4de8ab2ff04a9bf1c54e5a064b1, type: 3} propertyPath: m_AnchoredPosition.y @@ -33035,8 +33039,8 @@ Camera: m_GameObject: {fileID: 754533168} m_Enabled: 1 serializedVersion: 2 - m_ClearFlags: 4 - m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_ClearFlags: 2 + m_BackGroundColor: {r: 0, g: 0, b: 0, a: 1} m_projectionMatrixMode: 1 m_GateFitMode: 2 m_FOVAxisMode: 0 @@ -33149,6 +33153,7 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: targetAspect: 1.7777778 + lockAspect: 0 --- !u!1 &754636332 GameObject: m_ObjectHideFlags: 0 @@ -33435,8 +33440,8 @@ Transform: m_GameObject: {fileID: 766553120} serializedVersion: 2 m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: -0.0376, y: 2.0234, z: 0} - m_LocalScale: {x: 1.0466657, y: -0.45064414, z: 1} + m_LocalPosition: {x: -0.0376, y: 0.8541, z: 0} + m_LocalScale: {x: 1.0466657, y: -0.48661944, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 228531562} @@ -33486,7 +33491,7 @@ SpriteRenderer: m_SortingLayer: 0 m_SortingOrder: 4 m_Sprite: {fileID: 21300000, guid: cc94db22637159644b2d2327eeab6fe9, type: 3} - m_Color: {r: 0.13725491, g: 0.52156866, b: 1, a: 0.14901961} + m_Color: {r: 0.13725491, g: 0.52156866, b: 1, a: 0.05882353} m_FlipX: 0 m_FlipY: 0 m_DrawMode: 0 @@ -36947,8 +36952,8 @@ Transform: m_GameObject: {fileID: 820215022} serializedVersion: 2 m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 1.811, y: 5.3, z: 0} - m_LocalScale: {x: 0.89, y: 2.3747165, z: 1} + m_LocalPosition: {x: 1.811, y: 9.86, z: 0} + m_LocalScale: {x: 0.89, y: 2.5, z: 1} m_ConstrainProportionsScale: 0 m_Children: - {fileID: 189031531} @@ -37510,7 +37515,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -38147,8 +38152,8 @@ Transform: m_GameObject: {fileID: 856873760} serializedVersion: 2 m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: -0.0242, y: 1.6208, z: 0} - m_LocalScale: {x: 0.84892434, y: 0.5522165, z: 1} + m_LocalPosition: {x: -0.0242, y: -0.5834, z: 0} + m_LocalScale: {x: 0.84892434, y: 0.49281025, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 820215023} @@ -38198,7 +38203,7 @@ SpriteRenderer: m_SortingLayer: 0 m_SortingOrder: 4 m_Sprite: {fileID: 21300000, guid: 6191b3d03c22a7d47a6b3251b8064942, type: 3} - m_Color: {r: 0.13725491, g: 0.52156866, b: 1, a: 0.14901961} + m_Color: {r: 0.13725491, g: 0.52156866, b: 1, a: 0.05882353} m_FlipX: 0 m_FlipY: 0 m_DrawMode: 0 @@ -39594,7 +39599,7 @@ Transform: m_GameObject: {fileID: 917849125} serializedVersion: 2 m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: -5.525, y: -1.5379415, z: 0.046203207} + m_LocalPosition: {x: -5.526094, y: -1.78, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 1 m_Children: [] @@ -39703,8 +39708,8 @@ Transform: m_GameObject: {fileID: 919628104} serializedVersion: 2 m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: -0.0242, y: -2.106, z: 0} - m_LocalScale: {x: 0.84892434, y: -0.3924619, z: 1} + m_LocalPosition: {x: -0.0242, y: -3.9096, z: 0} + m_LocalScale: {x: 0.84892434, y: -0.35024172, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 820215023} @@ -39754,7 +39759,7 @@ SpriteRenderer: m_SortingLayer: 0 m_SortingOrder: 4 m_Sprite: {fileID: 21300000, guid: 6191b3d03c22a7d47a6b3251b8064942, type: 3} - m_Color: {r: 0.13725491, g: 0.52156866, b: 1, a: 0.14901961} + m_Color: {r: 0.13725491, g: 0.52156866, b: 1, a: 0.05882353} m_FlipX: 0 m_FlipY: 0 m_DrawMode: 0 @@ -40857,7 +40862,7 @@ SpriteRenderer: m_LightmapParameters: {fileID: 0} m_SortingLayerID: 0 m_SortingLayer: 0 - m_SortingOrder: 668 + m_SortingOrder: 1230 m_Sprite: {fileID: 21300000, guid: e816a07ba153c4647b5544d5edd6d3c6, type: 3} m_Color: {r: 1, g: 1, b: 1, a: 0.3529412} m_FlipX: 0 @@ -41365,8 +41370,8 @@ MonoBehaviour: m_TargetGraphic: {fileID: 1501988772} m_HandleRect: {fileID: 1501988771} m_Direction: 0 - m_Value: -0.109836064 - m_Size: 0.99996895 + m_Value: -0.11386139 + m_Size: 0.9999692 m_NumberOfSteps: 0 m_OnValueChanged: m_PersistentCalls: @@ -41576,8 +41581,8 @@ Transform: m_GameObject: {fileID: 997867645} serializedVersion: 2 m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: -0.0127, y: -2.0646, z: 0} - m_LocalScale: {x: 0.78261685, y: -0.4177, z: 1} + m_LocalPosition: {x: -0.0127, y: -3.8724, z: 0} + m_LocalScale: {x: 0.78261685, y: -0.37276474, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 1801052429} @@ -41627,7 +41632,7 @@ SpriteRenderer: m_SortingLayer: 0 m_SortingOrder: 4 m_Sprite: {fileID: 21300000, guid: 6191b3d03c22a7d47a6b3251b8064942, type: 3} - m_Color: {r: 0.13725491, g: 0.52156866, b: 1, a: 0.14901961} + m_Color: {r: 0.13725491, g: 0.52156866, b: 1, a: 0.05882353} m_FlipX: 0 m_FlipY: 0 m_DrawMode: 0 @@ -43105,7 +43110,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -43864,7 +43869,7 @@ Transform: m_GameObject: {fileID: 1067482187} serializedVersion: 2 m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: -1.81, y: -1.5379415, z: 0.046203207} + m_LocalPosition: {x: -1.8117939, y: -1.78, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 1 m_Children: [] @@ -44311,8 +44316,8 @@ Transform: m_GameObject: {fileID: 1083269822} serializedVersion: 2 m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: -3.76, y: 5.3, z: 0} - m_LocalScale: {x: 0.89, y: 2.3747165, z: 1} + m_LocalPosition: {x: -3.76, y: 9.86, z: 0} + m_LocalScale: {x: 0.89, y: 2.5, z: 1} m_ConstrainProportionsScale: 0 m_Children: - {fileID: 1997131773} @@ -45431,6 +45436,10 @@ PrefabInstance: serializedVersion: 3 m_TransformParent: {fileID: 675385942} m_Modifications: + - target: {fileID: 1151778081756335643, guid: cd3d579a2d65b3241a1812f639db37ec, type: 3} + propertyPath: m_RenderAlignment + value: 2 + objectReference: {fileID: 0} - target: {fileID: 3022102558446658867, guid: cd3d579a2d65b3241a1812f639db37ec, type: 3} propertyPath: m_Name value: VFX_Arcade_03 @@ -45443,13 +45452,33 @@ PrefabInstance: propertyPath: playOnAwake value: 0 objectReference: {fileID: 0} + - target: {fileID: 3584774378783718644, guid: cd3d579a2d65b3241a1812f639db37ec, type: 3} + propertyPath: moveWithTransform + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 3584774378783718644, guid: cd3d579a2d65b3241a1812f639db37ec, type: 3} + propertyPath: InitialModule.gravitySource + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 3584774378783718644, guid: cd3d579a2d65b3241a1812f639db37ec, type: 3} + propertyPath: InitialModule.startRotation.scalar + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 6864860825588444682, guid: cd3d579a2d65b3241a1812f639db37ec, type: 3} + propertyPath: m_LocalScale.x + value: 2 + objectReference: {fileID: 0} + - target: {fileID: 6864860825588444682, guid: cd3d579a2d65b3241a1812f639db37ec, type: 3} + propertyPath: m_LocalScale.y + value: 0.5 + objectReference: {fileID: 0} - target: {fileID: 6864860825588444682, guid: cd3d579a2d65b3241a1812f639db37ec, type: 3} propertyPath: m_LocalPosition.x value: 0 objectReference: {fileID: 0} - target: {fileID: 6864860825588444682, guid: cd3d579a2d65b3241a1812f639db37ec, type: 3} propertyPath: m_LocalPosition.y - value: 0 + value: -0.2 objectReference: {fileID: 0} - target: {fileID: 6864860825588444682, guid: cd3d579a2d65b3241a1812f639db37ec, type: 3} propertyPath: m_LocalPosition.z @@ -45483,10 +45512,38 @@ PrefabInstance: propertyPath: m_LocalEulerAnglesHint.z value: 0 objectReference: {fileID: 0} + - target: {fileID: 6990049465749588838, guid: cd3d579a2d65b3241a1812f639db37ec, type: 3} + propertyPath: m_RenderAlignment + value: 2 + objectReference: {fileID: 0} - target: {fileID: 7621220393334125566, guid: cd3d579a2d65b3241a1812f639db37ec, type: 3} propertyPath: playOnAwake value: 0 objectReference: {fileID: 0} + - target: {fileID: 7621220393334125566, guid: cd3d579a2d65b3241a1812f639db37ec, type: 3} + propertyPath: moveWithTransform + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7621220393334125566, guid: cd3d579a2d65b3241a1812f639db37ec, type: 3} + propertyPath: InitialModule.gravitySource + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 7621220393334125566, guid: cd3d579a2d65b3241a1812f639db37ec, type: 3} + propertyPath: InitialModule.startRotation.scalar + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7873122989201535488, guid: cd3d579a2d65b3241a1812f639db37ec, type: 3} + propertyPath: m_LocalScale.x + value: 2 + objectReference: {fileID: 0} + - target: {fileID: 7873122989201535488, guid: cd3d579a2d65b3241a1812f639db37ec, type: 3} + propertyPath: m_LocalScale.y + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 7873122989201535488, guid: cd3d579a2d65b3241a1812f639db37ec, type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} m_RemovedComponents: [] m_RemovedGameObjects: [] m_AddedGameObjects: [] @@ -47137,7 +47194,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -47320,11 +47377,11 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 682261594771255014, guid: 7e80d4de8ab2ff04a9bf1c54e5a064b1, type: 3} propertyPath: m_SizeDelta.x - value: 95.5 + value: 96.525 objectReference: {fileID: 0} - target: {fileID: 682261594771255014, guid: 7e80d4de8ab2ff04a9bf1c54e5a064b1, type: 3} propertyPath: m_AnchoredPosition.x - value: 96.5 + value: 95.85 objectReference: {fileID: 0} - target: {fileID: 682261594771255014, guid: 7e80d4de8ab2ff04a9bf1c54e5a064b1, type: 3} propertyPath: m_AnchoredPosition.y @@ -47340,7 +47397,7 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 4266895856353985475, guid: 7e80d4de8ab2ff04a9bf1c54e5a064b1, type: 3} propertyPath: m_SizeDelta.x - value: 88.5 + value: 87.75 objectReference: {fileID: 0} - target: {fileID: 4266895856353985475, guid: 7e80d4de8ab2ff04a9bf1c54e5a064b1, type: 3} propertyPath: m_AnchoredPosition.y @@ -47440,11 +47497,11 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 6759631360171910247, guid: 7e80d4de8ab2ff04a9bf1c54e5a064b1, type: 3} propertyPath: m_SizeDelta.x - value: 8 + value: 8.1 objectReference: {fileID: 0} - target: {fileID: 6759631360171910247, guid: 7e80d4de8ab2ff04a9bf1c54e5a064b1, type: 3} propertyPath: m_AnchoredPosition.x - value: 88.5 + value: 87.75 objectReference: {fileID: 0} - target: {fileID: 6759631360171910247, guid: 7e80d4de8ab2ff04a9bf1c54e5a064b1, type: 3} propertyPath: m_AnchoredPosition.y @@ -48680,7 +48737,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -48922,7 +48979,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -50391,8 +50448,8 @@ Transform: m_GameObject: {fileID: 1269063487} serializedVersion: 2 m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: -0.058, y: -1.9664, z: 0} - m_LocalScale: {x: 1, y: -0.4071988, z: 1} + m_LocalPosition: {x: -0.058, y: -3.7849, z: 0} + m_LocalScale: {x: 1, y: -0.36339322, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 471259274} @@ -50442,7 +50499,7 @@ SpriteRenderer: m_SortingLayer: 0 m_SortingOrder: 4 m_Sprite: {fileID: 21300000, guid: 68e83f8c404924741b242666f5029cef, type: 3} - m_Color: {r: 0.13725491, g: 0.52156866, b: 1, a: 0.14901961} + m_Color: {r: 0.13725491, g: 0.52156866, b: 1, a: 0.05882353} m_FlipX: 0 m_FlipY: 0 m_DrawMode: 0 @@ -50740,7 +50797,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -51280,7 +51337,7 @@ Transform: m_GameObject: {fileID: 1293318055} serializedVersion: 2 m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: -3.72, y: -1.5379415, z: 0.046203207} + m_LocalPosition: {x: -3.669094, y: -1.78, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 1 m_Children: [] @@ -52084,7 +52141,7 @@ SpriteRenderer: m_SortingLayer: 0 m_SortingOrder: 4 m_Sprite: {fileID: 4306421076497480165, guid: a4550097127810540bfea369dfdd9002, type: 3} - m_Color: {r: 0, g: 0.9490196, b: 0.99607843, a: 0.11764706} + m_Color: {r: 0, g: 0.9490196, b: 0.99607843, a: 0.019607844} m_FlipX: 0 m_FlipY: 0 m_DrawMode: 0 @@ -52425,14 +52482,14 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: slotIndex: 3 - maxHP: 570 - currentHP: 570 - maxMana: 200 + maxHP: 1500 + currentHP: 1500 + maxMana: 300 currentMana: 0 damageResistance: 0 - scoreEfficiency: 0.02 + scoreEfficiency: 0.09 bmm: {fileID: 1261342020} - attack: 8 + attack: 38 baseTrackScore: 1000 perfectRatio: 1 greatRatio: 0.75 @@ -54940,9 +54997,9 @@ Transform: - {fileID: 675385942} - {fileID: 917849126} - {fileID: 1293318058} - - {fileID: 628867851} - {fileID: 1067482190} - {fileID: 1646396270} + - {fileID: 628867851} m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &1410197819 @@ -55161,7 +55218,7 @@ SpriteRenderer: m_LightmapParameters: {fileID: 0} m_SortingLayerID: 0 m_SortingLayer: 0 - m_SortingOrder: 668 + m_SortingOrder: 1230 m_Sprite: {fileID: 21300000, guid: e816a07ba153c4647b5544d5edd6d3c6, type: 3} m_Color: {r: 1, g: 1, b: 1, a: 0.3529412} m_FlipX: 0 @@ -55951,7 +56008,7 @@ SpriteRenderer: m_SortingLayer: 0 m_SortingOrder: 4 m_Sprite: {fileID: 4306421076497480165, guid: a4550097127810540bfea369dfdd9002, type: 3} - m_Color: {r: 0.9764706, g: 0.53333336, b: 0.90588236, a: 0.11764706} + m_Color: {r: 0.9764706, g: 0.53333336, b: 0.90588236, a: 0.019607844} m_FlipX: 0 m_FlipY: 0 m_DrawMode: 0 @@ -56399,7 +56456,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -58615,8 +58672,8 @@ MonoBehaviour: m_ColorSpace: -1 m_NumColorKeys: 2 m_NumAlphaKeys: 2 - minParticleScale: 0.03 - maxParticleScale: 0.06 + minParticleScale: 0.015 + maxParticleScale: 0.03 enableParticles: 1 physicsLayerName: particles sortingLayerName: Particles @@ -59338,11 +59395,11 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 682261594771255014, guid: 7e80d4de8ab2ff04a9bf1c54e5a064b1, type: 3} propertyPath: m_SizeDelta.x - value: 95.5 + value: 96.525 objectReference: {fileID: 0} - target: {fileID: 682261594771255014, guid: 7e80d4de8ab2ff04a9bf1c54e5a064b1, type: 3} propertyPath: m_AnchoredPosition.x - value: 96.5 + value: 95.85 objectReference: {fileID: 0} - target: {fileID: 682261594771255014, guid: 7e80d4de8ab2ff04a9bf1c54e5a064b1, type: 3} propertyPath: m_AnchoredPosition.y @@ -59358,7 +59415,7 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 4266895856353985475, guid: 7e80d4de8ab2ff04a9bf1c54e5a064b1, type: 3} propertyPath: m_SizeDelta.x - value: 88.5 + value: 87.75 objectReference: {fileID: 0} - target: {fileID: 4266895856353985475, guid: 7e80d4de8ab2ff04a9bf1c54e5a064b1, type: 3} propertyPath: m_AnchoredPosition.y @@ -59458,11 +59515,11 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 6759631360171910247, guid: 7e80d4de8ab2ff04a9bf1c54e5a064b1, type: 3} propertyPath: m_SizeDelta.x - value: 8 + value: 8.1 objectReference: {fileID: 0} - target: {fileID: 6759631360171910247, guid: 7e80d4de8ab2ff04a9bf1c54e5a064b1, type: 3} propertyPath: m_AnchoredPosition.x - value: 88.5 + value: 87.75 objectReference: {fileID: 0} - target: {fileID: 6759631360171910247, guid: 7e80d4de8ab2ff04a9bf1c54e5a064b1, type: 3} propertyPath: m_AnchoredPosition.y @@ -61394,7 +61451,7 @@ SpriteRenderer: m_SortingLayer: 0 m_SortingOrder: 4 m_Sprite: {fileID: 4306421076497480165, guid: a4550097127810540bfea369dfdd9002, type: 3} - m_Color: {r: 0.98039216, g: 0.6627451, b: 0.5019608, a: 0.11764706} + m_Color: {r: 0.98039216, g: 0.6627451, b: 0.5019608, a: 0.019607844} m_FlipX: 0 m_FlipY: 0 m_DrawMode: 0 @@ -61565,7 +61622,7 @@ Transform: m_GameObject: {fileID: 1646396267} serializedVersion: 2 m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0.09, y: -1.5379415, z: 0.046203207} + m_LocalPosition: {x: 0.04490602, y: -1.78, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 1 m_Children: [] @@ -62637,7 +62694,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -65080,8 +65137,8 @@ Transform: m_GameObject: {fileID: 1801052428} serializedVersion: 2 m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: -1.903, y: 5.3, z: 0} - m_LocalScale: {x: 0.89, y: 2.3747165, z: 1} + m_LocalPosition: {x: -1.903, y: 9.86, z: 0} + m_LocalScale: {x: 0.89, y: 2.5, z: 1} m_ConstrainProportionsScale: 0 m_Children: - {fileID: 207233792} @@ -65265,7 +65322,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -65320,8 +65377,8 @@ Transform: m_GameObject: {fileID: 1814450259} serializedVersion: 2 m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: -0.058, y: 2.15, z: 0} - m_LocalScale: {x: -1, y: 0.5460128, z: 1} + m_LocalPosition: {x: -0.058, y: -0.111, z: 0} + m_LocalScale: {x: -1, y: 0.48727396, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 471259274} @@ -65371,7 +65428,7 @@ SpriteRenderer: m_SortingLayer: 0 m_SortingOrder: 4 m_Sprite: {fileID: 21300000, guid: 68e83f8c404924741b242666f5029cef, type: 3} - m_Color: {r: 0.13725491, g: 0.52156866, b: 1, a: 0.14901961} + m_Color: {r: 0.13725491, g: 0.52156866, b: 1, a: 0.05882353} m_FlipX: 0 m_FlipY: 0 m_DrawMode: 0 @@ -66044,7 +66101,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -67744,8 +67801,8 @@ Transform: m_GameObject: {fileID: 1899720853} serializedVersion: 2 m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0.0043, y: -2.0927, z: 0} - m_LocalScale: {x: 0.7957424, y: 0.42812917, z: 1} + m_LocalPosition: {x: 0.0043, y: -3.8976, z: 0} + m_LocalScale: {x: 0.7957424, y: 0.382072, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 1083269823} @@ -67795,7 +67852,7 @@ SpriteRenderer: m_SortingLayer: 0 m_SortingOrder: 4 m_Sprite: {fileID: 21300000, guid: 3e600073feb689a46b63b89d6b0978e1, type: 3} - m_Color: {r: 0.13725491, g: 0.52156866, b: 1, a: 0.14901961} + m_Color: {r: 0.13725491, g: 0.52156866, b: 1, a: 0.05882353} m_FlipX: 0 m_FlipY: 0 m_DrawMode: 0 @@ -68460,7 +68517,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -69282,7 +69339,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -69705,7 +69762,7 @@ SpriteRenderer: m_SortingLayer: 0 m_SortingOrder: 4 m_Sprite: {fileID: 4306421076497480165, guid: a4550097127810540bfea369dfdd9002, type: 3} - m_Color: {r: 0.972549, g: 0.43529412, b: 0.39215687, a: 0.11764706} + m_Color: {r: 0.972549, g: 0.43529412, b: 0.39215687, a: 0.019607844} m_FlipX: 0 m_FlipY: 0 m_DrawMode: 0 @@ -69928,7 +69985,7 @@ SpriteRenderer: m_LightmapParameters: {fileID: 0} m_SortingLayerID: 0 m_SortingLayer: 0 - m_SortingOrder: 668 + m_SortingOrder: 1230 m_Sprite: {fileID: 21300000, guid: e816a07ba153c4647b5544d5edd6d3c6, type: 3} m_Color: {r: 1, g: 1, b: 1, a: 0.3529412} m_FlipX: 0 @@ -69998,7 +70055,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -70169,7 +70226,7 @@ MonoBehaviour: - {fileID: 1641341447} - {fileID: 1459646399} - {fileID: 1320505694} - pressedAlpha: 30 + pressedAlpha: 3 showJudgeText: 1 keyActiveColor: {r: 0.9811321, g: 0.26992652, b: 0.0786757, a: 1} keyInactiveColor: {r: 1, g: 1, b: 1, a: 1} @@ -71503,7 +71560,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -77503,7 +77560,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 diff --git a/Assets/Scenes/selectYourSongFirst.unity b/Assets/Scenes/selectYourSongFirst.unity index 460226cf..140f8428 100644 --- a/Assets/Scenes/selectYourSongFirst.unity +++ b/Assets/Scenes/selectYourSongFirst.unity @@ -4647,7 +4647,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -4924,7 +4924,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -6091,7 +6091,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -14399,7 +14399,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -15745,7 +15745,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -16522,7 +16522,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -17089,7 +17089,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 diff --git a/Assets/VFXPACK_IMPACT_WALLCOEUR_FreeVersion/00_Prefab/0_Classic/VFX_Arcade_03.prefab b/Assets/VFXPACK_IMPACT_WALLCOEUR_FreeVersion/00_Prefab/0_Classic/VFX_Arcade_03.prefab index 2abda992..a9950862 100644 --- a/Assets/VFXPACK_IMPACT_WALLCOEUR_FreeVersion/00_Prefab/0_Classic/VFX_Arcade_03.prefab +++ b/Assets/VFXPACK_IMPACT_WALLCOEUR_FreeVersion/00_Prefab/0_Classic/VFX_Arcade_03.prefab @@ -4842,6 +4842,9 @@ ParticleSystemRenderer: m_ReflectionProbeUsage: 0 m_RayTracingMode: 0 m_RayTraceProcedural: 0 + m_RayTracingAccelStructBuildFlagsOverride: 0 + m_RayTracingAccelStructBuildFlags: 1 + m_SmallMeshCulling: 1 m_RenderingLayerMask: 1 m_RendererPriority: 0 m_Materials: @@ -4865,7 +4868,7 @@ ParticleSystemRenderer: m_LightmapParameters: {fileID: 0} m_SortingLayerID: 0 m_SortingLayer: 0 - m_SortingOrder: 1 + m_SortingOrder: 666 m_RenderMode: 0 m_MeshDistribution: 0 m_SortMode: 0 @@ -9730,6 +9733,9 @@ ParticleSystemRenderer: m_ReflectionProbeUsage: 0 m_RayTracingMode: 0 m_RayTraceProcedural: 0 + m_RayTracingAccelStructBuildFlagsOverride: 0 + m_RayTracingAccelStructBuildFlags: 1 + m_SmallMeshCulling: 1 m_RenderingLayerMask: 1 m_RendererPriority: 0 m_Materials: @@ -9753,7 +9759,7 @@ ParticleSystemRenderer: m_LightmapParameters: {fileID: 0} m_SortingLayerID: 0 m_SortingLayer: 0 - m_SortingOrder: 5 + m_SortingOrder: 667 m_RenderMode: 0 m_MeshDistribution: 0 m_SortMode: 0 diff --git a/Assets/VFXPACK_IMPACT_WALLCOEUR_FreeVersion/01_Material/ImpactAdd 1.mat b/Assets/VFXPACK_IMPACT_WALLCOEUR_FreeVersion/01_Material/ImpactAdd 1.mat index e5ee6c5e..180945fe 100644 --- a/Assets/VFXPACK_IMPACT_WALLCOEUR_FreeVersion/01_Material/ImpactAdd 1.mat +++ b/Assets/VFXPACK_IMPACT_WALLCOEUR_FreeVersion/01_Material/ImpactAdd 1.mat @@ -48,7 +48,7 @@ Material: m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} - _MainTex: - m_Texture: {fileID: 2800000, guid: bd62e8ff1fa61fd4fa46bd46b8f8f8d9, type: 3} + m_Texture: {fileID: 2800000, guid: ce611558bedadaf4c95f7bbfb79148d5, type: 3} m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} - _MetallicGlossMap: @@ -113,6 +113,7 @@ Material: - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} - _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1} m_BuildTextureStacks: [] + m_AllowLocking: 1 --- !u!114 &2870635716611149580 MonoBehaviour: m_ObjectHideFlags: 11 diff --git a/Assets/__UI_NEW/_pTITLES.meta b/Assets/__UI_NEW/_pTITLES.meta new file mode 100644 index 00000000..7d4d6617 --- /dev/null +++ b/Assets/__UI_NEW/_pTITLES.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 819e2b710aed6214b9a810183c515da0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/__UI_NEW/_pTITLES/2026HANGZHOU.png b/Assets/__UI_NEW/_pTITLES/2026HANGZHOU.png new file mode 100644 index 00000000..563bba84 Binary files /dev/null and b/Assets/__UI_NEW/_pTITLES/2026HANGZHOU.png differ diff --git a/Assets/__UI_NEW/_pTITLES/2026HANGZHOU.png.meta b/Assets/__UI_NEW/_pTITLES/2026HANGZHOU.png.meta new file mode 100644 index 00000000..43e5b8da --- /dev/null +++ b/Assets/__UI_NEW/_pTITLES/2026HANGZHOU.png.meta @@ -0,0 +1,156 @@ +fileFormatVersion: 2 +guid: 4e6799a77466162499c411ec44cadde5 +TextureImporter: + internalIDToNameTable: + - first: + 213: 1132443972303761909 + second: HANGZHOU_0 + 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: 1 + 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 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: HANGZHOU_0 + rect: + serializedVersion: 2 + x: 8 + y: 3 + width: 387 + height: 97 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 5f1b239facf37bf00800000000000000 + internalID: 1132443972303761909 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: + HANGZHOU_0: 1132443972303761909 + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/__UI_NEW/级别图标.meta b/Assets/__UI_NEW/级别图标.meta new file mode 100644 index 00000000..732feea4 --- /dev/null +++ b/Assets/__UI_NEW/级别图标.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1c0d52e56c99fd64ba8a763d79b33f6e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/__UI_NEW/级别图标/A.png b/Assets/__UI_NEW/级别图标/A.png new file mode 100644 index 00000000..162dd3a3 Binary files /dev/null and b/Assets/__UI_NEW/级别图标/A.png differ diff --git a/Assets/__UI_NEW/级别图标/A.png.meta b/Assets/__UI_NEW/级别图标/A.png.meta new file mode 100644 index 00000000..ebb047b3 --- /dev/null +++ b/Assets/__UI_NEW/级别图标/A.png.meta @@ -0,0 +1,156 @@ +fileFormatVersion: 2 +guid: 4f7ba39699e39c644b9bfd158796462b +TextureImporter: + internalIDToNameTable: + - first: + 213: -8680797543115379092 + second: A_0 + 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: 1 + 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 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: A_0 + rect: + serializedVersion: 2 + x: 44 + y: 41 + width: 61 + height: 69 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: c6e268b90ac978780800000000000000 + internalID: -8680797543115379092 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: + A_0: -8680797543115379092 + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/__UI_NEW/级别图标/B.png b/Assets/__UI_NEW/级别图标/B.png new file mode 100644 index 00000000..53da65ec Binary files /dev/null and b/Assets/__UI_NEW/级别图标/B.png differ diff --git a/Assets/__UI_NEW/级别图标/B.png.meta b/Assets/__UI_NEW/级别图标/B.png.meta new file mode 100644 index 00000000..67c83a84 --- /dev/null +++ b/Assets/__UI_NEW/级别图标/B.png.meta @@ -0,0 +1,156 @@ +fileFormatVersion: 2 +guid: d5bc5b236b366074eb46ab5ecf8a10b7 +TextureImporter: + internalIDToNameTable: + - first: + 213: 7425438597007568885 + second: B_0 + 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: 1 + 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 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: B_0 + rect: + serializedVersion: 2 + x: 49 + y: 43 + width: 51 + height: 65 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 5ff6c14ff057c0760800000000000000 + internalID: 7425438597007568885 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: + B_0: 7425438597007568885 + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/__UI_NEW/级别图标/C.png b/Assets/__UI_NEW/级别图标/C.png new file mode 100644 index 00000000..5c1e7530 Binary files /dev/null and b/Assets/__UI_NEW/级别图标/C.png differ diff --git a/Assets/__UI_NEW/级别图标/C.png.meta b/Assets/__UI_NEW/级别图标/C.png.meta new file mode 100644 index 00000000..5ce63cf7 --- /dev/null +++ b/Assets/__UI_NEW/级别图标/C.png.meta @@ -0,0 +1,156 @@ +fileFormatVersion: 2 +guid: a29dbc6744aba1a4691000dc9ee4a75e +TextureImporter: + internalIDToNameTable: + - first: + 213: -606033477821260893 + second: C_0 + 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: 1 + 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 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: C_0 + rect: + serializedVersion: 2 + x: 46 + y: 41 + width: 57 + height: 68 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 3ab187843cfe697f0800000000000000 + internalID: -606033477821260893 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: + C_0: -606033477821260893 + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/__UI_NEW/级别图标/D.png b/Assets/__UI_NEW/级别图标/D.png new file mode 100644 index 00000000..e5f015b9 Binary files /dev/null and b/Assets/__UI_NEW/级别图标/D.png differ diff --git a/Assets/__UI_NEW/级别图标/D.png.meta b/Assets/__UI_NEW/级别图标/D.png.meta new file mode 100644 index 00000000..4b0cba61 --- /dev/null +++ b/Assets/__UI_NEW/级别图标/D.png.meta @@ -0,0 +1,156 @@ +fileFormatVersion: 2 +guid: 07580ee8dbd8ad141b946540ba2f16ca +TextureImporter: + internalIDToNameTable: + - first: + 213: -962488092458481032 + second: D_0 + 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: 1 + 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 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: D_0 + rect: + serializedVersion: 2 + x: 45 + y: 43 + width: 59 + height: 65 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 87a087ced2e84a2f0800000000000000 + internalID: -962488092458481032 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: + D_0: -962488092458481032 + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/__UI_NEW/级别图标/E.png b/Assets/__UI_NEW/级别图标/E.png new file mode 100644 index 00000000..dd824e25 Binary files /dev/null and b/Assets/__UI_NEW/级别图标/E.png differ diff --git a/Assets/__UI_NEW/级别图标/E.png.meta b/Assets/__UI_NEW/级别图标/E.png.meta new file mode 100644 index 00000000..3876e7a6 --- /dev/null +++ b/Assets/__UI_NEW/级别图标/E.png.meta @@ -0,0 +1,156 @@ +fileFormatVersion: 2 +guid: 4c0892e362fbff34ba1a8be7c68b8def +TextureImporter: + internalIDToNameTable: + - first: + 213: -2224474878120320963 + second: E_0 + 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: 1 + 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 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: E_0 + rect: + serializedVersion: 2 + x: 49 + y: 43 + width: 51 + height: 65 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: d30abd552e31121e0800000000000000 + internalID: -2224474878120320963 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: + E_0: -2224474878120320963 + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/__UI_NEW/级别图标/F.png b/Assets/__UI_NEW/级别图标/F.png new file mode 100644 index 00000000..ca475131 Binary files /dev/null and b/Assets/__UI_NEW/级别图标/F.png differ diff --git a/Assets/__UI_NEW/级别图标/F.png.meta b/Assets/__UI_NEW/级别图标/F.png.meta new file mode 100644 index 00000000..03c2dd98 --- /dev/null +++ b/Assets/__UI_NEW/级别图标/F.png.meta @@ -0,0 +1,156 @@ +fileFormatVersion: 2 +guid: 4b177bd9bd5e28c48ab23e54856554c3 +TextureImporter: + internalIDToNameTable: + - first: + 213: -3687348052613884379 + second: F_0 + 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: 1 + 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 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: F_0 + rect: + serializedVersion: 2 + x: 50 + y: 43 + width: 49 + height: 65 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 52698b88b78e3dcc0800000000000000 + internalID: -3687348052613884379 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: + F_0: -3687348052613884379 + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/__UI_NEW/级别图标/NO.png b/Assets/__UI_NEW/级别图标/NO.png new file mode 100644 index 00000000..f8d652ea Binary files /dev/null and b/Assets/__UI_NEW/级别图标/NO.png differ diff --git a/Assets/__UI_NEW/级别图标/NO.png.meta b/Assets/__UI_NEW/级别图标/NO.png.meta new file mode 100644 index 00000000..6d2887aa --- /dev/null +++ b/Assets/__UI_NEW/级别图标/NO.png.meta @@ -0,0 +1,156 @@ +fileFormatVersion: 2 +guid: 9908f3fd330a4cd42a2ec2c1e54b13a6 +TextureImporter: + internalIDToNameTable: + - first: + 213: 7960712277792059792 + second: NO_0 + 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: 1 + 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 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: NO_0 + rect: + serializedVersion: 2 + x: 31 + y: 48 + width: 88 + height: 54 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 091f2e493a12a7e60800000000000000 + internalID: 7960712277792059792 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: + NO_0: 7960712277792059792 + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/__UI_NEW/级别图标/S.png b/Assets/__UI_NEW/级别图标/S.png new file mode 100644 index 00000000..fe6fff52 Binary files /dev/null and b/Assets/__UI_NEW/级别图标/S.png differ diff --git a/Assets/__UI_NEW/级别图标/S.png.meta b/Assets/__UI_NEW/级别图标/S.png.meta new file mode 100644 index 00000000..e5f7c195 --- /dev/null +++ b/Assets/__UI_NEW/级别图标/S.png.meta @@ -0,0 +1,156 @@ +fileFormatVersion: 2 +guid: d3eff8af718d9794989039a224975a65 +TextureImporter: + internalIDToNameTable: + - first: + 213: -1182827721247122346 + second: S_0 + 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: 1 + 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 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: S_0 + rect: + serializedVersion: 2 + x: 48 + y: 41 + width: 54 + height: 68 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 65c94945470c59fe0800000000000000 + internalID: -1182827721247122346 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: + S_0: -1182827721247122346 + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/__UI_NEW/级别图标/UF.png b/Assets/__UI_NEW/级别图标/UF.png new file mode 100644 index 00000000..04c1a128 Binary files /dev/null and b/Assets/__UI_NEW/级别图标/UF.png differ diff --git a/Assets/__UI_NEW/级别图标/UF.png.meta b/Assets/__UI_NEW/级别图标/UF.png.meta new file mode 100644 index 00000000..a207322d --- /dev/null +++ b/Assets/__UI_NEW/级别图标/UF.png.meta @@ -0,0 +1,156 @@ +fileFormatVersion: 2 +guid: 45cd768cb9f36174b9674957bafeb729 +TextureImporter: + internalIDToNameTable: + - first: + 213: 8382850858162810998 + second: UF_0 + 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: 1 + 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 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: UF_0 + rect: + serializedVersion: 2 + x: 33 + y: 37 + width: 84 + height: 76 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 6707fd5f07ed55470800000000000000 + internalID: 8382850858162810998 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: + UF_0: 8382850858162810998 + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/__UI_NEW/级别图标/cp.png b/Assets/__UI_NEW/级别图标/cp.png new file mode 100644 index 00000000..9210ddb6 Binary files /dev/null and b/Assets/__UI_NEW/级别图标/cp.png differ diff --git a/Assets/__UI_NEW/级别图标/cp.png.meta b/Assets/__UI_NEW/级别图标/cp.png.meta new file mode 100644 index 00000000..16a01596 --- /dev/null +++ b/Assets/__UI_NEW/级别图标/cp.png.meta @@ -0,0 +1,156 @@ +fileFormatVersion: 2 +guid: f519918083e39704baca99fcb140d16d +TextureImporter: + internalIDToNameTable: + - first: + 213: 5280719606315561652 + second: cp_0 + 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: 1 + 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 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: cp_0 + rect: + serializedVersion: 2 + x: 39 + y: 32 + width: 72 + height: 86 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 4b231e4e082e84940800000000000000 + internalID: 5280719606315561652 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: + cp_0: 5280719606315561652 + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/__UI_NEW/级别图标/fc.png b/Assets/__UI_NEW/级别图标/fc.png new file mode 100644 index 00000000..4d24ab16 Binary files /dev/null and b/Assets/__UI_NEW/级别图标/fc.png differ diff --git a/Assets/__UI_NEW/级别图标/fc.png.meta b/Assets/__UI_NEW/级别图标/fc.png.meta new file mode 100644 index 00000000..074b797f --- /dev/null +++ b/Assets/__UI_NEW/级别图标/fc.png.meta @@ -0,0 +1,156 @@ +fileFormatVersion: 2 +guid: ef8ca7664be195d4ab743719ccc29d28 +TextureImporter: + internalIDToNameTable: + - first: + 213: 2676571860423960204 + second: fc_0 + 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: 1 + 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 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: fc_0 + rect: + serializedVersion: 2 + x: 33 + y: 39 + width: 84 + height: 72 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: c86606c0de7152520800000000000000 + internalID: 2676571860423960204 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: + fc_0: 2676571860423960204 + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/__UI_NEW/级别图标/ss.png b/Assets/__UI_NEW/级别图标/ss.png new file mode 100644 index 00000000..931435f2 Binary files /dev/null and b/Assets/__UI_NEW/级别图标/ss.png differ diff --git a/Assets/__UI_NEW/级别图标/ss.png.meta b/Assets/__UI_NEW/级别图标/ss.png.meta new file mode 100644 index 00000000..f58b3b87 --- /dev/null +++ b/Assets/__UI_NEW/级别图标/ss.png.meta @@ -0,0 +1,156 @@ +fileFormatVersion: 2 +guid: c224c338e44a5b348848fab860d9ee18 +TextureImporter: + internalIDToNameTable: + - first: + 213: 3431852193575524028 + second: ss_0 + 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: 1 + 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 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: ss_0 + rect: + serializedVersion: 2 + x: 20 + y: 40 + width: 109 + height: 70 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: cb6d6b7236360af20800000000000000 + internalID: 3431852193575524028 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: + ss_0: 3431852193575524028 + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/__UI_NEW/级别图标/sss.png b/Assets/__UI_NEW/级别图标/sss.png new file mode 100644 index 00000000..096be476 Binary files /dev/null and b/Assets/__UI_NEW/级别图标/sss.png differ diff --git a/Assets/__UI_NEW/级别图标/sss.png.meta b/Assets/__UI_NEW/级别图标/sss.png.meta new file mode 100644 index 00000000..1e9629cf --- /dev/null +++ b/Assets/__UI_NEW/级别图标/sss.png.meta @@ -0,0 +1,156 @@ +fileFormatVersion: 2 +guid: f7451267a2064f840bd766b47a2fd160 +TextureImporter: + internalIDToNameTable: + - first: + 213: -6115231132429295599 + second: sss_0 + 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: 1 + 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 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: sss_0 + rect: + serializedVersion: 2 + x: 6 + y: 42 + width: 138 + height: 67 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 11064285fa5522ba0800000000000000 + internalID: -6115231132429295599 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: + sss_0: -6115231132429295599 + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/__so/levelConfig/RankConfig.asset b/Assets/__so/levelConfig/RankConfig.asset index c251b73a..a6e18b94 100644 --- a/Assets/__so/levelConfig/RankConfig.asset +++ b/Assets/__so/levelConfig/RankConfig.asset @@ -13,41 +13,41 @@ MonoBehaviour: m_Name: RankConfig m_EditorClassIdentifier: baseScore: 1350000 - defaultSprite: {fileID: 21300000, guid: 3677b51fb2d220745ae6584eafbeeb55, type: 3} + defaultSprite: {fileID: 21300000, guid: 9908f3fd330a4cd42a2ec2c1e54b13a6, type: 3} thresholds: - rankName: Mastery thresholdPercent: 1 - rankSprite: {fileID: 21300000, guid: 8c3097617fb4f324fb0e875f5409614e, type: 3} + rankSprite: {fileID: 21300000, guid: f519918083e39704baca99fcb140d16d, type: 3} - rankName: Completed thresholdPercent: 0.97 - rankSprite: {fileID: 21300000, guid: c7dae49e5552f77469db51d5bc7ebf58, type: 3} + rankSprite: {fileID: 21300000, guid: f7451267a2064f840bd766b47a2fd160, type: 3} - rankName: SS+ thresholdPercent: 0.94 - rankSprite: {fileID: 21300000, guid: 30faa7080ac84a34da3f164587c650f1, type: 3} + rankSprite: {fileID: 21300000, guid: c224c338e44a5b348848fab860d9ee18, type: 3} - rankName: SS thresholdPercent: 0.92 rankSprite: {fileID: 21300000, guid: 2eeace5e3ccb1de428206ae6d631fd2b, type: 3} - rankName: S thresholdPercent: 0.9 - rankSprite: {fileID: 21300000, guid: 60e640b1a571e1a43929d1a1225d06cb, type: 3} + rankSprite: {fileID: 21300000, guid: d3eff8af718d9794989039a224975a65, type: 3} - rankName: A thresholdPercent: 0.8 - rankSprite: {fileID: 21300000, guid: bb9014339ac7d074d81746f2a7e70005, type: 3} + rankSprite: {fileID: 21300000, guid: 4f7ba39699e39c644b9bfd158796462b, type: 3} - rankName: B thresholdPercent: 0.7 - rankSprite: {fileID: 21300000, guid: 5e915c1fa1dea8d4cb042ce3c5980dda, type: 3} + rankSprite: {fileID: 21300000, guid: d5bc5b236b366074eb46ab5ecf8a10b7, type: 3} - rankName: C thresholdPercent: 0.6 - rankSprite: {fileID: 21300000, guid: e058f5a9efdcb154eb6c989c0b3c97b4, type: 3} + rankSprite: {fileID: 21300000, guid: a29dbc6744aba1a4691000dc9ee4a75e, type: 3} - rankName: D thresholdPercent: 0.5 - rankSprite: {fileID: 21300000, guid: 1b7dbad2fea3eaf458c8a7d22eea7eb7, type: 3} + rankSprite: {fileID: 21300000, guid: 07580ee8dbd8ad141b946540ba2f16ca, type: 3} - rankName: E thresholdPercent: 0.4 - rankSprite: {fileID: 21300000, guid: 940a5e2347285cc429ce08bd04bba751, type: 3} + rankSprite: {fileID: 21300000, guid: 4c0892e362fbff34ba1a8be7c68b8def, type: 3} - rankName: F thresholdPercent: 0.3 - rankSprite: {fileID: 21300000, guid: 70edc06462d15fc4e914a8f9dbb5125c, type: 3} + rankSprite: {fileID: 21300000, guid: 4b177bd9bd5e28c48ab23e54856554c3, type: 3} - rankName: UF thresholdPercent: 0 - rankSprite: {fileID: 21300000, guid: b5c6222eb7f626a4e81e0a8306eed51e, type: 3} + rankSprite: {fileID: 21300000, guid: 45cd768cb9f36174b9674957bafeb729, type: 3} diff --git a/Assets/_eqpmtSys/equipSystems/eSmelt/equipSmelt.cs b/Assets/_eqpmtSys/equipSystems/eSmelt/equipSmelt.cs index 4718a9d6..6a5bc7d2 100644 --- a/Assets/_eqpmtSys/equipSystems/eSmelt/equipSmelt.cs +++ b/Assets/_eqpmtSys/equipSystems/eSmelt/equipSmelt.cs @@ -197,6 +197,11 @@ public class equipSmelt : MonoBehaviour public void RefreshPlayerSkillAdjustedUi() { + if (!IsRuntimeSceneInstance()) + { + return; + } + RefreshAllUi(); } @@ -1027,10 +1032,16 @@ public class equipSmelt : MonoBehaviour private void ClearSmeltPoolItems() { - for (int i = smeltPoolContent != null ? smeltPoolContent.childCount - 1 : -1; i >= 0; i--) + if (!IsRuntimeSceneInstance()) { - Transform child = smeltPoolContent.GetChild(i); - if (child == null) + spawnedPoolItems.Clear(); + return; + } + + for (int i = spawnedPoolItems.Count - 1; i >= 0; i--) + { + GameObject item = spawnedPoolItems[i]; + if (item == null) { continue; } @@ -1038,18 +1049,28 @@ public class equipSmelt : MonoBehaviour #if UNITY_EDITOR if (!Application.isPlaying) { - DestroyImmediate(child.gameObject); + DestroyImmediate(item); } else #endif { - Destroy(child.gameObject); + Destroy(item); } } spawnedPoolItems.Clear(); } + private bool IsRuntimeSceneInstance() + { + if (this == null || gameObject == null) + { + return false; + } + + return gameObject.scene.IsValid(); + } + private void RegisterInstance() { if (!Instances.Contains(this)) diff --git a/Assets/_galgame_inGame/inGal.prefab b/Assets/_galgame_inGame/inGal.prefab index 90435f44..710db43c 100644 --- a/Assets/_galgame_inGame/inGal.prefab +++ b/Assets/_galgame_inGame/inGal.prefab @@ -1291,7 +1291,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 diff --git a/Assets/_globalNotices/BansonicItemGet.cs b/Assets/_globalNotices/BansonicItemGet.cs index c02f9033..e81cd5f9 100644 --- a/Assets/_globalNotices/BansonicItemGet.cs +++ b/Assets/_globalNotices/BansonicItemGet.cs @@ -148,6 +148,7 @@ namespace Bansonic if (currentInstance != null && currentController != null) { ReparentIfNeeded(); + EnsureTopMostSorting(); if (!currentInstance.activeInHierarchy) { currentInstance.SetActive(true); @@ -171,6 +172,26 @@ namespace Bansonic currentInstance.name = prefab.name; currentController = currentInstance.GetComponent(); ReparentIfNeeded(); + EnsureTopMostSorting(); + } + + // 确保 itemGet 弹窗永远显示在所有 UI 之上(包括名为 "top" 的高层覆盖界面)。 + // itemGet.prefab 本身无 Canvas,靠父 Canvas 渲染,故会被 sortingOrder 更高的 Canvas 遮挡。 + // 方案:在实例根挂一个 override sorting 的 Canvas,设定极高 sortingOrder。 + // 仅表现层:不改 itemGet 内部结构/引用/逻辑,只保证其可见性置顶。 + private const int ItemGetSortingOrder = 32760; // 接近 short.MaxValue,高于常规 UI/top + private static void EnsureTopMostSorting() + { + if (currentInstance == null) return; + + Canvas canvas = currentInstance.GetComponent(); + if (canvas == null) canvas = currentInstance.AddComponent(); + canvas.overrideSorting = true; + canvas.sortingOrder = ItemGetSortingOrder; + + // override Canvas 需配 GraphicRaycaster 才能接收点击(关闭按钮等)。 + if (currentInstance.GetComponent() == null) + currentInstance.AddComponent(); } private static Transform ResolveParent() diff --git a/Assets/_globalNotices/BansonicSceneTransition.cs b/Assets/_globalNotices/BansonicSceneTransition.cs index 8c531fa0..f225c3d4 100644 --- a/Assets/_globalNotices/BansonicSceneTransition.cs +++ b/Assets/_globalNotices/BansonicSceneTransition.cs @@ -226,7 +226,9 @@ namespace Bansonic CanvasScaler scaler = root.GetComponent(); scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize; scaler.referenceResolution = new Vector2(1920f, 1080f); - scaler.matchWidthOrHeight = 0.5f; + // 锁高度缩放:分辨率跟随屏幕后,非 16:9 屏也能保证各 UI 层一致缩放、不错位。 + scaler.screenMatchMode = CanvasScaler.ScreenMatchMode.MatchWidthOrHeight; + scaler.matchWidthOrHeight = 1f; Image image = root.GetComponent(); image.color = Color.black; diff --git a/Assets/artworks/Songs_Select/BACK.prefab b/Assets/artworks/Songs_Select/BACK.prefab index f118c657..5d6153cd 100644 --- a/Assets/artworks/Songs_Select/BACK.prefab +++ b/Assets/artworks/Songs_Select/BACK.prefab @@ -214,7 +214,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 diff --git a/Assets/artworks/UI_UI/UI_Panel_Storywrite.prefab b/Assets/artworks/UI_UI/UI_Panel_Storywrite.prefab index 55867935..5a9bbb9a 100644 --- a/Assets/artworks/UI_UI/UI_Panel_Storywrite.prefab +++ b/Assets/artworks/UI_UI/UI_Panel_Storywrite.prefab @@ -660,7 +660,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 800, y: 600} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 diff --git a/Assets/artworks/UI_UI/writestory_UI.prefab b/Assets/artworks/UI_UI/writestory_UI.prefab index aec4a2b8..47e6a431 100644 --- a/Assets/artworks/UI_UI/writestory_UI.prefab +++ b/Assets/artworks/UI_UI/writestory_UI.prefab @@ -558,14 +558,14 @@ MonoBehaviour: m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UiScaleMode: 0 + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 1 m_ReferencePixelsPerUnit: 100 m_ScaleFactor: 1 - m_ReferenceResolution: {x: 800, y: 600} + m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 diff --git a/Assets/artworks/gamePlay_gamePlay/note_Notes/prefab/note_blue.prefab b/Assets/artworks/gamePlay_gamePlay/note_Notes/prefab/note_blue.prefab index f5a73a98..64f1815a 100644 --- a/Assets/artworks/gamePlay_gamePlay/note_Notes/prefab/note_blue.prefab +++ b/Assets/artworks/gamePlay_gamePlay/note_Notes/prefab/note_blue.prefab @@ -79,7 +79,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 diff --git a/Assets/artworks/notebook/notebook.prefab b/Assets/artworks/notebook/notebook.prefab index 3cc9fc1f..f37b0865 100644 --- a/Assets/artworks/notebook/notebook.prefab +++ b/Assets/artworks/notebook/notebook.prefab @@ -639,7 +639,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 diff --git a/Assets/artworks/notebook/writingStories.prefab b/Assets/artworks/notebook/writingStories.prefab index da28b70a..ab00a467 100644 --- a/Assets/artworks/notebook/writingStories.prefab +++ b/Assets/artworks/notebook/writingStories.prefab @@ -507,7 +507,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 diff --git a/Assets/artworks/selectYourSongFirst/heroes_level_image/loadDetailsPrefab.cs b/Assets/artworks/selectYourSongFirst/heroes_level_image/loadDetailsPrefab.cs index e4172e93..61b3f3c8 100644 --- a/Assets/artworks/selectYourSongFirst/heroes_level_image/loadDetailsPrefab.cs +++ b/Assets/artworks/selectYourSongFirst/heroes_level_image/loadDetailsPrefab.cs @@ -59,6 +59,12 @@ public class loadDetailsPrefab : MonoBehaviour } preferLeftOfCursor = ShouldDisplayOnLeft(type, heroLevel); + // 宿主 GameObject 处于非激活状态时无法启动协程(会抛异常)。此时直接跳过—— + // 悬浮详情本就依附于激活的界面,宿主未激活时不显示详情是合理且无副作用的。 + if (!isActiveAndEnabled) + { + return; + } showCoroutine = StartCoroutine(ShowDetailsDelayed(type, name, status, description, position, heroLevel)); } diff --git a/Assets/idolsDisplay/UI_Idols.cs b/Assets/idolsDisplay/UI_Idols.cs index 5fc8fd63..f769fb27 100644 --- a/Assets/idolsDisplay/UI_Idols.cs +++ b/Assets/idolsDisplay/UI_Idols.cs @@ -326,6 +326,10 @@ public class UI_Idols : MonoBehaviour SetObjectState(skillsObj, idolSkillsToggle != null && idolSkillsToggle.isOn); SetObjectState(skinsObj, idolSkinsToggle != null && idolSkinsToggle.isOn); SetObjectState(weaponObj, idolWeaponToggle != null && idolWeaponToggle.isOn); + if (detailPassageObj != null && detailPassageObj.activeSelf) + { + SyncCurrentHeroDocument(); + } PlayActiveSectionRefresh(); } @@ -580,12 +584,27 @@ public class UI_Idols : MonoBehaviour private void SetIdolDocumentText(string value) { + EnsureIdolDocumentBinding(); if (ido != null && ido.idol_documentText != null) { ido.idol_documentText.text = value ?? string.Empty; } } + private void SyncCurrentHeroDocument() + { + SetIdolDocumentText(currentSelectedHero != null ? currentSelectedHero.ally_heroDescription : string.Empty); + ApplyBehaviourRadar(currentSelectedHero); + } + + private void EnsureIdolDocumentBinding() + { + if (ido == null && detailPassageObj != null) + { + ido = detailPassageObj.GetComponentInChildren(true); + } + } + private void ApplyHeroImage(Sprite sprite) { ApplyHeroImage(sprite, true); diff --git a/Assets/pause.prefab b/Assets/pause.prefab index 8835e43e..563a8713 100644 --- a/Assets/pause.prefab +++ b/Assets/pause.prefab @@ -533,7 +533,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 diff --git a/Assets/scripts/Audio/BgmUiBinder.cs b/Assets/scripts/Audio/BgmUiBinder.cs index 0badd652..0b210c4d 100644 --- a/Assets/scripts/Audio/BgmUiBinder.cs +++ b/Assets/scripts/Audio/BgmUiBinder.cs @@ -713,7 +713,9 @@ public class BgmUiBinder : MonoBehaviour var scaler = go.GetComponent(); scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize; scaler.referenceResolution = new Vector2(1920f, 1080f); - scaler.matchWidthOrHeight = 0.5f; + // 锁高度缩放:分辨率跟随屏幕后,非 16:9 屏也能保证各 UI 层一致缩放、不错位。 + scaler.screenMatchMode = CanvasScaler.ScreenMatchMode.MatchWidthOrHeight; + scaler.matchWidthOrHeight = 1f; DontDestroyOnLoad(go); persistent = go; } diff --git a/Assets/scripts/UI/Panel/dontdestroyonload/btm and top.prefab b/Assets/scripts/UI/Panel/dontdestroyonload/btm and top.prefab index 676da0f5..a34cbf32 100644 --- a/Assets/scripts/UI/Panel/dontdestroyonload/btm and top.prefab +++ b/Assets/scripts/UI/Panel/dontdestroyonload/btm and top.prefab @@ -1758,9 +1758,9 @@ RectTransform: - {fileID: 1447481020518725738} m_Father: {fileID: 4008714089197239054} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0.5, y: 0.5} - m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: -628.13, y: -267.01} + m_AnchorMin: {x: 0, y: 0.5} + m_AnchorMax: {x: 0, y: 0.5} + m_AnchoredPosition: {x: 331.87, y: -267.01} m_SizeDelta: {x: 100, y: 100} m_Pivot: {x: 0.5, y: 0.5} --- !u!114 &8373938424588989755 @@ -2124,9 +2124,9 @@ RectTransform: - {fileID: 1318901128213550095} m_Father: {fileID: 5634981615641515618} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0.5, y: 0.5} - m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: 323.3, y: 5} + m_AnchorMin: {x: 1, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: -636.7, y: 5} m_SizeDelta: {x: 100, y: 100} m_Pivot: {x: 0.5, y: 0.5} --- !u!1 &1512308382957859215 @@ -2161,9 +2161,9 @@ RectTransform: m_Children: [] m_Father: {fileID: 6434860682258445909} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0.5, y: 0.5} - m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: -886.6095, y: -440.45862} + m_AnchorMin: {x: 0, y: 0.5} + m_AnchorMax: {x: 0, y: 0.5} + m_AnchoredPosition: {x: 73.3905, y: -440.45862} m_SizeDelta: {x: 146.7813, y: 61.0829} m_Pivot: {x: 0.5, y: 0.5} --- !u!222 &7958189264278634160 @@ -3023,9 +3023,9 @@ RectTransform: - {fileID: 5977557715898357349} m_Father: {fileID: 5634981615641515618} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0.5, y: 0.5} - m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: -280.4, y: 5.78} + m_AnchorMin: {x: 0, y: 0.5} + m_AnchorMax: {x: 0, y: 0.5} + m_AnchoredPosition: {x: 679.6, y: 5.78} m_SizeDelta: {x: 2410.4807, y: 100} m_Pivot: {x: 0.5, y: 0.5} --- !u!114 &4595481187193100221 @@ -3592,9 +3592,9 @@ RectTransform: - {fileID: 7954660427444040773} m_Father: {fileID: 5634981615641515618} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0.5, y: 0.5} - m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: -520.8, y: -0.00005340576} + m_AnchorMin: {x: 0, y: 0.5} + m_AnchorMax: {x: 0, y: 0.5} + m_AnchoredPosition: {x: 439.2, y: -0.00005340576} m_SizeDelta: {x: 128, y: 30} m_Pivot: {x: 0.5, y: 0.5} --- !u!1 &2463687307556080059 @@ -6388,9 +6388,9 @@ RectTransform: - {fileID: 6358183742841940414} m_Father: {fileID: 5634981615641515618} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0.5, y: 0.5} - m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: 518.05, y: 5} + m_AnchorMin: {x: 1, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: -441.95, y: 5} m_SizeDelta: {x: 100, y: 100} m_Pivot: {x: 0.5, y: 0.5} --- !u!1 &5054239668136224504 @@ -6478,7 +6478,7 @@ MonoBehaviour: m_ScaleFactor: 1 m_ReferenceResolution: {x: 1920, y: 1080} m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 + m_MatchWidthOrHeight: 1 m_PhysicalUnit: 3 m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 @@ -10513,9 +10513,9 @@ RectTransform: m_Children: [] m_Father: {fileID: 5634981615641515618} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0.5, y: 0.5} - m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: -825.01624, y: 0} + m_AnchorMin: {x: 0, y: 0.5} + m_AnchorMax: {x: 0, y: 0.5} + m_AnchoredPosition: {x: 134.984, y: 0} m_SizeDelta: {x: 307.5676, y: 50} m_Pivot: {x: 0.5, y: 0.5} --- !u!222 &8992617676759434598 diff --git a/Assets/scripts/UI/UIBackgroundCover.cs b/Assets/scripts/UI/UIBackgroundCover.cs new file mode 100644 index 00000000..b88a1e5b --- /dev/null +++ b/Assets/scripts/UI/UIBackgroundCover.cs @@ -0,0 +1,100 @@ +using UnityEngine; + +/// +/// 全屏背景/遮罩自适应(Cover):保持原始宽高比,等比放大到覆盖整个根 Canvas,超出部分裁切。 +/// 过覆盖 => 任意宽高比都无缝铺满、且 sizeDelta 永不为 0;对纯色遮罩与艺术背景都正确、不失真。 +/// 仅调整 sizeDelta(表现层),不改锚点/位置/pivot,不影响居中布局与位移动画。 +/// 16:9 屏下结果等于设计尺寸,与原始逐像素一致。由 UIResolutionAutoFitter 自动附加。 +/// +[RequireComponent(typeof(RectTransform))] +[DisallowMultipleComponent] +public class UIBackgroundCover : MonoBehaviour +{ + public float sourceAspect = 16f / 9f; + + private RectTransform rt; + private RectTransform coverTarget; + private float lastW = -1f, lastH = -1f; + private bool aspectResolved; + // 重入锁:设置 sizeDelta 会同步触发 OnRectTransformDimensionsChange, + // 若不拦截会无限递归导致 StackOverflow 崩溃。 + private bool _isFitting; + + private void OnEnable() + { + rt = GetComponent(); + ResolveAspectFromInitialSize(); + ResolveTarget(); + Fit(true); + } + + private void LateUpdate() + { + // 每帧检测 coverTarget 实际尺寸变化(而非只看 Screen):Unity 布局延迟更新, + // Screen 变化后 CanvasScaler 可能过几帧才把新尺寸写入 rootCanvas.rect。 + // Fit(false) 内部按 lastW/lastH 判重,尺寸未变时零开销,无需额外节流。 + if (coverTarget == null) ResolveTarget(); + if (coverTarget != null) + { + float pw = coverTarget.rect.width; + float ph = coverTarget.rect.height; + if (!Mathf.Approximately(pw, lastW) || !Mathf.Approximately(ph, lastH)) + { + Fit(false); + } + } + } + + /// 用元素初始 sizeDelta 推断原始宽高比,避免写死。 + private void ResolveAspectFromInitialSize() + { + if (aspectResolved) return; + if (rt == null) rt = GetComponent(); + Vector2 s = rt.sizeDelta; + if (s.x > 1f && s.y > 1f) sourceAspect = s.x / s.y; + aspectResolved = true; + } + + private void OnRectTransformDimensionsChange() + { + if (_isFitting) return; // 拦截自身写入触发的递归回调 + Fit(false); + } + + private void ResolveTarget() + { + Canvas canvas = GetComponentInParent(); + if (canvas != null) + { + Canvas root = canvas.rootCanvas != null ? canvas.rootCanvas : canvas; + coverTarget = root.GetComponent(); + } + } + + private void Fit(bool force) + { + if (_isFitting) return; + if (rt == null) rt = GetComponent(); + if (coverTarget == null) ResolveTarget(); + if (coverTarget == null || sourceAspect <= 0f) return; + + float pw = coverTarget.rect.width; + float ph = coverTarget.rect.height; + if (pw <= 0f || ph <= 0f) return; + if (!force && Mathf.Approximately(pw, lastW) && Mathf.Approximately(ph, lastH)) return; + lastW = pw; lastH = ph; + + float targetAspect = pw / ph; + float w, h; + if (targetAspect > sourceAspect) { w = pw; h = pw / sourceAspect; } + else { h = ph; w = ph * sourceAspect; } + + Vector2 newSize = new Vector2(w, h); + if (rt.sizeDelta != newSize) + { + _isFitting = true; + rt.sizeDelta = newSize; + _isFitting = false; + } + } +} diff --git a/Assets/scripts/UI/UIBackgroundCover.cs.meta b/Assets/scripts/UI/UIBackgroundCover.cs.meta new file mode 100644 index 00000000..f757c00c --- /dev/null +++ b/Assets/scripts/UI/UIBackgroundCover.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 2f19fe0a8ae05114bba0f36c5945c104 \ No newline at end of file diff --git a/Assets/scripts/UI/UICanvasMatchFitter.cs b/Assets/scripts/UI/UICanvasMatchFitter.cs new file mode 100644 index 00000000..3760e495 --- /dev/null +++ b/Assets/scripts/UI/UICanvasMatchFitter.cs @@ -0,0 +1,50 @@ +using UnityEngine; +using UnityEngine.UI; + +/// +/// 让 CanvasScaler 的 matchWidthOrHeight 随屏幕宽高比动态切换,实现“设计区域永不裁切”(contain): +/// - 屏幕比设计更宽(>16:9):锁高度(match=1),左右由背景 cover 填满,UI 不被竖向裁。 +/// - 屏幕比设计更窄(<16:9,如 16:10 / 4:3):锁宽度(match=0),上下由背景 cover 填满,UI 不被横向裁。 +/// 这样 1920x1080 设计范围内的所有 UI 在任意宽高比下都完整可见,仅“更宽松”的一侧留出由背景填充的余量。 +/// +/// 满足三要求: +/// 1) 不改业务逻辑、不改对象引用;只调 CanvasScaler 的一个表现参数。 +/// 2) 16:9 屏下 match=1 与原状态一致,逐像素不变;只改缩放基准,不动任何锚点/位置/动画。 +/// 3) 窄屏不再裁切、宽屏铺满,配合背景 cover 始终填满屏幕。 +/// +[RequireComponent(typeof(CanvasScaler))] +[DisallowMultipleComponent] +public sealed class UICanvasMatchFitter : MonoBehaviour +{ + private const float DesignAspect = 1920f / 1080f; + + private CanvasScaler scaler; + private float lastAspect = -1f; + + private void OnEnable() + { + scaler = GetComponent(); + Apply(); + } + + private void Update() + { + // 分辨率/窗口变化时才重算。 + float aspect = (float)Screen.width / Mathf.Max(1, Screen.height); + if (Mathf.Abs(aspect - lastAspect) > 0.0001f) Apply(); + } + + private void Apply() + { + if (scaler == null) scaler = GetComponent(); + if (scaler == null) return; + if (scaler.uiScaleMode != CanvasScaler.ScaleMode.ScaleWithScreenSize) return; + + float aspect = (float)Screen.width / Mathf.Max(1, Screen.height); + lastAspect = aspect; + + scaler.screenMatchMode = CanvasScaler.ScreenMatchMode.MatchWidthOrHeight; + // 更宽→锁高度(1);更窄→锁宽度(0)。等于始终匹配“更受限的一侧”,设计区域完整可见。 + scaler.matchWidthOrHeight = aspect >= DesignAspect ? 1f : 0f; + } +} diff --git a/Assets/scripts/UI/UICanvasMatchFitter.cs.meta b/Assets/scripts/UI/UICanvasMatchFitter.cs.meta new file mode 100644 index 00000000..95f8c9b5 --- /dev/null +++ b/Assets/scripts/UI/UICanvasMatchFitter.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 1a18755a72ae63a43b21a20c8f4489ca \ No newline at end of file diff --git a/Assets/scripts/UI/UIEdgeFollow.cs b/Assets/scripts/UI/UIEdgeFollow.cs new file mode 100644 index 00000000..cd40c11e --- /dev/null +++ b/Assets/scripts/UI/UIEdgeFollow.cs @@ -0,0 +1,114 @@ +using UnityEngine; + +/// +/// 让一个“中心锚定 + 固定横向偏移”的顶层 HUD 容器,在任意宽高比下横向跟随其设计所属的屏幕边缘。 +/// 只处理横向(X),纵向(Y)完全不动;保持 1920 设计宽度下的视觉位置逐像素不变。 +/// +/// 为什么用组件而非直接改业务脚本坐标:许多 HUD 的位置由业务脚本在运行时写死设置 +/// (relative 到这些容器)。本组件只移动“容器”本身到边缘相对位置,容器内部由脚本布置的 +/// 子元素保持相对关系不变——既实现了“跟随边缘”,又不触碰任何业务坐标逻辑。 +/// +/// 满足三要求:1) 不改业务逻辑/引用;2) 仅横向、16:9 逐像素一致、不动 Y 与动画;3) 跟随边缘。 +/// +[RequireComponent(typeof(RectTransform))] +[DisallowMultipleComponent] +public sealed class UIEdgeFollow : MonoBehaviour +{ + public enum Edge { Left, Right, Auto } + + public Edge edge = Edge.Auto; + + // 设计基准宽度:所有 gap 以此为参考,保证与首次附加时的分辨率无关。 + private const float DesignWidth = 1920f; + + private RectTransform rt; + private RectTransform rootRt; + private float gapX; // 元素中心距目标边缘的间距(设计参考像素,恒定) + private Edge resolved; + private bool measured; + private float lastRootW = -1f; + + private void OnEnable() + { + rt = GetComponent(); + ResolveRoot(); + Measure(); + ApplyIfNeeded(true); + } + + private void ResolveRoot() + { + Canvas c = GetComponentInParent(); + if (c != null) + { + Canvas root = c.rootCanvas != null ? c.rootCanvas : c; + rootRt = root.GetComponent(); + } + } + + // 元素在画布局部空间的设计 X(以画布中心为原点)。用世界坐标换算,正确处理嵌套父级 + // (如 bbt 挂在 logo 下,anchoredPosition 相对 logo 而非画布)。 + private float designCanvasX; + + private void Measure() + { + if (measured || rt == null || rootRt == null) return; + // 仅处理横向未拉伸 + 中心锚定的元素。 + if (Mathf.Abs(rt.anchorMax.x - rt.anchorMin.x) > 0.01f) return; + if (Mathf.Abs(rt.anchorMin.x - 0.5f) > 0.01f) return; + + // 用元素世界位置换算到"画布局部空间"的 X(画布中心为原点)。 + // 关键:InverseTransformPoint 已返回画布参考单位(reference pixels),且与分辨率无关 + //(anchoredPosition 固定在参考单位、画布缩放被 Inverse 抵消),直接用即可。 + // 绝不能再除以 rootW 归一——那会在非 16:9(rootW≠1920)时把坐标算错,元素停在中间。 + // 这对直接子级(uid/score)和嵌套子级(bbt 挂在 logo 下)都正确。 + float rootW = rootRt.rect.width; + if (rootW <= 0f) return; + designCanvasX = rootRt.InverseTransformPoint(rt.position).x; // 画布中心为原点,参考单位 + + // gap = 元素中心到"设计左/右缘"的距离(参考单位,恒定)。设计画布宽=DesignWidth。 + float distFromDesignLeft = DesignWidth * 0.5f + designCanvasX; // 到左缘距离 + resolved = edge; + if (resolved == Edge.Auto) + resolved = designCanvasX < 0f ? Edge.Left : Edge.Right; + + gapX = resolved == Edge.Left ? distFromDesignLeft : (DesignWidth - distFromDesignLeft); + measured = true; + } + + private void LateUpdate() + { + if (rootRt == null) { ResolveRoot(); return; } + if (!measured) { Measure(); if (!measured) return; } + float rootW = rootRt.rect.width; + if (Mathf.Abs(rootW - lastRootW) > 0.5f) ApplyIfNeeded(false); + } + + private void ApplyIfNeeded(bool force) + { + if (rt == null || rootRt == null) return; + if (!measured) { Measure(); if (!measured) return; } + + float rootW = rootRt.rect.width; + if (rootW <= 0f) return; + lastRootW = rootW; + + // 目标画布局部 X(画布中心为原点,参考单位):当前画布半宽=rootW/2。 + // 左贴边:目标 = -rootW/2 + gapX;右贴边:目标 = rootW/2 - gapX。 + float halfW = rootW * 0.5f; + float targetCanvasLocalX = resolved == Edge.Left ? (-halfW + gapX) : (halfW - gapX); + + // 当前画布局部 X;若已到位则跳过。 + Vector3 worldCur = rt.position; + Vector3 canvasCur = rootRt.InverseTransformPoint(worldCur); + if (Mathf.Abs(targetCanvasLocalX - canvasCur.x) <= 0.01f) return; + + // 画布局部目标 → 世界目标点 → 自身父空间 anchoredPosition.x(仅横向)。 + Vector3 worldTarget = rootRt.TransformPoint(new Vector3(targetCanvasLocalX, canvasCur.y, canvasCur.z)); + float worldDeltaX = worldTarget.x - worldCur.x; + Vector3 parentScale = rt.parent != null ? rt.parent.lossyScale : Vector3.one; + float parentScaleX = Mathf.Abs(parentScale.x) < 1e-6f ? 1f : parentScale.x; + Vector2 anchoredNow = rt.anchoredPosition; + rt.anchoredPosition = new Vector2(anchoredNow.x + worldDeltaX / parentScaleX, anchoredNow.y); + } +} diff --git a/Assets/scripts/UI/UIEdgeFollow.cs.meta b/Assets/scripts/UI/UIEdgeFollow.cs.meta new file mode 100644 index 00000000..bf177d25 --- /dev/null +++ b/Assets/scripts/UI/UIEdgeFollow.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 8745b948635db4f4187b2001878439b2 \ No newline at end of file diff --git a/Assets/scripts/UI/UIResolutionAutoFitter.cs b/Assets/scripts/UI/UIResolutionAutoFitter.cs new file mode 100644 index 00000000..42091ff1 --- /dev/null +++ b/Assets/scripts/UI/UIResolutionAutoFitter.cs @@ -0,0 +1,419 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.SceneManagement; +using UnityEngine.UI; + +/// +/// 全局分辨率自适应器:场景加载时自动扫描全屏背景类 Image(居中锚定 + 尺寸接近设计分辨率), +/// 为其附加 UIBackgroundCover,使背景在任意宽高比(含超宽 32:9)下等比放大铺满、不留黑边、不失真。 +/// +/// 设计原则(对应三要求): +/// 1) 零业务逻辑改动:不改脚本行为、不改对象引用,只在表现层调整背景 sizeDelta。 +/// 2) 不改锚点/pivot/位置:位移动画与居中布局完全不受影响;16:9 屏计算结果等于原设计尺寸。 +/// 3) 背景总是铺满屏幕。 +/// +/// 仅针对“全屏背景/遮罩”生效,普通按钮/面板/菜单等居中 UI 保持原样(它们本就该居中,不该拉伸)。 +/// +public sealed class UIResolutionAutoFitter : MonoBehaviour +{ + private const string BootstrapObjectName = "[UIResolutionAutoFitter]"; + private static UIResolutionAutoFitter _instance; + + // 设计基准分辨率(与全工程 CanvasScaler referenceResolution 一致)。 + private const float DesignWidth = 1920f; + private const float DesignHeight = 1080f; + + // 判定为“全屏背景”的尺寸容差:宽高需分别接近设计分辨率或其 2 倍(部分背景做了 3840x2160)。 + private const float SizeTolerance = 96f; + + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] + private static void Bootstrap() + { + if (_instance != null) return; + GameObject go = new GameObject(BootstrapObjectName); + _instance = go.AddComponent(); + DontDestroyOnLoad(go); + } + + private void OnEnable() + { + SceneManager.sceneLoaded += OnSceneLoaded; + } + + private void OnDisable() + { + SceneManager.sceneLoaded -= OnSceneLoaded; + } + + private void Start() + { + // 处理启动时已经加载好的首个场景。 + StartCoroutine(FitAfterFrame()); + // 低频常驻补扫:覆盖“任意时刻才实例化/打开”的 prefab 全屏底图 + //(结算、歌曲详情、角色/设置面板等可能在会话中随时弹出)。 + // 每次只给尚未挂 UIBackgroundCover 的背景加组件,已处理的直接跳过,单次开销很低。 + StartCoroutine(PeriodicRescan()); + } + + private void OnSceneLoaded(Scene scene, LoadSceneMode mode) + { + // 新场景的 Canvas 是新实例,旧记录已失效,清空以便重新 setup。 + _setupDoneCanvases.Clear(); + _enemyFollowAttached = false; + _trackStabilizerAttached = false; + _cameraTunerAttached = false; + StartCoroutine(FitAfterFrame()); + } + + private IEnumerator FitAfterFrame() + { + // 等一帧让 Canvas/布局初始化完成,再扫描(避免 sizeDelta 尚未就绪)。 + yield return null; + ScanAndFit(); + } + + // 当前是否为 gameplay 场景(名字含 gameplay/gamePlay)。仅该场景启用 HUD 自动贴边。 + private bool _gameplayActive; + + // 已完成一次性 setup(match 适配 + 边缘跟随)的 Canvas 集合,避免每次扫描重复全树遍历。 + // 切场景时清空(Canvas 会重建为新实例)。背景 cover 扫描不受此影响,仍每次执行。 + private readonly HashSet _setupDoneCanvases = new HashSet(); + + // 靠边判定阈值:元素中心距设计画布中心超过该值(参考像素)才自动贴边。 + private const float EdgeOffsetThreshold = 300f; + + // 自动贴边时跳过的名字关键字:全屏背景/遮罩(由 cover 负责)与天然应居中的元素。 + private static readonly string[] AutoEdgeSkip = + { + "bg", "background", "mask", "black", "white", "遮罩", "背景", + "pause", "已暂停", "start", "count", "321", "go" + }; + + private void UpdateGameplayFlag() + { + string sn = SceneManager.GetActiveScene().name; + _gameplayActive = !string.IsNullOrEmpty(sn) + && sn.ToLowerInvariant().Contains("gameplay"); + } + + // 按横向偏移自动贴边(仅 gameplay HUD 顶层容器用)。 + private static void TryAutoEdgeFollowByOffset(RectTransform rt, float canvasWidth) + { + if (rt == null) return; + if (rt.GetComponent() != null) return; + // 跳过:父级已有 UIEdgeFollow(子元素应相对父级布局,不独立贴边)。 + Transform parent = rt.parent; + while (parent != null) + { + if (parent.GetComponent() != null) return; + if (parent.GetComponent() != null) break; // 到达 Canvas 根停止 + parent = parent.parent; + } + // 仅横向未拉伸 + 锚点接近中心。 + if (Mathf.Abs(rt.anchorMax.x - rt.anchorMin.x) > 0.01f) return; + if (Mathf.Abs(rt.anchorMin.x - 0.5f) > 0.01f) return; + string lower = rt.gameObject.name.ToLowerInvariant(); + for (int i = 0; i < AutoEdgeSkip.Length; i++) + if (lower.Contains(AutoEdgeSkip[i])) return; + // 全屏尺寸的排除(背景类)。 + if (rt.sizeDelta.x >= canvasWidth - 1f) return; + // 计算元素中心的绝对X坐标(相对Canvas中心),用实际Canvas宽度而非硬编码1920。 + float absX = 0.5f * canvasWidth + rt.anchoredPosition.x; + float canvasCenter = 0.5f * canvasWidth; + if (Mathf.Abs(absX - canvasCenter) < EdgeOffsetThreshold) return; + rt.gameObject.AddComponent(); + } + + // gameplay 场景:递归扫描 Canvas 下所有 RectTransform,对符合条件的元素附加 UIEdgeFollow。 + // 深度优先遍历,覆盖嵌套的角色面板/技能指示器等。每个元素独立判定,避免打散成组布局。 + private static void RecursiveTryAutoEdgeFollow(RectTransform canvasRt) + { + if (canvasRt == null) return; + float canvasWidth = canvasRt.rect.width; + if (canvasWidth <= 0f) canvasWidth = DesignWidth; // fallback + RecursiveTryAutoEdgeFollowInternal(canvasRt, canvasWidth); + } + + private static void RecursiveTryAutoEdgeFollowInternal(RectTransform rt, float canvasWidth) + { + if (rt == null) return; + // 先尝试给当前元素附加(若符合条件)。 + TryAutoEdgeFollowByOffset(rt, canvasWidth); + // 再递归处理所有子级。 + for (int i = 0; i < rt.childCount; i++) + { + RectTransform child = rt.GetChild(i) as RectTransform; + if (child != null) RecursiveTryAutoEdgeFollowInternal(child, canvasWidth); + } + } + + private IEnumerator PeriodicRescan() + { + // 0.5s 兼顾"面板打开后尽快铺满背景"与常驻开销。 + // 注意:单次扫描含 FindObjectsByType + 逐 Canvas 的 GetComponentsInChildren(会分配数组), + // 属较重操作,间隔不宜过短(0.25s 会带来可感的 GC/CPU 尖峰)。ScanAndFit 内部对已处理的 + // Canvas(match/edgefollow)与已挂 cover 的 Image 都会跳过,避免重复重活。 + var wait = new WaitForSecondsRealtime(0.5f); + while (true) + { + yield return wait; + ScanAndFit(); + } + } + + private void ScanAndFit() + { + UpdateGameplayFlag(); + Canvas[] canvases = FindObjectsByType(FindObjectsInactive.Include, FindObjectsSortMode.None); + for (int i = 0; i < canvases.Length; i++) + { + Canvas canvas = canvases[i]; + if (canvas == null) continue; + + // 注意:不能按 Canvas 缓存跳过——像商店/邮件等面板是运行时挂到“已存在的场景 Canvas”下的, + // 若跳过已见 Canvas,这些后加入的全屏背景就永远不会被 cover(会露出背后界面)。 + // 改为在下面对每个 Image 用 GetComponent 判断是否已处理,成本很低。 + + // 跳过自管理布局/动画的特殊 UI(如全局通知 gNotice):它在 Awake 缓存自身位置并做 + // 弹出/上浮/缩放动画,若我们再改其 scaler/背景会造成实例化瞬间的跳动。名字或组件识别。 + if (ShouldSkipCanvas(canvas)) continue; + + // 性能:match 适配器与边缘跟随都是"每个 Canvas 一次性附加",无需每次扫描都重做 + // (它们含 GetComponentsInChildren 全树遍历 + 递归,较重)。已处理过的 Canvas 直接跳过这部分, + // 只让下面便宜的背景 cover 扫描继续每次执行(它需捕获运行时新挂入的面板底图)。 + bool canvasSetupDone = _setupDoneCanvases.Contains(canvas); + if (!canvasSetupDone) + { + // 所有带 CanvasScaler 的 Canvas 统一用 UICanvasMatchFitter:宽屏锁高度、窄屏锁宽度, + // 保证缩放系数正确、设计区域完整可见。绝不能宽屏锁宽度(会把 UI 放大数倍)。 + CanvasScaler scaler = canvas.GetComponent(); + if (scaler != null && scaler.GetComponent() == null) + { + scaler.gameObject.AddComponent(); + } + + // 结算是"整块按 1920 写死"的居中卡片,不做 HUD 边缘跟随(否则打散版式)。 + bool useEdgeFollowLayout = _gameplayActive && !IsSettlementCanvas(canvas); + + // 按名对已知独立小部件/HUD 容器附加 UIEdgeFollow(白名单,避免打散成组布局)。 + RectTransform[] allRects = canvas.GetComponentsInChildren(true); + for (int r = 0; r < allRects.Length; r++) + { + RectTransform rt = allRects[r]; + if (rt == null) continue; + if (EdgeFollowWhitelist.Contains(rt.gameObject.name)) + { + TryAttachEdgeFollow(rt); + } + // 父级名+子级名精确定位:某些边角元素的偏移在通用名(如"Image")的子级上, + // 直接把通用名加白名单会误伤同名对象,故用"父级名/子级名"精确命中。 + // 例:steamIcon 状态图标的偏移在其子物体 "Image"(左下角,-1751.5,-916)上。 + else if (rt.parent != null && ParentChildEdgeFollow.TryGetValue(rt.parent.name, out string childName) + && rt.gameObject.name == childName) + { + TryAttachEdgeFollow(rt); + } + } + + // gameplay 非结算 HUD:递归对中心锚定、明显靠边的元素附加 UIEdgeFollow。 + if (useEdgeFollowLayout && scaler != null) + { + RectTransform canvasRt = canvas.transform as RectTransform; + if (canvasRt != null) RecursiveTryAutoEdgeFollow(canvasRt); + } + + _setupDoneCanvases.Add(canvas); + } + + // 只处理根 Canvas 下的层级;子 Canvas 会被其根 Canvas 的遍历覆盖到。 + Image[] images = canvas.GetComponentsInChildren(true); + for (int j = 0; j < images.Length; j++) + { + Image img = images[j]; + if (img == null) continue; + RectTransform rt = img.rectTransform; + if (rt == null) continue; + if (!IsFullscreenBackground(rt)) continue; + if (img.GetComponent() == null) + { + // 统一用 Cover:等比放大到覆盖根 Canvas,过覆盖=无缝且永不为 0。 + // 之前的 Stretch(填满父级)对嵌套在小尺寸容器下的全屏图(如 quhuiImage 的父级仅100x100) + // 会把 sizeDelta 拉成 0 导致图片消失,故弃用。 + img.gameObject.AddComponent(); + } + } + + // RawImage(如 main_main 的视频背景 videoDisplay,用 RenderTexture 显示视频): + // RawImage 与 Image 同继承 Graphic,UIBackgroundCover 只改 sizeDelta 对二者一致; + // 其 uvRect=(0,0,1,1) 铺满纹理、RT 为 16:9,等比 cover 不会拉伸变形。 + // GetComponentsInChildren 抓不到 RawImage,故单独扫一遍。 + RawImage[] rawImages = canvas.GetComponentsInChildren(true); + for (int j = 0; j < rawImages.Length; j++) + { + RawImage raw = rawImages[j]; + if (raw == null) continue; + RectTransform rt = raw.rectTransform; + if (rt == null) continue; + if (!IsFullscreenBackground(rt)) continue; + if (raw.GetComponent() == null) + { + raw.gameObject.AddComponent(); + } + } + } + + // gameplay 世界空间背景(SpriteRenderer,如 bg_replace):由相机渲染、非 UI, + // 超宽屏下相机视野扩大会露出背景边缘外的黑边。扫描低 sortingOrder 的全屏 Sprite 背景, + // 附加 UISpriteBackgroundCover 按宽高比放大 localScale 覆盖。仅 gameplay 场景处理。 + if (_gameplayActive) + { + ScanSpriteBackgrounds(); + ScanEnemyFollow(); + ScanTrackRatioStabilizer(); + } + } + + // gameplay 主相机:附加 TrackScreenRatioStabilizer,按宽高比补偿垂直FOV, + // 使轨道横向屏占比在不同分辨率下大致恒定(避免超宽屏轨道太窄误触)。仅附加一次。 + private void ScanTrackRatioStabilizer() + { + if (!_trackStabilizerAttached) + { + Camera cam = Camera.main; + if (cam != null) + { + if (cam.GetComponent() == null) + cam.gameObject.AddComponent(); + _trackStabilizerAttached = true; + } + } + + // 相机分辨率微调器:挂到 effectEventController 单例对象上(它负责相机 pivot,微调经其安全施加)。 + // 独立于上面的标志重试——effectEventController 可能稍晚才初始化。 + if (!_cameraTunerAttached) + { + var eff = effectEventController.Instance; + if (eff != null) + { + if (eff.GetComponent() == null) + eff.gameObject.AddComponent(); + _cameraTunerAttached = true; + } + } + } + private bool _trackStabilizerAttached; + private bool _cameraTunerAttached; + + // gameplay 敌人容器(普通 Transform,非 RectTransform):让其跟随屏幕左缘。 + // 敌人显示对象是 enemyObject_toWiggle,其定位父级是名为 empty 的普通 Transform, + // 挂在 enemyHealthUI 的 ScreenSpaceCamera Canvas 下。给该定位父级附加 UITransformEdgeFollow(左)。 + private void ScanEnemyFollow() + { + if (_enemyFollowAttached) return; // 已附加则不再每次 GameObject.Find(字符串查找较贵)。 + GameObject enemyObj = GameObject.Find("enemyObject_toWiggle"); + if (enemyObj == null) return; // Find 只找 active 对象;敌人未激活时下次补扫再处理。 + // 取其定位父级 empty(承载横向偏移的那层);找不到就用自身。 + Transform target = enemyObj.transform.parent != null ? enemyObj.transform.parent : enemyObj.transform; + if (target.GetComponent() == null) + target.gameObject.AddComponent(); + _enemyFollowAttached = true; + } + private bool _enemyFollowAttached; + + // 扫描并处理世界空间 Sprite 背景(覆盖 gameplay 相机渲染的底图)。 + private static void ScanSpriteBackgrounds() + { + SpriteRenderer[] sprites = FindObjectsByType(FindObjectsInactive.Include, FindObjectsSortMode.None); + for (int i = 0; i < sprites.Length; i++) + { + SpriteRenderer sr = sprites[i]; + if (sr == null) continue; + // 仅处理"背景类":sortingOrder 很低(<= -100,如 bg_replace 的 -999)。 + // 这类是铺底背景,需覆盖;普通游戏 Sprite(音符/角色/特效)不动。 + if (sr.sortingOrder > -100) continue; + if (sr.GetComponent() != null) continue; + sr.gameObject.AddComponent(); + } + } + + // 已知“独立、不属于任何布局组”的边角小部件/HUD 容器精确名单。 + // 仅这些会被贴边跟随;功能界面的成组内容一律不动,避免打散版式。 + private static readonly HashSet EdgeFollowWhitelist = new HashSet + { + // 主界面:世界聊天入口按钮(独立浮标,中心锚定+右偏移)。 + "chat", + // Main_main 主菜单边角独立元素:跟随屏幕边缘。 + // 不含 logo/game_Logo/selectServer/anyButton(选服/进入按钮与logo,保持设计位置)。 + "exit", "help", "supporting", "steamIcon", "uid", "fdLogo", "logo_fdLogo", + // 版本号文本(左上角,挂在 logo 下)。logo 保持居中不动,故 bbt 需独立贴左缘。 + // 名字在 Main_main 唯一,直接加名不会误伤。 + "bbt", + }; + + // 父级名 → 子级名:偏移在通用名子级上的边角元素(直接把通用名加白名单会误伤同名对象)。 + // steamIcon(父)本身偏移为0,真正贴左下角的是它名为 "Image" 的子级(-1751.5,-916)。 + private static readonly Dictionary ParentChildEdgeFollow = new Dictionary + { + { "steamIcon", "Image" }, + }; + + private static void TryAttachEdgeFollow(RectTransform rt) + { + if (rt == null) return; + if (rt.GetComponent() != null) return; + // 仅横向未拉伸 + 锚点接近中心(其余情形本就贴边或拉伸,无需处理)。 + if (Mathf.Abs(rt.anchorMax.x - rt.anchorMin.x) > 0.01f) return; + if (Mathf.Abs(rt.anchorMin.x - 0.5f) > 0.01f) return; + rt.gameObject.AddComponent(); + } + + // 判定 Canvas 是否属于结算(settlement)界面:祖先链里有名为 settlement 的对象。 + // 结算是整块按 1920 写死的居中布局(靠 match=1 锁高度天然居中),不做 HUD 边缘跟随以免打散版式。 + private static bool IsSettlementCanvas(Canvas canvas) + { + if (canvas == null) return false; + Transform t = canvas.transform; + while (t != null) + { + if (t.gameObject.name == "settlement") return true; + t = t.parent; + } + return false; + } + + // 跳过自管理的特殊 UI 根:按名匹配(gNotice 全局通知实例)。 + private static bool ShouldSkipCanvas(Canvas canvas) + { + if (canvas == null) return false; + string n = canvas.gameObject.name; + // gNotice 实例根名 "GlobalNoticeSystem_SceneInstance" 及其 prefab 名。 + if (n.Contains("GlobalNoticeSystem")) return true; + return false; + } + + /// + /// 判定是否为全屏背景:居中锚定(非拉伸)且尺寸接近设计分辨率(或其 2 倍)。 + /// 排除已经是全拉伸(0-1)的(那类天然铺满,无需处理)与尺寸偏小的普通 UI。 + /// + private static bool IsFullscreenBackground(RectTransform rt) + { + Vector2 aMin = rt.anchorMin; + Vector2 aMax = rt.anchorMax; + + // 已全拉伸:无需处理。 + bool stretched = Mathf.Abs(aMax.x - aMin.x) > 0.99f && Mathf.Abs(aMax.y - aMin.y) > 0.99f; + if (stretched) return false; + + // 仅处理居中/固定锚定(锚点宽高跨度接近 0)。 + bool fixedAnchor = Mathf.Abs(aMax.x - aMin.x) < 0.01f && Mathf.Abs(aMax.y - aMin.y) < 0.01f; + if (!fixedAnchor) return false; + + Vector2 size = rt.sizeDelta; + bool matchDesign = Mathf.Abs(size.x - DesignWidth) < SizeTolerance + && Mathf.Abs(size.y - DesignHeight) < SizeTolerance; + bool matchDouble = Mathf.Abs(size.x - DesignWidth * 2f) < SizeTolerance * 2f + && Mathf.Abs(size.y - DesignHeight * 2f) < SizeTolerance * 2f; + return matchDesign || matchDouble; + } +} diff --git a/Assets/scripts/UI/UIResolutionAutoFitter.cs.meta b/Assets/scripts/UI/UIResolutionAutoFitter.cs.meta new file mode 100644 index 00000000..6455819b --- /dev/null +++ b/Assets/scripts/UI/UIResolutionAutoFitter.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 5ab6a774083052748a8da59390e563dc \ No newline at end of file diff --git a/Assets/scripts/UI/UISpriteBackgroundCover.cs b/Assets/scripts/UI/UISpriteBackgroundCover.cs new file mode 100644 index 00000000..14282e51 --- /dev/null +++ b/Assets/scripts/UI/UISpriteBackgroundCover.cs @@ -0,0 +1,62 @@ +using UnityEngine; + +/// +/// gameplay 世界空间背景(SpriteRenderer,如 bg_replace)自适应覆盖。 +/// 该背景由透视相机渲染、带旋转/缩放,尺寸按 16:9 设计。超宽屏(21:9/32:9)下相机 +/// 水平视野扩大会看到背景边缘之外的黑边,故按屏幕宽高比等比放大其 localScale 使其覆盖。 +/// +/// 仅调整 localScale(表现层),不改旋转/位置/材质/引用,不影响业务逻辑与动画。 +/// 16:9 屏下缩放系数=1,与原设计逐像素一致。由 UIResolutionAutoFitter 自动附加。 +/// +/// 满足三要求:1) 不改业务逻辑/引用;2) 16:9 缩放=1、不动旋转位置;3) 超宽屏铺满。 +/// +[RequireComponent(typeof(SpriteRenderer))] +[DisallowMultipleComponent] +public sealed class UISpriteBackgroundCover : MonoBehaviour +{ + private const float DesignAspect = 16f / 9f; + + private Transform tf; + private Vector3 baseScale; // 初始设计缩放(16:9 基准),永不变 + private bool baseCaptured; + private int lastW = -1, lastH = -1; + + private void OnEnable() + { + tf = transform; + CaptureBaseScale(); + Apply(); + } + + private void CaptureBaseScale() + { + if (baseCaptured) return; + baseScale = tf.localScale; + baseCaptured = true; + } + + private void LateUpdate() + { + if (Screen.width != lastW || Screen.height != lastH) + { + Apply(); + } + } + + private void Apply() + { + if (!baseCaptured) CaptureBaseScale(); + lastW = Screen.width; + lastH = Screen.height; + + float aspect = (float)Screen.width / Mathf.Max(1, Screen.height); + // 更宽的屏:水平视野变宽,需按 aspect/DesignAspect 放大以覆盖两侧。 + // 更窄的屏:垂直视野相对更高,需按 DesignAspect/aspect 放大以覆盖上下。 + // 取二者较大值(cover),保证任一方向都不露黑边。16:9 时系数=1。 + float widthFactor = aspect > DesignAspect ? aspect / DesignAspect : 1f; + float heightFactor = aspect < DesignAspect ? DesignAspect / aspect : 1f; + float factor = Mathf.Max(widthFactor, heightFactor); + + tf.localScale = baseScale * factor; + } +} diff --git a/Assets/scripts/UI/UISpriteBackgroundCover.cs.meta b/Assets/scripts/UI/UISpriteBackgroundCover.cs.meta new file mode 100644 index 00000000..6a511993 --- /dev/null +++ b/Assets/scripts/UI/UISpriteBackgroundCover.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: d9611e36b8928ad4183b10e194cfa053 \ No newline at end of file diff --git a/Assets/scripts/UI/UITransformEdgeFollow.cs b/Assets/scripts/UI/UITransformEdgeFollow.cs new file mode 100644 index 00000000..ef96d6c5 --- /dev/null +++ b/Assets/scripts/UI/UITransformEdgeFollow.cs @@ -0,0 +1,104 @@ +using UnityEngine; + +/// +/// 让一个"普通 Transform"(非 RectTransform,如 gameplay 敌人容器 empty/enemyObject)在分辨率变化时 +/// 横向跟随其所属 Canvas 的某一屏幕边缘,保持到该边缘的间距恒定。 +/// +/// 用于敌人这类"用普通 Transform 本地坐标定位、挂在 ScreenSpaceCamera Canvas 下"的对象—— +/// 它们无锚点,UIEdgeFollow(要求 RectTransform)用不了。本组件自测量:运行时读取对象在所属 +/// Canvas 局部空间的 X,算出到选定边缘的间距并保持恒定,与该 Canvas 的精确坐标系无关(健壮)。 +/// +/// 仅改 localPosition.x(表现层),不改 Y/Z/旋转/缩放/引用,不与只改 alpha/scaleY 的入场动画冲突。 +/// 满足三要求:1) 不改业务逻辑/引用;2) 仅横向,首帧于设计分辨率(16:9)测量则位置逐像素不变; +/// 3) 跟随边缘。 +/// +[DisallowMultipleComponent] +public sealed class UITransformEdgeFollow : MonoBehaviour +{ + public enum Edge { Left, Right } + + [SerializeField] private Edge edge = Edge.Left; + + // 设计基准宽度:gap 以 16:9(1920)设计画布为基准计算,与首次附加时的实际分辨率无关, + // 保证 16:9 逐像素一致、其它分辨率下敌人始终贴同一边缘、露出同样部分。 + private const float DesignWidth = 1920f; + + private Transform tf; + private RectTransform rootRt; // 所属 Canvas 的 RectTransform + private float gap; // 对象中心到选定边缘的间距(设计参考单位,恒定) + private bool measured; + private float lastRootW = -1f; + + private void OnEnable() + { + tf = transform; + ResolveRoot(); + Measure(); + } + + private void ResolveRoot() + { + Canvas c = GetComponentInParent(); + if (c != null) + { + Canvas root = c.rootCanvas != null ? c.rootCanvas : c; + rootRt = root.GetComponent(); + } + } + + private void Measure() + { + if (measured || tf == null || rootRt == null) return; + float rootW = rootRt.rect.width; + if (rootW <= 0f) return; + + // 对象在 Canvas 局部空间的 X。该值由固定 localPosition 决定,与分辨率无关(缩放均匀), + // 即为设计位置。Canvas 关于中心对称(rect 以 0 为中心),故设计左/右缘 = ∓DesignWidth/2。 + float localX = rootRt.InverseTransformPoint(tf.position).x; + float designLeft = -DesignWidth * 0.5f; // 16:9 设计左缘 = -960 + float designRight = DesignWidth * 0.5f; // 16:9 设计右缘 = +960 + // gap = 对象中心到选定边缘的距离(设计参考单位,恒定)。 + // 敌人 gap 会是负值(设计上就在左缘之外,只露右半)——正是要保持的视觉。 + gap = edge == Edge.Left ? (localX - designLeft) : (designRight - localX); + lastRootW = rootW; + measured = true; + + // 应用一次,使当前分辨率立即到位(不必等分辨率变化)。 + ApplyToEdge(); + } + + private void LateUpdate() + { + if (rootRt == null) { ResolveRoot(); return; } + if (!measured) { Measure(); return; } + + float rootW = rootRt.rect.width; + if (Mathf.Abs(rootW - lastRootW) <= 0.5f) return; + lastRootW = rootW; + ApplyToEdge(); + } + + // 让对象中心距当前画布选定边缘保持恒定的 gap(设计参考单位)。 + // 画布关于中心对称,故当前左缘 = -rootW/2、右缘 = +rootW/2。 + private void ApplyToEdge() + { + if (tf == null || rootRt == null || !measured) return; + float rootW = rootRt.rect.width; + if (rootW <= 0f) return; + + float curLeft = -rootW * 0.5f; + float curRight = rootW * 0.5f; + float targetLocalX = edge == Edge.Left ? (curLeft + gap) : (curRight - gap); + + float curLocalX = rootRt.InverseTransformPoint(tf.position).x; + float deltaLocalX = targetLocalX - curLocalX; + if (Mathf.Abs(deltaLocalX) <= 0.01f) return; + + // 把 Canvas 局部 X 位移换算到对象自身父空间的 localPosition.x。 + Vector3 worldCur = tf.position; + Vector3 localCurInCanvas = rootRt.InverseTransformPoint(worldCur); + Vector3 worldTarget = rootRt.TransformPoint(new Vector3(targetLocalX, localCurInCanvas.y, localCurInCanvas.z)); + Vector3 parentTarget = tf.parent != null ? tf.parent.InverseTransformPoint(worldTarget) : worldTarget; + tf.localPosition = new Vector3(parentTarget.x, tf.localPosition.y, tf.localPosition.z); + } +} diff --git a/Assets/scripts/UI/UITransformEdgeFollow.cs.meta b/Assets/scripts/UI/UITransformEdgeFollow.cs.meta new file mode 100644 index 00000000..64fd1252 --- /dev/null +++ b/Assets/scripts/UI/UITransformEdgeFollow.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 2faaf8d3e94085a4784340c9bf1db125 \ No newline at end of file diff --git a/Assets/scripts/UI/UnimplementedFeaturePrompt.cs b/Assets/scripts/UI/UnimplementedFeaturePrompt.cs index d44d6089..a430db38 100644 --- a/Assets/scripts/UI/UnimplementedFeaturePrompt.cs +++ b/Assets/scripts/UI/UnimplementedFeaturePrompt.cs @@ -409,7 +409,9 @@ public class UnimplementedFeaturePrompt : MonoBehaviour { scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize; scaler.referenceResolution = new Vector2(1920f, 1080f); - scaler.matchWidthOrHeight = 0.5f; + // 锁高度缩放:分辨率跟随屏幕后,非 16:9 屏也能保证各 UI 层一致缩放、不错位。 + scaler.screenMatchMode = CanvasScaler.ScreenMatchMode.MatchWidthOrHeight; + scaler.matchWidthOrHeight = 1f; } return canvas; diff --git a/Assets/scripts/friendSystem/friendSystem.cs b/Assets/scripts/friendSystem/friendSystem.cs index 270b3b77..d82a6af2 100644 --- a/Assets/scripts/friendSystem/friendSystem.cs +++ b/Assets/scripts/friendSystem/friendSystem.cs @@ -27,6 +27,8 @@ public sealed class FriendCardViewData public string SteamId; public string DisplayName; public string AvatarUrl; + public string PlayerTitleId; + public string PlayerTitle; public string StatusText; public bool IsOnline; public bool IsStarred; @@ -362,6 +364,12 @@ public class friendSystem : MonoBehaviour steamFriend != null ? steamFriend.AvatarUrl : string.Empty, NetworkManager.ResolveAvatarUrl(gameFriend.friend_avatar, steamId), steamId), + PlayerTitleId = !string.IsNullOrWhiteSpace(gameFriend.player_title_id) + ? gameFriend.player_title_id + : (steamFriend != null ? steamFriend.PlayerTitleId : string.Empty), + PlayerTitle = !string.IsNullOrWhiteSpace(gameFriend.player_title) + ? gameFriend.player_title + : (steamFriend != null ? steamFriend.PlayerTitle : string.Empty), StatusText = mergedStatus, IsOnline = mergedOnline, IsStarred = LoadStarredState(steamId), @@ -419,6 +427,12 @@ public class friendSystem : MonoBehaviour steamFriend != null ? steamFriend.AvatarUrl : string.Empty, NetworkManager.ResolveAvatarUrl(profile.avatar_url, steamId), steamId), + PlayerTitleId = !string.IsNullOrWhiteSpace(profile.player_title_id) + ? profile.player_title_id + : (!string.IsNullOrWhiteSpace(profile.primary_honor?.honor_key) ? profile.primary_honor.honor_key : string.Empty), + PlayerTitle = !string.IsNullOrWhiteSpace(profile.player_title) + ? profile.player_title + : (!string.IsNullOrWhiteSpace(profile.primary_honor?.honor_name) ? profile.primary_honor.honor_name : string.Empty), StatusText = mergedStatus, IsOnline = mergedOnline, IsStarred = LoadStarredState(steamId), diff --git a/Assets/scripts/gTransBlack.cs b/Assets/scripts/gTransBlack.cs index 5c95d033..a1082abc 100644 --- a/Assets/scripts/gTransBlack.cs +++ b/Assets/scripts/gTransBlack.cs @@ -1,3 +1,4 @@ +using System.Collections; using UnityEngine; using UnityEngine.UI; using UnityEngine.SceneManagement; @@ -7,36 +8,70 @@ public class gTransBlack : MonoBehaviour [SerializeField] private Canvas b_Canvas; [SerializeField] private CanvasGroup b_CG; [SerializeField] private Text nowLoadingText; + [SerializeField] private int postSceneLoadCameraRefreshFrames = 12; public Canvas Canvas => b_Canvas; public CanvasGroup CanvasGroup => b_CG; + private Camera boundCamera; + private Coroutine cameraRefreshRoutine; + private int lastScreenWidth; + private int lastScreenHeight; + private void Awake() { EnsureReferences(); - ApplySceneCamera(); + ConfigureCanvasForLetterbox(); + ApplySceneCamera(true); } private void OnEnable() { SceneManager.sceneLoaded -= HandleSceneLoaded; SceneManager.sceneLoaded += HandleSceneLoaded; - ApplySceneCamera(); + SceneManager.activeSceneChanged -= HandleActiveSceneChanged; + SceneManager.activeSceneChanged += HandleActiveSceneChanged; + + ConfigureCanvasForLetterbox(); + StartCameraRefreshRoutine(); } private void OnDisable() { SceneManager.sceneLoaded -= HandleSceneLoaded; + SceneManager.activeSceneChanged -= HandleActiveSceneChanged; + + if (cameraRefreshRoutine != null) + { + StopCoroutine(cameraRefreshRoutine); + cameraRefreshRoutine = null; + } + } + + private void Update() + { + if (Screen.width != lastScreenWidth || Screen.height != lastScreenHeight || NeedsCameraRefresh()) + { + ConfigureCanvasForLetterbox(); + ApplySceneCamera(false); + } } private void HandleSceneLoaded(Scene scene, LoadSceneMode mode) { - ApplySceneCamera(); + StartCameraRefreshRoutine(); + } + + private void HandleActiveSceneChanged(Scene oldScene, Scene newScene) + { + StartCameraRefreshRoutine(); } public void RefreshCanvasCamera() { - ApplySceneCamera(); + ConfigureCanvasForLetterbox(); + ApplySceneCamera(true); + StartCameraRefreshRoutine(); } public void SetNowLoadingText(string text) @@ -64,7 +99,7 @@ public class gTransBlack : MonoBehaviour } } - private void ApplySceneCamera() + private void ConfigureCanvasForLetterbox() { EnsureReferences(); @@ -73,10 +108,9 @@ public class gTransBlack : MonoBehaviour return; } - if (b_Canvas.renderMode == RenderMode.ScreenSpaceOverlay) + if (b_Canvas.renderMode != RenderMode.ScreenSpaceCamera) { - b_Canvas.worldCamera = null; - return; + b_Canvas.renderMode = RenderMode.ScreenSpaceCamera; } if (b_Canvas.transform.localScale == Vector3.zero) @@ -84,19 +118,107 @@ public class gTransBlack : MonoBehaviour b_Canvas.transform.localScale = Vector3.one; } + if (b_Canvas.planeDistance <= 0f) + { + b_Canvas.planeDistance = 100f; + } + + b_Canvas.sortingOrder = short.MaxValue; + + CanvasScaler scaler = b_Canvas.GetComponent(); + if (scaler != null) + { + scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize; + scaler.referenceResolution = new Vector2(1920f, 1080f); + scaler.screenMatchMode = CanvasScaler.ScreenMatchMode.MatchWidthOrHeight; + // 锁高度缩放:分辨率跟随屏幕后,非 16:9 屏也能保证各 UI 层一致缩放、不错位。 + scaler.matchWidthOrHeight = 1f; + } + } + + private bool ApplySceneCamera(bool force) + { + EnsureReferences(); + + if (b_Canvas == null) + { + return false; + } + + ConfigureCanvasForLetterbox(); + Camera targetCamera = ResolveFirstSceneCamera(); if (targetCamera == null) + { + return false; + } + + if (force || b_Canvas.worldCamera != targetCamera || boundCamera != targetCamera) + { + b_Canvas.worldCamera = targetCamera; + boundCamera = targetCamera; + } + + lastScreenWidth = Screen.width; + lastScreenHeight = Screen.height; + Canvas.ForceUpdateCanvases(); + return true; + } + + private bool NeedsCameraRefresh() + { + if (b_Canvas == null) + { + return true; + } + + if (boundCamera == null || !boundCamera.isActiveAndEnabled) + { + return true; + } + + if (b_Canvas.renderMode != RenderMode.ScreenSpaceCamera) + { + return true; + } + + return b_Canvas.worldCamera != boundCamera; + } + + private void StartCameraRefreshRoutine() + { + if (!isActiveAndEnabled) { return; } - b_Canvas.worldCamera = targetCamera; + if (cameraRefreshRoutine != null) + { + StopCoroutine(cameraRefreshRoutine); + } + + cameraRefreshRoutine = StartCoroutine(RefreshCameraForSeveralFrames()); + } + + private IEnumerator RefreshCameraForSeveralFrames() + { + int frames = Mathf.Max(1, postSceneLoadCameraRefreshFrames); + for (int i = 0; i < frames; i++) + { + ApplySceneCamera(true); + yield return null; + } + + yield return new WaitForEndOfFrame(); + ApplySceneCamera(true); + cameraRefreshRoutine = null; } private static Camera ResolveFirstSceneCamera() { + Scene activeScene = SceneManager.GetActiveScene(); Camera mainCam = Camera.main; - if (mainCam != null && mainCam.gameObject.scene.IsValid() && mainCam.gameObject.scene.isLoaded) + if (IsUsableSceneCamera(mainCam, activeScene, true)) { return mainCam; } @@ -105,19 +227,47 @@ public class gTransBlack : MonoBehaviour for (int i = 0; i < cameras.Length; i++) { Camera camera = cameras[i]; - if (camera == null || !camera.isActiveAndEnabled) + if (IsUsableSceneCamera(camera, activeScene, true)) { - continue; + return camera; } + } - if (!camera.gameObject.scene.IsValid() || !camera.gameObject.scene.isLoaded) + if (IsUsableSceneCamera(mainCam, activeScene, false)) + { + return mainCam; + } + + for (int i = 0; i < cameras.Length; i++) + { + Camera camera = cameras[i]; + if (IsUsableSceneCamera(camera, activeScene, false)) { - continue; + return camera; } - - return camera; } return null; } + + private static bool IsUsableSceneCamera(Camera camera, Scene preferredScene, bool requirePreferredScene) + { + if (camera == null || !camera.isActiveAndEnabled) + { + return false; + } + + Scene cameraScene = camera.gameObject.scene; + if (!cameraScene.IsValid() || !cameraScene.isLoaded) + { + return false; + } + + if (requirePreferredScene && cameraScene != preferredScene) + { + return false; + } + + return true; + } } diff --git a/Assets/scripts/gamePlay_gameplay/AnimationController.cs b/Assets/scripts/gamePlay_gameplay/AnimationController.cs index dcf11cea..9fa701c9 100644 --- a/Assets/scripts/gamePlay_gameplay/AnimationController.cs +++ b/Assets/scripts/gamePlay_gameplay/AnimationController.cs @@ -40,8 +40,8 @@ public class AnimationController : MonoBehaviour private bool isHolding = false; private static bool loggedMissingHitParticleSource; - // Track active particle instances for immediate cleanup - private List activeParticles = new List(); + // Track active hold-loop particle instances for immediate cleanup on hold release. + private readonly List activeHoldParticles = new List(); // Per-hit FX pooling. PlayDestroyAnimation used to Instantiate + Destroy three // objects on every judge (hit particle, hit ring, judge text prefab). Under dense @@ -53,7 +53,18 @@ public class AnimationController : MonoBehaviour private sealed class FxCacheEntry { public ParticleSystem[] Systems; + public Animator[] Animators; public float Lifetime; + // 模板(prefab/场景源)的设计本地旋转。特效作者常给 ring 之类加了朝向(如 -90°X), + // 播放时必须沿用,否则扁平粒子侧向对相机几乎不可见。 + public Quaternion LocalRotation; + // 根粒子系统:只对它 Play(true)(withChildren 级联到激活的子系统),避免对每个子系统重复触发 burst。 + public ParticleSystem RootSystem; + // clone 时每个子物体的原始 activeSelf:复用时恢复到这个初始态。 + // 关键:特效里有默认 inactive 的备用子层(如 CFXR3 的 "Ring"、trackStar 的 Spikes/Aura), + // 绝不能被复用逻辑盲目激活(会粒子变多);而 stopAction=Disable 误关的该显示层要恢复回来。 + public Transform[] ChildTransforms; + public bool[] ChildInitialActive; } private readonly Dictionary> fxPools = @@ -73,6 +84,7 @@ public class AnimationController : MonoBehaviour private int fxRentCounter; private readonly Dictionary fxRentId = new Dictionary(); private Transform fxPoolRoot; + private string hitRingPathUnderParticleSource; private void EnsureFxPoolRoot() { @@ -85,6 +97,71 @@ public class AnimationController : MonoBehaviour } } + private static Transform GetVisibleFxParent(Transform candidate) + { + return candidate != null && candidate.gameObject.activeInHierarchy ? candidate : null; + } + + private static string BuildRelativePath(Transform root, Transform child) + { + if (root == null || child == null || child == root || !child.IsChildOf(root)) + return null; + + var names = new List(); + Transform current = child; + while (current != null && current != root) + { + names.Add(current.name); + current = current.parent; + } + + names.Reverse(); + return names.Count > 0 ? string.Join("/", names.ToArray()) : null; + } + + private void CacheNestedRingPath() + { + hitRingPathUnderParticleSource = null; + if (hit_particular_object == null || hit_ring_object == null) + return; + + Transform particleRoot = hit_particular_object.transform; + Transform ringTransform = hit_ring_object.transform; + if (ringTransform != particleRoot && ringTransform.IsChildOf(particleRoot)) + { + hitRingPathUnderParticleSource = BuildRelativePath(particleRoot, ringTransform); + } + } + + private Transform GetNestedRingCloneForParticleTemplate(GameObject template, GameObject instance) + { + if (template != hit_particular_object || instance == null || string.IsNullOrEmpty(hitRingPathUnderParticleSource)) + return null; + + return instance.transform.Find(hitRingPathUnderParticleSource); + } + + private static ParticleSystem[] FilterParticleSystems(ParticleSystem[] systems, Transform excludedRoot) + { + if (systems == null || systems.Length == 0 || excludedRoot == null) + return systems ?? new ParticleSystem[0]; + + var filtered = new List(systems.Length); + foreach (var ps in systems) + { + if (ps == null) + continue; + + Transform t = ps.transform; + if (t == excludedRoot || t.IsChildOf(excludedRoot)) + continue; + + filtered.Add(ps); + } + + return filtered.ToArray(); + } + // Creates one instance of the template, caches its particle systems + lifetime, // warms the play path once, and leaves it stopped/cleared ready for reuse. private GameObject CreateFxInstance(GameObject template) @@ -92,20 +169,55 @@ public class AnimationController : MonoBehaviour if (template == null) return null; - GameObject instance = Instantiate(template); - var systems = instance.GetComponentsInChildren(true); + EnsureFxPoolRoot(); + GameObject instance = Instantiate(template, fxPoolRoot, false); + instance.SetActive(false); + Transform excludedNestedRing = GetNestedRingCloneForParticleTemplate(template, instance); + if (excludedNestedRing != null) + { + excludedNestedRing.gameObject.SetActive(false); + } + + var systems = FilterParticleSystems(instance.GetComponentsInChildren(true), excludedNestedRing); if (systems == null) systems = new ParticleSystem[0]; + var animators = instance.GetComponentsInChildren(true); + if (animators == null) + animators = new Animator[0]; + + // 根粒子系统(实例根上的 PS,或第一个未被排除的 PS)。只对它 Play(true) 级联播放。 + ParticleSystem rootPs = instance.GetComponent(); + if (rootPs == null && systems.Length > 0) rootPs = systems[0]; + + // 记录每个子物体(含自身外的所有后代)的初始 activeSelf——此刻已处理完嵌套 ring 的 SetActive(false), + // 即为"设计初始态"。复用时据此恢复,既不激活默认关闭的备用层,也能修好被 stopAction=Disable 误关的层。 + Transform[] allChildren = instance.GetComponentsInChildren(true); + var childList = new List(allChildren.Length); + var childActive = new List(allChildren.Length); + foreach (var ct in allChildren) + { + if (ct == null || ct == instance.transform) continue; // 跳过根(根由 SetActive 单独控制) + childList.Add(ct); + childActive.Add(ct.gameObject.activeSelf); + } var entry = new FxCacheEntry { Systems = systems, - Lifetime = ComputeFxLifetime(systems) + Animators = animators, + Lifetime = ComputeFxLifetime(systems, animators), + // 记录模板设计本地旋转(clone 自 template,此时 localRotation 即模板设计朝向)。 + LocalRotation = template.transform.localRotation, + RootSystem = rootPs, + ChildTransforms = childList.ToArray(), + ChildInitialActive = childActive.ToArray() }; foreach (var ps in systems) { if (ps == null) continue; + var main = ps.main; + main.stopAction = ParticleSystemStopAction.None; try { ps.Play(true); } catch { } try { ps.Stop(true, ParticleSystemStopBehavior.StopEmittingAndClear); } catch { } try { ps.Clear(true); } catch { } @@ -130,6 +242,7 @@ public class AnimationController : MonoBehaviour GameObject pooled = pool.Dequeue(); if (pooled != null && fxCache.TryGetValue(pooled, out entry)) { + pooled.transform.SetParent(null, false); rentToken = MarkRented(pooled); return pooled; } @@ -168,15 +281,34 @@ public class AnimationController : MonoBehaviour return; fxRentId.Remove(instance); - activeParticles.Remove(instance); + activeHoldParticles.Remove(instance); - if (fxCache.TryGetValue(instance, out var entry) && entry.Systems != null) + if (fxCache.TryGetValue(instance, out var entry)) { - foreach (var ps in entry.Systems) + if (entry.Systems != null) { - if (ps == null) continue; - try { ps.Stop(true, ParticleSystemStopBehavior.StopEmittingAndClear); } catch { } - try { ps.Clear(true); } catch { } + foreach (var ps in entry.Systems) + { + if (ps == null) continue; + var main = ps.main; + main.stopAction = ParticleSystemStopAction.None; + try { ps.Stop(true, ParticleSystemStopBehavior.StopEmittingAndClear); } catch { } + try { ps.Clear(true); } catch { } + } + } + + // 回收时把子物体激活态恢复到 clone 初始态:stopAction=Disable 的层播放完被 SetActive(false), + // 若不恢复,下次复用就少一层(粒子变少/ring 不出现)。默认 inactive 的备用层仍保持关闭。 + if (entry.ChildTransforms != null && entry.ChildInitialActive != null) + { + for (int i = 0; i < entry.ChildTransforms.Length; i++) + { + var ct = entry.ChildTransforms[i]; + if (ct == null) continue; + bool want = entry.ChildInitialActive[i]; + if (ct.gameObject.activeSelf != want) + ct.gameObject.SetActive(want); + } } } @@ -201,7 +333,10 @@ public class AnimationController : MonoBehaviour private IEnumerator RecycleFxRoutine(GameObject instance, int rentToken, float delay) { - yield return GameplayClock.WaitForSeconds(delay); + // Visual FX lifetimes must not depend on the DSP/song clock. If the chart + // clock pauses, resets, or is not initialized, pooled particles still need + // to return or the pool eventually runs out of reusable visible instances. + yield return new WaitForSecondsRealtime(Mathf.Max(0f, delay)); if (instance == null) yield break; @@ -214,21 +349,124 @@ public class AnimationController : MonoBehaviour ReturnFxInstance(instance); } - private static float ComputeFxLifetime(ParticleSystem[] systems) + private void ReturnAllRentedFx() { - float maxLifetime = 0f; - if (systems == null) - return maxLifetime; - - foreach (var ps in systems) + var snapshot = new List(rentedFx); + foreach (var instance in snapshot) { - if (ps == null) continue; - var main = ps.main; - var lifetime = main.startLifetime; - float life = lifetime.constantMax; - if (life <= 0f) life = lifetime.constant; - if (life > maxLifetime) maxLifetime = life; + ReturnFxInstance(instance); } + + activeHoldParticles.Clear(); + } + + private void OnDisable() + { + holdActive = false; + holdParticleCoroutine = null; + ReturnAllRentedFx(); + } + + private void OnDestroy() + { + if (Global == this) + { + Global = null; + } + + ReturnAllRentedFx(); + } + + private static void RestartFxPlayback(FxCacheEntry entry, Color tint) + { + if (entry == null) + return; + + // 第一步:把所有子物体的激活态恢复到 clone 初始态。 + // 这修复"粒子逐渐变少":stopAction=Disable 的粒子层播放完会被 Unity SetActive(false), + // 回收/复用时若不恢复就少一层。同时不会激活默认 inactive 的备用层(它们初始态就是 false)。 + if (entry.ChildTransforms != null && entry.ChildInitialActive != null) + { + for (int i = 0; i < entry.ChildTransforms.Length; i++) + { + var ct = entry.ChildTransforms[i]; + if (ct == null) continue; + bool want = entry.ChildInitialActive[i]; + if (ct.gameObject.activeSelf != want) + ct.gameObject.SetActive(want); + } + } + + // 第二步:停止并清空所有粒子系统的残留粒子,设 stopAction=None 防止播放结束再次自我禁用, + // 并刷新 startColor。此处只 Stop/Clear,不逐个 Play。 + if (entry.Systems != null) + { + foreach (var ps in entry.Systems) + { + if (ps == null) continue; + var main = ps.main; + main.stopAction = ParticleSystemStopAction.None; + main.startColor = tint; + try { ps.Stop(true, ParticleSystemStopBehavior.StopEmittingAndClear); } catch { } + try { ps.Clear(true); } catch { } + } + } + + // 第三步:只对根系统 Play(true)——withChildren 会级联播放当前处于激活态的子系统, + // 不会触发默认 inactive 备用层。绝不逐个子系统 Play(那会对同层重复 burst=粒子变多)。 + if (entry.RootSystem != null) + { + try { entry.RootSystem.Play(true); } catch { } + } + else if (entry.Systems != null && entry.Systems.Length > 0 && entry.Systems[0] != null) + { + try { entry.Systems[0].Play(true); } catch { } + } + + // 这两个打击特效无 Animator;保留极简 Rebind 仅对"本就处于激活态"的 Animator(其它含动画的特效复用兜底), + // 绝不为此激活任何子节点(那正是上一版把隐藏备用层强开导致粒子变多的错误)。 + if (entry.Animators != null) + { + foreach (var animator in entry.Animators) + { + if (animator == null || !animator.isActiveAndEnabled) continue; + try { animator.Rebind(); animator.Update(0f); } catch { } + } + } + } + + + private static float ComputeFxLifetime(ParticleSystem[] systems, Animator[] animators) + { + float maxLifetime = 0.5f; + if (systems != null) + { + foreach (var ps in systems) + { + if (ps == null) continue; + var main = ps.main; + var lifetime = main.startLifetime; + float life = lifetime.constantMax; + if (life <= 0f) life = lifetime.constant; + maxLifetime = Mathf.Max(maxLifetime, main.duration + life + 0.25f); + } + } + + if (animators != null) + { + foreach (var animator in animators) + { + if (animator == null || animator.runtimeAnimatorController == null) + continue; + + foreach (var clip in animator.runtimeAnimatorController.animationClips) + { + if (clip != null) + maxLifetime = Mathf.Max(maxLifetime, clip.length + 0.1f); + } + } + } + return maxLifetime; } @@ -245,95 +483,140 @@ public class AnimationController : MonoBehaviour public TextMeshProUGUI purple_track_judgementText; public TextMeshProUGUI blue_track_judgementText; + // 当前正在按住的长音符集合(按 hold note id)。不能按 trackIndex 记账: + // 同一轨道上的旧段回收/下一条长音符会互相 Stop,导致长按后半段特效频率越来越低。 + private readonly HashSet _activeHoldKeys = new HashSet(); + // 各长音符当前颜色,供 routine 逐条播放对应色。 + private readonly Dictionary _holdKeyColor = new Dictionary(); + public void StartHoldParticles(string color) { - // Prefer the Global controller if available so Start/Stop always affect the same instance + StartHoldParticles(color, 0); + } + + public void StartHoldParticles(string color, int holdKey) + { if (AnimationController.Global != null && AnimationController.Global != this) { - AnimationController.Global.InternalStartHoldParticles(color); + AnimationController.Global.InternalStartHoldParticles(color, holdKey); return; } - - InternalStartHoldParticles(color); + InternalStartHoldParticles(color, holdKey); } public void StopHoldParticles() + { + StopHoldParticles(0); + } + + public void StopHoldParticles(int holdKey) { if (AnimationController.Global != null && AnimationController.Global != this) { - AnimationController.Global.InternalStopHoldParticles(); + AnimationController.Global.InternalStopHoldParticles(holdKey); return; } - - InternalStopHoldParticles(); + InternalStopHoldParticles(holdKey); } // Internal implementations operate on this instance - private void InternalStartHoldParticles(string color) + private void InternalStartHoldParticles(string color, int holdKey) { - if (holdActive) return; - - holdActive = true; currentHoldColor = color; + _activeHoldKeys.Add(holdKey); + _holdKeyColor[holdKey] = color; - if (holdParticleCoroutine != null) + // 只要有轨道在按住就保证 routine 在跑;重复调用不会重启(避免 tick 相位错乱)。 + holdActive = true; + if (holdParticleCoroutine == null) { - StopCoroutine(holdParticleCoroutine); + holdParticleCoroutine = StartCoroutine(HoldParticleRoutine()); } - - holdParticleCoroutine = StartCoroutine(HoldParticleRoutine(color)); } - private void InternalStopHoldParticles() + private void InternalStopHoldParticles(int holdKey) { - holdActive = false; + // 本长音符结束:从活跃集合移除。仍有其它长音符按住时,routine 继续跑。 + _activeHoldKeys.Remove(holdKey); + _holdKeyColor.Remove(holdKey); + if (_activeHoldKeys.Count > 0) + { + return; // 还有别的长音符在按,不停整体循环。 + } + + // 全部松手:只停止后续 tick。已经发出的命中特效是 one-shot, + // 让它按自身 lifetime 自然回收,避免刚生成就被清掉造成后段频率变低。 + holdActive = false; if (holdParticleCoroutine != null) { try { StopCoroutine(holdParticleCoroutine); } catch { } holdParticleCoroutine = null; } - // Immediately return all active pooled instances (was Destroy). Returning is - // idempotent and token-guarded, so a later timed RecycleFxRoutine for the same - // instance becomes a no-op. Iterate a snapshot because ReturnFxInstance removes - // the instance from activeParticles (mutating the list mid-enumeration would throw). - var snapshot = activeParticles.ToArray(); - foreach (var p in snapshot) - { - if (p != null) - { - ReturnFxInstance(p); - } - } - activeParticles.Clear(); + activeHoldParticles.Clear(); } - private IEnumerator HoldParticleRoutine(string color) + private IEnumerator HoldParticleRoutine() { - while (holdActive) + float nextTickTime = Time.unscaledTime + Mathf.Max(0.01f, holdParticleInterval); + + while (holdActive && _activeHoldKeys.Count > 0) { float waitSeconds = Mathf.Max(0.01f, holdParticleInterval); - yield return GameplayClock.WaitForSeconds(waitSeconds); - if (!holdActive) break; - PlayDestroyAnimation(color); + while (holdActive && _activeHoldKeys.Count > 0 && Time.unscaledTime < nextTickTime) + { + yield return null; + } + + if (!holdActive || _activeHoldKeys.Count == 0) break; + nextTickTime += waitSeconds; + if (Time.unscaledTime - nextTickTime > waitSeconds) + { + nextTickTime = Time.unscaledTime + waitSeconds; + } + + // 为当前所有按住的轨道各播一次持续粒子(逐轨对应色)。 + try + { + // 复制到临时数组避免迭代中集合被改。 + _holdTickBuffer.Clear(); + foreach (var kv in _holdKeyColor) _holdTickBuffer.Add(kv.Value); + for (int i = 0; i < _holdTickBuffer.Count; i++) + { + PlayDestroyAnimation(_holdTickBuffer[i], true); + } + } + catch (System.Exception ex) + { + Debug.LogWarning($"[AnimationController] Hold particle tick failed: {ex.Message}"); + } } + + holdParticleCoroutine = null; } + private readonly List _holdTickBuffer = new List(); private void Awake() { - if (isGlobalController) + // 自动当选 Global:场景里没有实例勾选 isGlobalController(全为 false),导致 Global 恒 null, + // tap/长条判定的 PlayDestroyAnimation(Global ?? anim) 从不执行、hold 状态在多个 note 实例间错乱。 + // 判据:真正配置了特效源(hit_particular_object + hit_ring_object)的那个场景实例才是全局控制器; + // note 预制体上挂的 20 个 AnimationController 这两个字段为空,不参与竞选。 + bool isConfiguredController = isGlobalController + || (hit_particular_object != null && hit_ring_object != null); + if (isConfiguredController) { if (Global != null && Global != this) { - Debug.LogWarning("[AnimationController] Duplicate global detected, destroying self"); - Destroy(this); - return; + if (JudgeManager.IsDebugEnabled) Debug.LogWarning("[AnimationController] Duplicate global detected, ignoring self"); + // 不 Destroy(this):该组件可能挂在还承载其它引用的场景对象上,仅放弃全局身份即可。 + } + else + { + Global = this; + if (JudgeManager.IsDebugEnabled) Debug.Log("[AnimationController] Global AnimationController registered"); } - - Global = this; - DontDestroyOnLoad(gameObject); - if (JudgeManager.IsDebugEnabled) Debug.Log("[AnimationController] Global AnimationController registered"); } // Animator cache @@ -378,9 +661,37 @@ public class AnimationController : MonoBehaviour "or tag the scene particle source with 'HitParticleSource', or place a GameObject named 'HitParticleSource' in the scene."); } } + + CacheNestedRingPath(); + + // 从根上消除"开局克隆继承模板活粒子":把作为特效模板的场景源(hit_particular_object / hit_ring_object) + // 自身的粒子系统停播并清空,使其成为纯静态模板、永不持有活粒子。这样任何时刻 Instantiate 出来的 + // 克隆都从零粒子开始,开局与后期完全一致(不再前多后少)。 + StopAndClearTemplate(hit_particular_object); + StopAndClearTemplate(hit_ring_object); + } + + private static void StopAndClearTemplate(GameObject template) + { + if (template == null) return; + var systems = template.GetComponentsInChildren(true); + if (systems == null) return; + foreach (var ps in systems) + { + if (ps == null) continue; + var main = ps.main; + main.playOnAwake = false; // 模板绝不自动播放 + try { ps.Stop(true, ParticleSystemStopBehavior.StopEmittingAndClear); } catch { } + try { ps.Clear(true); } catch { } + } } public void PlayDestroyAnimation(string color) + { + PlayDestroyAnimation(color, false); + } + + private void PlayDestroyAnimation(string color, bool trackAsHoldParticle) { // Only use the scene object as the template. No prefab fallback. if (hit_particular_object == null) @@ -409,6 +720,8 @@ public class AnimationController : MonoBehaviour case "blue": if (blueEffect != null) { spawnPos = blueEffect.transform.position; parentTransform = blueEffect.transform; } break; } + parentTransform = GetVisibleFxParent(parentTransform); + // Documentation text normalized. Color trackColor; string hexCode = GetHexCodeForColor(color); @@ -420,84 +733,88 @@ public class AnimationController : MonoBehaviour if (JudgeManager.IsDebugEnabled) Debug.LogWarning($"Failed to parse hex color for '{color}' ({hexCode}). Using white."); } - SpawnJudgePrefabByTrackText(color); - // Rent a pooled copy of the scene particle source (was Instantiate + Destroy per hit). - GameObject particleInstance = RentFxInstance(source, out var particleEntry, out int particleToken); - if (particleInstance == null) + // 判定字(PERFECT/GREAT 等)统一且仅由 Animation_GenerateJudgementSituationPrefab 负责生成, + // 本方法只负责打击粒子 + ring,不碰判定字。 + + // 【彻底去池化】前几轮所有"粒子变多/变少、ring 不激活、复用状态错乱"都源于对象池复用时 + // 子节点激活态/粒子播放态无法可靠复位。改回最朴素可靠的 Instantiate + 定时 Destroy: + // 每次判定 new 一个全新干净实例(与 prefab 设计态完全一致),播放完销毁。无复用=无脏状态。 + // 这正是加池化之前本就正常工作的行为。 + + // 粒子本体:以场景源为模板实例化一份全新拷贝。 + SpawnOneShotFx(source, spawnPos, parentTransform, trackColor, true); + + // Ring(叠加环):tap / hold 头尾 / hold 持续 tick 都按同一频率生成一次性实例。 + // 实例会按自身生命周期 Destroy,不会修改或启动场景里的模板对象。 + if (hit_ring_object != null) { - Debug.LogError("Failed to instantiate hit_particular_object"); - TriggerAnimatorEffect(color); - return; + SpawnOneShotFx(hit_ring_object, spawnPos, parentTransform, trackColor, true); + } + } + + // 实例化一个一次性特效(粒子/ring),播放后按自身生命周期 Destroy。无对象池、无复用。 + // applyTint=true 时把粒子 startColor 染成轨道色(粒子本体);ring 保留自身配色(false)。 + private void SpawnOneShotFx(GameObject template, Vector3 spawnPos, Transform parentTransform, Color tint, bool applyTint) + { + if (template == null) return; + + GameObject instance = Instantiate(template); + if (instance == null) return; + + // 去除粒子本体克隆里"自带的嵌套 ring":hit_ring_object 本身是 hit_particular_object 的子物体, + // Instantiate(粒子本体) 会连它一起克隆(原色,未染色) → 与我另外单独实例化的染色 ring 叠成双层。 + // 先 SetActive(false) 立即让它停播,并从下面的系统列表中排除,再销毁;只保留单独实例化的染色 ring。 + Transform nestedRing = null; + if (template == hit_particular_object && !string.IsNullOrEmpty(hitRingPathUnderParticleSource)) + { + nestedRing = instance.transform.Find(hitRingPathUnderParticleSource); + if (nestedRing != null) + { + nestedRing.gameObject.SetActive(false); + } } - // Place at spawn position, then optionally parent under the effect object so it - // moves with UI/slot (worldPositionStays=true keeps world pos at spawnPos). - particleInstance.transform.SetParent(parentTransform, false); - particleInstance.transform.position = spawnPos; - particleInstance.transform.rotation = Quaternion.identity; - particleInstance.SetActive(true); + // 定位:跟随分轨效果对象(worldPositionStays=false 保留模板设计的本地朝向,如 ring 的 -90°X)。 + instance.transform.SetParent(parentTransform, false); + instance.transform.position = spawnPos; + instance.transform.localRotation = template.transform.localRotation; + instance.SetActive(true); - var systems = particleEntry != null ? particleEntry.Systems : null; + // 排除嵌套 ring 的粒子系统,避免把那层原色 ring 播出来。 + var systems = FilterParticleSystems(instance.GetComponentsInChildren(true), nestedRing); + if (nestedRing != null) Destroy(nestedRing.gameObject); + float lifetime = 0.5f; if (systems != null && systems.Length > 0) { + lifetime = ComputeFxLifetime(systems, null); + // 关键修复(开局粒子多、之后变少的衰减):模板 hit_particular_object 是活动场景对象, + // Instantiate 会连同模板粒子系统"当前缓冲里的活粒子"一起克隆——歌曲早期模板残留/预热粒子多 + // → 克隆多;随模板粒子消亡 → 克隆少。故必须把克隆继承的模拟状态彻底重置为"时间0、零粒子", + // 再从头播放,保证每次一致、与模板当时状态无关。 foreach (var ps in systems) { if (ps == null) continue; var main = ps.main; - main.startColor = trackColor; - ps.Play(); + if (applyTint) main.startColor = tint; + try { ps.Stop(true, ParticleSystemStopBehavior.StopEmittingAndClear); } catch { } + try { ps.Clear(true); } catch { } + // Simulate(0, withChildren:false, restart:true) 强制该系统回到时间 0 的干净态, + // 抹掉 Instantiate 继承的任何已模拟粒子(单靠 Clear 有时不彻底)。 + try { ps.Simulate(0f, false, true); } catch { } + try { ps.Clear(true); } catch { } } - - // Recycle after cached lifetime + small buffer (token-guarded). - StartCoroutine(RecycleFxRoutine(particleInstance, particleToken, Mathf.Max(0.5f, particleEntry.Lifetime + 0.1f))); - - // Track for immediate cleanup on hold stop. - activeParticles.Add(particleInstance); + // 全部重置后,只对根系统 Play(true) 级联播放,从零开始正常发射。 + var rootPs = instance.GetComponent(); + if (rootPs == null) rootPs = systems[0]; + try { rootPs.Play(true); } catch { } } else { - Debug.LogError("No ParticleSystem components found on hit_particular_object instance"); - ReturnFxInstance(particleInstance); - TriggerAnimatorEffect(color); + var animators = instance.GetComponentsInChildren(true); + lifetime = ComputeFxLifetime(null, animators); } - // Ring effect (overlay) if assigned. - if (hit_ring_object != null) - { - GameObject ringInstance = RentFxInstance(hit_ring_object, out var ringEntry, out int ringToken); - if (ringInstance != null) - { - // Parent before activation to avoid transform surprises when Simulation Space = Local. - ringInstance.transform.SetParent(parentTransform, false); - ringInstance.transform.position = spawnPos; - ringInstance.transform.rotation = Quaternion.identity; - ringInstance.SetActive(true); - - var ringSystems = ringEntry != null ? ringEntry.Systems : null; - if (ringSystems != null && ringSystems.Length > 0) - { - foreach (var rps in ringSystems) - { - if (rps == null) continue; - var rmain = rps.main; - rmain.startColor = trackColor; - rps.Play(); - } - - StartCoroutine(RecycleFxRoutine(ringInstance, ringToken, Mathf.Max(0.5f, ringEntry.Lifetime + 0.1f))); - activeParticles.Add(ringInstance); - } - else - { - if (JudgeManager.IsDebugEnabled) Debug.LogWarning("hit_ring_object has no ParticleSystem components"); - ReturnFxInstance(ringInstance); - } - } - else - { - Debug.LogError("Failed to instantiate hit_ring_object"); - } - } + Destroy(instance, Mathf.Max(0.5f, lifetime + 0.1f)); } // Documentation text normalized. @@ -556,65 +873,9 @@ public class AnimationController : MonoBehaviour break; } } - /// - /// Documentation text normalized. - /// - private void SpawnJudgePrefabByTrackText(string color) - { - TextMeshProUGUI targetText = null; - Transform spawnPoint = null; - - // Documentation text normalized. - switch (color) - { - case "red": targetText = red_track_judgementText; spawnPoint = redEffect != null ? redEffect.transform : null; break; - case "green": targetText = green_track_judgementText; spawnPoint = greenEffect != null ? greenEffect.transform : null; break; - case "yellow": targetText = yellow_track_judgementText; spawnPoint = yellowEffect != null ? yellowEffect.transform : null; break; - case "purple": targetText = purple_track_judgementText; spawnPoint = purpleEffect != null ? purpleEffect.transform : null; break; - case "blue": targetText = blue_track_judgementText; spawnPoint = blueEffect != null ? blueEffect.transform : null; break; - } - if (targetText != null && spawnPoint != null) - { - // Documentation text normalized. - if (JudgeManager.IsDebugEnabled) Debug.Log($"判定 {color} 当前读取到的文字为 [{targetText.text}]"); - } - - // Documentation text normalized. - if (targetText != null && spawnPoint != null && !string.IsNullOrEmpty(targetText.text)) - { - DoExecutePrefabSpawn(targetText.text, spawnPoint); - } - } - - /// - /// Documentation text normalized. - /// - private void DoExecutePrefabSpawn(string judgeResult, Transform spawnTransform) - { - GameObject prefabToUse = null; - - // Documentation text normalized. - if (judgeResult.Contains("Perfect")) prefabToUse = perfect_judge_prefab; - else if (judgeResult.Contains("Great")) prefabToUse = great_judge_prefab; - else if (judgeResult.Contains("Good")) prefabToUse = good_judge_prefab; - else if (judgeResult.Contains("Miss")) prefabToUse = miss_judge_prefab; - - if (prefabToUse != null) - { - // Rent a pooled copy of the judge-text prefab (was Instantiate + Destroy per hit). - GameObject instance = RentFxInstance(prefabToUse, out _, out int judgeToken); - if (instance == null) - return; - - instance.transform.SetParent(null, false); - instance.transform.position = spawnTransform.position; - instance.transform.rotation = Quaternion.identity; - instance.SetActive(true); - - // Same 1.0s visible lifetime as before, token-guarded recycle instead of Destroy. - StartCoroutine(RecycleFxRoutine(instance, judgeToken, 1.0f)); - } - } + // 注:判定字生成已完全移交给 Animation_GenerateJudgementSituationPrefab。 + // 原 SpawnJudgePrefabByTrackText / DoExecutePrefabSpawn 是重复的第二套判定字来源,已删除, + // 避免同一次判定出现两套判定字重叠(一大一小)。judge prefab 字段仅供 prewarm 预热池使用。 /// /// Public API to prewarm particle instances. Call during loading/pause time to avoid hitch on first use. diff --git a/Assets/scripts/gamePlay_gameplay/Animation_GenerateJudgementSituationPrefab.cs b/Assets/scripts/gamePlay_gameplay/Animation_GenerateJudgementSituationPrefab.cs index b59993f3..f8468959 100644 --- a/Assets/scripts/gamePlay_gameplay/Animation_GenerateJudgementSituationPrefab.cs +++ b/Assets/scripts/gamePlay_gameplay/Animation_GenerateJudgementSituationPrefab.cs @@ -32,6 +32,14 @@ public class Animation_GenerateJudgementSituationPrefab : MonoBehaviour [Header("Inspector")] public float jumpForce = 5.0f; // Documentation text normalized. public float gravity = -16f; // Documentation text normalized. + [Tooltip("Horizontal drift distance range for judge popup text. Adds a real arc instead of a straight pop.")] + public Vector2 horizontalDriftRange = new Vector2(0.25f, 0.65f); + [Tooltip("Random Z rotation range applied over the popup lifetime.")] + public float rotationRange = 8f; + [Tooltip("Temporary scale punch at the beginning of the popup.")] + public float scalePunch = 0.18f; + [Tooltip("How long the initial scale punch takes before settling back.")] + public float scalePunchDuration = 0.18f; [Header("Inspector")] public float fadeInTime = 0.1f; // Documentation text normalized. @@ -50,6 +58,8 @@ public class Animation_GenerateJudgementSituationPrefab : MonoBehaviour private Coroutine prewarmJudgeCoroutine; private readonly System.Collections.Generic.Dictionary> judgePools = new System.Collections.Generic.Dictionary>(); + private readonly System.Collections.Generic.HashSet rentedJudges + = new System.Collections.Generic.HashSet(); private void Awake() { @@ -160,6 +170,7 @@ public class Animation_GenerateJudgementSituationPrefab : MonoBehaviour return; instance.transform.localPosition = Vector3.zero; + instance.transform.localRotation = Quaternion.identity; // Documentation text normalized. float finalScale = baseScale; @@ -205,6 +216,10 @@ public class Animation_GenerateJudgementSituationPrefab : MonoBehaviour try { instance = CreatePooledJudge(prefab); + if (instance != null) + { + rentedJudges.Add(instance); + } ReturnJudgeToPool(instance); } catch { } @@ -220,21 +235,18 @@ public class Animation_GenerateJudgementSituationPrefab : MonoBehaviour { if (obj == null) yield break; - SpriteRenderer sr = obj.GetComponent(); + SpriteRenderer[] renderers = obj.GetComponentsInChildren(true); float elapsed = 0f; float vVelocity = jumpForce; - Vector3 currentLocalPos = Vector3.zero; - - // Documentation text normalized. float totalLifeTime = fadeOutStartTime + fadeOutDuration; + float driftSign = Random.value < 0.5f ? -1f : 1f; + float driftDistance = Random.Range(horizontalDriftRange.x, horizontalDriftRange.y) * driftSign; + float horizontalVelocity = totalLifeTime > 0.001f ? driftDistance / totalLifeTime : 0f; + float targetRotation = Random.Range(-rotationRange, rotationRange); + Vector3 currentLocalPos = Vector3.zero; + Vector3 baseScaleValue = obj.transform.localScale; - // Documentation text normalized. - if (sr != null) - { - Color c = sr.color; - c.a = 0f; - sr.color = c; - } + SetRenderersAlpha(renderers, 0f); // Documentation text normalized. while (elapsed < totalLifeTime) @@ -246,45 +258,46 @@ public class Animation_GenerateJudgementSituationPrefab : MonoBehaviour // Documentation text normalized. vVelocity += gravity * dt; + currentLocalPos.x += horizontalVelocity * dt; currentLocalPos.y += vVelocity * dt; obj.transform.localPosition = currentLocalPos; + obj.transform.localRotation = Quaternion.Euler(0f, 0f, Mathf.Lerp(0f, targetRotation, Mathf.Clamp01(elapsed / totalLifeTime))); + + float scaleT = scalePunchDuration > 0.001f ? Mathf.Clamp01(elapsed / scalePunchDuration) : 1f; + float punch = Mathf.Sin(scaleT * Mathf.PI) * scalePunch; + obj.transform.localScale = baseScaleValue * (1f + punch); // Documentation text normalized. - if (sr != null) + float alpha; + + // Documentation text normalized. + if (elapsed < fadeInTime) { - float alpha; - - // Documentation text normalized. - if (elapsed < fadeInTime) - { - alpha = Mathf.InverseLerp(0f, fadeInTime, elapsed); - } - // Documentation text normalized. - else if (elapsed > fadeOutStartTime) - { - // Documentation text normalized. - alpha = Mathf.InverseLerp(totalLifeTime, fadeOutStartTime, elapsed); - } - // Documentation text normalized. - else - { - alpha = 1f; - } - - Color c = sr.color; - c.a = Mathf.Clamp01(alpha); - sr.color = c; + alpha = Mathf.InverseLerp(0f, fadeInTime, elapsed); } + // Documentation text normalized. + else if (elapsed > fadeOutStartTime) + { + // Documentation text normalized. + alpha = Mathf.InverseLerp(totalLifeTime, fadeOutStartTime, elapsed); + } + // Documentation text normalized. + else + { + alpha = 1f; + } + + SetRenderersAlpha(renderers, Mathf.Clamp01(alpha)); yield return null; } // Documentation text normalized. - if (obj != null && sr != null) + if (obj != null) { - Color c = sr.color; - c.a = 0f; - sr.color = c; + obj.transform.localScale = baseScaleValue; + obj.transform.localRotation = Quaternion.identity; + SetRenderersAlpha(renderers, 0f); } // Documentation text normalized. @@ -292,6 +305,23 @@ public class Animation_GenerateJudgementSituationPrefab : MonoBehaviour if (obj != null) ReturnJudgeToPool(obj); } + private static void SetRenderersAlpha(SpriteRenderer[] renderers, float alpha) + { + if (renderers == null) + return; + + for (int i = 0; i < renderers.Length; i++) + { + SpriteRenderer sr = renderers[i]; + if (sr == null) + continue; + + Color c = sr.color; + c.a = alpha; + sr.color = c; + } + } + private GameObject GetPooledJudge(GameObject prefab, Transform parent) { if (prefab == null || parent == null) @@ -319,6 +349,7 @@ public class Animation_GenerateJudgementSituationPrefab : MonoBehaviour instance.transform.SetParent(parent, false); instance.SetActive(true); + rentedJudges.Add(instance); return instance; } @@ -341,6 +372,9 @@ public class Animation_GenerateJudgementSituationPrefab : MonoBehaviour if (instance == null) return; + if (!rentedJudges.Remove(instance)) + return; + var tag = instance.GetComponent(); if (tag == null || tag.prefabSource == null) { diff --git a/Assets/scripts/gamePlay_gameplay/BeatmapManager.cs b/Assets/scripts/gamePlay_gameplay/BeatmapManager.cs index 16394fa2..1cc59896 100644 --- a/Assets/scripts/gamePlay_gameplay/BeatmapManager.cs +++ b/Assets/scripts/gamePlay_gameplay/BeatmapManager.cs @@ -1,13 +1,18 @@ -using System.IO; -using UnityEngine; -using UnityEngine.UI; -using System.Collections.Generic; -using TMPro; +using System.IO; +using System.Collections; +using UnityEngine; +using UnityEngine.UI; +using System.Collections.Generic; +using TMPro; +using UnityEngine.SceneManagement; +using Bansonic; public class BeatmapManager : MonoBehaviour { private static readonly bool VerboseLogs = false; + private const string MissingSongDataFallbackScene = "selectYourSongFirst"; public static BeatmapManager Instance { get; private set; } + private bool missingSongDataRedirectStarted; private void Awake() { @@ -315,25 +320,43 @@ public class BeatmapManager : MonoBehaviour void Start() { // 如果 assignedSongData 为空,尝试从 SongDataHolder 获取,作为最后的兜底 - if (pendingSongData == null && assignedSongData == null) - { - assignedSongData = SongDataHolder.SelectedSongData; + if (pendingSongData == null && assignedSongData == null) + { + assignedSongData = SongDataHolder.SelectedSongData; if (VerboseLogs) Debug.Log($"[BeatmapManager] No pending song, fallback to SongDataHolder: {(assignedSongData != null ? assignedSongData.songName : "null")}"); - } + } + + if (!GameConfig.testMode && pendingSongData == null && assignedSongData == null) + { + RedirectToSongSelectForMissingSongData("no pending SongData and no assigned SongData"); + return; + } // 无论如何,在加载谱面前先同步敌人编队到 teamUIController SyncEnemyListToUI(); - if (pendingSongData != null) - { - if (VerboseLogs) Debug.Log($"BeatmapManager.Start: pendingSongData detected: {pendingSongData.songName}, difficulty={pendingDifficulty}"); - // Documentation text normalized. - assignedSongData = pendingSongData; - assignedDifficulty = pendingDifficulty; - - // Documentation text normalized. - bool ok = LoadBeatmapFromSongData(assignedSongData, assignedDifficulty, true); - if (!ok) Debug.LogWarning("BeatmapManager.Start: LoadBeatmapFromSongData failed"); + if (pendingSongData != null || assignedSongData != null) + { + SongData startupSongData = pendingSongData != null ? pendingSongData : assignedSongData; + int startupDifficulty = ResolveStartupDifficulty(startupSongData, pendingSongData != null ? pendingDifficulty : assignedDifficulty); + if (VerboseLogs) Debug.Log($"BeatmapManager.Start: startup SongData detected: {startupSongData.songName}, difficulty={startupDifficulty}"); + // Documentation text normalized. + assignedSongData = startupSongData; + assignedDifficulty = startupDifficulty; + + // Documentation text normalized. + bool ok = LoadBeatmapFromSongData(assignedSongData, assignedDifficulty, true); + if (!ok) + { + Debug.LogWarning("BeatmapManager.Start: LoadBeatmapFromSongData failed"); + pendingSongData = null; + pendingDifficulty = -1; + if (!GameConfig.testMode) + { + RedirectToSongSelectForMissingSongData("SongData exists but chart load failed"); + return; + } + } else { if (VerboseLogs) Debug.Log("BeatmapManager.Start: chart parsed from SongData, attempting to assign audio and pause system"); @@ -438,12 +461,82 @@ public class BeatmapManager : MonoBehaviour if (VerboseLogs) Debug.Log("Default automatic demo beatmap load is commented out to prioritize SO-provided charts."); } - UpdateGameplayUI(); - - } - - private void UpdateGameplayUI() - { + UpdateGameplayUI(); + + } + + private int ResolveStartupDifficulty(SongData song, int requestedDifficulty) + { + if (requestedDifficulty >= 0) + { + return requestedDifficulty; + } + + if (song != null) + { + int selectedDifficulty = Mathf.Clamp(song.thisLevel_selectedDifficultyID, 0, 3); + if (song.GetResolvedChartFile(selectedDifficulty) != null) + { + return selectedDifficulty; + } + + int songDifficulty = Mathf.Clamp(song.difficultyID, 0, 3); + if (song.GetResolvedChartFile(songDifficulty) != null) + { + return songDifficulty; + } + } + + if (song != null && song.chartFiles != null) + { + for (int i = 0; i < song.chartFiles.Count; i++) + { + ChartFileEntry entry = song.chartFiles[i]; + if (entry != null && entry.chartFile != null) + { + return entry.difficulty; + } + } + } + + return 0; + } + + private void RedirectToSongSelectForMissingSongData(string reason) + { + if (missingSongDataRedirectStarted) + { + return; + } + + missingSongDataRedirectStarted = true; + Debug.LogWarning($"[BeatmapManager] Missing valid SongData ({reason}). Returning to {MissingSongDataFallbackScene}."); + try { Time.timeScale = 1f; } catch { } + StartCoroutine(LoadMissingSongDataFallbackScene()); + } + + private IEnumerator LoadMissingSongDataFallbackScene() + { + yield return null; + + if (gTransition.LoadScene(MissingSongDataFallbackScene, LoadSceneMode.Single)) + { + while (gTransition.IsBusy) + { + yield return null; + } + yield break; + } + + AsyncOperation asyncLoad = SceneManager.LoadSceneAsync(MissingSongDataFallbackScene, LoadSceneMode.Single); + while (asyncLoad != null && !asyncLoad.isDone) + { + yield return null; + } + } + + private void UpdateGameplayUI() + { if (assignedSongData == null) return; if (gameplay_songname != null) diff --git a/Assets/scripts/gamePlay_gameplay/CameraResolutionTuner.cs b/Assets/scripts/gamePlay_gameplay/CameraResolutionTuner.cs new file mode 100644 index 00000000..1ac61ba0 --- /dev/null +++ b/Assets/scripts/gamePlay_gameplay/CameraResolutionTuner.cs @@ -0,0 +1,91 @@ +using UnityEngine; + +/// +/// 根据屏幕宽高比,对 gameplay 相机做"适当微调":叠加一点 X 旋转(俯角)与 Z 距离增量。 +/// 目的:不同分辨率下让轨道透视观感更协调(如超宽屏略微拉远/调俯角),与 contain 式 FOV 适配互补。 +/// +/// 安全性(核心):**绝不直接写相机 transform**。所有微调通过 effectEventController.SetResolutionCameraAdjust +/// 施加到"漂移 pivot"(顶层基准节点),并由该方法同步漂移基准 z——因此与相机漂移、SmoothShake 抖动、 +/// 技能偏移、冲刺特效等所有"写相机位姿"的业务逻辑完全不冲突(它们叠加在 pivot 之下或相机自身)。 +/// +/// 用一个 bool(enableTuning)开关。关闭时把增量清零(恢复设计基准),行为与未加此脚本一致。 +/// 增量相对"设计基准"计算,不累积;16:9 时增量为 0(与原设计逐像素一致)。 +/// +[DisallowMultipleComponent] +public sealed class CameraResolutionTuner : MonoBehaviour +{ + [Tooltip("是否启用按分辨率微调相机(X旋转/Z)。关闭则恢复设计基准。")] + public bool enableTuning = true; + + [Tooltip("设计基准宽高比。16:9 = 1.7778。此比例下增量为 0。")] + public float designAspect = 16f / 9f; + + [Header("宽屏(aspect > 设计)微调")] + [Tooltip("每偏离设计宽高比 1.0,额外叠加的 X 旋转角度(正=更俯视)。建议很小。")] + public float widePerAspectRotX = 3f; + [Tooltip("每偏离设计宽高比 1.0,额外叠加的 Z 距离(负=相机后退拉远)。")] + public float widePerAspectZ = -1.0f; + [Tooltip("宽屏微调的绝对上限,避免极端超宽屏过度。")] + public float wideMaxRotX = 6f; + public float wideMaxZ = -2.0f; + + [Header("窄屏(aspect < 设计)微调")] + [Tooltip("每偏离设计宽高比 1.0,额外叠加的 X 旋转角度。")] + public float narrowPerAspectRotX = 0f; + [Tooltip("每偏离设计宽高比 1.0,额外叠加的 Z 距离。")] + public float narrowPerAspectZ = 0f; + public float narrowMaxRotX = 4f; + public float narrowMaxZ = 2.0f; + + private float _lastAspect = -1f; + private bool _lastEnabled; + + private void OnEnable() + { + _lastAspect = -1f; + Apply(); + } + + private void Update() + { + float aspect = (float)Screen.width / Mathf.Max(1, Screen.height); + if (Mathf.Abs(aspect - _lastAspect) > 0.0001f || enableTuning != _lastEnabled) + { + Apply(); + } + } + + private void Apply() + { + var eff = effectEventController.Instance; + if (eff == null) return; + + float aspect = (float)Screen.width / Mathf.Max(1, Screen.height); + _lastAspect = aspect; + _lastEnabled = enableTuning; + + if (!enableTuning) + { + eff.SetResolutionCameraAdjust(0f, 0f); // 恢复设计基准 + return; + } + + float rotX = 0f; + float z = 0f; + if (aspect > designAspect) + { + float dev = aspect - designAspect; // 宽屏偏离量 + rotX = Mathf.Clamp(widePerAspectRotX * dev, Mathf.Min(0f, wideMaxRotX), Mathf.Max(0f, wideMaxRotX)); + z = Mathf.Clamp(widePerAspectZ * dev, Mathf.Min(0f, wideMaxZ), Mathf.Max(0f, wideMaxZ)); + } + else if (aspect < designAspect) + { + float dev = designAspect - aspect; // 窄屏偏离量 + rotX = Mathf.Clamp(narrowPerAspectRotX * dev, Mathf.Min(0f, narrowMaxRotX), Mathf.Max(0f, narrowMaxRotX)); + z = Mathf.Clamp(narrowPerAspectZ * dev, Mathf.Min(0f, narrowMaxZ), Mathf.Max(0f, narrowMaxZ)); + } + // 16:9:rotX=z=0,无微调。 + + eff.SetResolutionCameraAdjust(rotX, z); + } +} diff --git a/Assets/scripts/gamePlay_gameplay/CameraResolutionTuner.cs.meta b/Assets/scripts/gamePlay_gameplay/CameraResolutionTuner.cs.meta new file mode 100644 index 00000000..1452423b --- /dev/null +++ b/Assets/scripts/gamePlay_gameplay/CameraResolutionTuner.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: a3cb6af3bd8ac8f46af425d446ea3222 \ No newline at end of file diff --git a/Assets/scripts/gamePlay_gameplay/GameManager.cs b/Assets/scripts/gamePlay_gameplay/GameManager.cs index ad3b70d7..a5404d81 100644 --- a/Assets/scripts/gamePlay_gameplay/GameManager.cs +++ b/Assets/scripts/gamePlay_gameplay/GameManager.cs @@ -1331,6 +1331,22 @@ public class GameManager : MonoBehaviour private IEnumerator HandleNormalModeStartup() { + bool hasStartupSongDataBeforeParse = + BeatmapManager.pendingSongData != null + || SongDataHolder.SelectedSongData != null + || (beatmapManager != null && beatmapManager.assignedSongData != null); + + if (hasStartupSongDataBeforeParse && beatmapManager != null && beatmapManager.beatmap == null) + { + const int parseWaitFrameLimit = 120; + int waitedFrames = 0; + while (waitedFrames < parseWaitFrameLimit && beatmapManager != null && beatmapManager.beatmap == null) + { + waitedFrames++; + yield return null; + } + } + // If a Beatmap was already provided by previous scene (pendingSongData path), skip loading default JSON if (beatmapManager != null && beatmapManager.beatmap != null) { @@ -1411,6 +1427,25 @@ public class GameManager : MonoBehaviour yield break; } + bool hasStartupSongData = + BeatmapManager.pendingSongData != null + || SongDataHolder.SelectedSongData != null + || (beatmapManager != null && beatmapManager.assignedSongData != null); + + if (!hasStartupSongData) + { + Debug.LogWarning("[GameManager] No SongData available for normal gameplay startup. Returning to selectYourSongFirst."); + yield return FadeToBlackAndLoad("selectYourSongFirst", 0.25f); + yield break; + } + + if (hasStartupSongData) + { + Debug.LogWarning("[GameManager] SongData was available, but BeatmapManager did not produce a beatmap. Returning to selectYourSongFirst."); + yield return FadeToBlackAndLoad("selectYourSongFirst", 0.25f); + yield break; + } + // Original default demo load commented out; manual load only when needed string beatmapFilePath = Path.Combine(Application.streamingAssetsPath, "Emilia_demo.json"); diff --git a/Assets/scripts/gamePlay_gameplay/HoldNote.cs b/Assets/scripts/gamePlay_gameplay/HoldNote.cs index 085389a6..bca32f88 100644 --- a/Assets/scripts/gamePlay_gameplay/HoldNote.cs +++ b/Assets/scripts/gamePlay_gameplay/HoldNote.cs @@ -216,6 +216,9 @@ public class HoldNote : BaseNote if (controller != null) { controller.OnJudgeZoneChanged += OnJudgeZoneChanged; + // 去物理判定:进入/离开判定区的分段逻辑由 controller 几何驱动回调触发(替代自身 OnTrigger)。 + controller.OnZoneEnterGeometry += HandleZoneEnter; + controller.OnZoneExitGeometry += HandleZoneExit; } cachedJudgeManager = JudgeManager.Instance; @@ -322,6 +325,8 @@ public class HoldNote : BaseNote if (controller != null) { controller.OnJudgeZoneChanged -= OnJudgeZoneChanged; + controller.OnZoneEnterGeometry -= HandleZoneEnter; + controller.OnZoneExitGeometry -= HandleZoneExit; } if (JudgeManager.Instance != null) @@ -342,13 +347,53 @@ public class HoldNote : BaseNote private void PlayHitAnimation() { - var controller = AnimationController.Global ?? anim; + var controller = GetAnimationController(); if (controller != null) { controller.PlayDestroyAnimation(noteColor); } } + private void PlayMiddleSegmentHitFx() + { + PlayHitAnimation(); + TrackJudgeHitEffectController.PlayTrackHitFx(trackIndex); + } + + private void EnsureHoldParticleLoop() + { + if (!isHoldActive || string.IsNullOrEmpty(noteColor)) + { + return; + } + + // 按长音符 id 记账,避免同轨道旧段回收误停当前长按特效。 + GetAnimationController()?.StartHoldParticles(noteColor, id); + } + + private AnimationController GetAnimationController() + { + if (AnimationController.Global != null) + return AnimationController.Global; + + if (anim == null) + { + anim = SceneObjectLookupCache.FindAny(); + } + + return anim; + } + + private void StartHoldFxLoop() + { + GetAnimationController()?.StartHoldParticles(noteColor, id); + } + + private void StopHoldFxLoop() + { + GetAnimationController()?.StopHoldParticles(id); + } + private IEnumerator DelayedDisableAnimation(GameObject animationObject, float delay) { // No-op: we used to disable the shared AnimationController here which stopped coroutines. @@ -481,24 +526,43 @@ public class HoldNote : BaseNote if (!isHoldActive && jm != null && jm.IsStartJudged(noteID) && !jm.HasNoteReleased(noteID) && keyHeld) { isHoldActive = true; - AnimationController.Global?.StartHoldParticles(noteColor); + StartHoldFxLoop(); if (debugEnabled) Debug.Log($"[HoldNote] Start particles started for {noteID} color={noteColor} at time={now:F3}"); } + if (isHoldActive && jm != null && jm.IsStartJudged(noteID) && !jm.HasNoteReleased(noteID) && keyHeld) + { + EnsureHoldParticleLoop(); + } + // Auto-miss checks when inside judge line if (hasEnteredLine) { float missRangeScaled = (judgeConfig?.missRange ?? 0.5f) * holdWindowMultiplier; + // 只对"尚未判定"的 start 段做超时 auto-Miss。已成功判定的 start 段(玩家已按下、 + // 正持续按住)绝不能在此被误判 Miss——否则 EvaluateHoldEnd(forceMiss) 会调 StopHoldParticles, + // 把长按持续特效杀掉。物理版时 collider 早已离开判定区不会走到这里;几何版 exit 更晚才暴露此隐患。 + bool startAlreadyJudged = jm != null && jm.IsStartJudged(noteID); if (segment == NoteSegment.Start && now > hitTime + missRangeScaled) { - if (debugEnabled) Debug.Log($"[HoldNote] START auto-Miss: {noteColor}"); - - // Register miss properly via EvaluateHoldEnd - EvaluateHoldEnd(now, true); - - isJudged = true; - ScheduleReturnToPool(0.2f); - return; + if (!startAlreadyJudged) + { + if (debugEnabled) Debug.Log($"[HoldNote] START auto-Miss: {noteColor}"); + // 未判定的 start 超时 → 正常 Miss。 + EvaluateHoldEnd(now, true); + isJudged = true; + ScheduleReturnToPool(0.2f); + return; + } + else + { + // 已成功判定的 start 段:其视觉/判定使命已完成(end 段负责收尾), + // 静默回收即可,绝不能走 EvaluateHoldEnd(会 StopHoldParticles 杀掉长按持续特效)。 + // isHoldActive 由 middle/end 段各自维持,不受本段回收影响。 + isJudged = true; + ScheduleReturnToPool(0.2f); + return; + } } else if (segment == NoteSegment.End && now > scheduledEndTime + missRangeScaled) @@ -515,7 +579,7 @@ public class HoldNote : BaseNote if (isHoldActive && keyUp) { isHoldActive = false; - AnimationController.Global?.StopHoldParticles(); + StopHoldFxLoop(); if (debugEnabled) Debug.Log($"[HoldNote] KeyUp {keyToPress} detected. NoteID: {noteID}, Segment: {segment}, Type: {type}"); if (!hasReleased) @@ -571,15 +635,18 @@ public class HoldNote : BaseNote } else if (segment == NoteSegment.Middle && jm != null && jm.IsStartJudged(noteID) - && isHoldActive + && keyHeld && !jm.HasNoteReleased(noteID)) { + isHoldActive = true; + EnsureHoldParticleLoop(); if (now >= hitTime) { if (hasEnteredLine) { if (JudgeManager.IsDebugEnabled) Debug.Log($"[HoldNote] Middle passed: {noteColor}"); - PlayHitAnimation(); + // 按住阶段粒子由 AnimationController 的固定 tick 统一生成。 + // 中段经过只负责保持循环,不额外加打一组,避免长音符前半段因中段密集而粒子频率过高。 jm?.RegisterMiddlePassed(noteID); ScheduleReturnToPool(0.2f); isJudged = true; @@ -610,6 +677,11 @@ public class HoldNote : BaseNote isHoldActive = true; } + if (isHoldActive && jm != null && jm.IsStartJudged(noteID) && !jm.HasNoteReleased(noteID)) + { + EnsureHoldParticleLoop(); + } + if (segment == NoteSegment.Start) { bool startResolved = jm != null && jm.IsStartJudged(noteID); @@ -642,7 +714,7 @@ public class HoldNote : BaseNote if (now >= hitTime && hasEnteredLine) { if (debugEnabled) Debug.Log($"[HoldNote.AutoPlay] Middle passed: {noteColor}"); - PlayHitAnimation(); + // 按住阶段粒子由 AnimationController 的固定 tick 统一生成。 jm?.RegisterMiddlePassed(noteID); ScheduleReturnToPool(0.2f); isJudged = true; @@ -690,7 +762,7 @@ public class HoldNote : BaseNote JudgeManager.Instance.RegisterStartJudged(noteID, true); isHoldActive = true; PlayHitAnimation(); - AnimationController.Global?.StartHoldParticles(noteColor); + StartHoldFxLoop(); holdStartTime = pressTime; HoldNoteJudgePool.RegisterStart(noteID, pressTime, hitTime, scheduledEndTime, noteColor, trackIndex, (object)noteData); @@ -707,10 +779,9 @@ public class HoldNote : BaseNote globalNoteEffect.TryTrigger(noteData != null ? noteData.noteFunction : null); } - private void OnTriggerEnter2D(Collider2D collision) + // 去物理判定:原 OnTriggerEnter2D 的分段逻辑,改由 controller 几何驱动调用,逻辑完全一致。 + private void HandleZoneEnter() { - if (!collision.CompareTag("JudgmentLine")) return; - hasEnteredLine = true; if (segment == NoteSegment.Start) @@ -753,7 +824,7 @@ public class HoldNote : BaseNote isJudged = true; // Terminate input - mark key as released isHoldActive = false; - AnimationController.Global?.StopHoldParticles(); + StopHoldFxLoop(); return; } @@ -761,10 +832,9 @@ public class HoldNote : BaseNote } } - private void OnTriggerExit2D(Collider2D collision) + // 去物理判定:原 OnTriggerExit2D 的分段逻辑,改由 controller 几何驱动调用,逻辑完全一致。 + private void HandleZoneExit() { - if (!collision.CompareTag("JudgmentLine")) return; - if (segment == NoteSegment.Start) { UnregisterQueueIfNeeded(); @@ -922,7 +992,7 @@ public class HoldNote : BaseNote JudgeManager.Instance.RegisterStartJudged(noteID, true); isHoldActive = true; PlayHitAnimation(); - AnimationController.Global?.StartHoldParticles(noteColor); + StartHoldFxLoop(); // record when the hold started so we can compute held fraction later holdStartTime = pressTime; @@ -938,7 +1008,7 @@ public class HoldNote : BaseNote JudgeManager.Instance.RegisterStartJudged(noteID, true); isHoldActive = true; PlayHitAnimation(); - AnimationController.Global?.StartHoldParticles(noteColor); + StartHoldFxLoop(); holdStartTime = pressTime; @@ -952,7 +1022,7 @@ public class HoldNote : BaseNote JudgeManager.Instance.RegisterStartJudged(noteID, true); isHoldActive = true; PlayHitAnimation(); - AnimationController.Global?.StartHoldParticles(noteColor); + StartHoldFxLoop(); holdStartTime = pressTime; @@ -1260,7 +1330,21 @@ public class HoldNote : BaseNote if (JudgeManager.IsDebugEnabled) Debug.Log($"[HoldNote] Hold end NotifyNoteHit called: TrackIndex={TrackIndex} trackIndexField={trackIndex} result={result} triggeredHold={triggeredHold} triggeredTap={triggeredTap}"); } - AnimationController.Global?.StopHoldParticles(); + // 只有命中(非 Miss)才播放打击特效;Miss 不该触发击打效果。 + // 与上面 1253-1256 的 TrackJudgeHitEffectController 守卫保持一致。 + if (result != "Miss") + { + PlayHitAnimation(); + } + + // 关键修复(长条结束仍按住→持续特效不停):hold 已完整结算,标记该 note 为"已释放/已完结"。 + // 否则玩家继续按住时,其它仍存活的段 Update 满足 (isHoldActive && IsStartJudged && !HasNoteReleased + // && keyHeld) 会再次 EnsureHoldParticleLoop 重启持续 tick——即使 hold 逻辑上已经结束。 + // 置 released 后,所有段的 Update 门槛 !HasNoteReleased 不再成立,持续循环不会被重启。 + hasReleased = true; + JudgeManager.Instance?.RegisterNoteReleased(noteID, true); + + StopHoldFxLoop(); // Release the track lock immediately after end evaluation so the next hold can start on time ReleaseTrackJudgeLockSafe(); @@ -1390,10 +1474,18 @@ public class HoldNote : BaseNote hitTime = 0f; scheduledEndTime = 0f; hasEnteredLine = false; + // 普通 start/middle 段回收时,同一条长音符可能仍在持续按住,不能在这里停掉持续特效。 + // 真正停止由 keyUp / end 判定路径负责;这里只兜底处理 end 段池化泄漏。 + if (isHoldActive && segment == NoteSegment.End) + { + StopHoldFxLoop(); + } isJudged = false; isHoldActive = false; hasBeenHeldFromStart = false; prevTrackHeld = false; + // 去物理判定:池化复用时重置 controller 的几何判定状态(重新算阈值、清进入标志)。 + if (controller != null) controller.ResetJudgeZoneGeometry(); holdStartTime = -1f; diff --git a/Assets/scripts/gamePlay_gameplay/HoldNoteController.cs b/Assets/scripts/gamePlay_gameplay/HoldNoteController.cs index 3285b5e4..e10efff5 100644 --- a/Assets/scripts/gamePlay_gameplay/HoldNoteController.cs +++ b/Assets/scripts/gamePlay_gameplay/HoldNoteController.cs @@ -5,34 +5,86 @@ public class HoldNoteController : MonoBehaviour { private bool isInsideJudgeZone = false; public event Action OnJudgeZoneChanged; + // 去物理判定:几何驱动的进入/离开回调(替代 HoldNote 自身的 OnTriggerEnter2D/Exit2D)。 + public event Action OnZoneEnterGeometry; + public event Action OnZoneExitGeometry; private bool isMoving = false; private float speed = 0f; private float activationTime; + // 去物理判定:用几何阈值复现 Trigger 进入/离开时刻。 + private Collider2D _col; + private float _enterY, _exitY; + private bool _thresholdsReady; + // Absolute positioning for hold segments (keeps segments connected under frame spikes) private bool useAbsolutePositioning = false; private Vector3 spawnPosition; private float baseSpawnYOffset = 0f; // can be negative to offset upward for delayed segments private float visualOffset = 0f; // additional Y offset for visual compensation + private void Awake() + { + _col = GetComponent(); + // 去物理判定:关闭 Rigidbody2D 模拟,消除每帧移动刚体的物理开销(判定改几何驱动)。 + var rb = GetComponent(); + if (rb != null) rb.simulated = false; + } + private void Update() { if (useAbsolutePositioning) { - if (!isMoving) return; - ApplyAbsolutePosition(GameplayClock.NowSongTime); - return; + if (isMoving) ApplyAbsolutePosition(GameplayClock.NowSongTime); + } + else + { + // Start moving after activation time in legacy mode + if (!isMoving && GameplayClock.NowSongTime >= activationTime) + { + isMoving = true; + } + + if (isMoving) + { + transform.Translate(Vector3.down * speed * Time.deltaTime); + } } - // Start moving after activation time in legacy mode - if (!isMoving && GameplayClock.NowSongTime >= activationTime) + // 去物理判定:用几何阈值复现进入/离开判定区(替代 OnTriggerEnter2D/Exit2D)。 + UpdateJudgeZoneByGeometry(); + } + + private void UpdateJudgeZoneByGeometry() + { + if (!_thresholdsReady) { - isMoving = true; + if (!JudgeZoneGeometry.LineReady) return; + if (_col == null) _col = GetComponent(); + if (!JudgeZoneGeometry.TryGetThresholds(_col, transform, out _enterY, out _exitY)) return; + _thresholdsReady = true; } - if (isMoving) + float noteY = transform.position.y; + if (!isInsideJudgeZone && noteY <= _enterY) { - transform.Translate(Vector3.down * speed * Time.deltaTime); + isInsideJudgeZone = true; + // 顺序与原物理一致:先置 hasEnteredLine(OnJudgeZoneChanged),再跑 HoldNote 分段逻辑。 + OnJudgeZoneChanged?.Invoke(true); + OnZoneEnterGeometry?.Invoke(); + // 单帧穿透:一帧内越过整个判定区,立即补离开,行为与物理一致。 + if (noteY <= _exitY) + { + isInsideJudgeZone = false; + OnJudgeZoneChanged?.Invoke(false); + OnZoneExitGeometry?.Invoke(); + } + } + else if (isInsideJudgeZone && noteY <= _exitY) + { + isInsideJudgeZone = false; + OnJudgeZoneChanged?.Invoke(false); + OnZoneExitGeometry?.Invoke(); } } @@ -88,20 +140,13 @@ public class HoldNoteController : MonoBehaviour visualOffset = 0f; } - private void OnTriggerEnter2D(Collider2D collision) + // 去物理判定:进入/离开判定区改由 UpdateJudgeZoneByGeometry 驱动,原 OnTrigger 回调移除。 + + // 池化复用时重置几何判定状态。 + public void ResetJudgeZoneGeometry() { - if (!collision.CompareTag("JudgmentLine")) return; - - isInsideJudgeZone = true; - OnJudgeZoneChanged?.Invoke(true); - } - - private void OnTriggerExit2D(Collider2D collision) - { - if (!collision.CompareTag("JudgmentLine")) return; - isInsideJudgeZone = false; - OnJudgeZoneChanged?.Invoke(false); + _thresholdsReady = false; } public bool IsInsideJudgArea() diff --git a/Assets/scripts/gamePlay_gameplay/InputManager.cs b/Assets/scripts/gamePlay_gameplay/InputManager.cs index 81782f23..239b4f8a 100644 --- a/Assets/scripts/gamePlay_gameplay/InputManager.cs +++ b/Assets/scripts/gamePlay_gameplay/InputManager.cs @@ -46,10 +46,12 @@ public class InputManager : MonoBehaviour private KeyCode[] cachedKeys = new KeyCode[5]; private bool pauseBlockedLastFrame = false; - // Per-track held state. Written by both keyboard (Update) and touch (PressTrack/ + // Per-track held count. Written by both keyboard (Update) and touch (PressTrack/ // ReleaseTrack) so hold-note logic can query one platform-agnostic source instead // of polling Input.GetKey directly (which cannot be driven by touch on Android). - private bool[] trackHeld = new bool[5]; + // Count-based tracking fixes multi-touch on the same lane: one finger lifting no + // longer releases the lane while another finger is still holding it. + private int[] trackHeldCount = new int[5]; /// /// True while the given track (0-4) is currently held, regardless of whether the @@ -57,8 +59,8 @@ public class InputManager : MonoBehaviour /// public bool IsTrackHeld(int trackIndex) { - if (trackIndex < 0 || trackIndex >= trackHeld.Length) return false; - return trackHeld[trackIndex]; + if (trackIndex < 0 || trackIndex >= trackHeldCount.Length) return false; + return trackHeldCount[trackIndex] > 0; } private void Awake() @@ -145,9 +147,10 @@ public class InputManager : MonoBehaviour public void PressTrack(int index) { if (index < 0 || index >= TrackColors.Length) return; - if (trackHeld[index]) return; // already held; avoid duplicate press events + bool wasHeld = trackHeldCount[index] > 0; + trackHeldCount[index]++; - trackHeld[index] = true; + if (wasHeld) return; // already held; avoid duplicate press events KeyCode key = cachedKeys[index]; if (key != KeyCode.None) @@ -170,9 +173,10 @@ public class InputManager : MonoBehaviour public void ReleaseTrack(int index) { if (index < 0 || index >= TrackColors.Length) return; - if (!trackHeld[index]) return; // not held; nothing to release + if (trackHeldCount[index] <= 0) return; // not held; nothing to release - trackHeld[index] = false; + trackHeldCount[index]--; + if (trackHeldCount[index] > 0) return; // another finger/key is still holding this lane KeyCode key = cachedKeys[index]; if (key != KeyCode.None) @@ -204,10 +208,14 @@ public class InputManager : MonoBehaviour for (int i = 0; i < TrackColors.Length; i++) { string color = TrackColors[i]; - trackHeld[i] = false; // clear held state so hold notes don't see a stale press after pause/clear + bool wasHeld = trackHeldCount[i] > 0; + trackHeldCount[i] = 0; // clear held state so hold notes don't see a stale press after pause/clear KeyCode key = KeyBindingManager.GetKeyForColor(color); if (key == KeyCode.None) continue; - try { OnKeyReleased?.Invoke(key); } catch { } + if (wasHeld) + { + try { OnKeyReleased?.Invoke(key); } catch { } + } int index = GetIndexForColor(color); if (laneSprites != null && index >= 0 && index < laneSprites.Length) diff --git a/Assets/scripts/gamePlay_gameplay/Judge/NoteJudgeConfig.asset b/Assets/scripts/gamePlay_gameplay/Judge/NoteJudgeConfig.asset index 4a121c84..b8c4d56b 100644 --- a/Assets/scripts/gamePlay_gameplay/Judge/NoteJudgeConfig.asset +++ b/Assets/scripts/gamePlay_gameplay/Judge/NoteJudgeConfig.asset @@ -12,7 +12,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 088ed1ed6b6731f43ad3166781e3e931, type: 3} m_Name: NoteJudgeConfig m_EditorClassIdentifier: - perfectRange: 0.1 - greatRange: 0.15 - goodRange: 0.2 - missRange: 0.2 + perfectRange: 0.15 + greatRange: 0.2 + goodRange: 0.25 + missRange: 0.3 diff --git a/Assets/scripts/gamePlay_gameplay/JudgeZoneGeometry.cs b/Assets/scripts/gamePlay_gameplay/JudgeZoneGeometry.cs new file mode 100644 index 00000000..29ed7876 --- /dev/null +++ b/Assets/scripts/gamePlay_gameplay/JudgeZoneGeometry.cs @@ -0,0 +1,96 @@ +using UnityEngine; + +/// +/// 判定区几何工具:把"音符 Collider 与判定线 Collider 在 Y 轴是否重叠"这一原本由 +/// Physics2D 触发器(OnTriggerEnter2D/Exit2D)判断的条件,改为纯几何/时间计算, +/// 用于去掉每帧移动 Collider 触发的 Physics2D 开销,同时保持判定"进入/离开判定区" +/// 的时刻与原物理触发**完全一致**。 +/// +/// 原理:判定线静态不动(世界 Y 固定),音符沿 -Y 匀速下落。两个 AxisAligned Box 在 Y 轴 +/// 重叠 ⇔ 音符 collider 上边缘 ≥ 判定线下边缘 且 音符 collider 下边缘 ≤ 判定线上边缘。 +/// 用音符 transform.position.y 表达为一对阈值: +/// 进入(overlap 开始): noteY ≤ lineTop + noteHalfH - noteOffY +/// 离开(overlap 结束): noteY < lineBottom - noteHalfH - noteOffY +/// 这与物理 trigger 的 enter/exit 触发时刻等价(同一 AABB 重叠判据)。 +/// +/// 判定结果本身仍由 hitTime(时间)决定,本类只复现"何时注册/注销到 TrackKeyManager"。 +/// +public static class JudgeZoneGeometry +{ + private static bool _lineCaptured; + private static float _lineTopY; // 判定线 collider 世界上边缘 + private static float _lineBottomY; // 判定线 collider 世界下边缘 + + public static bool LineReady => _lineCaptured; + + /// + /// 捕获判定线 collider 的世界 Y 范围(只需一次,判定线静态不动)。 + /// 传入任一带 tag "JudgmentLine" 的 Collider2D。 + /// + public static void CaptureLine(Collider2D lineCollider) + { + if (_lineCaptured || lineCollider == null) return; + Transform t = lineCollider.transform; + if (lineCollider is BoxCollider2D box) + { + // 直接由 size/offset/世界缩放算,避免依赖 bounds 的物理同步时机。 + float scaleY = Mathf.Abs(t.lossyScale.y); + float centerY = t.position.y + box.offset.y * scaleY; + float halfH = box.size.y * 0.5f * scaleY; + _lineTopY = centerY + halfH; + _lineBottomY = centerY - halfH; + } + else + { + Physics2D.SyncTransforms(); + Bounds b = lineCollider.bounds; + _lineTopY = b.max.y; + _lineBottomY = b.min.y; + } + _lineCaptured = true; + } + + /// 切场景/重开时清空,让新判定线重新捕获。 + public static void Reset() + { + _lineCaptured = false; + } + + /// + /// 从音符自身 Collider 计算它的进入/离开阈值(以 transform.position.y 表示)。 + /// halfH = collider 世界半高;offY = collider 中心相对 transform 原点的 Y 偏移(世界)。 + /// + public static bool TryGetThresholds(Collider2D noteCollider, Transform noteTf, + out float enterY, out float exitY) + { + enterY = 0f; exitY = 0f; + if (!_lineCaptured || noteCollider == null || noteTf == null) return false; + + float halfH, offY; + // 关键:不能用 Collider2D.bounds——本工程 Physics2D AutoSyncTransforms=0, + // 且音符 Rigidbody2D.simulated=false,bounds 不随 transform 主动重算而滞后。 + // 对 hold 的 middle/end 段(被 baseSpawnYOffset 大幅上移)会算出错误的 offY, + // 导致 enterY/exitY 整体错位、中尾段几乎进不了判定区。 + // 改为直接用 BoxCollider2D 的 size/offset + 世界缩放计算(与物理同步时机无关)。 + if (noteCollider is BoxCollider2D box) + { + float scaleY = Mathf.Abs(noteTf.lossyScale.y); + halfH = box.size.y * 0.5f * scaleY; // collider 世界半高 + offY = box.offset.y * scaleY; // collider 中心相对 transform 原点的世界 Y 偏移 + } + else + { + // 其它 collider 类型:先强制同步一次再读 bounds,尽量准确。 + Physics2D.SyncTransforms(); + Bounds b = noteCollider.bounds; + halfH = b.extents.y; + offY = b.center.y - noteTf.position.y; + } + + // overlap 开始:音符下边缘(noteY+offY-halfH) ≤ 判定线上边缘。 + enterY = _lineTopY + halfH - offY; + // overlap 结束:音符上边缘(noteY+offY+halfH) < 判定线下边缘。 + exitY = _lineBottomY - halfH - offY; + return true; + } +} diff --git a/Assets/scripts/gamePlay_gameplay/JudgeZoneGeometry.cs.meta b/Assets/scripts/gamePlay_gameplay/JudgeZoneGeometry.cs.meta new file mode 100644 index 00000000..f8b3e284 --- /dev/null +++ b/Assets/scripts/gamePlay_gameplay/JudgeZoneGeometry.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 3cb21799f3a295d4480155f158f4b841 \ No newline at end of file diff --git a/Assets/scripts/gamePlay_gameplay/Note.cs b/Assets/scripts/gamePlay_gameplay/Note.cs index 8c0b5589..ba3d3063 100644 --- a/Assets/scripts/gamePlay_gameplay/Note.cs +++ b/Assets/scripts/gamePlay_gameplay/Note.cs @@ -157,6 +157,13 @@ public class Note : BaseNote float.NaN); } + // 缓存本音符的实例ID字符串:GameObject 实例ID终身不变(池化复用也不变), + // 缓存后避免每次判定/进出判定区都 GetInstanceID().ToString() 分配字符串(热路径 GC)。 + private string _cachedId; + private string CachedId => _cachedId ?? (_cachedId = gameObject.GetInstanceID().ToString()); + // 供 NoteController 等复用同一缓存id(避免它们各自再 ToString 分配)。 + public string GetCachedInstanceId() => CachedId; + private void Awake() { anim = AnimationController.Global; @@ -207,7 +214,7 @@ public class Note : BaseNote // Release lock if we still hold it if (hasLock) { - TrackKeyManager.Instance?.UnlockTrackForJudge(TrackIndex, gameObject.GetInstanceID().ToString()); + TrackKeyManager.Instance?.UnlockTrackForJudge(TrackIndex, CachedId); hasLock = false; } } @@ -237,7 +244,7 @@ public class Note : BaseNote { if (isJudged) return; - string myId = gameObject.GetInstanceID().ToString(); + string myId = CachedId; // Acquire the track lock to stay compatible with the existing single-judge-per-track invariants. bool locked = false; @@ -322,7 +329,7 @@ public class Note : BaseNote if (isJudged || key != keyToPress) return; - string myId = gameObject.GetInstanceID().ToString(); + string myId = CachedId; // Try to acquire lock for this note (prevents multiple notes on same track being judged at once) if (TrackKeyManager.Instance != null && !TrackKeyManager.Instance.TryLockTrackForJudge(TrackIndex, myId)) @@ -502,7 +509,7 @@ public class Note : BaseNote } // Remove from per-track queue immediately so following notes become head - string myId = gameObject.GetInstanceID().ToString(); + string myId = CachedId; TrackKeyManager.Instance?.UnregisterKey(TrackIndex, myId); // Release lock if we held it @@ -584,7 +591,7 @@ public class Note : BaseNote InputManager.OnKeyPressed -= HandlePress; // CRITICAL: Always release lock and unregister before deactivating - string myId = gameObject.GetInstanceID().ToString(); + string myId = CachedId; // Release lock if we still hold it ReleaseTrackLock(myId); diff --git a/Assets/scripts/gamePlay_gameplay/NoteController.cs b/Assets/scripts/gamePlay_gameplay/NoteController.cs index d04f391e..0fcddc7a 100644 --- a/Assets/scripts/gamePlay_gameplay/NoteController.cs +++ b/Assets/scripts/gamePlay_gameplay/NoteController.cs @@ -9,6 +9,11 @@ public class NoteController : MonoBehaviour private ParticleSystem hitEffect; private Note linkedNote; private bool useAbsolutePositioning = false; + + // 去物理判定:用几何阈值复现原 Trigger 的进入/离开时刻。 + private Collider2D _col; + private float _enterY, _exitY; + private bool _thresholdsReady; // For absolute position tracking instead of relative translate private Vector3 spawnPosition; @@ -20,6 +25,12 @@ public class NoteController : MonoBehaviour hitEffect = GetComponentInChildren(); linkedNote = GetComponent(); spawnPosition = transform.position; + _col = GetComponent(); + // 去物理判定:判定改为几何驱动,音符不再需要 Physics2D 模拟。 + // 关闭 Rigidbody2D 模拟,消除每帧移动 kinematic 刚体触发的物理同步/重叠检测开销。 + // 保留 Collider 组件本身(仅用于读取其 bounds 计算阈值,不参与物理)。 + var rb = GetComponent(); + if (rb != null) rb.simulated = false; } private void Update() @@ -29,12 +40,41 @@ public class NoteController : MonoBehaviour // Use absolute positioning based on elapsed time since activation float elapsedSinceActivation = GameplayClock.NowSongTime - activationTime; float travelDistance = speed * Mathf.Max(0f, elapsedSinceActivation); - + // Position = spawnPoint + initial offset + downward travel Vector3 newPos = spawnPosition; newPos.y -= (baseSpawnYOffset + travelDistance); transform.position = newPos; } + + // 去物理判定:用音符 Y 与阈值的比较复现 OnTriggerEnter2D/Exit2D 的进入/离开时刻。 + UpdateJudgeZoneByGeometry(); + } + + private void UpdateJudgeZoneByGeometry() + { + if (linkedNote == null) return; + if (!_thresholdsReady) + { + // 判定线捕获后,用音符自身 collider 计算进入/离开阈值(只算一次)。 + if (!JudgeZoneGeometry.LineReady) return; + if (!JudgeZoneGeometry.TryGetThresholds(_col, transform, out _enterY, out _exitY)) return; + _thresholdsReady = true; + } + + float noteY = transform.position.y; + // 进入:noteY 下降到 ≤ enterY 且尚未进入。 + if (!isInJudgeZone && noteY <= _enterY) + { + EnterJudgeZone(); + // 单帧穿透(帧尖峰导致一帧内越过整个判定区):立即补一次离开,行为与物理一致。 + if (noteY <= _exitY) ExitJudgeZone(); + } + // 离开:noteY 继续下降到 ≤ exitY 且当前在区内。 + else if (isInJudgeZone && noteY <= _exitY) + { + ExitJudgeZone(); + } } public void SetSpeed(float newSpeed) @@ -89,6 +129,7 @@ public class NoteController : MonoBehaviour baseSpawnYOffset = 0f; spawnPosition = transform.position; useAbsolutePositioning = false; + _thresholdsReady = false; // 池化复用:下次重新计算阈值。 if (hitEffect != null) { @@ -97,31 +138,23 @@ public class NoteController : MonoBehaviour } } - private void OnTriggerEnter2D(Collider2D collision) + // 进入判定区(原 OnTriggerEnter2D 逻辑,保持完全一致)。 + private void EnterJudgeZone() { - if (collision.CompareTag("JudgmentLine")) - { - if (linkedNote != null) - { - isInJudgeZone = true; - // register note by instance id so TrackKeyManager can prioritize - // tap notes are short notes without hold - TrackKeyManager.Instance.RegisterKey(linkedNote.GetTrackIndex(), linkedNote.gameObject.GetInstanceID().ToString(), "tap", linkedNote.HitTime); - } - } + if (linkedNote == null) return; + isInJudgeZone = true; + // register note by instance id so TrackKeyManager can prioritize + // tap notes are short notes without hold + TrackKeyManager.Instance.RegisterKey(linkedNote.GetTrackIndex(), linkedNote.GetCachedInstanceId(), "tap", linkedNote.HitTime); } - private void OnTriggerExit2D(Collider2D collision) + // 离开判定区(原 OnTriggerExit2D 逻辑,保持完全一致)。 + private void ExitJudgeZone() { - if (collision.CompareTag("JudgmentLine")) - { - if (linkedNote != null) - { - isInJudgeZone = false; - TrackKeyManager.Instance.UnregisterKey(linkedNote.GetTrackIndex(), linkedNote.gameObject.GetInstanceID().ToString()); - linkedNote.SetJudgeZone(isInJudgeZone); - } - } + if (linkedNote == null) return; + isInJudgeZone = false; + TrackKeyManager.Instance.UnregisterKey(linkedNote.GetTrackIndex(), linkedNote.GetCachedInstanceId()); + linkedNote.SetJudgeZone(isInJudgeZone); } /// diff --git a/Assets/scripts/gamePlay_gameplay/NoteSpawner.cs b/Assets/scripts/gamePlay_gameplay/NoteSpawner.cs index 1aeed7b8..e6b82afd 100644 --- a/Assets/scripts/gamePlay_gameplay/NoteSpawner.cs +++ b/Assets/scripts/gamePlay_gameplay/NoteSpawner.cs @@ -86,7 +86,14 @@ public class NoteSpawner : MonoBehaviour // optional: constants for runtime clamping (kept for internal use) private const float SpeedMultiplierMin = 0.5f; private const float SpeedMultiplierMax = 2f; - private const float FlowSpeedGlobalMultiplier = 1.5f; + // 全局流速系数:与用户可调流速(speedMultiplier)相乘的独立系数,加快音符下落。 + // 为什么用它而非 bpm 倍率:noteSpeed = 10.75 * sm * bpm / 240,若靠 ×bpm 提速, + // 长条音符的视觉长度由 ApplyVisualScale(sm) 决定(只随 sm 不随 bpm)、且分段数 segmentInterval=(60/bpm)/4 + // 也会变,导致长条视觉与下落速度不匹配而错乱。故 bpm 方案不可行;sm 才是让 noteSpeed 与 + // 长条视觉/粒子一致缩放的唯一安全杠杆。按用户指示设为 2。 + // 判定不受影响:音符恒在 hitTime 抵达判定线,speed 仅改视觉下落快慢与出现时机, + // 判定链只依赖真实音符时间(hitTime ± range),与 speed 无共享变量。 + private const float FlowSpeedGlobalMultiplier = 2.0f; public float EffectiveSpeedMultiplier { @@ -125,6 +132,8 @@ public class NoteSpawner : MonoBehaviour private void Awake() { + // 去物理判定:清空上一场景/上一局缓存的判定线几何,重新捕获(判定线位置可能变)。 + JudgeZoneGeometry.Reset(); EnsureDefaultNoteSpeedPreference(); // Load saved visual speed multiplier before any spawning logic uses it float saved = PlayerPrefs.GetFloat(NoteSpeedPrefKey, NoteSpeedDefault); @@ -576,9 +585,18 @@ public class NoteSpawner : MonoBehaviour private void EnsureJudgmentLine() { - if (judgmentLine != null) return; - GameObject go = GameObject.FindGameObjectWithTag("JudgmentLine"); - if (go != null) judgmentLine = go.transform; + if (judgmentLine == null) + { + GameObject go = GameObject.FindGameObjectWithTag("JudgmentLine"); + if (go != null) judgmentLine = go.transform; + } + // 去物理判定:捕获判定线 collider 的世界 Y 范围(只一次),供音符用几何阈值判进出判定区。 + if (judgmentLine != null && !JudgeZoneGeometry.LineReady) + { + Collider2D lineCol = judgmentLine.GetComponent(); + if (lineCol == null) lineCol = judgmentLine.GetComponentInChildren(); + if (lineCol != null) JudgeZoneGeometry.CaptureLine(lineCol); + } } private float[] BuildLaneTravelTimes(float noteSpeed) diff --git a/Assets/scripts/gamePlay_gameplay/TrackJudgeHitEffectController.cs b/Assets/scripts/gamePlay_gameplay/TrackJudgeHitEffectController.cs index 2c34bd89..4a4829c0 100644 --- a/Assets/scripts/gamePlay_gameplay/TrackJudgeHitEffectController.cs +++ b/Assets/scripts/gamePlay_gameplay/TrackJudgeHitEffectController.cs @@ -43,6 +43,9 @@ public class TrackJudgeHitEffectController : MonoBehaviour private readonly Queue particlePool = new Queue(); private Transform particlePoolRoot; + private readonly HashSet rentedParticles = new HashSet(); + private readonly Dictionary particleRentIds = new Dictionary(); + private int particleRentCounter; // Per-instance cache: the particle systems and computed lifetime are resolved once // when an instance is created, so the burst hot path never calls @@ -72,6 +75,21 @@ public class TrackJudgeHitEffectController : MonoBehaviour } } + private void OnDisable() + { + ReturnAllRentedParticles(); + } + + private void OnDestroy() + { + if (Instance == this) + { + Instance = null; + } + + ReturnAllRentedParticles(); + } + public static void PlayTrackHitFx(int trackIndex) { var controller = Instance != null ? Instance : SceneObjectLookupCache.FindAny(); @@ -271,7 +289,8 @@ public class TrackJudgeHitEffectController : MonoBehaviour if (instance == null) return; - instance.transform.SetParent(parent, false); + Transform safeParent = parent != null && parent.gameObject.activeInHierarchy ? parent : transform; + instance.transform.SetParent(safeParent, false); instance.transform.localPosition = trackParticleLocalPosition; instance.transform.localRotation = Quaternion.Euler(trackParticleLocalEulerAngles); instance.transform.localScale = trackParticleLocalScale; @@ -280,7 +299,7 @@ public class TrackJudgeHitEffectController : MonoBehaviour Color tint = GetTrackColor(trackIndex); ApplyParticleColor(entry, tint); - StartCoroutine(RecycleParticleRoutine(instance, entry, Mathf.Max(0.05f, entry.Lifetime))); + StartCoroutine(RecycleParticleRoutine(instance, entry, CurrentParticleRentToken(instance), Mathf.Max(0.05f, entry.Lifetime))); } // Prewarm the track particle pool during load so the first judge does not pay @@ -354,27 +373,65 @@ public class TrackJudgeHitEffectController : MonoBehaviour { GameObject pooled = particlePool.Dequeue(); if (pooled != null && particleCache.TryGetValue(pooled, out entry)) + { + pooled.transform.SetParent(null, false); + MarkParticleRented(pooled); return pooled; + } } GameObject created = CreateParticleInstance(); if (created != null && particleCache.TryGetValue(created, out entry)) + { + MarkParticleRented(created); return created; + } entry = null; return created; } - private IEnumerator RecycleParticleRoutine(GameObject instance, ParticleCacheEntry entry, float delay) + private int MarkParticleRented(GameObject instance) { - if (useUnscaledTime) - yield return new WaitForSecondsRealtime(delay); - else - yield return GameplayClock.WaitForSeconds(delay); + if (instance == null) + return -1; + + rentedParticles.Add(instance); + int token = ++particleRentCounter; + particleRentIds[instance] = token; + return token; + } + + private int CurrentParticleRentToken(GameObject instance) + { + return instance != null && particleRentIds.TryGetValue(instance, out int token) ? token : -1; + } + + private IEnumerator RecycleParticleRoutine(GameObject instance, ParticleCacheEntry entry, int rentToken, float delay) + { + // Short visual FX should always recycle in real time. Tying them to + // GameplayClock can leak rented objects while the song clock is paused. + yield return new WaitForSecondsRealtime(Mathf.Max(0f, delay)); if (instance == null) yield break; + if (CurrentParticleRentToken(instance) != rentToken) + yield break; + + ReturnParticleInstance(instance, entry); + } + + private void ReturnParticleInstance(GameObject instance, ParticleCacheEntry entry) + { + if (instance == null) + return; + + if (!rentedParticles.Remove(instance)) + return; + + particleRentIds.Remove(instance); + if (entry != null && entry.Systems != null) { foreach (var ps in entry.Systems) @@ -391,6 +448,19 @@ public class TrackJudgeHitEffectController : MonoBehaviour particlePool.Enqueue(instance); } + private void ReturnAllRentedParticles() + { + var snapshot = new List(rentedParticles); + foreach (var instance in snapshot) + { + if (instance == null) + continue; + + particleCache.TryGetValue(instance, out var entry); + ReturnParticleInstance(instance, entry); + } + } + private Color GetTrackColor(int trackIndex) { if (trackColors != null && trackIndex >= 0 && trackIndex < trackColors.Length) diff --git a/Assets/scripts/gamePlay_gameplay/TrackScreenRatioStabilizer.cs b/Assets/scripts/gamePlay_gameplay/TrackScreenRatioStabilizer.cs new file mode 100644 index 00000000..94d13178 --- /dev/null +++ b/Assets/scripts/gamePlay_gameplay/TrackScreenRatioStabilizer.cs @@ -0,0 +1,98 @@ +using UnityEngine; + +/// +/// 让 gameplay 画面在任意分辨率/宽高比下都"完整可见、绝不裁剪"(contain 容纳式), +/// 同时尽量维持轨道的可点击尺寸。避免此前 cover 式补偿(缩小FOV=镜头拉近)把上下/背景裁掉的问题。 +/// +/// 原理(透视相机、垂直 FOV 控制):轨道/背景是世界空间对象(Z=0 平面)。 +/// 垂直半可视世界高 ∝ tan(vFov/2);水平半可视世界宽 ∝ tan(vFov/2) · aspect。 +/// 要"包含"住 16:9 设计画面(设计横向范围 + 设计纵向范围)且绝不裁剪,取二者所需 FOV 的较大值: +/// tan(vFov/2) = tan(designVFov/2) · max(1, designAspect / aspect) +/// - 16:9:max(1,1)=1 → vFov = designVFov(与原设计逐像素一致)。 +/// - 更宽(21:9/32:9,aspect>designAspect):max=1 → vFov 保持 designVFov。 +/// 纵向完整不变、横向自然更宽(显示更多内容/背景),一寸不裁;轨道显得细些—— +/// 由已有的点击区兜底(OverlapPointAll+最近轨道匹配,横向无缝)保证仍好点,不误触。 +/// - 更窄(4:3,aspect1 → vFov 增大(镜头拉远),保证设计横向范围完整可见, +/// 纵向显示更多,同样不裁剪。 +/// 本式**永不缩小 FOV**(不拉近),因此绝不会裁掉设计画面——这是与之前 cover 式的本质区别。 +/// +/// 只调相机一个表现参数(fieldOfView),不动任何 Transform;音符/轨道/点击区在同一世界平面, +/// 相对对齐不受 FOV 影响;TrackTouchInput 每帧用当前相机状态做屏幕→世界命中,自动跟随。 +/// +/// 用一个 bool(enableStabilization)开关。关闭时恢复设计 FOV,行为与未加此脚本一致。 +/// +[RequireComponent(typeof(Camera))] +[DisallowMultipleComponent] +public sealed class TrackScreenRatioStabilizer : MonoBehaviour +{ + [Tooltip("是否启用轨道屏占比稳定(按宽高比补偿相机垂直FOV)。关闭则恢复设计FOV。")] + public bool enableStabilization = true; + + [Tooltip("设计基准宽高比(轨道占比在此比例下为设计值)。16:9 = 1.7778。")] + public float designAspect = 16f / 9f; + + [Tooltip("设计基准垂直FOV(该相机在16:9下的原始FOV)。留 0 则启动时自动取相机当前FOV。")] + public float designVerticalFov = 0f; + + [Tooltip("补偿后垂直FOV的安全范围,避免极端宽高比下过小/过大。")] + public float minFov = 20f; + public float maxFov = 100f; + + private Camera _cam; + private float _lastAspect = -1f; + private bool _lastEnabled; + + private void OnEnable() + { + _cam = GetComponent(); + // 自动记录设计 FOV(仅一次):此时相机 FOV 即 16:9 设计值。 + if (designVerticalFov <= 0f && _cam != null) + { + designVerticalFov = _cam.fieldOfView; + } + _lastAspect = -1f; // 强制下一次 Apply + Apply(); + } + + private void Update() + { + float aspect = GetAspect(); + // 宽高比或开关变化时才重算。 + if (Mathf.Abs(aspect - _lastAspect) > 0.0001f || enableStabilization != _lastEnabled) + { + Apply(); + } + } + + private float GetAspect() + { + // 优先用相机自身 aspect(可能被 viewport 影响),否则用屏幕。 + if (_cam != null && _cam.aspect > 0.0001f) return _cam.aspect; + return (float)Screen.width / Mathf.Max(1, Screen.height); + } + + private void Apply() + { + if (_cam == null) _cam = GetComponent(); + if (_cam == null || _cam.orthographic) return; // 仅透视相机适用 + if (designVerticalFov <= 0f) designVerticalFov = _cam.fieldOfView; + + float aspect = GetAspect(); + _lastAspect = aspect; + _lastEnabled = enableStabilization; + + if (!enableStabilization) + { + _cam.fieldOfView = designVerticalFov; // 关闭:恢复设计 FOV + return; + } + + // contain(容纳、绝不裁剪):tan(vFov/2) = tan(designVFov/2) · max(1, designAspect/aspect) + // max(1, …) 保证 FOV 永不小于设计值(不拉近、不裁上下);窄屏才放大以容纳设计横向范围。 + float designHalfTan = Mathf.Tan(designVerticalFov * 0.5f * Mathf.Deg2Rad); + float widen = (aspect > 0.0001f) ? Mathf.Max(1f, designAspect / aspect) : 1f; + float targetHalfTan = designHalfTan * widen; + float targetFov = 2f * Mathf.Atan(targetHalfTan) * Mathf.Rad2Deg; + _cam.fieldOfView = Mathf.Clamp(targetFov, minFov, maxFov); + } +} diff --git a/Assets/scripts/gamePlay_gameplay/TrackScreenRatioStabilizer.cs.meta b/Assets/scripts/gamePlay_gameplay/TrackScreenRatioStabilizer.cs.meta new file mode 100644 index 00000000..a7a95e2b --- /dev/null +++ b/Assets/scripts/gamePlay_gameplay/TrackScreenRatioStabilizer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 95e86c3f767fdb84fa3ea1cb479fd141 \ No newline at end of file diff --git a/Assets/scripts/gamePlay_gameplay/TrackTouchInput.cs b/Assets/scripts/gamePlay_gameplay/TrackTouchInput.cs index 26e212b0..32160f05 100644 --- a/Assets/scripts/gamePlay_gameplay/TrackTouchInput.cs +++ b/Assets/scripts/gamePlay_gameplay/TrackTouchInput.cs @@ -68,6 +68,11 @@ public class TrackTouchInput : MonoBehaviour private void Update() { +#if UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN + // Windows 平台:禁用轨道点击/触摸轮询,只依赖按键输入。 + // 编辑器(Win)也一并禁用,便于在 PC 上以键盘方式测试真实 Windows 行为。 + return; +#else var im = InputManager.Instance; if (im == null) return; @@ -80,6 +85,7 @@ public class TrackTouchInput : MonoBehaviour { ProcessMouse(im, cam); } +#endif } /// 处理所有并发触点,返回本帧触点数量。 @@ -198,6 +204,7 @@ public class TrackTouchInput : MonoBehaviour /// private int ResolveTrack(Camera cam, Vector2 screenPos) { + EnsureOverlapFilter(); Vector2 point; if (forceOrthographicMode || cam.orthographic) @@ -222,12 +229,58 @@ public class TrackTouchInput : MonoBehaviour point = new Vector2(world.x, world.y); } - Collider2D hit = Physics2D.OverlapPoint(point, hitLayers); - if (hit == null) return -1; + // 用 OverlapPointAll 遍历所有命中的碰撞体,挑出带 TrackTouchZone 的那个。 + // 关键修复:判定线附近同一屏幕点常密集着 note 的 Collider2D 与 judgeline 触发器, + // 单值版 OverlapPoint 只返回其中一个,若不是 tap zone 就丢判定(=点了轨道却没反应)。 + // 遍历全部命中即可穿透这些遮挡,可靠找到轨道点击区。 + int count = Physics2D.OverlapPoint(point, _overlapFilter, _overlapResults); + for (int i = 0; i < count; i++) + { + Collider2D hit = _overlapResults[i]; + if (hit == null) continue; + TrackTouchZone zone = hit.GetComponent(); + if (zone == null) zone = hit.GetComponentInParent(); + if (zone != null) return zone.trackIndex; + } - TrackTouchZone zone = hit.GetComponent(); - if (zone == null) zone = hit.GetComponentInParent(); - return zone != null ? zone.trackIndex : -1; + // 兜底:没有精确命中任何 zone(点落在轨道间缝隙或紧邻边缘)。 + // 取横向最近的 zone,只要触点在其 Collider 的纵向范围内即算命中—— + // 等效于把相邻轨道点击区在横向补满、消除缝隙,且不误触远离轨道区的点击。 + return ResolveNearestZone(point); + } + + // 横向最近轨道兜底:在所有 zone 中找触点纵向落在其包围盒内、且横向距离最近的一个。 + private int ResolveNearestZone(Vector2 point) + { + var zones = TrackTouchZone.All; + int best = -1; + float bestDist = float.MaxValue; + for (int i = 0; i < zones.Count; i++) + { + TrackTouchZone z = zones[i]; + if (z == null || z.Collider == null) continue; + Bounds b = z.Collider.bounds; + // 纵向必须落在该点击区范围内(留一点容差),避免点屏幕别处也触发轨道。 + if (point.y < b.min.y - 0.1f || point.y > b.max.y + 0.1f) continue; + float dx = Mathf.Abs(point.x - b.center.x); + if (dx < bestDist) { bestDist = dx; best = z.trackIndex; } + } + return best; + } + + // OverlapPoint 的复用缓冲与过滤器(避免每次触摸分配 GC)。 + private static readonly Collider2D[] _overlapResults = new Collider2D[16]; + private ContactFilter2D _overlapFilter; + private bool _filterReady; + + private void EnsureOverlapFilter() + { + if (_filterReady) return; + _overlapFilter = new ContactFilter2D(); + _overlapFilter.useLayerMask = true; + _overlapFilter.SetLayerMask(hitLayers); + _overlapFilter.useTriggers = true; // tap zone 可能是触发器,需包含 + _filterReady = true; } private void OnDisable() diff --git a/Assets/scripts/gamePlay_gameplay/TrackTouchZone.cs b/Assets/scripts/gamePlay_gameplay/TrackTouchZone.cs index 75f0dfd1..24555a9b 100644 --- a/Assets/scripts/gamePlay_gameplay/TrackTouchZone.cs +++ b/Assets/scripts/gamePlay_gameplay/TrackTouchZone.cs @@ -37,11 +37,27 @@ public class TrackTouchZone : MonoBehaviour } } + // 全部启用中的 zone 注册表:供 TrackTouchInput 在"点到轨道间缝隙/边缘"时做最近轨道兜底, + // 无需改场景碰撞体尺寸即可消除轨道间空隙导致的漏点。 + private static readonly System.Collections.Generic.List _all = + new System.Collections.Generic.List(); + public static System.Collections.Generic.IReadOnlyList All => _all; + private void Awake() { _collider = GetComponent(); } + private void OnEnable() + { + if (!_all.Contains(this)) _all.Add(this); + } + + private void OnDisable() + { + _all.Remove(this); + } + private void LateUpdate() { // 在所有晃动逻辑(Update)之后对齐,避免落后一帧。 diff --git a/Assets/scripts/gamePlay_gameplay/effectEventController.cs b/Assets/scripts/gamePlay_gameplay/effectEventController.cs index 4a80cdac..fee093e8 100644 --- a/Assets/scripts/gamePlay_gameplay/effectEventController.cs +++ b/Assets/scripts/gamePlay_gameplay/effectEventController.cs @@ -36,6 +36,14 @@ public class effectEventController : MonoBehaviour private float cameraDriftSeedX; private float cameraDriftSeedY; + // 分辨率相机微调:改的是"漂移 pivot"(顶层节点,承载 -40°/-8 基准),不碰相机自身, + // 因此不与 SmoothShake(写相机 local)、技能偏移(写技能 pivot)、冲刺(写相机 z)冲突。 + // 改 pivot 的 X 旋转无任何系统覆盖;改 pivot 的 Z 必须同步 cameraDriftBaseLocalPosition.z, + // 否则 UpdateCameraDrift/ResetCameraDriftIfNeeded 会用旧基准把 z 拉回。 + private bool _cameraBaseCaptured; + private float _designPivotRotX; // pivot 初始 X 旋转(如 -40) + private float _designPivotZ; // pivot 初始 Z(如 -8) + private void Awake() { if (Instance == null) @@ -60,9 +68,23 @@ public class effectEventController : MonoBehaviour CacheTrackCrashController(); } + // 门控:漂移关闭且已归位后,跳过每帧的 Perlin/缓存查找;开关切换时才归位一次。 + private bool _driftResetDone; + private void Update() { - UpdateCameraDrift(); + if (enableCameraDrift) + { + _driftResetDone = false; + UpdateCameraDrift(); + } + else if (!_driftResetDone) + { + // 关闭瞬间归位一次,之后不再每帧空跑。 + UpdateCameraDrift(); + _driftResetDone = true; + } + UpdatePlayerSkillCameraOffset(); } @@ -85,6 +107,43 @@ public class effectEventController : MonoBehaviour } } + // 捕获漂移 pivot 的设计基准(X旋转/Z)一次。pivot 建好后调用即安全。 + private void CaptureCameraBaseIfNeeded() + { + if (_cameraBaseCaptured) return; + if (cachedCameraDriftPivot == null) + { + CacheShakeTarget(); // 确保 pivot 已建立 + if (cachedCameraDriftPivot == null) return; + } + _designPivotRotX = cachedCameraDriftPivot.localEulerAngles.x; + _designPivotZ = cachedCameraDriftPivot.localPosition.z; + _cameraBaseCaptured = true; + } + + /// + /// 按分辨率微调相机:在设计基准上叠加 X 旋转增量与 Z 位置增量。 + /// 改的是漂移 pivot(不动相机本身),且同步 cameraDriftBaseLocalPosition.z, + /// 与漂移/抖动/技能偏移/冲刺全部不冲突。可重复调用(总是相对设计基准,不累积)。 + /// + public void SetResolutionCameraAdjust(float extraRotX, float extraZ) + { + CaptureCameraBaseIfNeeded(); + if (cachedCameraDriftPivot == null) return; + + // X 旋转:设计值 + 增量。pivot 的 rotation 无系统写入,直接设安全。 + Vector3 euler = cachedCameraDriftPivot.localEulerAngles; + euler.x = _designPivotRotX + extraRotX; + cachedCameraDriftPivot.localEulerAngles = euler; + + // Z:设计值 + 增量,并同步漂移基准 z(漂移只改 x,y,z 恒取基准)。 + float targetZ = _designPivotZ + extraZ; + Vector3 lp = cachedCameraDriftPivot.localPosition; + lp.z = targetZ; + cachedCameraDriftPivot.localPosition = lp; + cameraDriftBaseLocalPosition.z = targetZ; // 关键:否则会被 UpdateCameraDrift/Reset 拉回 + } + private void PrewarmShakeComponent() { if (cachedShakeTarget == null) diff --git a/Assets/scripts/gamePlay_gameplay/groundParticularController.cs b/Assets/scripts/gamePlay_gameplay/groundParticularController.cs index 3418cfa6..6dd828e6 100644 --- a/Assets/scripts/gamePlay_gameplay/groundParticularController.cs +++ b/Assets/scripts/gamePlay_gameplay/groundParticularController.cs @@ -88,6 +88,17 @@ public class groundParticularController : MonoBehaviour private float[] _audioSamples = new float[128]; private float _currentAverageVolume = 0f; private float _emitTimer = 0f; + + // 性能:复用一个 MaterialPropertyBlock,避免每颗粒子 new(GC)。 + private MaterialPropertyBlock _sharedPropBlock; + // 性能:缓存粒子的 Renderer,避免 Emit/MoveRoutine 每次 GetComponent。 + private readonly Dictionary _rendererCache = new Dictionary(); + // 性能:记录已对某共享材质设过 renderQueue,避免重复写。 + private readonly HashSet _renderQueueApplied = new HashSet(); + // Shader 属性 ID 缓存(比字符串查找快,且避免每帧字符串)。 + private static readonly int _headColorId = Shader.PropertyToID("_HeadColor"); + private static readonly int _tailColorId = Shader.PropertyToID("_TailColor"); + private static readonly int _moveDirId = Shader.PropertyToID("_MoveDir"); // 材质均衡分配逻辑 private List _cachedEnabledConfigs = new List(); @@ -99,11 +110,15 @@ public class groundParticularController : MonoBehaviour private void Awake() { if (startPoint != null) _originalStartScale = startPoint.localScale; + _sharedPropBlock = new MaterialPropertyBlock(); _pool = new ObjectPool( createFunc: () => { GameObject go = Instantiate(particlePrefab); go.SetActive(false); + // 创建时缓存 Renderer,后续 Emit/Move 复用,避免每颗粒子 GetComponent。 + var r = go.GetComponent(); + if (r != null) _rendererCache[go] = r; return go; }, actionOnGet: (obj) => { @@ -155,10 +170,11 @@ public class groundParticularController : MonoBehaviour // 批量生成 for (int i = 0; i < emitBatchSize; i++) { - // 引入混乱度:随机延迟发射 + // 引入混乱度:随机延迟发射。用协程替代 Invoke(nameof)—— + // 后者每次做字符串反射+分配;协程延迟无字符串开销。 if (chaosRandomDelay > 0) { - Invoke(nameof(DelayedEmit), Random.Range(0f, chaosRandomDelay)); + StartCoroutine(DelayedEmitRoutine(Random.Range(0f, chaosRandomDelay))); } else { @@ -168,11 +184,22 @@ public class groundParticularController : MonoBehaviour } } - private void DelayedEmit() + private System.Collections.IEnumerator DelayedEmitRoutine(float delay) { + if (delay > 0f) yield return new WaitForSeconds(delay); Emit(); } + // 取粒子缓存的 Renderer;未缓存(异常情况)则补取一次。 + private Renderer GetCachedRenderer(GameObject particle) + { + if (particle == null) return null; + if (_rendererCache.TryGetValue(particle, out Renderer r) && r != null) return r; + r = particle.GetComponent(); + if (r != null) _rendererCache[particle] = r; + return r; + } + private void AnalyzeAudio() { if (musicSource == null || !musicSource.isPlaying || !useAudioAnalysis) @@ -233,7 +260,7 @@ public class groundParticularController : MonoBehaviour particle.layer = layer; } - var renderer = particle.GetComponent(); + Renderer renderer = GetCachedRenderer(particle); if (renderer != null) { // 设置渲染层级 @@ -242,11 +269,17 @@ public class groundParticularController : MonoBehaviour if (selectedConfig != null) { - // 使用实例化材质以允许独立修改 RenderQueue - renderer.material = selectedConfig.Value.material; - if (renderQueueOffset != 0) + Material mat = selectedConfig.Value.material; + // 用共享材质(sharedMaterial)避免克隆实例产生 GC / 破坏合批。 + // renderQueue 是全局统一配置(renderQueueOffset),只需对每个材质设一次即可, + // 所有用该材质的粒子渲染队列一致,视觉与原来相同。 + if (renderQueueOffset != 0 && _renderQueueApplied.Add(mat)) { - renderer.material.renderQueue = selectedConfig.Value.material.renderQueue + renderQueueOffset; + mat.renderQueue = mat.renderQueue + renderQueueOffset; + } + if (renderer.sharedMaterial != mat) + { + renderer.sharedMaterial = mat; } } } @@ -310,9 +343,9 @@ public class groundParticularController : MonoBehaviour particle.transform.position = spawnWorldPos; - // 获取材质属性块用于动态修改颜色 (不产生材质实例 GC) - MaterialPropertyBlock propBlock = new MaterialPropertyBlock(); - var renderer = particle.GetComponent(); + // 复用共享属性块(不 new,避免每颗粒子 GC)与缓存的 Renderer。 + MaterialPropertyBlock propBlock = _sharedPropBlock; + Renderer renderer = GetCachedRenderer(particle); while (particle != null && particle.activeInHierarchy) { @@ -346,10 +379,10 @@ public class groundParticularController : MonoBehaviour Color tailColor = config.Value.colorGradient.Evaluate(0f); renderer.GetPropertyBlock(propBlock); - // 对应 Shader 中的属性 - propBlock.SetColor("_HeadColor", headColor); - propBlock.SetColor("_TailColor", tailColor); - propBlock.SetVector("_MoveDir", moveDir); + // 用缓存的属性 ID(避免每帧字符串查找) + propBlock.SetColor(_headColorId, headColor); + propBlock.SetColor(_tailColorId, tailColor); + propBlock.SetVector(_moveDirId, moveDir); renderer.SetPropertyBlock(propBlock); } diff --git a/Assets/scripts/gamePlay_gameplay/network_submit/ArenaRoomService.cs b/Assets/scripts/gamePlay_gameplay/network_submit/ArenaRoomService.cs index b43ab7bd..fa30303c 100644 --- a/Assets/scripts/gamePlay_gameplay/network_submit/ArenaRoomService.cs +++ b/Assets/scripts/gamePlay_gameplay/network_submit/ArenaRoomService.cs @@ -1377,6 +1377,7 @@ namespace GameServer.Client data["display_name"]?.ToString(), data["avatar_url"]?.ToString()); } + Enqueue(() => ApplyHonorUpdate(data)); _socialConnectedTcs?.TrySetResult(true); return; case "unread_count": @@ -1454,6 +1455,11 @@ namespace GameServer.Client Enqueue(() => ApplyPresenceUpdate(presence)); return; } + case "honor_updated": + { + Enqueue(() => ApplyHonorUpdate(data)); + return; + } case "presence_updated": return; case "friend_removed": @@ -2126,13 +2132,169 @@ namespace GameServer.Client entry.friend_name = NetworkManager.ResolveDisplayName(presence.display_name, presence.steam_id, false); entry.friend_avatar = NetworkManager.ResolveAvatarUrl(presence.avatar_url, presence.steam_id); + entry.player_title_id = presence.player_title_id ?? string.Empty; + entry.player_title = presence.player_title ?? string.Empty; entry.online = !string.Equals(presence.status, "OFFLINE", StringComparison.OrdinalIgnoreCase); entry.status = presence.status; UpsertFriend(entry); + ApplyTitleUpdate(presence.steam_id, entry.player_title_id, entry.player_title); OnFriendsListChanged?.Invoke(GetFriendsSnapshot()); } + private void ApplyHonorUpdate(JObject data) + { + if (data == null) + { + return; + } + + string steamId = data["steam_id"]?.ToString(); + if (string.IsNullOrWhiteSpace(steamId)) + { + steamId = NetworkManager.Instance != null ? NetworkManager.Instance.SteamId : string.Empty; + } + + JObject primaryHonor = data["primary_honor"] as JObject; + string titleId = primaryHonor?["honor_key"]?.ToString() ?? data["player_title_id"]?.ToString() ?? string.Empty; + string title = primaryHonor?["honor_name"]?.ToString() ?? data["player_title"]?.ToString() ?? string.Empty; + ApplyTitleUpdate(steamId, titleId, title); + } + + private void ApplyTitleUpdate(string steamId, string titleId, string title) + { + if (string.IsNullOrWhiteSpace(steamId)) + { + return; + } + + string safeTitleId = titleId ?? string.Empty; + string safeTitle = title ?? string.Empty; + bool roomChanged = ApplyTitleToCurrentRoom(steamId, safeTitleId, safeTitle); + bool friendsChanged = ApplyTitleToFriends(steamId, safeTitleId, safeTitle); + bool roomChatChanged = ApplyTitleToMessages(_roomChatMessages, steamId, safeTitleId, safeTitle); + bool worldChatChanged = ApplyTitleToMessages(_worldChatMessages, steamId, safeTitleId, safeTitle); + bool privateChatChanged = false; + + foreach (List messages in _privateChatMessages.Values) + { + privateChatChanged |= ApplyTitleToMessages(messages, steamId, safeTitleId, safeTitle); + } + + if (roomChanged) + { + OnRoomSnapshotChanged?.Invoke(CurrentRoom); + } + + if (friendsChanged) + { + OnFriendsListChanged?.Invoke(GetFriendsSnapshot()); + } + + if (roomChatChanged) + { + OnRoomChatMessagesChanged?.Invoke(GetRoomChatMessages()); + } + + if (worldChatChanged) + { + OnWorldChatMessagesChanged?.Invoke(GetWorldChatMessages()); + } + + if (privateChatChanged) + { + foreach (string partnerId in _privateChatMessages.Keys.ToList()) + { + OnPrivateChatMessagesChanged?.Invoke(partnerId, GetPrivateChatMessages(partnerId)); + } + } + } + + private bool ApplyTitleToCurrentRoom(string steamId, string titleId, string title) + { + if (CurrentRoom == null || CurrentRoom.participants == null) + { + return false; + } + + bool changed = false; + foreach (ArenaRoomParticipant participant in CurrentRoom.participants) + { + if (participant == null || !string.Equals(participant.steam_id, steamId, StringComparison.Ordinal)) + { + continue; + } + + if (!string.Equals(participant.player_title_id ?? string.Empty, titleId, StringComparison.Ordinal)) + { + participant.player_title_id = titleId; + changed = true; + } + + if (!string.Equals(participant.player_title ?? string.Empty, title, StringComparison.Ordinal)) + { + participant.player_title = title; + changed = true; + } + } + + return changed; + } + + private bool ApplyTitleToFriends(string steamId, string titleId, string title) + { + if (!_friends.TryGetValue(steamId, out SocialFriendEntry friend) || friend == null) + { + return false; + } + + bool changed = false; + if (!string.Equals(friend.player_title_id ?? string.Empty, titleId, StringComparison.Ordinal)) + { + friend.player_title_id = titleId; + changed = true; + } + + if (!string.Equals(friend.player_title ?? string.Empty, title, StringComparison.Ordinal)) + { + friend.player_title = title; + changed = true; + } + + return changed; + } + + private static bool ApplyTitleToMessages(IEnumerable messages, string steamId, string titleId, string title) + { + if (messages == null) + { + return false; + } + + bool changed = false; + foreach (ArenaRoomChatMessage message in messages) + { + if (message == null || !string.Equals(GetChatMessageSteamId(message), steamId, StringComparison.Ordinal)) + { + continue; + } + + if (!string.Equals(message.player_title_id ?? string.Empty, titleId, StringComparison.Ordinal)) + { + message.player_title_id = titleId; + changed = true; + } + + if (!string.Equals(message.player_title ?? string.Empty, title, StringComparison.Ordinal)) + { + message.player_title = title; + changed = true; + } + } + + return changed; + } + private void RemoveFriend(string steamId) { if (string.IsNullOrWhiteSpace(steamId)) @@ -2947,6 +3109,16 @@ namespace GameServer.Client participant.avatar_url = existing.avatar_url; } + if (string.IsNullOrWhiteSpace(participant.player_title_id)) + { + participant.player_title_id = existing.player_title_id; + } + + if (string.IsNullOrWhiteSpace(participant.player_title)) + { + participant.player_title = existing.player_title; + } + if (participant.join_order <= 0) { participant.join_order = existing.join_order; diff --git a/Assets/scripts/gamePlay_gameplay/network_submit/MessageTypes.cs b/Assets/scripts/gamePlay_gameplay/network_submit/MessageTypes.cs index 07af7606..9b17af70 100644 --- a/Assets/scripts/gamePlay_gameplay/network_submit/MessageTypes.cs +++ b/Assets/scripts/gamePlay_gameplay/network_submit/MessageTypes.cs @@ -107,6 +107,22 @@ namespace GameServer.Client [JsonProperty("total_plays")] public int total_plays; [JsonProperty("actime")] public string actime; [JsonProperty("u_reg_id")] public int u_reg_id; + [JsonProperty("player_title_id")] public string player_title_id; + [JsonProperty("player_title")] public string player_title; + [JsonProperty("primary_honor")] public HonorData primary_honor; + } + + [Serializable] + public class HonorData + { + [JsonProperty("id")] public int id; + [JsonProperty("honor_key")] public string honor_key; + [JsonProperty("honor_name")] public string honor_name; + [JsonProperty("honor_desc")] public string honor_desc; + [JsonProperty("honor_tier")] public string honor_tier; + [JsonProperty("granted_by")] public string granted_by; + [JsonProperty("granted_at")] public string granted_at; + [JsonProperty("expires_at")] public string expires_at; } [Serializable] @@ -285,6 +301,8 @@ namespace GameServer.Client [JsonProperty("uid")] public int uid; [JsonProperty("display_name")] public string display_name; [JsonProperty("avatar_url")] public string avatar_url; + [JsonProperty("player_title_id")] public string player_title_id; + [JsonProperty("player_title")] public string player_title; [JsonProperty("is_host")] public bool is_host; [JsonProperty("is_ready")] public bool is_ready; [JsonProperty("join_order")] public int join_order; @@ -337,6 +355,7 @@ namespace GameServer.Client [JsonProperty("receiver_id")] public string receiver_id; [JsonProperty("uid")] public int uid; [JsonProperty("display_name")] public string display_name; + [JsonProperty("player_title_id")] public string player_title_id; [JsonProperty("player_title")] public string player_title; [JsonProperty("avatar_url")] public string avatar_url; [JsonProperty("content")] public string content; @@ -371,6 +390,8 @@ namespace GameServer.Client [JsonProperty("uid")] public int uid; [JsonProperty("friend_name")] public string friend_name; [JsonProperty("friend_avatar")] public string friend_avatar; + [JsonProperty("player_title_id")] public string player_title_id; + [JsonProperty("player_title")] public string player_title; [JsonProperty("online")] public bool online; [JsonProperty("status")] public string status; [JsonProperty("since")] public string since; @@ -476,6 +497,8 @@ namespace GameServer.Client [JsonProperty("uid")] public int uid; [JsonProperty("display_name")] public string display_name; [JsonProperty("avatar_url")] public string avatar_url; + [JsonProperty("player_title_id")] public string player_title_id; + [JsonProperty("player_title")] public string player_title; [JsonProperty("status")] public string status; } diff --git a/Assets/scripts/gamePlay_gameplay/network_submit/NetworkManager.cs b/Assets/scripts/gamePlay_gameplay/network_submit/NetworkManager.cs index 6eda8fb9..55db3227 100644 --- a/Assets/scripts/gamePlay_gameplay/network_submit/NetworkManager.cs +++ b/Assets/scripts/gamePlay_gameplay/network_submit/NetworkManager.cs @@ -366,6 +366,7 @@ public class NetworkManager : MonoBehaviour } ProfileData data = await GetJson(BuildApiUrl($"/api/profile/{targetSteamId}"), CancellationToken.None); + NormalizeProfileTitle(data); CacheIdentity(targetSteamId, data != null ? data.display_name : null, data != null ? data.avatar_url : null); return data; } @@ -439,11 +440,35 @@ public class NetworkManager : MonoBehaviour } ProfileData data = await GetJson(BuildApiUrl($"/api/players/uid/{uid}"), CancellationToken.None); + NormalizeProfileTitle(data); string identitySteamId = data != null ? data.steam_id : null; CacheIdentity(identitySteamId, data != null ? data.display_name : null, data != null ? data.avatar_url : null); return data; } + private static void NormalizeProfileTitle(ProfileData data) + { + if (data == null) + { + return; + } + + if (data.primary_honor == null) + { + return; + } + + if (string.IsNullOrWhiteSpace(data.player_title_id)) + { + data.player_title_id = data.primary_honor.honor_key; + } + + if (string.IsNullOrWhiteSpace(data.player_title)) + { + data.player_title = data.primary_honor.honor_name; + } + } + public async Task ImportSteamFriends(IEnumerable steamFriends) { if (OnlineModeSettings.IsLocalOnlyMode) diff --git a/Assets/scripts/localization/LocalizationRuntimeBootstrap.cs b/Assets/scripts/localization/LocalizationRuntimeBootstrap.cs index db7de90f..cd6acaf2 100644 --- a/Assets/scripts/localization/LocalizationRuntimeBootstrap.cs +++ b/Assets/scripts/localization/LocalizationRuntimeBootstrap.cs @@ -39,6 +39,9 @@ public class LocalizationRuntimeBootstrap : MonoBehaviour private void Start() { + // 引擎主循环已运行,此处安全地完成 Localization(Addressables)初始化—— + // 绝不能在 BeforeSceneLoad 的 Bootstrap() 里同步等它(会死锁)。 + LocalizationService.EnsureLocalizationSettingsInitialized(); StartCoroutine(ApplyLocalizationDeferred()); } diff --git a/Assets/scripts/localization/LocalizationService.cs b/Assets/scripts/localization/LocalizationService.cs index b3b24cb5..616a954d 100644 --- a/Assets/scripts/localization/LocalizationService.cs +++ b/Assets/scripts/localization/LocalizationService.cs @@ -84,6 +84,9 @@ public static class LocalizationService return results; } + // Addressables/LocalizationSettings 是否已完成初始化(与基础初始化分离)。 + private static bool _settingsInitialized; + public static void EnsureInitialized() { if (_initialized) @@ -98,14 +101,41 @@ public static class LocalizationService return; } + // 只做"安全的同步基础初始化":语言偏好 + 运行时回退包(从 StreamingAssets 读)。 + // Get()/TryGet() 会先查表、查不到再走这些回退包,所以此时本地化已可用。 _currentLanguageCode = NormalizeLanguageCode(PlayerPrefs.GetString(LanguagePrefKey, ResolveStartupLanguageCode())); PlayerPrefs.SetString(LanguagePrefKey, _currentLanguageCode); PlayerPrefs.Save(); LoadRuntimeFallbackPack(DefaultLanguageCode); LoadRuntimeFallbackPack("en-US"); + _initialized = true; + } + + // 关键(修复启动死锁):绝不在此处同步 WaitForCompletion 等 Addressables 初始化。 + // 该方法可能在 [RuntimeInitializeOnLoadMethod(BeforeSceneLoad)] 阶段被调用, + // 此时引擎主循环尚未运行,WaitForCompletion 会自旋泵送 Addressables 异步链, + // 而其 continuation 需要主线程/尚未就绪的子系统 → WaitOnAddress 永远等不到信号而死锁。 + // 改为把 LocalizationSettings 初始化推迟到引擎就绪后(EnsureLocalizationSettingsInitialized)。 + } + + /// + /// 初始化 Unity Localization(Addressables 表数据库)。必须在引擎主循环运行后调用 + /// (如首帧协程 / 场景加载后),不能在 BeforeSceneLoad 同步阶段调用,否则死锁。 + /// 未完成前,本地化走运行时回退包,不影响 Get() 可用性。 + /// + public static void EnsureLocalizationSettingsInitialized() + { + if (_settingsInitialized) return; + + lock (SyncRoot) + { + if (_settingsInitialized) return; + if (!_initialized) EnsureInitialized(); + if (LocalizationSettings.HasSettings) { + // 引擎已就绪,此时 WaitForCompletion 安全(异步链能被正常泵送完成)。 LocalizationSettings.InitializeSynchronously = true; var init = LocalizationSettings.InitializationOperation; if (!init.IsDone) @@ -123,13 +153,15 @@ public static class LocalizationService ApplySelectedLocale(_currentLanguageCode, savePreference: true, notifyListeners: false); } - _initialized = true; + _settingsInitialized = true; } } public static void SetLanguage(string languageCode) { EnsureInitialized(); + // 运行时切换语言由 UI 触发(引擎已就绪),此处确保 Localization 设置已初始化,安全。 + EnsureLocalizationSettingsInitialized(); string normalized = NormalizeLanguageCode(languageCode); if (string.Equals(_currentLanguageCode, normalized, StringComparison.OrdinalIgnoreCase)) { diff --git a/Assets/scripts/roomSystem/globalChatSystem.cs b/Assets/scripts/roomSystem/globalChatSystem.cs index fc461eaa..395f7e95 100644 --- a/Assets/scripts/roomSystem/globalChatSystem.cs +++ b/Assets/scripts/roomSystem/globalChatSystem.cs @@ -943,8 +943,10 @@ public class globalChatSystem : MonoBehaviour playerMessagePrefab controller = instance.GetComponentInChildren(); if (controller != null) { + string titleId = !string.IsNullOrWhiteSpace(message.player_title_id) ? message.player_title_id : string.Empty; string title = !string.IsNullOrWhiteSpace(message.player_title) ? message.player_title : string.Empty; - controller.Bind(senderSteamId, avatarUrl, displayName, title, message.content, bubbleColor); + PlayerTitleResolver.ResolvedTitle resolvedTitle = PlayerTitleResolver.Resolve(titleId, title); + controller.Bind(senderSteamId, avatarUrl, displayName, resolvedTitle.titleId, resolvedTitle.titleText, message.content, bubbleColor); } return instance; diff --git a/Assets/scripts/roomSystem/playerMessagePrefab/PlayerTitleLibrary.cs b/Assets/scripts/roomSystem/playerMessagePrefab/PlayerTitleLibrary.cs new file mode 100644 index 00000000..e9d7a9d0 --- /dev/null +++ b/Assets/scripts/roomSystem/playerMessagePrefab/PlayerTitleLibrary.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +[CreateAssetMenu(fileName = "PlayerTitleLibrary", menuName = "Bansonic/Player Title Library")] +public class PlayerTitleLibrary : ScriptableObject +{ + [Serializable] + public class PlayerTitleEntry + { + public string titleId; + public Sprite titleSprite; + public string chineseName; + public string englishName; + } + + [SerializeField] private List titles = new List(); + + private Dictionary lookup; + + public bool TryGetTitle(string key, out PlayerTitleEntry entry) + { + EnsureLookup(); + + entry = null; + if (string.IsNullOrWhiteSpace(key)) + { + return false; + } + + return lookup.TryGetValue(NormalizeKey(key), out entry) && entry != null; + } + + private void EnsureLookup() + { + if (lookup != null) + { + return; + } + + lookup = new Dictionary(StringComparer.OrdinalIgnoreCase); + for (int i = 0; i < titles.Count; i++) + { + PlayerTitleEntry entry = titles[i]; + if (entry == null) + { + continue; + } + + AddLookup(entry.titleId, entry); + AddLookup(entry.chineseName, entry); + AddLookup(entry.englishName, entry); + } + } + + private void AddLookup(string key, PlayerTitleEntry entry) + { + string normalized = NormalizeKey(key); + if (!string.IsNullOrEmpty(normalized) && !lookup.ContainsKey(normalized)) + { + lookup.Add(normalized, entry); + } + } + + private static string NormalizeKey(string key) + { + return string.IsNullOrWhiteSpace(key) ? string.Empty : key.Trim(); + } +} diff --git a/Assets/scripts/roomSystem/playerMessagePrefab/PlayerTitleLibrary.cs.meta b/Assets/scripts/roomSystem/playerMessagePrefab/PlayerTitleLibrary.cs.meta new file mode 100644 index 00000000..9d51baa6 --- /dev/null +++ b/Assets/scripts/roomSystem/playerMessagePrefab/PlayerTitleLibrary.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a77a5d11c6274a94bb16e9d477a17301 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/scripts/roomSystem/playerMessagePrefab/PlayerTitleResolver.cs b/Assets/scripts/roomSystem/playerMessagePrefab/PlayerTitleResolver.cs new file mode 100644 index 00000000..4133775f --- /dev/null +++ b/Assets/scripts/roomSystem/playerMessagePrefab/PlayerTitleResolver.cs @@ -0,0 +1,66 @@ +using UnityEngine; + +public static class PlayerTitleResolver +{ + private const string PlayerTitleLibraryResourcePath = "so/player_titles/PlayerTitleLibrary"; + + private static PlayerTitleLibrary cachedTitleLibrary; + + public readonly struct ResolvedTitle + { + public readonly string titleId; + public readonly string titleText; + public readonly Sprite titleSprite; + + public bool HasSprite => titleSprite != null; + public bool HasText => !string.IsNullOrWhiteSpace(titleText); + public bool HasAny => HasSprite || HasText; + + public ResolvedTitle(string titleId, string titleText, Sprite titleSprite) + { + this.titleId = titleId ?? string.Empty; + this.titleText = titleText ?? string.Empty; + this.titleSprite = titleSprite; + } + } + + public static ResolvedTitle Resolve(string titleId, string fallbackText) + { + string safeTitleId = string.IsNullOrWhiteSpace(titleId) ? string.Empty : titleId.Trim(); + string safeFallbackText = string.IsNullOrWhiteSpace(fallbackText) ? string.Empty : fallbackText.Trim(); + Sprite sprite = null; + string resolvedText = safeFallbackText; + + PlayerTitleLibrary library = GetTitleLibrary(); + if (library != null && !string.IsNullOrEmpty(safeTitleId) + && library.TryGetTitle(safeTitleId, out PlayerTitleLibrary.PlayerTitleEntry entry) + && entry != null) + { + sprite = entry.titleSprite; + + if (string.IsNullOrWhiteSpace(resolvedText)) + { + resolvedText = !string.IsNullOrWhiteSpace(entry.chineseName) + ? entry.chineseName.Trim() + : (!string.IsNullOrWhiteSpace(entry.englishName) ? entry.englishName.Trim() : safeTitleId); + } + } + + return new ResolvedTitle(safeTitleId, resolvedText, sprite); + } + + public static Sprite ResolveSprite(string titleId) + { + return Resolve(titleId, string.Empty).titleSprite; + } + + public static PlayerTitleLibrary GetTitleLibrary() + { + if (cachedTitleLibrary == null) + { + cachedTitleLibrary = Resources.Load(PlayerTitleLibraryResourcePath); + } + + return cachedTitleLibrary; + } +} diff --git a/Assets/scripts/roomSystem/playerMessagePrefab/PlayerTitleResolver.cs.meta b/Assets/scripts/roomSystem/playerMessagePrefab/PlayerTitleResolver.cs.meta new file mode 100644 index 00000000..7e1f488c --- /dev/null +++ b/Assets/scripts/roomSystem/playerMessagePrefab/PlayerTitleResolver.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: fa6b1900d3d4e05499405619dcf2ff36 \ No newline at end of file diff --git a/Assets/scripts/roomSystem/playerMessagePrefab/playerMessagePrefab.cs b/Assets/scripts/roomSystem/playerMessagePrefab/playerMessagePrefab.cs index 514b36a6..6c708631 100644 --- a/Assets/scripts/roomSystem/playerMessagePrefab/playerMessagePrefab.cs +++ b/Assets/scripts/roomSystem/playerMessagePrefab/playerMessagePrefab.cs @@ -13,6 +13,7 @@ using Steamworks; public class playerMessagePrefab : MonoBehaviour { [SerializeField] Image playerProfile; + [SerializeField] Image playerTitleImage; [SerializeField] Text playerTitle; [SerializeField] Text playerName; [SerializeField] Text messageText; @@ -48,14 +49,16 @@ public class playerMessagePrefab : MonoBehaviour } public void Bind(string steamId, string avatarUrl, string displayName, string title, string content, Color bubbleColor) + { + Bind(steamId, avatarUrl, displayName, string.Empty, title, content, bubbleColor); + } + + public void Bind(string steamId, string avatarUrl, string displayName, string titleId, string title, string content, Color bubbleColor) { _boundSteamId = steamId ?? string.Empty; _boundAvatarUrl = avatarUrl ?? string.Empty; - if (playerTitle != null) - { - playerTitle.text = string.IsNullOrWhiteSpace(title) ? string.Empty : title; - } + BindPlayerTitle(titleId, title); if (playerName != null) { @@ -79,6 +82,51 @@ public class playerMessagePrefab : MonoBehaviour } } + private void BindPlayerTitle(string titleId, string title) + { + EnsureTitleImageReference(); + + PlayerTitleResolver.ResolvedTitle resolvedTitle = PlayerTitleResolver.Resolve(titleId, title); + bool hasTitleSprite = resolvedTitle.HasSprite; + bool hasTitleText = resolvedTitle.HasText; + + if (playerTitleImage != null) + { + playerTitleImage.sprite = resolvedTitle.titleSprite; + playerTitleImage.enabled = hasTitleSprite; + playerTitleImage.gameObject.SetActive(hasTitleSprite); + if (!hasTitleSprite) + { + playerTitleImage.sprite = null; + } + } + + if (playerTitle != null) + { + playerTitle.text = !hasTitleSprite && hasTitleText ? resolvedTitle.titleText : string.Empty; + playerTitle.gameObject.SetActive(!hasTitleSprite && hasTitleText); + } + } + + private void EnsureTitleImageReference() + { + if (playerTitleImage != null) + { + return; + } + + Transform[] children = GetComponentsInChildren(true); + for (int i = 0; i < children.Length; i++) + { + Transform child = children[i]; + if (child != null && child.name == "玩家称号image") + { + playerTitleImage = child.GetComponent(); + return; + } + } + } + public static async Task WarmAvatarCacheAsync(string steamId, string avatarUrl) { if (string.IsNullOrWhiteSpace(steamId) && string.IsNullOrWhiteSpace(avatarUrl)) diff --git a/Assets/scripts/roomSystem/playerMessagePrefab/playerMessagePrefab.prefab b/Assets/scripts/roomSystem/playerMessagePrefab/playerMessagePrefab.prefab index 2c2e1ecc..b453372c 100644 --- a/Assets/scripts/roomSystem/playerMessagePrefab/playerMessagePrefab.prefab +++ b/Assets/scripts/roomSystem/playerMessagePrefab/playerMessagePrefab.prefab @@ -363,7 +363,7 @@ RectTransform: 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: 63.484863} + m_AnchoredPosition: {x: 0, y: 62.853333} m_SizeDelta: {x: 40, y: 40} m_Pivot: {x: 0.5, y: 1} --- !u!222 &225269693782171328 @@ -439,7 +439,7 @@ RectTransform: m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 1} m_AnchorMax: {x: 0, y: 1} - m_AnchoredPosition: {x: 118, y: -2} + m_AnchoredPosition: {x: 243, y: -2} m_SizeDelta: {x: 116, y: 20} m_Pivot: {x: 0, y: 0.5} --- !u!222 &2431985745475878602 @@ -533,7 +533,7 @@ RectTransform: m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 1} m_AnchorMax: {x: 0, y: 1} - m_AnchoredPosition: {x: 128, y: -63.484863} + m_AnchoredPosition: {x: 128, y: -62.853333} m_SizeDelta: {x: 256, y: 0} m_Pivot: {x: 0.5, y: 0.5} --- !u!114 &5490276556566493605 @@ -576,6 +576,42 @@ MonoBehaviour: m_EditorClassIdentifier: m_HorizontalFit: 0 m_VerticalFit: 2 +--- !u!1 &3193694844664355718 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5657557821638488651} + m_Layer: 0 + m_Name: GameObject + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &5657557821638488651 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3193694844664355718} + 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: 9105474240358439909} + m_Father: {fileID: 4409505319181468130} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 178, y: 3} + m_SizeDelta: {x: 120, y: 30} + m_Pivot: {x: 0.5, y: 0.5} --- !u!1 &3794995701616312333 GameObject: m_ObjectHideFlags: 0 @@ -616,7 +652,7 @@ RectTransform: m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 1} m_AnchoredPosition: {x: 0, y: -143.99913} - m_SizeDelta: {x: 0, y: 63.484863} + m_SizeDelta: {x: 0, y: 62.853333} m_Pivot: {x: 0.5, y: 1} --- !u!114 &6728628998878729785 MonoBehaviour: @@ -631,6 +667,7 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: playerProfile: {fileID: 5695022340294760842} + playerTitleImage: {fileID: 9105474240358439911} playerTitle: {fileID: 5888169934928062198} playerName: {fileID: 7841361681403526646} messageText: {fileID: 5951147724285136445} @@ -691,7 +728,7 @@ MonoBehaviour: m_MinWidth: -1 m_MinHeight: -1 m_PreferredWidth: -1 - m_PreferredHeight: 63.484863 + m_PreferredHeight: 62.853333 m_FlexibleWidth: -1 m_FlexibleHeight: -1 m_LayoutPriority: 2 @@ -743,6 +780,7 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: - {fileID: 423933864671952839} + - {fileID: 5657557821638488651} - {fileID: 8469056815856914825} m_Father: {fileID: 4696069065802349809} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} @@ -905,3 +943,99 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: maxPreferredWidth: 810 +--- !u!1 &9105474240358439908 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 9105474240358439909} + - component: {fileID: 9105474240358439910} + - component: {fileID: 9105474240358439911} + - component: {fileID: 9105474240358439912} + m_Layer: 0 + m_Name: playerTitleImage + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &9105474240358439909 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9105474240358439908} + 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: 5657557821638488651} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -60, y: -7} + m_SizeDelta: {x: 120, y: 30} + m_Pivot: {x: 0, y: 0.5} +--- !u!222 &9105474240358439910 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9105474240358439908} + m_CullTransparentMesh: 1 +--- !u!114 &9105474240358439911 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9105474240358439908} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 0 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 1 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!114 &9105474240358439912 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9105474240358439908} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 306cc8c2b49d7114eaa3623786fc2126, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreLayout: 0 + m_MinWidth: -1 + m_MinHeight: -1 + m_PreferredWidth: 64 + m_PreferredHeight: 20 + m_FlexibleWidth: -1 + m_FlexibleHeight: -1 + m_LayoutPriority: 1 diff --git a/Assets/scripts/roomSystem/playerMessagePrefab/playerMessagePrefab_self.prefab b/Assets/scripts/roomSystem/playerMessagePrefab/playerMessagePrefab_self.prefab index 28d9be26..56f40078 100644 --- a/Assets/scripts/roomSystem/playerMessagePrefab/playerMessagePrefab_self.prefab +++ b/Assets/scripts/roomSystem/playerMessagePrefab/playerMessagePrefab_self.prefab @@ -139,6 +139,42 @@ MonoBehaviour: m_FlexibleWidth: -1 m_FlexibleHeight: -1 m_LayoutPriority: 1 +--- !u!1 &1187413930585374572 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 9034680032282737475} + m_Layer: 0 + m_Name: GameObject + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &9034680032282737475 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1187413930585374572} + 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: 9105474240358439909} + m_Father: {fileID: 4409505319181468130} + 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: 120, y: 30} + m_Pivot: {x: 0.5, y: 0.5} --- !u!1 &1296804937323052155 GameObject: m_ObjectHideFlags: 0 @@ -174,7 +210,7 @@ RectTransform: m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 1} m_AnchorMax: {x: 0, y: 1} - m_AnchoredPosition: {x: 121, y: -2} + m_AnchoredPosition: {x: 246, y: -2} m_SizeDelta: {x: 113, y: 20} m_Pivot: {x: 0, y: 0.5} --- !u!222 &6919442420098058668 @@ -363,7 +399,7 @@ RectTransform: 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: 62.501953} + m_AnchoredPosition: {x: 0, y: 62.500916} m_SizeDelta: {x: 40, y: 40} m_Pivot: {x: 0.5, y: 1} --- !u!222 &225269693782171328 @@ -533,7 +569,7 @@ RectTransform: m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 1} m_AnchorMax: {x: 0, y: 1} - m_AnchoredPosition: {x: 3840, y: -62.501953} + m_AnchoredPosition: {x: 2560, y: -62.500916} m_SizeDelta: {x: 256, y: 0} m_Pivot: {x: 1, y: 0.5} --- !u!114 &5490276556566493605 @@ -616,7 +652,7 @@ RectTransform: m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 1} m_AnchoredPosition: {x: 0, y: -143.99913} - m_SizeDelta: {x: 0, y: 62.501953} + m_SizeDelta: {x: 0, y: 62.500916} m_Pivot: {x: 0.5, y: 1} --- !u!114 &6728628998878729785 MonoBehaviour: @@ -631,6 +667,7 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: playerProfile: {fileID: 5695022340294760842} + playerTitleImage: {fileID: 9105474240358439911} playerTitle: {fileID: 5888169934928062198} playerName: {fileID: 7841361681403526646} messageText: {fileID: 5951147724285136445} @@ -691,7 +728,7 @@ MonoBehaviour: m_MinWidth: -1 m_MinHeight: -1 m_PreferredWidth: -1 - m_PreferredHeight: 62.501953 + m_PreferredHeight: 62.500916 m_FlexibleWidth: -1 m_FlexibleHeight: -1 m_LayoutPriority: 2 @@ -743,6 +780,7 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: - {fileID: 8469056815856914825} + - {fileID: 9034680032282737475} - {fileID: 423933864671952839} m_Father: {fileID: 4696069065802349809} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} @@ -905,3 +943,99 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: maxPreferredWidth: 810 +--- !u!1 &9105474240358439908 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 9105474240358439909} + - component: {fileID: 9105474240358439910} + - component: {fileID: 9105474240358439911} + - component: {fileID: 9105474240358439912} + m_Layer: 0 + m_Name: playerTitleImage + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &9105474240358439909 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9105474240358439908} + 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: 9034680032282737475} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -60, y: -7} + m_SizeDelta: {x: 120, y: 30} + m_Pivot: {x: 0, y: 0.5} +--- !u!222 &9105474240358439910 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9105474240358439908} + m_CullTransparentMesh: 1 +--- !u!114 &9105474240358439911 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9105474240358439908} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 0 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 1 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!114 &9105474240358439912 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9105474240358439908} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 306cc8c2b49d7114eaa3623786fc2126, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreLayout: 0 + m_MinWidth: -1 + m_MinHeight: -1 + m_PreferredWidth: 64 + m_PreferredHeight: 20 + m_FlexibleWidth: -1 + m_FlexibleHeight: -1 + m_LayoutPriority: 1 diff --git a/Assets/scripts/roomSystem/roomDetails.cs b/Assets/scripts/roomSystem/roomDetails.cs index 4ca5302b..94ae78dc 100644 --- a/Assets/scripts/roomSystem/roomDetails.cs +++ b/Assets/scripts/roomSystem/roomDetails.cs @@ -814,7 +814,11 @@ public class roomDetails : MonoBehaviour if (controller != null) { string avatarUrl = GameServer.Client.NetworkManager.ResolveAvatarUrl(message.avatar_url, senderSteamId); - controller.Bind(senderSteamId, avatarUrl, displayName, title, message.content, bubbleColor); + string titleId = message != null && !string.IsNullOrWhiteSpace(message.player_title_id) + ? message.player_title_id + : string.Empty; + PlayerTitleResolver.ResolvedTitle resolvedTitle = PlayerTitleResolver.Resolve(titleId, title); + controller.Bind(senderSteamId, avatarUrl, displayName, resolvedTitle.titleId, resolvedTitle.titleText, message.content, bubbleColor); } UI_OrderedEntryAnimator.PlayFadeOnly(instance, Mathf.Max(0, messageParent.childCount - 1), 0.14f, 0.01f, true); diff --git a/Assets/scripts/roomSystem/roomDetails.prefab b/Assets/scripts/roomSystem/roomDetails.prefab index ee00d74d..cc5d2cb6 100644 --- a/Assets/scripts/roomSystem/roomDetails.prefab +++ b/Assets/scripts/roomSystem/roomDetails.prefab @@ -294,7 +294,7 @@ RectTransform: m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: -413.0012, y: -70.99978} + m_AnchoredPosition: {x: 0, y: 0} m_SizeDelta: {x: 100, y: 100} m_Pivot: {x: 0.5, y: 0.5} --- !u!114 &5886067044144465411 diff --git a/ProjectSettings/ProjectSettings.asset b/ProjectSettings/ProjectSettings.asset index 7f03dc39..8557bc15 100644 --- a/ProjectSettings/ProjectSettings.asset +++ b/ProjectSettings/ProjectSettings.asset @@ -142,7 +142,7 @@ PlayerSettings: loadStoreDebugModeEnabled: 0 visionOSBundleVersion: 1.0 tvOSBundleVersion: 1.0 - bundleVersion: 1.0.01 + bundleVersion: 1.0.02 preloadedAssets: - {fileID: 11400000, guid: 87fa00178d138a349884b45f12225fea, type: 2} metroInputSource: 0 diff --git a/gameServerPython b/gameServerPython index addc5fa5..f102c208 160000 --- a/gameServerPython +++ b/gameServerPython @@ -1 +1 @@ -Subproject commit addc5fa5715a04dac5a8bfe9106c83a903ee0d29 +Subproject commit f102c208a45698ead780c3c3037e9d3445ad2487