From ef015c666597301a47d8f50ebd03d8ba15b27e06 Mon Sep 17 00:00:00 2001 From: Mausham Date: Thu, 18 Dec 2025 12:32:06 -0800 Subject: [PATCH] added UI dodging nozzle on phones --- Assets/CrystalFramework.meta | 8 + Assets/CrystalFramework/Utility.meta | 8 + Assets/CrystalFramework/Utility/SafeArea.cs | 233 ++++++++++++++++++ .../CrystalFramework/Utility/SafeArea.cs.meta | 18 ++ .../Core/Contracts/ILeaderBoardController.cs | 5 +- .../DarkMatter/Code/Core/CoreAssembly.asmdef | 3 +- .../DarkMatter/Code/Domain/GenericPool.meta | 8 + .../Code/Domain/GenericPool/ObjectPool.cs | 57 +++++ .../Domain/GenericPool/ObjectPool.cs.meta | 2 + .../LeaderBoard/LeaderBoardInitializer.cs | 3 +- .../Code/Presentation/Platforms/Platform.cs | 1 - .../Presentation/PresentationAssembly.asmdef | 3 +- .../Presentation/UI/DeathScreenController.cs | 2 +- .../Presentation/UI/GameScreenController.cs | 1 - .../Presentation/UI/LeaderBoardController.cs | 13 +- .../Code/Presentation/UI/LeaderBoardView.cs | 6 + .../Presentation/UI/StartScreenController.cs | 1 - Assets/Resources/Materials/Player.mat | 4 +- Assets/Resources/Materials/death.mat | 2 +- Assets/Resources/Materials/safe.mat | 2 +- Assets/Scenes/GameScene.unity | 163 +++++++++++- Packages/manifest.json | 1 + Packages/packages-lock.json | 7 + ProjectSettings/ProjectSettings.asset | 5 +- 24 files changed, 534 insertions(+), 22 deletions(-) create mode 100644 Assets/CrystalFramework.meta create mode 100644 Assets/CrystalFramework/Utility.meta create mode 100644 Assets/CrystalFramework/Utility/SafeArea.cs create mode 100644 Assets/CrystalFramework/Utility/SafeArea.cs.meta create mode 100644 Assets/DarkMatter/Code/Domain/GenericPool.meta create mode 100644 Assets/DarkMatter/Code/Domain/GenericPool/ObjectPool.cs create mode 100644 Assets/DarkMatter/Code/Domain/GenericPool/ObjectPool.cs.meta diff --git a/Assets/CrystalFramework.meta b/Assets/CrystalFramework.meta new file mode 100644 index 0000000..c061fcf --- /dev/null +++ b/Assets/CrystalFramework.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e8572b3145bb59e4fbe17b91176d1013 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/CrystalFramework/Utility.meta b/Assets/CrystalFramework/Utility.meta new file mode 100644 index 0000000..0136c5b --- /dev/null +++ b/Assets/CrystalFramework/Utility.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b45c7b45c9256a745978ed0eb3cf5663 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/CrystalFramework/Utility/SafeArea.cs b/Assets/CrystalFramework/Utility/SafeArea.cs new file mode 100644 index 0000000..7ac1a57 --- /dev/null +++ b/Assets/CrystalFramework/Utility/SafeArea.cs @@ -0,0 +1,233 @@ +using UnityEngine; + +namespace Crystal +{ + /// + /// Safe area implementation for notched mobile devices. Usage: + /// (1) Add this component to the top level of any GUI panel. + /// (2) If the panel uses a full screen background image, then create an immediate child and put the component on that instead, with all other elements childed below it. + /// This will allow the background image to stretch to the full extents of the screen behind the notch, which looks nicer. + /// (3) For other cases that use a mixture of full horizontal and vertical background stripes, use the Conform X & Y controls on separate elements as needed. + /// + public class SafeArea : MonoBehaviour + { + #region Simulations + /// + /// Simulation device that uses safe area due to a physical notch or software home bar. For use in Editor only. + /// + public enum SimDevice + { + /// + /// Don't use a simulated safe area - GUI will be full screen as normal. + /// + None, + /// + /// Simulate the iPhone X and Xs (identical safe areas). + /// + iPhoneX, + /// + /// Simulate the iPhone Xs Max and XR (identical safe areas). + /// + iPhoneXsMax, + /// + /// Simulate the Google Pixel 3 XL using landscape left. + /// + Pixel3XL_LSL, + /// + /// Simulate the Google Pixel 3 XL using landscape right. + /// + Pixel3XL_LSR + } + + /// + /// Simulation mode for use in editor only. This can be edited at runtime to toggle between different safe areas. + /// + public static SimDevice Sim = SimDevice.None; + + /// + /// Normalised safe areas for iPhone X with Home indicator (ratios are identical to Xs, 11 Pro). Absolute values: + /// PortraitU x=0, y=102, w=1125, h=2202 on full extents w=1125, h=2436; + /// PortraitD x=0, y=102, w=1125, h=2202 on full extents w=1125, h=2436 (not supported, remains in Portrait Up); + /// LandscapeL x=132, y=63, w=2172, h=1062 on full extents w=2436, h=1125; + /// LandscapeR x=132, y=63, w=2172, h=1062 on full extents w=2436, h=1125. + /// Aspect Ratio: ~19.5:9. + /// + Rect[] NSA_iPhoneX = new Rect[] + { + new Rect (0f, 102f / 2436f, 1f, 2202f / 2436f), // Portrait + new Rect (132f / 2436f, 63f / 1125f, 2172f / 2436f, 1062f / 1125f) // Landscape + }; + + /// + /// Normalised safe areas for iPhone Xs Max with Home indicator (ratios are identical to XR, 11, 11 Pro Max). Absolute values: + /// PortraitU x=0, y=102, w=1242, h=2454 on full extents w=1242, h=2688; + /// PortraitD x=0, y=102, w=1242, h=2454 on full extents w=1242, h=2688 (not supported, remains in Portrait Up); + /// LandscapeL x=132, y=63, w=2424, h=1179 on full extents w=2688, h=1242; + /// LandscapeR x=132, y=63, w=2424, h=1179 on full extents w=2688, h=1242. + /// Aspect Ratio: ~19.5:9. + /// + Rect[] NSA_iPhoneXsMax = new Rect[] + { + new Rect (0f, 102f / 2688f, 1f, 2454f / 2688f), // Portrait + new Rect (132f / 2688f, 63f / 1242f, 2424f / 2688f, 1179f / 1242f) // Landscape + }; + + /// + /// Normalised safe areas for Pixel 3 XL using landscape left. Absolute values: + /// PortraitU x=0, y=0, w=1440, h=2789 on full extents w=1440, h=2960; + /// PortraitD x=0, y=0, w=1440, h=2789 on full extents w=1440, h=2960; + /// LandscapeL x=171, y=0, w=2789, h=1440 on full extents w=2960, h=1440; + /// LandscapeR x=0, y=0, w=2789, h=1440 on full extents w=2960, h=1440. + /// Aspect Ratio: 18.5:9. + /// + Rect[] NSA_Pixel3XL_LSL = new Rect[] + { + new Rect (0f, 0f, 1f, 2789f / 2960f), // Portrait + new Rect (0f, 0f, 2789f / 2960f, 1f) // Landscape + }; + + /// + /// Normalised safe areas for Pixel 3 XL using landscape right. Absolute values and aspect ratio same as above. + /// + Rect[] NSA_Pixel3XL_LSR = new Rect[] + { + new Rect (0f, 0f, 1f, 2789f / 2960f), // Portrait + new Rect (171f / 2960f, 0f, 2789f / 2960f, 1f) // Landscape + }; + #endregion + + RectTransform Panel; + Rect LastSafeArea = new Rect (0, 0, 0, 0); + Vector2Int LastScreenSize = new Vector2Int (0, 0); + ScreenOrientation LastOrientation = ScreenOrientation.AutoRotation; + [SerializeField] bool ConformX = true; // Conform to screen safe area on X-axis (default true, disable to ignore) + [SerializeField] bool ConformY = true; // Conform to screen safe area on Y-axis (default true, disable to ignore) + [SerializeField] bool Logging = false; // Conform to screen safe area on Y-axis (default true, disable to ignore) + + void Awake () + { + Panel = GetComponent (); + + if (Panel == null) + { + Debug.LogError ("Cannot apply safe area - no RectTransform found on " + name); + Destroy (gameObject); + } + + Refresh (); + } + + void Update () + { + Refresh (); + } + + void Refresh () + { + Rect safeArea = GetSafeArea (); + + if (safeArea != LastSafeArea + || Screen.width != LastScreenSize.x + || Screen.height != LastScreenSize.y + || Screen.orientation != LastOrientation) + { + // Fix for having auto-rotate off and manually forcing a screen orientation. + // See https://forum.unity.com/threads/569236/#post-4473253 and https://forum.unity.com/threads/569236/page-2#post-5166467 + LastScreenSize.x = Screen.width; + LastScreenSize.y = Screen.height; + LastOrientation = Screen.orientation; + + ApplySafeArea (safeArea); + } + } + + Rect GetSafeArea () + { + Rect safeArea = Screen.safeArea; + + if (Application.isEditor && Sim != SimDevice.None) + { + Rect nsa = new Rect (0, 0, Screen.width, Screen.height); + + switch (Sim) + { + case SimDevice.iPhoneX: + if (Screen.height > Screen.width) // Portrait + nsa = NSA_iPhoneX[0]; + else // Landscape + nsa = NSA_iPhoneX[1]; + break; + case SimDevice.iPhoneXsMax: + if (Screen.height > Screen.width) // Portrait + nsa = NSA_iPhoneXsMax[0]; + else // Landscape + nsa = NSA_iPhoneXsMax[1]; + break; + case SimDevice.Pixel3XL_LSL: + if (Screen.height > Screen.width) // Portrait + nsa = NSA_Pixel3XL_LSL[0]; + else // Landscape + nsa = NSA_Pixel3XL_LSL[1]; + break; + case SimDevice.Pixel3XL_LSR: + if (Screen.height > Screen.width) // Portrait + nsa = NSA_Pixel3XL_LSR[0]; + else // Landscape + nsa = NSA_Pixel3XL_LSR[1]; + break; + default: + break; + } + + safeArea = new Rect (Screen.width * nsa.x, Screen.height * nsa.y, Screen.width * nsa.width, Screen.height * nsa.height); + } + + return safeArea; + } + + void ApplySafeArea (Rect r) + { + LastSafeArea = r; + + // Ignore x-axis? + if (!ConformX) + { + r.x = 0; + r.width = Screen.width; + } + + // Ignore y-axis? + if (!ConformY) + { + r.y = 0; + r.height = Screen.height; + } + + // Check for invalid screen startup state on some Samsung devices (see below) + if (Screen.width > 0 && Screen.height > 0) + { + // Convert safe area rectangle from absolute pixels to normalised anchor coordinates + Vector2 anchorMin = r.position; + Vector2 anchorMax = r.position + r.size; + anchorMin.x /= Screen.width; + anchorMin.y /= Screen.height; + anchorMax.x /= Screen.width; + anchorMax.y /= Screen.height; + + // Fix for some Samsung devices (e.g. Note 10+, A71, S20) where Refresh gets called twice and the first time returns NaN anchor coordinates + // See https://forum.unity.com/threads/569236/page-2#post-6199352 + if (anchorMin.x >= 0 && anchorMin.y >= 0 && anchorMax.x >= 0 && anchorMax.y >= 0) + { + Panel.anchorMin = anchorMin; + Panel.anchorMax = anchorMax; + } + } + + if (Logging) + { + Debug.LogFormat ("New safe area applied to {0}: x={1}, y={2}, w={3}, h={4} on full extents w={5}, h={6}", + name, r.x, r.y, r.width, r.height, Screen.width, Screen.height); + } + } + } +} diff --git a/Assets/CrystalFramework/Utility/SafeArea.cs.meta b/Assets/CrystalFramework/Utility/SafeArea.cs.meta new file mode 100644 index 0000000..7c604b6 --- /dev/null +++ b/Assets/CrystalFramework/Utility/SafeArea.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: c97afc556caea1c44969477eb7ddec74 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 130488 + packageName: Safe Area Helper + packageVersion: 1.0.6 + assetPath: Assets/CrystalFramework/Utility/SafeArea.cs + uploadId: 385285 diff --git a/Assets/DarkMatter/Code/Core/Contracts/ILeaderBoardController.cs b/Assets/DarkMatter/Code/Core/Contracts/ILeaderBoardController.cs index 0ee7f33..b5eb51d 100644 --- a/Assets/DarkMatter/Code/Core/Contracts/ILeaderBoardController.cs +++ b/Assets/DarkMatter/Code/Core/Contracts/ILeaderBoardController.cs @@ -1,10 +1,11 @@ +using Cysharp.Threading.Tasks; using UnityEngine; namespace Darkmatter.Core { public interface ILeaderBoardController { - void ShowLeaderBoard(); - void UpdateLeaderBoardScore(int score); + UniTask ShowLeaderBoardAsync(); + UniTask UpdateLeaderBoardScore(int score); } } diff --git a/Assets/DarkMatter/Code/Core/CoreAssembly.asmdef b/Assets/DarkMatter/Code/Core/CoreAssembly.asmdef index 0f01b10..ea2ccda 100644 --- a/Assets/DarkMatter/Code/Core/CoreAssembly.asmdef +++ b/Assets/DarkMatter/Code/Core/CoreAssembly.asmdef @@ -4,7 +4,8 @@ "references": [ "GUID:4307f53044263cf4b835bd812fc161a4", "GUID:b0214a6008ed146ff8f122a6a9c2f6cc", - "GUID:75469ad4d38634e559750d17036d5f7c" + "GUID:75469ad4d38634e559750d17036d5f7c", + "GUID:f51ebe6a0ceec4240a699833d6309b23" ], "includePlatforms": [], "excludePlatforms": [], diff --git a/Assets/DarkMatter/Code/Domain/GenericPool.meta b/Assets/DarkMatter/Code/Domain/GenericPool.meta new file mode 100644 index 0000000..b36c544 --- /dev/null +++ b/Assets/DarkMatter/Code/Domain/GenericPool.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 75a2920ba3d7abc4b94a5b95351e7dac +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/DarkMatter/Code/Domain/GenericPool/ObjectPool.cs b/Assets/DarkMatter/Code/Domain/GenericPool/ObjectPool.cs new file mode 100644 index 0000000..d2ccfb9 --- /dev/null +++ b/Assets/DarkMatter/Code/Domain/GenericPool/ObjectPool.cs @@ -0,0 +1,57 @@ +using Darkmatter.Core; +using System.Collections.Generic; +using UnityEngine; +using VContainer; +using VContainer.Unity; + +namespace Darkmatter.Domain +{ + public class ObjectPool : MonoBehaviour,IPool where T : Component + { + [SerializeField] T prefab; + [SerializeField] private Transform prefabParent; + [SerializeField] private int poolSize = 15; + + public Queue pool = new Queue(); + [Inject] IObjectResolver resolver; + + public IReadOnlyCollection All => pool; + + private void Awake() + { + CreateObjectPool(); + } + + private void CreateObjectPool() + { + for(int i=0;i