Rework of base interactables and managed behaviors

This commit is contained in:
Michal Pikulski
2025-11-04 11:11:27 +01:00
committed by Michal Pikulski
parent 00e1746ac4
commit f88bd0e2c9
60 changed files with 11175 additions and 1340 deletions

View File

@@ -1,4 +1,5 @@
using System;
using Core.Lifecycle;
using UnityEngine;
namespace UI.Core
@@ -6,12 +7,17 @@ namespace UI.Core
/// <summary>
/// Base class for UI pages that can transition in and out.
/// Extended by specific UI page implementations for the card system.
/// Now inherits from ManagedBehaviour for lifecycle support.
/// Children can override lifecycle hooks if they need boot-dependent initialization.
/// </summary>
public abstract class UIPage : MonoBehaviour
public abstract class UIPage : ManagedBehaviour
{
[Header("Page Settings")]
public string PageName;
// UI pages load after UI infrastructure (UIPageController is priority 50)
public override int ManagedAwakePriority => 200;
// Events using System.Action instead of UnityEvents
public event Action OnTransitionInStarted;
public event Action OnTransitionInCompleted;

View File

@@ -1,8 +1,7 @@
using System;
using System.Collections.Generic;
using Bootstrap;
using Core;
using UnityEngine;
using Core.Lifecycle;
using UnityEngine.InputSystem;
namespace UI.Core
@@ -11,7 +10,7 @@ namespace UI.Core
/// Manages UI page transitions and maintains a stack of active pages.
/// Pages are pushed onto a stack for navigation and popped when going back.
/// </summary>
public class UIPageController : MonoBehaviour
public class UIPageController : ManagedBehaviour
{
private static UIPageController _instance;
public static UIPageController Instance => _instance;
@@ -30,36 +29,25 @@ namespace UI.Core
private PlayerInput _playerInput;
private InputAction _cancelAction;
private void Awake()
public override int ManagedAwakePriority => 50; // UI infrastructure
private new void Awake()
{
base.Awake(); // CRITICAL: Register with LifecycleManager!
// Set instance immediately so it's available before OnManagedAwake() is called
_instance = this;
// TODO: Handle generic "cancel" action
// _playerInput = FindFirstObjectByType<PlayerInput>();
// if (_playerInput == null)
// {
// Logging.Warning("[UIPageController] No PlayerInput found in the scene. Cancel action might not work.");
// }
// else
// {
// // Get the Cancel action from the UI action map
// _cancelAction = _playerInput.actions.FindAction("UI/Cancel");
// if (_cancelAction != null)
// {
// _cancelAction.performed += OnCancelActionPerformed;
// }
// else
// {
// Logging.Warning("[UIPageController] Cancel action not found in the input actions asset.");
// }
// }
// Register for post-boot initialization
BootCompletionService.RegisterInitAction(InitializePostBoot);
}
private void OnDestroy()
protected override void OnManagedAwake()
{
Logging.Debug("[UIPageController] Initialized");
}
protected override void OnDestroy()
{
base.OnDestroy();
// Clean up event subscription when the controller is destroyed
if (_cancelAction != null)
{
@@ -74,12 +62,6 @@ namespace UI.Core
_pageStack.Peek().OnBackPressed();
}
}
private void InitializePostBoot()
{
// Initialize any dependencies that require other services to be ready
Logging.Debug("[UIPageController] Post-boot initialization complete");
}
/// <summary>
/// Pushes a new page onto the stack, hiding the current page and showing the new one.

View File

@@ -1,16 +1,16 @@
using System.Collections;
using System;
using Bootstrap;
using Core;
using Core.Lifecycle;
using UnityEngine;
using UnityEngine.UI;
using Core;
namespace UI
{
/// <summary>
/// Controls the loading screen UI display, progress updates, and timing
/// </summary>
public class LoadingScreenController : MonoBehaviour
public class LoadingScreenController : ManagedBehaviour
{
[Header("UI References")]
[SerializeField] private GameObject loadingScreenContainer;
@@ -53,10 +53,17 @@ namespace UI
/// </summary>
public static LoadingScreenController Instance => _instance;
private void Awake()
// ManagedBehaviour configuration
public override int ManagedAwakePriority => 45; // UI infrastructure, before UIPageController
private new void Awake()
{
base.Awake(); // CRITICAL: Register with LifecycleManager!
// Set instance immediately so it's available before OnManagedAwake() is called
_instance = this;
// Set up container reference early
if (loadingScreenContainer == null)
loadingScreenContainer = gameObject;
@@ -65,15 +72,11 @@ namespace UI
{
loadingScreenContainer.SetActive(false);
}
// Register for post-boot initialization
BootCompletionService.RegisterInitAction(InitializePostBoot);
}
private void InitializePostBoot()
protected override void OnManagedAwake()
{
// Initialize any dependencies that require other services to be ready
Logging.Debug("[LoadingScreenController] Post-boot initialization complete");
Logging.Debug("[LoadingScreenController] Initialized");
}
/// <summary>

View File

@@ -2,7 +2,6 @@ using System;
using Core;
using UnityEngine;
using UnityEngine.SceneManagement;
using Bootstrap;
using UI.Core;
using Pixelplacement;
@@ -22,9 +21,14 @@ namespace UI
[SerializeField] private GameObject pauseButton;
[SerializeField] private CanvasGroup canvasGroup;
// After UIPageController (50)
public override int ManagedAwakePriority => 55;
private void Awake()
private new void Awake()
{
base.Awake(); // CRITICAL: Register with LifecycleManager!
// Set instance immediately so it's available before OnManagedAwake() is called
_instance = this;
// Ensure we have a CanvasGroup for transitions
@@ -32,18 +36,22 @@ namespace UI
canvasGroup = GetComponent<CanvasGroup>();
if (canvasGroup == null)
canvasGroup = gameObject.AddComponent<CanvasGroup>();
// Set initial state
canvasGroup.alpha = 0f;
canvasGroup.interactable = false;
canvasGroup.blocksRaycasts = false;
gameObject.SetActive(false);
// Register for post-boot initialization
BootCompletionService.RegisterInitAction(InitializePostBoot);
}
protected override void OnManagedAwake()
{
// Component setup already done in Awake
}
private void InitializePostBoot()
protected override void OnSceneReady()
{
// Subscribe to scene loaded events
// Subscribe to scene-dependent events
SceneManagerService.Instance.SceneLoadCompleted += SetPauseMenuByLevel;
// Also react to global UI hide/show events from the page controller
@@ -53,16 +61,16 @@ namespace UI
UIPageController.Instance.OnAllUIShown += HandleAllUIShown;
}
// SceneManagerService subscription moved to InitializePostBoot
// Set initial state based on current scene
SetPauseMenuByLevel(SceneManager.GetActiveScene().name);
Logging.Debug("[PauseMenu] Subscribed to SceneManagerService events");
}
private void OnDestroy()
protected override void OnDestroy()
{
base.OnDestroy();
// Unsubscribe when destroyed
if (SceneManagerService.Instance != null)
{

View File

@@ -1,6 +1,6 @@
using System.Collections;
using Bootstrap;
using Core;
using Core.Lifecycle;
using Core.SaveLoad;
using Input;
using Pixelplacement;
@@ -9,7 +9,7 @@ using UnityEngine;
namespace UI.Tutorial
{
public class DivingTutorial : MonoBehaviour, ITouchInputConsumer
public class DivingTutorial : ManagedBehaviour, ITouchInputConsumer
{
public enum ProgressType
{
@@ -27,18 +27,14 @@ namespace UI.Tutorial
private bool _canAcceptInput;
private Coroutine _waitLoopCoroutine;
// Start is called once before the first execution of Update after the MonoBehaviour is created
void Start()
{
BootCompletionService.RegisterInitAction(InitializeTutorial);
public override int ManagedAwakePriority => 200; // Tutorial runs late, after other systems
protected override void OnManagedAwake()
{
// Ensure prompt is hidden initially (even before tutorial initialization)
if (tapPrompt != null)
tapPrompt.SetActive(false);
}
void InitializeTutorial()
{
if (playTutorial && !SaveLoadManager.Instance.currentSaveData.playedDivingTutorial)
{
// TODO: Possibly do it better, but for now just mark tutorial as played immediately
@@ -221,7 +217,7 @@ namespace UI.Tutorial
// Manual mode: enable input and wait for player tap
SetInputEnabled(true);
}
_waitLoopCoroutine = null;
}
}