app.hypergames.hypersdk 1.3.4 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/Editor/{HyperSDK.Editor.asmdef → Hyper.Editor.asmdef} +1 -1
  3. package/Editor/Resources/ControlBarPreviews/Dark/Default.png +0 -0
  4. package/Editor/Resources/ControlBarPreviews/Dark/Default.png.meta +143 -0
  5. package/Editor/Resources/ControlBarPreviews/Dark/HealthBarLeft.png +0 -0
  6. package/Editor/Resources/ControlBarPreviews/Dark/HealthBarLeft.png.meta +143 -0
  7. package/Editor/Resources/ControlBarPreviews/Dark/HeartsLeft.png +0 -0
  8. package/Editor/Resources/ControlBarPreviews/Dark/HeartsLeft.png.meta +169 -0
  9. package/Editor/Resources/ControlBarPreviews/Dark.meta +8 -0
  10. package/Editor/Resources/ControlBarPreviews/Light/Default.png +0 -0
  11. package/Editor/Resources/ControlBarPreviews/Light/Default.png.meta +143 -0
  12. package/Editor/Resources/ControlBarPreviews/Light/HealthBarLeft.png +0 -0
  13. package/Editor/Resources/ControlBarPreviews/Light/HealthBarLeft.png.meta +143 -0
  14. package/Editor/Resources/ControlBarPreviews/Light/HeartsLeft.png +0 -0
  15. package/Editor/Resources/ControlBarPreviews/Light/HeartsLeft.png.meta +143 -0
  16. package/Editor/Resources/ControlBarPreviews/Light.meta +8 -0
  17. package/Editor/Resources/ControlBarPreviews.meta +8 -0
  18. package/Editor/Scripts/Inspectors/HyperSDKSettingsEditor.cs +206 -0
  19. package/Editor/Scripts/Inspectors/HyperSDKSettingsEditor.cs.meta +2 -0
  20. package/Editor/Scripts/Inspectors.meta +8 -0
  21. package/Editor/Scripts/Windows/HyperCoreSettingsWindow.cs +0 -8
  22. package/Editor/Scripts/Windows/HyperGameContentWindow.cs +0 -8
  23. package/Editor/Scripts/Windows/HyperSettingsWindow.cs +3 -3
  24. package/HyperLoader.unity +4 -49
  25. package/Runtime/Internal/AssemblyInfo.cs +1 -1
  26. package/Runtime/Internal/Managers/EventManager.cs +4 -0
  27. package/Runtime/Internal/Managers/GameManager.cs +135 -2
  28. package/Runtime/Internal/ScriptableObjects/HyperSDKSettings.cs +16 -10
  29. package/Runtime/Internal/UI/Animation/BlinkingText.cs +1 -1
  30. package/Runtime/Internal/UI/Animation/HyperTween.cs +88 -0
  31. package/Runtime/Internal/UI/Components/ControlBar.cs +220 -40
  32. package/Runtime/Internal/UI/Components/HealthBarDisplay.cs +269 -0
  33. package/Runtime/Internal/UI/Components/HealthBarDisplay.cs.meta +2 -0
  34. package/Runtime/Internal/UI/Components/LivesDisplay.cs +327 -0
  35. package/Runtime/Internal/UI/Components/LivesDisplay.cs.meta +2 -0
  36. package/Runtime/Internal/UI/Modals/StartingInstructionModal.cs +202 -3
  37. package/Runtime/Internal/Utils/HyperConstants.cs +27 -0
  38. package/Runtime/Public/Core/HyperSDK.cs +68 -0
  39. package/Runtime/Resources/Fonts/Wonder Boys/Wonder Boys + Hyper BIG.mat +1 -1
  40. package/Runtime/Resources/HyperSDKSettings.asset +3 -2
  41. package/Runtime/Resources/Sprites/Control Bar/Ellipse 3.png +0 -0
  42. package/Runtime/Resources/Sprites/Control Bar/Ellipse 3.png.meta +169 -0
  43. package/Runtime/Resources/Sprites/Control Bar/Health Bar - Green Fill.png +0 -0
  44. package/Runtime/Resources/Sprites/Control Bar/Health Bar - Green Fill.png.meta +169 -0
  45. package/Runtime/Resources/Sprites/Control Bar/Health Bar - Underlay.png +0 -0
  46. package/Runtime/Resources/Sprites/Control Bar/Health Bar - Underlay.png.meta +169 -0
  47. package/Runtime/Resources/Sprites/Control Bar/Health Bar.png +0 -0
  48. package/Runtime/Resources/Sprites/Control Bar/Health Bar.png.meta +169 -0
  49. package/Runtime/Resources/Sprites/Control Bar/heart.empty.png +0 -0
  50. package/Runtime/Resources/Sprites/Control Bar/heart.empty.png.meta +169 -0
  51. package/Runtime/Resources/Sprites/Control Bar/heart.fill.png +0 -0
  52. package/Runtime/Resources/Sprites/Control Bar/heart.fill.png.meta +169 -0
  53. package/Runtime/Resources/Sprites/Frames/{Game Over P.png.meta → Game Over.png.meta } +4 -4
  54. package/Runtime/Resources/Sprites/HYPERGAMES_Logo.png.meta +3 -3
  55. package/Runtime/Resources/Sprites/Hyper Atlas.spriteatlasv2 +6 -0
  56. package/Runtime/Resources/Sprites/Start CTAs/Hand.PNG +0 -0
  57. package/Runtime/Resources/Sprites/Start CTAs/Hand.PNG.meta +169 -0
  58. package/Runtime/Resources/Sprites/Start CTAs/Line .PNG +0 -0
  59. package/Runtime/Resources/Sprites/Start CTAs/Line .PNG.meta +169 -0
  60. package/Runtime/Resources/Sprites/Start CTAs/Swipe Gesture GIF.controller +130 -0
  61. package/Runtime/Resources/Sprites/Start CTAs/Swipe Gesture GIF.controller.meta +8 -0
  62. package/Runtime/Resources/Sprites/Start CTAs/Swipe Gesture.anim +158 -0
  63. package/Runtime/Resources/Sprites/Start CTAs/Swipe Gesture.anim.meta +8 -0
  64. package/Runtime/Resources/Sprites/Start CTAs.meta +8 -0
  65. package/Runtime/Resources/UIPrefabs/Control Bar Objects/Health Bar Display.prefab +361 -0
  66. package/Runtime/Resources/UIPrefabs/Control Bar Objects/Health Bar Display.prefab.meta +7 -0
  67. package/Runtime/Resources/UIPrefabs/Control Bar Objects/Lives Display .prefab +246 -0
  68. package/Runtime/Resources/UIPrefabs/Control Bar Objects/Lives Display .prefab.meta +7 -0
  69. package/Runtime/Resources/UIPrefabs/Control Bar Objects.meta +8 -0
  70. package/Runtime/Resources/UIPrefabs/ControlBar.prefab +131 -17
  71. package/Runtime/Resources/UIPrefabs/StartingInstructionModal.prefab +271 -57
  72. package/Runtime/Resources/UIPrefabs/TutorialLandscapeModal.prefab +1 -1
  73. package/Runtime/Resources/UIPrefabs/TutorialPortraitModal.prefab +1 -1
  74. package/Runtime/Shared/DTOs/Enums.cs +22 -6
  75. package/package.json +1 -1
  76. /package/Editor/{HyperSDK.Editor.asmdef.meta → Hyper.Editor.asmdef.meta} +0 -0
  77. /package/Runtime/Resources/Sprites/Frames/{Game Over P.png → Game Over.png} +0 -0
@@ -42,6 +42,47 @@ namespace Hyper.Internal.Managers
42
42
  }
43
43
 
44
44
  _isPortrait = Screen.height > Screen.width;
45
+ SubscribeToLivesEvents();
46
+ }
47
+
48
+ private void SubscribeToLivesEvents()
49
+ {
50
+ // Default behavior: automatically end game when lives are exhausted
51
+ // Developers can still subscribe to OnLivesExhausted for custom behavior
52
+ _eventManager.OnLivesExhausted += HandleLivesExhausted;
53
+ _eventManager.OnHealthExhausted += HandleHealthExhausted;
54
+ }
55
+
56
+ private void HandleLivesExhausted()
57
+ {
58
+ if (!IsInGameScene || _hasGameEnded || !_hasGameStarted) return;
59
+
60
+ // Automatically end the game when lives are exhausted
61
+ // Use appropriate method based on game mode
62
+ if (IsBattleMode)
63
+ {
64
+ EndBattleGame();
65
+ }
66
+ else
67
+ {
68
+ EndPracticeGame();
69
+ }
70
+ }
71
+
72
+ private void HandleHealthExhausted()
73
+ {
74
+ if (!IsInGameScene || _hasGameEnded || !_hasGameStarted) return;
75
+
76
+ // Automatically end the game when health is exhausted
77
+ // Use appropriate method based on game mode
78
+ if (IsBattleMode)
79
+ {
80
+ EndBattleGame();
81
+ }
82
+ else
83
+ {
84
+ EndPracticeGame();
85
+ }
45
86
  }
46
87
 
47
88
  internal void Cleanup()
@@ -107,6 +148,7 @@ namespace Hyper.Internal.Managers
107
148
 
108
149
  internal ControlBarTheme ControlBarTheme { get; private set; }
109
150
  internal ControlBarLayout ControlBarLayout { get; private set; }
151
+ internal StartCTA StartCTA { get; private set; }
110
152
 
111
153
  internal void PauseGame()
112
154
  {
@@ -144,6 +186,90 @@ namespace Hyper.Internal.Managers
144
186
  _controlBarModal?.UpdateScoreLabel();
145
187
  }
146
188
 
189
+ internal void InitializeLives(int maxLives, int initialLives = -1)
190
+ {
191
+ var livesDisplay = _controlBarModal?.GetLivesDisplay();
192
+ livesDisplay?.Initialize(maxLives, initialLives);
193
+ }
194
+
195
+ internal void SetLives(int lives)
196
+ {
197
+ var livesDisplay = _controlBarModal?.GetLivesDisplay();
198
+ livesDisplay?.SetLives(lives);
199
+ }
200
+
201
+ internal void AddLife()
202
+ {
203
+ var livesDisplay = _controlBarModal?.GetLivesDisplay();
204
+ livesDisplay?.AddLife();
205
+ }
206
+
207
+ internal void RemoveLife()
208
+ {
209
+ var livesDisplay = _controlBarModal?.GetLivesDisplay();
210
+ livesDisplay?.RemoveLife();
211
+ }
212
+
213
+ internal int GetCurrentLives()
214
+ {
215
+ var livesDisplay = _controlBarModal?.GetLivesDisplay();
216
+ return livesDisplay?.GetCurrentLives() ?? 0;
217
+ }
218
+
219
+ internal int GetMaxLives()
220
+ {
221
+ var livesDisplay = _controlBarModal?.GetLivesDisplay();
222
+ return livesDisplay?.GetMaxLives() ?? 0;
223
+ }
224
+
225
+ internal void InitializeHealth(float maxHealth, float initialHealth = -1f, bool isNormalized = false)
226
+ {
227
+ var healthBarDisplay = _controlBarModal?.GetHealthBarDisplay();
228
+ healthBarDisplay?.Initialize(maxHealth, initialHealth, isNormalized);
229
+ }
230
+
231
+ internal void SetHealth(float health)
232
+ {
233
+ var healthBarDisplay = _controlBarModal?.GetHealthBarDisplay();
234
+ healthBarDisplay?.SetHealth(health);
235
+ }
236
+
237
+ internal void SetHealthNormalized(float normalizedHealth)
238
+ {
239
+ var healthBarDisplay = _controlBarModal?.GetHealthBarDisplay();
240
+ healthBarDisplay?.SetHealthNormalized(normalizedHealth);
241
+ }
242
+
243
+ internal void AddHealth(float amount)
244
+ {
245
+ var healthBarDisplay = _controlBarModal?.GetHealthBarDisplay();
246
+ healthBarDisplay?.AddHealth(amount);
247
+ }
248
+
249
+ internal void RemoveHealth(float amount)
250
+ {
251
+ var healthBarDisplay = _controlBarModal?.GetHealthBarDisplay();
252
+ healthBarDisplay?.RemoveHealth(amount);
253
+ }
254
+
255
+ internal float GetCurrentHealth()
256
+ {
257
+ var healthBarDisplay = _controlBarModal?.GetHealthBarDisplay();
258
+ return healthBarDisplay?.GetCurrentHealth() ?? 0f;
259
+ }
260
+
261
+ internal float GetMaxHealth()
262
+ {
263
+ var healthBarDisplay = _controlBarModal?.GetHealthBarDisplay();
264
+ return healthBarDisplay?.GetMaxHealth() ?? 0f;
265
+ }
266
+
267
+ internal float GetHealthNormalized()
268
+ {
269
+ var healthBarDisplay = _controlBarModal?.GetHealthBarDisplay();
270
+ return healthBarDisplay?.GetHealthNormalized() ?? 0f;
271
+ }
272
+
147
273
  internal void ShowConnectionLost()
148
274
  {
149
275
  if (!IsInGameScene) return;
@@ -389,8 +515,9 @@ namespace Hyper.Internal.Managers
389
515
 
390
516
  private void LoadConfiguration()
391
517
  {
392
- ControlBarLayout = HyperRuntime.Settings.topBarLayout;
393
- ControlBarTheme = HyperRuntime.Settings.topBarTheme;
518
+ ControlBarLayout = HyperRuntime.Settings.controlBarLayout;
519
+ ControlBarTheme = HyperRuntime.Settings.controlBarTheme;
520
+ StartCTA = HyperRuntime.Settings.startCTA;
394
521
  }
395
522
 
396
523
  #if UNITY_WEBGL && !UNITY_EDITOR
@@ -1268,6 +1395,12 @@ namespace Hyper.Internal.Managers
1268
1395
 
1269
1396
  _startingInstructionModal = instance;
1270
1397
  _startingInstructionModalComponent = instance.GetComponent<StartingInstructionModal>();
1398
+
1399
+ // Configure the CTA text based on settings
1400
+ if (_startingInstructionModalComponent != null)
1401
+ {
1402
+ _startingInstructionModalComponent.Configure(StartCTA);
1403
+ }
1271
1404
  }
1272
1405
 
1273
1406
  private void HideStartingInstructionModal()
@@ -31,24 +31,30 @@ namespace Hyper.Internal
31
31
 
32
32
  #endregion
33
33
 
34
- #region Control Bar Configuration
34
+ #region Start CTA
35
35
 
36
- // [Space(20)]
37
- // [Header("Top Bar Configurations")]
38
- // [Tooltip("Select the color theme (light or dark) for the top bar.")]
39
- [HideInInspector]
40
- public ControlBarTheme topBarTheme = ControlBarTheme.Dark;
36
+ [Space(20)]
37
+ [Header("Start CTA Overlay")]
38
+ [Tooltip("Choose the start CTA overlay shown before gameplay begins. Hyper requires one of these overlays - do not add your own start buttons.")]
39
+ public StartCTA startCTA = StartCTA.TapToPlay;
40
+
41
+ #endregion
42
+
43
+ #region Control Bar Settings
44
+
45
+ [Space(20)]
46
+ [Header("Control Bar Settings")]
47
+ [Tooltip("Select the layout type for the in-game control bar.")]
48
+ public ControlBarLayout controlBarLayout = ControlBarLayout.Default;
41
49
 
42
50
  // [Space(5)]
43
- // [Tooltip("Select the layout type for the in-game top bar.")]
51
+ // [Tooltip("Select the color theme (light or dark) for the control bar.")]
44
52
  [HideInInspector]
45
- public ControlBarLayout topBarLayout = ControlBarLayout.Default;
53
+ public ControlBarTheme controlBarTheme = ControlBarTheme.Dark;
46
54
 
47
55
  #endregion
48
56
 
49
57
  #region Editor Testing
50
-
51
- [Space(10)]
52
58
  [Header("Editor Simulation")]
53
59
  [Tooltip("Configuration settings for testing within the Unity Editor.")]
54
60
  public URLData _settings;
@@ -4,7 +4,7 @@ using TMPro;
4
4
  namespace Hyper.Internal
5
5
  {
6
6
  [RequireComponent(typeof(TMP_Text))]
7
- internal class BlinkText : MonoBehaviour
7
+ internal class BlinkingText : MonoBehaviour
8
8
  {
9
9
  private float blinkSpeed = 6f;
10
10
  private TMP_Text text;
@@ -162,6 +162,34 @@ namespace Hyper.Internal.Animation
162
162
  return handle;
163
163
  }
164
164
 
165
+ /// <summary>
166
+ /// Animates an Image's fillAmount (0-1).
167
+ /// </summary>
168
+ public static TweenHandle DoFillAmount(Image target, float endValue, float duration)
169
+ {
170
+ EnsureCoroutineRunner();
171
+ var handle = new TweenHandle();
172
+ var coroutine = coroutineRunner.StartCoroutine(AnimateFillAmount(target, endValue, duration, handle));
173
+ TrackCoroutine(target, coroutine);
174
+ handle.coroutine = coroutine;
175
+ handle.target = target;
176
+ return handle;
177
+ }
178
+
179
+ /// <summary>
180
+ /// Animates a Transform's local scale.
181
+ /// </summary>
182
+ public static TweenHandle DoScale(Transform target, Vector3 endValue, float duration)
183
+ {
184
+ EnsureCoroutineRunner();
185
+ var handle = new TweenHandle();
186
+ var coroutine = coroutineRunner.StartCoroutine(AnimateScale(target, endValue, duration, handle));
187
+ TrackCoroutine(target, coroutine);
188
+ handle.coroutine = coroutine;
189
+ handle.target = target;
190
+ return handle;
191
+ }
192
+
165
193
  /// <summary>
166
194
  /// Executes a callback after a delay.
167
195
  /// </summary>
@@ -345,6 +373,56 @@ namespace Hyper.Internal.Animation
345
373
  handle.InvokeComplete();
346
374
  }
347
375
 
376
+ private static IEnumerator AnimateFillAmount(Image target, float endValue, float duration, TweenHandle handle)
377
+ {
378
+ float startValue = target.fillAmount;
379
+ float elapsed = 0f;
380
+
381
+ while (elapsed < duration)
382
+ {
383
+ if (target == null)
384
+ {
385
+ UntrackCoroutine(target, handle.coroutine);
386
+ yield break;
387
+ }
388
+
389
+ elapsed += handle.useUnscaledTime ? Time.unscaledDeltaTime : Time.deltaTime;
390
+ float t = Mathf.Clamp01(elapsed / duration);
391
+ float easedT = ApplyEasing(t, handle.ease);
392
+ target.fillAmount = Mathf.Lerp(startValue, endValue, easedT);
393
+ yield return null;
394
+ }
395
+
396
+ target.fillAmount = endValue;
397
+ UntrackCoroutine(target, handle.coroutine);
398
+ handle.InvokeComplete();
399
+ }
400
+
401
+ private static IEnumerator AnimateScale(Transform target, Vector3 endValue, float duration, TweenHandle handle)
402
+ {
403
+ Vector3 startValue = target.localScale;
404
+ float elapsed = 0f;
405
+
406
+ while (elapsed < duration)
407
+ {
408
+ if (target == null)
409
+ {
410
+ UntrackCoroutine(target, handle.coroutine);
411
+ yield break;
412
+ }
413
+
414
+ elapsed += handle.useUnscaledTime ? Time.unscaledDeltaTime : Time.deltaTime;
415
+ float t = Mathf.Clamp01(elapsed / duration);
416
+ float easedT = ApplyEasing(t, handle.ease);
417
+ target.localScale = Vector3.Lerp(startValue, endValue, easedT);
418
+ yield return null;
419
+ }
420
+
421
+ target.localScale = endValue;
422
+ UntrackCoroutine(target, handle.coroutine);
423
+ handle.InvokeComplete();
424
+ }
425
+
348
426
  private static IEnumerator DelayedCallCoroutine(float delay, Action callback, TweenHandle handle)
349
427
  {
350
428
  float elapsed = 0f;
@@ -467,6 +545,16 @@ namespace Hyper.Internal.Animation
467
545
  return HyperTween.DoColor(target, endValue, duration);
468
546
  }
469
547
 
548
+ public static HyperTween.TweenHandle DOFillAmount(this Image target, float endValue, float duration)
549
+ {
550
+ return HyperTween.DoFillAmount(target, endValue, duration);
551
+ }
552
+
553
+ public static HyperTween.TweenHandle DOScale(this Transform target, Vector3 endValue, float duration)
554
+ {
555
+ return HyperTween.DoScale(target, endValue, duration);
556
+ }
557
+
470
558
  public static void DOKill(this Component target)
471
559
  {
472
560
  HyperTween.Kill(target);
@@ -4,32 +4,82 @@ using TMPro;
4
4
  using UnityEngine;
5
5
  using UnityEngine.UI;
6
6
 
7
-
8
7
  namespace Hyper.Internal
9
8
  {
10
9
  internal class ControlBar : MonoBehaviour
11
10
  {
11
+ [Header("UI Components")]
12
+ public Image roundedBG;
12
13
  [SerializeField] TextMeshProUGUI scoreText;
13
14
  [SerializeField] private RectTransform scoreTextRect;
14
15
  [SerializeField] private RectTransform timerText;
15
16
  [SerializeField] private Image safeAreaFillerBG;
16
- public Image roundedBG;
17
17
  [SerializeField] private Image pauseButtonImage;
18
18
  [SerializeField] private Image pauseBarsImage;
19
+ [SerializeField] private Button connectionStatusIcon;
20
+
21
+ [Header("Sprites")]
19
22
  [SerializeField] Sprite portraitBG;
20
23
  [SerializeField] Sprite landscapeBG;
21
24
  [SerializeField] Sprite pauseBarsLight;
22
25
  [SerializeField] Sprite pauseBarsDark;
23
26
 
27
+ [Header("Lives Display")]
28
+ [SerializeField] private GameObject livesDisplayPrefab;
29
+
30
+ [Header("Health Bar Display")]
31
+ [SerializeField] private GameObject healthBarDisplayPrefab;
32
+
24
33
  private GameManager _gameManager;
34
+ private TextMeshProUGUI _scoreTextComponent;
35
+ private TextMeshProUGUI _timerTextComponent;
36
+ private LivesDisplay _livesDisplay;
37
+ private HealthBarDisplay _healthBarDisplay;
38
+
39
+ // Layout constants
40
+ private const float CENTERED_LAYOUT_SCORE_Y = 31f;
41
+ private const float CENTERED_LAYOUT_TIMER_Y = -13f;
42
+ private const float CENTERED_LAYOUT_SCORE_FONT_SIZE = 100f;
43
+ private const float CENTERED_LAYOUT_TIMER_FONT_SIZE = 50f;
44
+
45
+ private const float DEFAULT_LAYOUT_SCORE_Y = 10f;
46
+ private const float DEFAULT_LAYOUT_TIMER_X = 35f;
47
+ private const float DEFAULT_LAYOUT_TIMER_Y = 10f;
48
+ private const float DEFAULT_LAYOUT_SCORE_FONT_SIZE = 100f;
49
+ private const float DEFAULT_LAYOUT_TIMER_FONT_SIZE = 60f;
50
+
51
+ // Theme constants
52
+ private const string LIGHT_THEME_BG_COLOR = "#F5F5F5";
53
+ private const string LIGHT_THEME_TEXT_COLOR = "#434343";
54
+ private const float DARK_THEME_PAUSE_BUTTON_ALPHA = 0.25f;
55
+ private const float LIGHT_THEME_PAUSE_BUTTON_ALPHA = 1f;
25
56
 
26
57
  void Awake()
27
58
  {
28
59
  _gameManager = HyperRuntime.GameManager;
60
+ CacheTextComponents();
29
61
 
30
62
  RectTransform rect = transform.GetComponent<RectTransform>();
63
+ ConfigureOrientation(rect);
64
+ ConfigureLayout();
65
+ ConfigureTheme();
66
+
67
+ connectionStatusIcon.onClick.AddListener(ShowConnectionLostStatus);
68
+ }
31
69
 
32
- // Choose correct sprite based on Orientation
70
+ private void OnDestroy()
71
+ {
72
+ connectionStatusIcon.onClick.RemoveListener(ShowConnectionLostStatus);
73
+ }
74
+
75
+ private void CacheTextComponents()
76
+ {
77
+ _scoreTextComponent = scoreTextRect.GetComponent<TextMeshProUGUI>();
78
+ _timerTextComponent = timerText.GetComponent<TextMeshProUGUI>();
79
+ }
80
+
81
+ private void ConfigureOrientation(RectTransform rect)
82
+ {
33
83
  if (_gameManager.IsPortrait())
34
84
  {
35
85
  roundedBG.sprite = portraitBG;
@@ -40,62 +90,174 @@ namespace Hyper.Internal
40
90
  roundedBG.sprite = landscapeBG;
41
91
  rect.sizeDelta = new Vector2(rect.sizeDelta.x, 180);
42
92
  }
93
+ }
43
94
 
95
+ private void ConfigureLayout()
96
+ {
97
+ switch (_gameManager.ControlBarLayout)
98
+ {
99
+ case ControlBarLayout.HeartsLeft:
100
+ ApplyCenteredLayout();
101
+ SetupLivesDisplay();
102
+ break;
103
+ case ControlBarLayout.HealthBarLeft:
104
+ ApplyCenteredLayout();
105
+ HideLivesDisplay();
106
+ SetupHealthBarDisplay();
107
+ break;
108
+ case ControlBarLayout.Default:
109
+ ApplyDefaultLayout();
110
+ HideLivesDisplay();
111
+ HideHealthBarDisplay();
112
+ break;
113
+ }
114
+ }
44
115
 
45
- // Configure correct positioning based on the selected Layout
46
- if (_gameManager.ControlBarLayout == ControlBarLayout.CustomLeft)
116
+ private void SetupLivesDisplay()
117
+ {
118
+ if (_livesDisplay == null && livesDisplayPrefab != null)
47
119
  {
48
- scoreTextRect.anchoredPosition = new Vector2(0, 31);
49
- scoreTextRect.GetComponent<TextMeshProUGUI>().fontSize = 100;
120
+ GameObject livesInstance = Instantiate(livesDisplayPrefab, roundedBG.transform);
121
+ _livesDisplay = livesInstance.GetComponent<LivesDisplay>();
50
122
 
51
- timerText.anchoredPosition = new Vector2(0, -13);
52
- timerText.anchorMin = new Vector2(0.5f, 0.5f);
53
- timerText.anchorMax = new Vector2(0.5f, 0.5f);
54
- timerText.pivot = new Vector2(0.5f, 0.5f);
55
- timerText.GetComponent<TextMeshProUGUI>().fontSize = 50;
123
+ if (_livesDisplay == null)
124
+ {
125
+ Debug.LogError("[ControlBar] LivesDisplay prefab does not have LivesDisplay component!");
126
+ Destroy(livesInstance);
127
+ return;
128
+ }
129
+
130
+ // Position on the left side where timer would be in default layout
131
+ RectTransform livesRect = livesInstance.GetComponent<RectTransform>();
132
+ if (livesRect != null)
133
+ {
134
+ livesRect.anchoredPosition = new Vector2(DEFAULT_LAYOUT_TIMER_X, DEFAULT_LAYOUT_TIMER_Y);
135
+ livesRect.anchorMin = new Vector2(0f, 0.5f);
136
+ livesRect.anchorMax = new Vector2(0f, 0.5f);
137
+ livesRect.pivot = new Vector2(0, 0.5f);
138
+ }
56
139
  }
57
- else if (_gameManager.ControlBarLayout == ControlBarLayout.Default)
140
+
141
+ if (_livesDisplay != null)
58
142
  {
59
- scoreTextRect.anchoredPosition = new Vector2(0, 10);
60
- scoreTextRect.GetComponent<TextMeshProUGUI>().fontSize = 100;
143
+ _livesDisplay.gameObject.SetActive(true);
144
+ }
145
+ }
61
146
 
62
- timerText.anchoredPosition = new Vector2(40, 10);
63
- timerText.anchorMin = new Vector2(0f, 0.5f);
64
- timerText.anchorMax = new Vector2(0f, 0.5f);
65
- timerText.pivot = new Vector2(0, 0.5f);
66
- timerText.GetComponent<TextMeshProUGUI>().fontSize = 60;
67
- timerText.GetComponent<TextMeshProUGUI>().alignment = TextAlignmentOptions.MidlineLeft;
147
+ private void HideLivesDisplay()
148
+ {
149
+ if (_livesDisplay != null)
150
+ {
151
+ _livesDisplay.gameObject.SetActive(false);
68
152
  }
153
+ }
69
154
 
70
- //Configure correct coloring based on selected theme
71
- if (_gameManager.ControlBarTheme == ControlBarTheme.Dark)
155
+ private void SetupHealthBarDisplay()
156
+ {
157
+ if (_healthBarDisplay == null && healthBarDisplayPrefab != null)
72
158
  {
73
- roundedBG.color = Color.black;
74
- safeAreaFillerBG.color = Color.black;
159
+ GameObject healthBarInstance = Instantiate(healthBarDisplayPrefab, roundedBG.transform);
160
+ _healthBarDisplay = healthBarInstance.GetComponent<HealthBarDisplay>();
75
161
 
76
- scoreTextRect.GetComponent<TextMeshProUGUI>().color = Color.white;
77
- timerText.GetComponent<TextMeshProUGUI>().color = Color.white;
162
+ if (_healthBarDisplay == null)
163
+ {
164
+ Debug.LogError("[ControlBar] HealthBarDisplay prefab does not have HealthBarDisplay component!");
165
+ Destroy(healthBarInstance);
166
+ return;
167
+ }
78
168
 
79
- //pauseButtonImage.sprite = pauseButtonDark;
80
- pauseButtonImage.color = new Color(1, 1, 1, 0.25f);
81
- pauseBarsImage.sprite = pauseBarsDark;
169
+ // Position on the left side where timer would be in default layout
170
+ RectTransform healthBarRect = healthBarInstance.GetComponent<RectTransform>();
171
+ if (healthBarRect != null)
172
+ {
173
+ healthBarRect.anchoredPosition = new Vector2(DEFAULT_LAYOUT_TIMER_X, DEFAULT_LAYOUT_TIMER_Y);
174
+ healthBarRect.anchorMin = new Vector2(0f, 0.5f);
175
+ healthBarRect.anchorMax = new Vector2(0f, 0.5f);
176
+ healthBarRect.pivot = new Vector2(0, 0.5f);
177
+ }
178
+ }
179
+
180
+ if (_healthBarDisplay != null)
181
+ {
182
+ _healthBarDisplay.gameObject.SetActive(true);
82
183
  }
83
- else if (_gameManager.ControlBarTheme == ControlBarTheme.Light)
184
+ }
185
+
186
+ private void HideHealthBarDisplay()
187
+ {
188
+ if (_healthBarDisplay != null)
84
189
  {
85
- roundedBG.color = HexToColor("#F5F5F5");
86
- safeAreaFillerBG.color = HexToColor("#F5F5F5");
190
+ _healthBarDisplay.gameObject.SetActive(false);
191
+ }
192
+ }
193
+
194
+ private void ApplyCenteredLayout()
195
+ {
196
+ scoreTextRect.anchoredPosition = new Vector2(0, CENTERED_LAYOUT_SCORE_Y);
197
+ _scoreTextComponent.fontSize = CENTERED_LAYOUT_SCORE_FONT_SIZE;
87
198
 
88
- scoreTextRect.GetComponent<TextMeshProUGUI>().color = HexToColor("#434343");
89
- timerText.GetComponent<TextMeshProUGUI>().color = HexToColor("#434343");
199
+ timerText.anchoredPosition = new Vector2(0, CENTERED_LAYOUT_TIMER_Y);
200
+ timerText.anchorMin = new Vector2(0.5f, 0.5f);
201
+ timerText.anchorMax = new Vector2(0.5f, 0.5f);
202
+ timerText.pivot = new Vector2(0.5f, 0.5f);
203
+ _timerTextComponent.fontSize = CENTERED_LAYOUT_TIMER_FONT_SIZE;
204
+ }
205
+
206
+ private void ApplyDefaultLayout()
207
+ {
208
+ scoreTextRect.anchoredPosition = new Vector2(0, DEFAULT_LAYOUT_SCORE_Y);
209
+ _scoreTextComponent.fontSize = DEFAULT_LAYOUT_SCORE_FONT_SIZE;
90
210
 
91
- //pauseButtonImage.sprite = pauseButtonLight;
92
- pauseButtonImage.color = new Color(1, 1, 1, 1);
93
- pauseBarsImage.sprite = pauseBarsLight;
94
- }
211
+ timerText.anchoredPosition = new Vector2(DEFAULT_LAYOUT_TIMER_X, DEFAULT_LAYOUT_TIMER_Y);
212
+ timerText.anchorMin = new Vector2(0f, 0.5f);
213
+ timerText.anchorMax = new Vector2(0f, 0.5f);
214
+ timerText.pivot = new Vector2(0, 0.5f);
215
+ _timerTextComponent.fontSize = DEFAULT_LAYOUT_TIMER_FONT_SIZE;
216
+ _timerTextComponent.alignment = TextAlignmentOptions.MidlineLeft;
95
217
  }
96
218
 
97
- public void ShowConnectionLostStatus()
219
+ private void ConfigureTheme()
98
220
  {
221
+ switch (_gameManager.ControlBarTheme)
222
+ {
223
+ case ControlBarTheme.Dark:
224
+ ApplyDarkTheme();
225
+ break;
226
+ case ControlBarTheme.Light:
227
+ ApplyLightTheme();
228
+ break;
229
+ }
230
+ }
231
+
232
+ private void ApplyDarkTheme()
233
+ {
234
+ roundedBG.color = Color.black;
235
+ safeAreaFillerBG.color = Color.black;
236
+
237
+ _scoreTextComponent.color = Color.white;
238
+ _timerTextComponent.color = Color.white;
239
+
240
+ pauseButtonImage.color = new Color(1, 1, 1, DARK_THEME_PAUSE_BUTTON_ALPHA);
241
+ pauseBarsImage.sprite = pauseBarsDark;
242
+ }
243
+
244
+ private void ApplyLightTheme()
245
+ {
246
+ Color bgColor = HexToColor(LIGHT_THEME_BG_COLOR);
247
+ Color textColor = HexToColor(LIGHT_THEME_TEXT_COLOR);
248
+
249
+ roundedBG.color = bgColor;
250
+ safeAreaFillerBG.color = bgColor;
251
+
252
+ _scoreTextComponent.color = textColor;
253
+ _timerTextComponent.color = textColor;
254
+
255
+ pauseButtonImage.color = new Color(1, 1, 1, LIGHT_THEME_PAUSE_BUTTON_ALPHA);
256
+ pauseBarsImage.sprite = pauseBarsLight;
257
+ }
258
+
259
+ private void ShowConnectionLostStatus()
260
+ {
99
261
  // Show the connection lost status
100
262
  _gameManager.ShowConnectionLost();
101
263
  }
@@ -105,6 +267,24 @@ namespace Hyper.Internal
105
267
  scoreText.SetText(HyperRuntime.DataManager.CurrentScore.ToString("N0"));
106
268
  }
107
269
 
270
+ /// <summary>
271
+ /// Gets the LivesDisplay component if available.
272
+ /// Only available when ControlBarLayout is set to HeartsLeft.
273
+ /// </summary>
274
+ public LivesDisplay GetLivesDisplay()
275
+ {
276
+ return _livesDisplay;
277
+ }
278
+
279
+ /// <summary>
280
+ /// Gets the HealthBarDisplay component if available.
281
+ /// Only available when ControlBarLayout is set to HealthBarGreenLeft.
282
+ /// </summary>
283
+ public HealthBarDisplay GetHealthBarDisplay()
284
+ {
285
+ return _healthBarDisplay;
286
+ }
287
+
108
288
  Color HexToColor(string hex)
109
289
  {
110
290
  if (ColorUtility.TryParseHtmlString(hex, out Color color))