Add docs, cleanup structure
This commit is contained in:
@@ -3189,9 +3189,6 @@ PrefabInstance:
|
|||||||
- targetCorrespondingSourceObject: {fileID: 7404622075362872657, guid: f44866deaba5f5c4a90f0330dd9957f0, type: 3}
|
- targetCorrespondingSourceObject: {fileID: 7404622075362872657, guid: f44866deaba5f5c4a90f0330dd9957f0, type: 3}
|
||||||
insertIndex: -1
|
insertIndex: -1
|
||||||
addedObject: {fileID: 1460027150}
|
addedObject: {fileID: 1460027150}
|
||||||
- targetCorrespondingSourceObject: {fileID: 7404622075362872657, guid: f44866deaba5f5c4a90f0330dd9957f0, type: 3}
|
|
||||||
insertIndex: -1
|
|
||||||
addedObject: {fileID: 1460027149}
|
|
||||||
m_SourcePrefab: {fileID: 100100000, guid: f44866deaba5f5c4a90f0330dd9957f0, type: 3}
|
m_SourcePrefab: {fileID: 100100000, guid: f44866deaba5f5c4a90f0330dd9957f0, type: 3}
|
||||||
--- !u!4 &1460027142 stripped
|
--- !u!4 &1460027142 stripped
|
||||||
Transform:
|
Transform:
|
||||||
@@ -3214,18 +3211,6 @@ MonoBehaviour:
|
|||||||
specificPhotoId:
|
specificPhotoId:
|
||||||
applyPivotOffset: 1
|
applyPivotOffset: 1
|
||||||
showDebugInfo: 1
|
showDebugInfo: 1
|
||||||
--- !u!114 &1460027149
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 175866977}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: acf5624b19664ce5900f1a7c1328edbc, type: 3}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier: AppleHillsScripts::Minigames.StatueDressup.Controllers.StatueDressupSettings
|
|
||||||
--- !u!114 &1460027150
|
--- !u!114 &1460027150
|
||||||
MonoBehaviour:
|
MonoBehaviour:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
|
|||||||
@@ -2086,8 +2086,9 @@ GameObject:
|
|||||||
- component: {fileID: 1181815686}
|
- component: {fileID: 1181815686}
|
||||||
- component: {fileID: 1181815685}
|
- component: {fileID: 1181815685}
|
||||||
- component: {fileID: 1181815684}
|
- component: {fileID: 1181815684}
|
||||||
|
- component: {fileID: 1181815687}
|
||||||
m_Layer: 0
|
m_Layer: 0
|
||||||
m_Name: SFXManager
|
m_Name: DecorationEventManager
|
||||||
m_TagString: Untagged
|
m_TagString: Untagged
|
||||||
m_Icon: {fileID: 0}
|
m_Icon: {fileID: 0}
|
||||||
m_NavMeshLayer: 0
|
m_NavMeshLayer: 0
|
||||||
@@ -2221,6 +2222,18 @@ Transform:
|
|||||||
m_Children: []
|
m_Children: []
|
||||||
m_Father: {fileID: 0}
|
m_Father: {fileID: 0}
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!114 &1181815687
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1181815683}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 5c9796e0044a4fcd95b02a19925a6b2b, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier: AppleHillsScripts::Minigames.StatueDressup.Events.DecorationEventsManager
|
||||||
--- !u!1 &1217454514
|
--- !u!1 &1217454514
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
@@ -2864,7 +2877,6 @@ GameObject:
|
|||||||
m_Component:
|
m_Component:
|
||||||
- component: {fileID: 1647993459}
|
- component: {fileID: 1647993459}
|
||||||
- component: {fileID: 1647993458}
|
- component: {fileID: 1647993458}
|
||||||
- component: {fileID: 1647993461}
|
|
||||||
- component: {fileID: 1647993460}
|
- component: {fileID: 1647993460}
|
||||||
m_Layer: 0
|
m_Layer: 0
|
||||||
m_Name: StatueDecorationController
|
m_Name: StatueDecorationController
|
||||||
@@ -2922,18 +2934,6 @@ MonoBehaviour:
|
|||||||
m_Script: {fileID: 11500000, guid: afa56ec5b1f84b32ba014a91d9d9a0a0, type: 3}
|
m_Script: {fileID: 11500000, guid: afa56ec5b1f84b32ba014a91d9d9a0a0, type: 3}
|
||||||
m_Name:
|
m_Name:
|
||||||
m_EditorClassIdentifier: AppleHillsScripts::Minigames.StatueDressup.Controllers.DecorationDataManager
|
m_EditorClassIdentifier: AppleHillsScripts::Minigames.StatueDressup.Controllers.DecorationDataManager
|
||||||
--- !u!114 &1647993461
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 1647993457}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: acf5624b19664ce5900f1a7c1328edbc, type: 3}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier: AppleHillsScripts::Minigames.StatueDressup.Controllers.StatueDressupSettings
|
|
||||||
--- !u!1 &1685271989
|
--- !u!1 &1685271989
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
|
|||||||
@@ -2,27 +2,73 @@
|
|||||||
using Core;
|
using Core;
|
||||||
using Core.Lifecycle;
|
using Core.Lifecycle;
|
||||||
using Minigames.StatueDressup.Data;
|
using Minigames.StatueDressup.Data;
|
||||||
|
using UnityEngine;
|
||||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||||
using Utils;
|
using Utils;
|
||||||
|
|
||||||
namespace Minigames.StatueDressup.Controllers
|
namespace Minigames.StatueDressup.Controllers
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Singleton manager for decoration data loading and caching.
|
/// Singleton manager for statue dressup data loading and caching.
|
||||||
/// Loads all DecorationData assets once via Addressables and provides shared access.
|
/// Loads settings first, then decoration data via Addressables and provides shared access.
|
||||||
/// Used by both minigame and town map to avoid duplicate loading.
|
/// Used by both minigame and town map to avoid duplicate loading.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class DecorationDataManager : ManagedBehaviour
|
public class DecorationDataManager : ManagedBehaviour, IReadyNotifier
|
||||||
{
|
{
|
||||||
public static DecorationDataManager Instance { get; private set; }
|
public static DecorationDataManager Instance { get; private set; }
|
||||||
|
|
||||||
|
// Static callback queue for when instance doesn't exist yet
|
||||||
|
private static readonly List<System.Action> PendingCallbacks = new List<System.Action>();
|
||||||
|
private AppleHills.Core.Settings.IStatueDressupSettings settings;
|
||||||
private Dictionary<string, DecorationData> decorationDataDict;
|
private Dictionary<string, DecorationData> decorationDataDict;
|
||||||
private AsyncOperationHandle<System.Collections.Generic.IList<DecorationData>> decorationDataHandle;
|
private AsyncOperationHandle<System.Collections.Generic.IList<DecorationData>> decorationDataHandle;
|
||||||
private bool isLoaded;
|
private bool isLoaded;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Check if data is loaded and ready
|
/// Get the settings instance
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
public AppleHills.Core.Settings.IStatueDressupSettings Settings => settings;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check if data is loaded and ready (implements IReadyNotifier)
|
||||||
|
/// </summary>
|
||||||
|
public bool IsReady => isLoaded;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event invoked when data is loaded and ready (implements IReadyNotifier)
|
||||||
|
/// </summary>
|
||||||
|
public event System.Action OnReady;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Static method to register callbacks that will execute when manager is ready.
|
||||||
|
/// Can be called before instance exists - callbacks will be queued and executed when ready.
|
||||||
|
/// Handles null instance gracefully by queuing callbacks until instance is created and ready.
|
||||||
|
/// </summary>
|
||||||
|
public static void WhenReady(System.Action callback)
|
||||||
|
{
|
||||||
|
if (callback == null) return;
|
||||||
|
|
||||||
|
// If instance exists and is ready, execute immediately
|
||||||
|
if (Instance != null && Instance.IsReady)
|
||||||
|
{
|
||||||
|
callback.Invoke();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If instance exists but not ready, use instance method
|
||||||
|
if (Instance != null)
|
||||||
|
{
|
||||||
|
(Instance as IReadyNotifier).WhenReady(callback);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Instance doesn't exist yet - queue callback
|
||||||
|
PendingCallbacks.Add(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Legacy property - use IsReady instead
|
||||||
|
/// </summary>
|
||||||
|
[System.Obsolete("Use IsReady instead")]
|
||||||
public bool IsLoaded => isLoaded;
|
public bool IsLoaded => isLoaded;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -32,8 +78,6 @@ namespace Minigames.StatueDressup.Controllers
|
|||||||
|
|
||||||
internal override void OnManagedAwake()
|
internal override void OnManagedAwake()
|
||||||
{
|
{
|
||||||
base.OnManagedAwake();
|
|
||||||
|
|
||||||
// Singleton pattern
|
// Singleton pattern
|
||||||
if (Instance != null && Instance != this)
|
if (Instance != null && Instance != this)
|
||||||
{
|
{
|
||||||
@@ -45,11 +89,31 @@ namespace Minigames.StatueDressup.Controllers
|
|||||||
Instance = this;
|
Instance = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override async void OnManagedStart()
|
internal override void OnManagedStart()
|
||||||
{
|
{
|
||||||
base.OnManagedStart();
|
StartCoroutine(LoadSettingsAndData());
|
||||||
|
}
|
||||||
|
|
||||||
await LoadAllDecorationData();
|
/// <summary>
|
||||||
|
/// Load settings first, then decoration data
|
||||||
|
/// </summary>
|
||||||
|
private System.Collections.IEnumerator LoadSettingsAndData()
|
||||||
|
{
|
||||||
|
Logging.Debug("[DecorationDataManager] Waiting for GameManager to be accessible...");
|
||||||
|
|
||||||
|
// Wait until GameManager is accessible and settings can be retrieved
|
||||||
|
settings = GameManager.GetSettingsObject<AppleHills.Core.Settings.IStatueDressupSettings>();
|
||||||
|
|
||||||
|
Logging.Debug("[DecorationDataManager] Settings loaded successfully");
|
||||||
|
|
||||||
|
// Now load decoration data
|
||||||
|
var loadTask = LoadAllDecorationData();
|
||||||
|
yield return new WaitUntil(() => loadTask.IsCompleted);
|
||||||
|
|
||||||
|
if (loadTask.IsFaulted)
|
||||||
|
{
|
||||||
|
Logging.Error($"[DecorationDataManager] Failed to load decoration data: {loadTask.Exception}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -63,7 +127,6 @@ namespace Minigames.StatueDressup.Controllers
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var settings = StatueDressupSettings.Instance?.Settings;
|
|
||||||
string label = settings?.DecorationDataLabel;
|
string label = settings?.DecorationDataLabel;
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(label))
|
if (string.IsNullOrEmpty(label))
|
||||||
@@ -85,6 +148,20 @@ namespace Minigames.StatueDressup.Controllers
|
|||||||
isLoaded = true;
|
isLoaded = true;
|
||||||
|
|
||||||
Logging.Debug($"[DecorationDataManager] Loaded {decorationDataDict.Count} DecorationData assets");
|
Logging.Debug($"[DecorationDataManager] Loaded {decorationDataDict.Count} DecorationData assets");
|
||||||
|
|
||||||
|
// Subscribe all pending callbacks to OnReady event before invoking
|
||||||
|
if (PendingCallbacks.Count > 0)
|
||||||
|
{
|
||||||
|
Logging.Debug($"[DecorationDataManager] Subscribing {PendingCallbacks.Count} pending callbacks to OnReady");
|
||||||
|
foreach (var callback in PendingCallbacks)
|
||||||
|
{
|
||||||
|
OnReady += callback;
|
||||||
|
}
|
||||||
|
PendingCallbacks.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark as ready and notify listeners (including pending callbacks)
|
||||||
|
OnReady?.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -122,10 +199,8 @@ namespace Minigames.StatueDressup.Controllers
|
|||||||
return decorationDataDict.TryGetValue(decorationId, out data);
|
return decorationDataDict.TryGetValue(decorationId, out data);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override void OnManagedDestroy()
|
private void OnDestroy()
|
||||||
{
|
{
|
||||||
base.OnManagedDestroy();
|
|
||||||
|
|
||||||
// Release Addressables handle
|
// Release Addressables handle
|
||||||
AddressablesUtility.ReleaseHandle(decorationDataHandle);
|
AddressablesUtility.ReleaseHandle(decorationDataHandle);
|
||||||
|
|
||||||
|
|||||||
@@ -35,9 +35,6 @@ namespace Minigames.StatueDressup.Controllers
|
|||||||
public int CurrentPage => currentPage;
|
public int CurrentPage => currentPage;
|
||||||
public int TotalPages => totalPages;
|
public int TotalPages => totalPages;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Early initialization - singleton setup
|
|
||||||
/// </summary>
|
|
||||||
internal override void OnManagedAwake()
|
internal override void OnManagedAwake()
|
||||||
{
|
{
|
||||||
base.OnManagedAwake();
|
base.OnManagedAwake();
|
||||||
@@ -66,7 +63,19 @@ namespace Minigames.StatueDressup.Controllers
|
|||||||
{
|
{
|
||||||
base.OnManagedStart();
|
base.OnManagedStart();
|
||||||
|
|
||||||
var settings = StatueDressupSettings.Instance?.Settings;
|
// Wait for data manager to be ready before initializing
|
||||||
|
DecorationDataManager.WhenReady(() =>
|
||||||
|
{
|
||||||
|
InitializeMenu();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initialize menu once data manager is ready
|
||||||
|
/// </summary>
|
||||||
|
private void InitializeMenu()
|
||||||
|
{
|
||||||
|
var settings = DecorationDataManager.Instance?.Settings;
|
||||||
|
|
||||||
if (settings == null)
|
if (settings == null)
|
||||||
{
|
{
|
||||||
@@ -75,7 +84,7 @@ namespace Minigames.StatueDressup.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
var allDecorations = settings.AllDecorations;
|
var allDecorations = settings.AllDecorations;
|
||||||
int itemsPerPage = settings.ItemsPerPage;
|
int itemsPerPage = settings?.ItemsPerPage ?? StatueDressupConstants.DefaultMenuItemsPerPage;
|
||||||
|
|
||||||
Logging.Debug($"[DecorationMenuController] Initializing with {allDecorations?.Count ?? 0} decorations");
|
Logging.Debug($"[DecorationMenuController] Initializing with {allDecorations?.Count ?? 0} decorations");
|
||||||
|
|
||||||
@@ -114,7 +123,7 @@ namespace Minigames.StatueDressup.Controllers
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void PopulateCurrentPage()
|
private void PopulateCurrentPage()
|
||||||
{
|
{
|
||||||
var settings = StatueDressupSettings.Instance?.Settings;
|
var settings = DecorationDataManager.Instance?.Settings;
|
||||||
if (settings == null) return;
|
if (settings == null) return;
|
||||||
|
|
||||||
var allDecorations = settings.AllDecorations;
|
var allDecorations = settings.AllDecorations;
|
||||||
@@ -196,7 +205,7 @@ namespace Minigames.StatueDressup.Controllers
|
|||||||
outlineRect,
|
outlineRect,
|
||||||
StatueDecorationController.Instance.StatueParent,
|
StatueDecorationController.Instance.StatueParent,
|
||||||
StatueDecorationController.Instance,
|
StatueDecorationController.Instance,
|
||||||
StatueDressupSettings.Instance.Settings,
|
DecorationDataManager.Instance.Settings,
|
||||||
OnDraggableFinished,
|
OnDraggableFinished,
|
||||||
ShowStatueOutline,
|
ShowStatueOutline,
|
||||||
HideStatueOutline
|
HideStatueOutline
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Core;
|
using Core;
|
||||||
using Core.Lifecycle;
|
using Core.Lifecycle;
|
||||||
@@ -44,9 +44,6 @@ namespace Minigames.StatueDressup.Controllers
|
|||||||
public Transform StatueParent => statueParent;
|
public Transform StatueParent => statueParent;
|
||||||
public RectTransform StatueArea => statueArea;
|
public RectTransform StatueArea => statueArea;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Early initialization - singleton setup
|
|
||||||
/// </summary>
|
|
||||||
internal override void OnManagedAwake()
|
internal override void OnManagedAwake()
|
||||||
{
|
{
|
||||||
base.OnManagedAwake();
|
base.OnManagedAwake();
|
||||||
@@ -71,30 +68,12 @@ namespace Minigames.StatueDressup.Controllers
|
|||||||
|
|
||||||
Logging.Debug("[StatueDecorationController] Initializing minigame");
|
Logging.Debug("[StatueDecorationController] Initializing minigame");
|
||||||
|
|
||||||
// DecorationDataManager exists (initialized in OnManagedAwake) but data loads async in OnManagedStart
|
// Wait for decoration data to be ready before initializing
|
||||||
// Wait for data to finish loading before initializing
|
DecorationDataManager.WhenReady(() =>
|
||||||
if (!DecorationDataManager.Instance.IsLoaded)
|
|
||||||
{
|
{
|
||||||
Logging.Debug("[StatueDecorationController] Waiting for DecorationData to load...");
|
Logging.Debug("[StatueDecorationController] DecorationData ready, initializing minigame");
|
||||||
StartCoroutine(WaitForDataAndInitialize());
|
InitializeMinigame();
|
||||||
return;
|
});
|
||||||
}
|
|
||||||
|
|
||||||
InitializeMinigame();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Wait for data manager to finish loading data before initializing
|
|
||||||
/// </summary>
|
|
||||||
private System.Collections.IEnumerator WaitForDataAndInitialize()
|
|
||||||
{
|
|
||||||
while (!DecorationDataManager.Instance.IsLoaded)
|
|
||||||
{
|
|
||||||
yield return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Logging.Debug("[StatueDecorationController] DecorationData loaded, initializing minigame");
|
|
||||||
InitializeMinigame();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -342,7 +321,7 @@ namespace Minigames.StatueDressup.Controllers
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void SaveStatueState()
|
private void SaveStatueState()
|
||||||
{
|
{
|
||||||
var settings = StatueDressupSettings.Instance?.Settings;
|
var settings = DecorationDataManager.Instance?.Settings;
|
||||||
|
|
||||||
// Check if persistence is enabled
|
// Check if persistence is enabled
|
||||||
if (settings == null || !settings.EnableStatePersistence)
|
if (settings == null || !settings.EnableStatePersistence)
|
||||||
@@ -363,7 +342,7 @@ namespace Minigames.StatueDressup.Controllers
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void LoadStatueState()
|
private void LoadStatueState()
|
||||||
{
|
{
|
||||||
var settings = StatueDressupSettings.Instance?.Settings;
|
var settings = DecorationDataManager.Instance?.Settings;
|
||||||
|
|
||||||
// Check if persistence is enabled
|
// Check if persistence is enabled
|
||||||
if (settings == null || !settings.EnableStatePersistence)
|
if (settings == null || !settings.EnableStatePersistence)
|
||||||
@@ -435,7 +414,7 @@ namespace Minigames.StatueDressup.Controllers
|
|||||||
var context = DecorationDragContext.CreateForPlaced(
|
var context = DecorationDragContext.CreateForPlaced(
|
||||||
decorationData,
|
decorationData,
|
||||||
this,
|
this,
|
||||||
StatueDressupSettings.Instance.Settings,
|
DecorationDataManager.Instance.Settings,
|
||||||
statueArea,
|
statueArea,
|
||||||
canvasParent,
|
canvasParent,
|
||||||
showOutlineCallback,
|
showOutlineCallback,
|
||||||
@@ -512,3 +491,4 @@ namespace Minigames.StatueDressup.Controllers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,59 +0,0 @@
|
|||||||
using Core;
|
|
||||||
using Core.Lifecycle;
|
|
||||||
|
|
||||||
namespace Minigames.StatueDressup.Controllers
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Singleton manager for StatueDressup settings access.
|
|
||||||
/// Loads settings once and provides global access point.
|
|
||||||
/// </summary>
|
|
||||||
public class StatueDressupSettings : ManagedBehaviour
|
|
||||||
{
|
|
||||||
public static StatueDressupSettings Instance { get; private set; }
|
|
||||||
|
|
||||||
private AppleHills.Core.Settings.IStatueDressupSettings settings;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get the settings instance
|
|
||||||
/// </summary>
|
|
||||||
public AppleHills.Core.Settings.IStatueDressupSettings Settings => settings;
|
|
||||||
|
|
||||||
internal override void OnManagedAwake()
|
|
||||||
{
|
|
||||||
base.OnManagedAwake();
|
|
||||||
|
|
||||||
// Singleton pattern
|
|
||||||
if (Instance != null && Instance != this)
|
|
||||||
{
|
|
||||||
Logging.Warning("[StatueDressupSettings] Duplicate instance detected. Destroying duplicate.");
|
|
||||||
Destroy(gameObject);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Instance = this;
|
|
||||||
|
|
||||||
// Load settings once
|
|
||||||
settings = GameManager.GetSettingsObject<AppleHills.Core.Settings.IStatueDressupSettings>();
|
|
||||||
|
|
||||||
if (settings == null)
|
|
||||||
{
|
|
||||||
Logging.Error("[StatueDressupSettings] Failed to load StatueDressupSettings!");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Logging.Debug("[StatueDressupSettings] Settings loaded successfully");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal override void OnManagedDestroy()
|
|
||||||
{
|
|
||||||
base.OnManagedDestroy();
|
|
||||||
|
|
||||||
if (Instance == this)
|
|
||||||
{
|
|
||||||
Instance = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: acf5624b19664ce5900f1a7c1328edbc
|
|
||||||
timeCreated: 1764240158
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Core;
|
using Core;
|
||||||
using Core.Lifecycle;
|
using Core.Lifecycle;
|
||||||
@@ -40,9 +40,9 @@ namespace Minigames.StatueDressup.Controllers
|
|||||||
private bool isLoadingPage;
|
private bool isLoadingPage;
|
||||||
private PhotoEnlargeController enlargeController;
|
private PhotoEnlargeController enlargeController;
|
||||||
|
|
||||||
internal override void OnManagedStart()
|
internal override void OnManagedAwake()
|
||||||
{
|
{
|
||||||
base.OnManagedStart();
|
base.OnManagedAwake();
|
||||||
|
|
||||||
// Singleton pattern
|
// Singleton pattern
|
||||||
if (Instance != null && Instance != this)
|
if (Instance != null && Instance != this)
|
||||||
@@ -53,11 +53,29 @@ namespace Minigames.StatueDressup.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
Instance = this;
|
Instance = this;
|
||||||
|
}
|
||||||
|
|
||||||
var settings = StatueDressupSettings.Instance?.Settings;
|
internal override void OnManagedStart()
|
||||||
|
{
|
||||||
|
base.OnManagedStart();
|
||||||
|
|
||||||
|
// Wait for data manager to be ready before initializing
|
||||||
|
DecorationDataManager.WhenReady(() =>
|
||||||
|
{
|
||||||
|
InitializeGallery();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initialize gallery once data manager is ready
|
||||||
|
/// </summary>
|
||||||
|
private void InitializeGallery()
|
||||||
|
{
|
||||||
|
var settings = DecorationDataManager.Instance?.Settings;
|
||||||
|
|
||||||
// Initialize enlarge controller
|
// Initialize enlarge controller
|
||||||
enlargeController = new PhotoEnlargeController(backdrop, enlargedContainer, settings?.GalleryAnimationDuration ?? 0.3f);
|
enlargeController = new PhotoEnlargeController(backdrop, enlargedContainer,
|
||||||
|
settings?.GalleryAnimationDuration ?? StatueDressupConstants.DefaultAnimationDuration);
|
||||||
|
|
||||||
// Setup page navigation buttons
|
// Setup page navigation buttons
|
||||||
if (previousPageButton != null)
|
if (previousPageButton != null)
|
||||||
@@ -108,7 +126,7 @@ namespace Minigames.StatueDressup.Controllers
|
|||||||
ClearGrid();
|
ClearGrid();
|
||||||
|
|
||||||
// Get photos for current page
|
// Get photos for current page
|
||||||
int itemsPerPage = StatueDressupSettings.Instance?.Settings?.GalleryItemsPerPage ?? 20;
|
int itemsPerPage = DecorationDataManager.Instance?.Settings?.GalleryItemsPerPage ?? StatueDressupConstants.DefaultGalleryItemsPerPage;
|
||||||
List<string> pagePhotoIds = PhotoManager.GetPhotoIdsPage(CaptureType.StatueMinigame, currentPage, itemsPerPage);
|
List<string> pagePhotoIds = PhotoManager.GetPhotoIdsPage(CaptureType.StatueMinigame, currentPage, itemsPerPage);
|
||||||
|
|
||||||
Logging.Debug($"[StatuePhotoGalleryController] Displaying page {currentPage + 1}: {pagePhotoIds.Count} items");
|
Logging.Debug($"[StatuePhotoGalleryController] Displaying page {currentPage + 1}: {pagePhotoIds.Count} items");
|
||||||
@@ -134,7 +152,7 @@ namespace Minigames.StatueDressup.Controllers
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void UpdatePageButtons()
|
private void UpdatePageButtons()
|
||||||
{
|
{
|
||||||
int itemsPerPage = StatueDressupSettings.Instance?.Settings?.GalleryItemsPerPage ?? 20;
|
int itemsPerPage = DecorationDataManager.Instance?.Settings?.GalleryItemsPerPage ?? StatueDressupConstants.DefaultGalleryItemsPerPage;
|
||||||
int totalPages = Mathf.CeilToInt((float)allPhotoIds.Count / itemsPerPage);
|
int totalPages = Mathf.CeilToInt((float)allPhotoIds.Count / itemsPerPage);
|
||||||
|
|
||||||
// Enable/disable previous button
|
// Enable/disable previous button
|
||||||
@@ -168,7 +186,7 @@ namespace Minigames.StatueDressup.Controllers
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void OnNextPageClicked()
|
private void OnNextPageClicked()
|
||||||
{
|
{
|
||||||
int itemsPerPage = StatueDressupSettings.Instance?.Settings?.GalleryItemsPerPage ?? 20;
|
int itemsPerPage = DecorationDataManager.Instance?.Settings?.GalleryItemsPerPage ?? StatueDressupConstants.DefaultGalleryItemsPerPage;
|
||||||
int totalPages = Mathf.CeilToInt((float)allPhotoIds.Count / itemsPerPage);
|
int totalPages = Mathf.CeilToInt((float)allPhotoIds.Count / itemsPerPage);
|
||||||
|
|
||||||
if (currentPage < totalPages - 1)
|
if (currentPage < totalPages - 1)
|
||||||
@@ -224,7 +242,7 @@ namespace Minigames.StatueDressup.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create thumbnail
|
// Create thumbnail
|
||||||
int thumbSize = StatueDressupSettings.Instance?.Settings?.GalleryThumbnailSize ?? 256;
|
int thumbSize = DecorationDataManager.Instance?.Settings?.GalleryThumbnailSize ?? StatueDressupConstants.DefaultThumbnailSize;
|
||||||
Texture2D thumbnail = PhotoManager.CreateThumbnail(fullPhoto, thumbSize);
|
Texture2D thumbnail = PhotoManager.CreateThumbnail(fullPhoto, thumbSize);
|
||||||
|
|
||||||
// Destroy full photo immediately (we only need thumbnail)
|
// Destroy full photo immediately (we only need thumbnail)
|
||||||
@@ -250,7 +268,7 @@ namespace Minigames.StatueDressup.Controllers
|
|||||||
thumbnailCacheOrder.Enqueue(photoId);
|
thumbnailCacheOrder.Enqueue(photoId);
|
||||||
|
|
||||||
// Evict oldest if over limit
|
// Evict oldest if over limit
|
||||||
int maxCached = StatueDressupSettings.Instance?.Settings?.GalleryMaxCachedThumbnails ?? 50;
|
int maxCached = DecorationDataManager.Instance?.Settings?.GalleryMaxCachedThumbnails ?? StatueDressupConstants.DefaultMaxCachedThumbnails;
|
||||||
while (thumbnailCache.Count > maxCached && thumbnailCacheOrder.Count > 0)
|
while (thumbnailCache.Count > maxCached && thumbnailCacheOrder.Count > 0)
|
||||||
{
|
{
|
||||||
string oldestId = thumbnailCacheOrder.Dequeue();
|
string oldestId = thumbnailCacheOrder.Dequeue();
|
||||||
@@ -284,7 +302,7 @@ namespace Minigames.StatueDressup.Controllers
|
|||||||
|
|
||||||
Logging.Debug($"[StatuePhotoGalleryController] Enlarging photo: {photoId}");
|
Logging.Debug($"[StatuePhotoGalleryController] Enlarging photo: {photoId}");
|
||||||
|
|
||||||
float enlargedScale = StatueDressupSettings.Instance?.Settings?.GalleryEnlargedScale ?? 2.5f;
|
float enlargedScale = DecorationDataManager.Instance?.Settings?.GalleryEnlargedScale ?? StatueDressupConstants.DefaultEnlargedScale;
|
||||||
|
|
||||||
// Check cache first
|
// Check cache first
|
||||||
if (fullPhotoCache.TryGetValue(photoId, out Texture2D fullPhoto))
|
if (fullPhotoCache.TryGetValue(photoId, out Texture2D fullPhoto))
|
||||||
@@ -404,3 +422,4 @@ namespace Minigames.StatueDressup.Controllers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Minigames.StatueDressup.Data
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Event data passed with decoration events for VFX/SFX responses
|
||||||
|
/// </summary>
|
||||||
|
public class DecorationEventData
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The decoration data (sprite, id, etc.)
|
||||||
|
/// </summary>
|
||||||
|
public DecorationData DecorationData { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The GameObject instance of the decoration (if applicable)
|
||||||
|
/// </summary>
|
||||||
|
public GameObject Instance { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Position where the event occurred (world space)
|
||||||
|
/// </summary>
|
||||||
|
public Vector3 Position { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether this decoration was dragged from the menu or from the statue
|
||||||
|
/// </summary>
|
||||||
|
public bool FromStatue { get; set; }
|
||||||
|
|
||||||
|
public DecorationEventData(DecorationData data, GameObject instance, Vector3 position, bool fromStatue = false)
|
||||||
|
{
|
||||||
|
DecorationData = data;
|
||||||
|
Instance = instance;
|
||||||
|
Position = position;
|
||||||
|
FromStatue = fromStatue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 5d9b3e7728c0420c8290986c31d5b738
|
||||||
|
timeCreated: 1764248890
|
||||||
@@ -39,29 +39,15 @@ namespace Minigames.StatueDressup.Display
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecorationDataManager exists (initialized in OnManagedAwake) but data loads async
|
// Wait for decoration data manager to be ready (static method handles null instance)
|
||||||
// Wait for data to finish loading before displaying decorations
|
DecorationDataManager.WhenReady(() =>
|
||||||
StartCoroutine(WaitForDataAndDisplay());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Wait for DecorationDataManager to finish loading data before displaying decorations
|
|
||||||
/// </summary>
|
|
||||||
private System.Collections.IEnumerator WaitForDataAndDisplay()
|
|
||||||
{
|
|
||||||
// Wait for data to load (manager is guaranteed to exist)
|
|
||||||
while (!DecorationDataManager.Instance.IsLoaded)
|
|
||||||
{
|
{
|
||||||
yield return null;
|
if (showDebugInfo)
|
||||||
}
|
{
|
||||||
|
Logging.Debug("[StatueDecorationLoader] DecorationData ready, displaying decorations");
|
||||||
if (showDebugInfo)
|
}
|
||||||
{
|
LoadAndDisplayDecorations();
|
||||||
Logging.Debug("[StatueDecorationLoader] DecorationData loaded, displaying decorations");
|
});
|
||||||
}
|
|
||||||
|
|
||||||
// Load and display decorations
|
|
||||||
LoadAndDisplayDecorations();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -70,7 +56,7 @@ namespace Minigames.StatueDressup.Display
|
|||||||
public void LoadAndDisplayDecorations()
|
public void LoadAndDisplayDecorations()
|
||||||
{
|
{
|
||||||
// Check if DecorationData is loaded via manager
|
// Check if DecorationData is loaded via manager
|
||||||
if (DecorationDataManager.Instance == null || !DecorationDataManager.Instance.IsLoaded)
|
if (DecorationDataManager.Instance == null || !DecorationDataManager.Instance.IsReady)
|
||||||
{
|
{
|
||||||
Logging.Warning("[StatueDecorationLoader] DecorationDataManager not ready. Cannot display decorations.");
|
Logging.Warning("[StatueDecorationLoader] DecorationDataManager not ready. Cannot display decorations.");
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using Core;
|
using Core;
|
||||||
using Minigames.StatueDressup.Controllers;
|
using Minigames.StatueDressup.Controllers;
|
||||||
using Minigames.StatueDressup.Data;
|
using Minigames.StatueDressup.Data;
|
||||||
|
using Minigames.StatueDressup.Events;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.EventSystems;
|
using UnityEngine.EventSystems;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
@@ -155,6 +156,10 @@ namespace Minigames.StatueDressup.DragDrop
|
|||||||
{
|
{
|
||||||
isDragging = true;
|
isDragging = true;
|
||||||
|
|
||||||
|
// Broadcast started dragging event (from grid)
|
||||||
|
var eventDataObj = new DecorationEventData(decorationData, gameObject, transform.position, fromStatue: false);
|
||||||
|
DecorationEventsManager.BroadcastDecorationStartedDragging(eventDataObj);
|
||||||
|
|
||||||
// Calculate offset from cursor to object center
|
// Calculate offset from cursor to object center
|
||||||
RectTransformUtility.ScreenPointToLocalPointInRectangle(
|
RectTransformUtility.ScreenPointToLocalPointInRectangle(
|
||||||
canvas.transform as RectTransform,
|
canvas.transform as RectTransform,
|
||||||
@@ -193,6 +198,10 @@ namespace Minigames.StatueDressup.DragDrop
|
|||||||
|
|
||||||
Logging.Debug($"[DecorationDraggableInstance] Drag ended: {decorationData?.DecorationName}");
|
Logging.Debug($"[DecorationDraggableInstance] Drag ended: {decorationData?.DecorationName}");
|
||||||
|
|
||||||
|
// Broadcast finished dragging event
|
||||||
|
var eventDataObj = new DecorationEventData(decorationData, gameObject, transform.position, fromStatue: isPlacedOnStatue);
|
||||||
|
DecorationEventsManager.BroadcastDecorationFinishedDragging(eventDataObj);
|
||||||
|
|
||||||
// Check if overlapping with statue
|
// Check if overlapping with statue
|
||||||
if (IsOverlappingStatue())
|
if (IsOverlappingStatue())
|
||||||
{
|
{
|
||||||
@@ -250,6 +259,10 @@ namespace Minigames.StatueDressup.DragDrop
|
|||||||
|
|
||||||
isPlacedOnStatue = true;
|
isPlacedOnStatue = true;
|
||||||
|
|
||||||
|
// Broadcast dropped on statue event
|
||||||
|
var eventDataObj = new DecorationEventData(decorationData, gameObject, transform.position, fromStatue: false);
|
||||||
|
DecorationEventsManager.BroadcastDecorationDroppedOnStatue(eventDataObj);
|
||||||
|
|
||||||
// Move to statue parent if specified
|
// Move to statue parent if specified
|
||||||
if (statueParent != null && transform.parent != statueParent)
|
if (statueParent != null && transform.parent != statueParent)
|
||||||
{
|
{
|
||||||
@@ -273,14 +286,22 @@ namespace Minigames.StatueDressup.DragDrop
|
|||||||
{
|
{
|
||||||
Logging.Debug($"[DecorationDraggableInstance] Pop-out and destroy: {decorationData?.DecorationName}");
|
Logging.Debug($"[DecorationDraggableInstance] Pop-out and destroy: {decorationData?.DecorationName}");
|
||||||
|
|
||||||
|
// Broadcast dropped out event (animation starting)
|
||||||
|
var eventDataObj = new DecorationEventData(decorationData, gameObject, transform.position, fromStatue: false);
|
||||||
|
DecorationEventsManager.BroadcastDecorationDroppedOut(eventDataObj);
|
||||||
|
|
||||||
// Notify menu controller to hide outline immediately
|
// Notify menu controller to hide outline immediately
|
||||||
onFinishedCallback?.Invoke();
|
onFinishedCallback?.Invoke();
|
||||||
|
|
||||||
float duration = settings?.PlacementAnimationDuration ?? 0.3f;
|
float duration = settings?.PlacementAnimationDuration ?? StatueDressupConstants.DefaultAnimationDuration;
|
||||||
|
|
||||||
// Play pop-out with fade animation
|
// Play pop-out with fade animation
|
||||||
TweenAnimationUtility.PopOutWithFade(transform, canvasGroup, duration, () =>
|
TweenAnimationUtility.PopOutWithFade(transform, canvasGroup, duration, () =>
|
||||||
{
|
{
|
||||||
|
// Broadcast finished dropping out event (animation complete)
|
||||||
|
var finalEventData = new DecorationEventData(decorationData, gameObject, transform.position, fromStatue: false);
|
||||||
|
DecorationEventsManager.BroadcastDecorationFinishedDroppingOut(finalEventData);
|
||||||
|
|
||||||
Destroy(gameObject);
|
Destroy(gameObject);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -301,6 +322,10 @@ namespace Minigames.StatueDressup.DragDrop
|
|||||||
isPlacedOnStatue = false;
|
isPlacedOnStatue = false;
|
||||||
isDragging = true;
|
isDragging = true;
|
||||||
|
|
||||||
|
// Broadcast started dragging event (from statue)
|
||||||
|
var eventDataObj = new DecorationEventData(decorationData, gameObject, transform.position, fromStatue: true);
|
||||||
|
DecorationEventsManager.BroadcastDecorationStartedDragging(eventDataObj);
|
||||||
|
|
||||||
// Show statue outline when picking up from statue
|
// Show statue outline when picking up from statue
|
||||||
if (onShowOutlineCallback != null)
|
if (onShowOutlineCallback != null)
|
||||||
{
|
{
|
||||||
@@ -345,6 +370,10 @@ namespace Minigames.StatueDressup.DragDrop
|
|||||||
|
|
||||||
Logging.Debug($"[DecorationDraggableInstance] Decoration tapped: {decorationData?.DecorationName}");
|
Logging.Debug($"[DecorationDraggableInstance] Decoration tapped: {decorationData?.DecorationName}");
|
||||||
|
|
||||||
|
// Broadcast tap event
|
||||||
|
var eventDataObj = new DecorationEventData(decorationData, gameObject, transform.position, fromStatue: true);
|
||||||
|
DecorationEventsManager.BroadcastDecorationTappedOnStatue(eventDataObj);
|
||||||
|
|
||||||
// Future: Open detail view, play sound effect, show info popup, etc.
|
// Future: Open detail view, play sound effect, show info popup, etc.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
using Core;
|
using Core;
|
||||||
|
using Minigames.StatueDressup.Controllers;
|
||||||
using Minigames.StatueDressup.Data;
|
using Minigames.StatueDressup.Data;
|
||||||
|
using Minigames.StatueDressup.Events;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.EventSystems;
|
using UnityEngine.EventSystems;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
@@ -17,7 +19,7 @@ namespace Minigames.StatueDressup.DragDrop
|
|||||||
[SerializeField] private Image iconImage;
|
[SerializeField] private Image iconImage;
|
||||||
[SerializeField] private DecorationData decorationData;
|
[SerializeField] private DecorationData decorationData;
|
||||||
|
|
||||||
private Controllers.DecorationMenuController _menuController;
|
private DecorationMenuController _menuController;
|
||||||
private DecorationDraggableInstance _activeDraggableInstance;
|
private DecorationDraggableInstance _activeDraggableInstance;
|
||||||
|
|
||||||
// Properties
|
// Properties
|
||||||
@@ -26,7 +28,7 @@ namespace Minigames.StatueDressup.DragDrop
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initialize the icon with decoration data
|
/// Initialize the icon with decoration data
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Initialize(DecorationData data, Controllers.DecorationMenuController controller)
|
public void Initialize(DecorationData data, DecorationMenuController controller)
|
||||||
{
|
{
|
||||||
decorationData = data;
|
decorationData = data;
|
||||||
_menuController = controller;
|
_menuController = controller;
|
||||||
@@ -46,6 +48,11 @@ namespace Minigames.StatueDressup.DragDrop
|
|||||||
if (_activeDraggableInstance == null)
|
if (_activeDraggableInstance == null)
|
||||||
{
|
{
|
||||||
Logging.Debug($"[DecorationGridIcon] Item tapped: {decorationData?.DecorationName}");
|
Logging.Debug($"[DecorationGridIcon] Item tapped: {decorationData?.DecorationName}");
|
||||||
|
|
||||||
|
// Broadcast tapped in grid event
|
||||||
|
var eventDataObj = new DecorationEventData(decorationData, gameObject, transform.position, fromStatue: false);
|
||||||
|
DecorationEventsManager.BroadcastDecorationTappedInGrid(eventDataObj);
|
||||||
|
|
||||||
// Future: Open detail view, preview, etc.
|
// Future: Open detail view, preview, etc.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
3
Assets/Scripts/Minigames/StatueDressup/Events.meta
Normal file
3
Assets/Scripts/Minigames/StatueDressup/Events.meta
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: fd293a0b6d2e4b28bd74bc8aff5fea01
|
||||||
|
timeCreated: 1764248911
|
||||||
@@ -0,0 +1,172 @@
|
|||||||
|
using Core;
|
||||||
|
using Core.Lifecycle;
|
||||||
|
using Minigames.StatueDressup.Data;
|
||||||
|
|
||||||
|
namespace Minigames.StatueDressup.Events
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Manager for decoration VFX/SFX events.
|
||||||
|
/// Listens to decoration state changes and triggers audio/visual feedback.
|
||||||
|
/// </summary>
|
||||||
|
public class DecorationEventsManager : ManagedBehaviour
|
||||||
|
{
|
||||||
|
public static DecorationEventsManager Instance { get; private set; }
|
||||||
|
|
||||||
|
// Static events for decoration state changes
|
||||||
|
public static event System.Action<DecorationEventData> OnDecorationTappedInGrid;
|
||||||
|
public static event System.Action<DecorationEventData> OnDecorationTappedOnStatue;
|
||||||
|
public static event System.Action<DecorationEventData> OnDecorationStartedDragging;
|
||||||
|
public static event System.Action<DecorationEventData> OnDecorationFinishedDragging;
|
||||||
|
public static event System.Action<DecorationEventData> OnDecorationDroppedOnStatue;
|
||||||
|
public static event System.Action<DecorationEventData> OnDecorationDroppedOut;
|
||||||
|
public static event System.Action<DecorationEventData> OnDecorationFinishedDroppingOut;
|
||||||
|
|
||||||
|
internal override void OnManagedAwake()
|
||||||
|
{
|
||||||
|
base.OnManagedAwake();
|
||||||
|
|
||||||
|
// Singleton pattern
|
||||||
|
if (Instance != null && Instance != this)
|
||||||
|
{
|
||||||
|
Logging.Warning("[DecorationEventsManager] Duplicate instance detected. Destroying duplicate.");
|
||||||
|
Destroy(gameObject);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Instance = this;
|
||||||
|
|
||||||
|
// Subscribe to all events
|
||||||
|
OnDecorationTappedInGrid += HandleDecorationTappedInGrid;
|
||||||
|
OnDecorationTappedOnStatue += HandleDecorationTappedOnStatue;
|
||||||
|
OnDecorationStartedDragging += HandleDecorationStartedDragging;
|
||||||
|
OnDecorationFinishedDragging += HandleDecorationFinishedDragging;
|
||||||
|
OnDecorationDroppedOnStatue += HandleDecorationDroppedOnStatue;
|
||||||
|
OnDecorationDroppedOut += HandleDecorationDroppedOut;
|
||||||
|
OnDecorationFinishedDroppingOut += HandleDecorationFinishedDroppingOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDestroy()
|
||||||
|
{
|
||||||
|
// Unsubscribe from all events
|
||||||
|
if (Instance == this)
|
||||||
|
{
|
||||||
|
OnDecorationTappedInGrid -= HandleDecorationTappedInGrid;
|
||||||
|
OnDecorationTappedOnStatue -= HandleDecorationTappedOnStatue;
|
||||||
|
OnDecorationStartedDragging -= HandleDecorationStartedDragging;
|
||||||
|
OnDecorationFinishedDragging -= HandleDecorationFinishedDragging;
|
||||||
|
OnDecorationDroppedOnStatue -= HandleDecorationDroppedOnStatue;
|
||||||
|
OnDecorationDroppedOut -= HandleDecorationDroppedOut;
|
||||||
|
OnDecorationFinishedDroppingOut -= HandleDecorationFinishedDroppingOut;
|
||||||
|
|
||||||
|
Instance = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Static Broadcasting Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Broadcast that a decoration was tapped in the grid menu
|
||||||
|
/// </summary>
|
||||||
|
public static void BroadcastDecorationTappedInGrid(DecorationEventData eventData)
|
||||||
|
{
|
||||||
|
OnDecorationTappedInGrid?.Invoke(eventData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Broadcast that a decoration already on the statue was tapped
|
||||||
|
/// </summary>
|
||||||
|
public static void BroadcastDecorationTappedOnStatue(DecorationEventData eventData)
|
||||||
|
{
|
||||||
|
OnDecorationTappedOnStatue?.Invoke(eventData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Broadcast that a decoration started being dragged
|
||||||
|
/// </summary>
|
||||||
|
public static void BroadcastDecorationStartedDragging(DecorationEventData eventData)
|
||||||
|
{
|
||||||
|
OnDecorationStartedDragging?.Invoke(eventData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Broadcast that a decoration finished being dragged (released)
|
||||||
|
/// </summary>
|
||||||
|
public static void BroadcastDecorationFinishedDragging(DecorationEventData eventData)
|
||||||
|
{
|
||||||
|
OnDecorationFinishedDragging?.Invoke(eventData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Broadcast that a decoration was successfully dropped on the statue
|
||||||
|
/// </summary>
|
||||||
|
public static void BroadcastDecorationDroppedOnStatue(DecorationEventData eventData)
|
||||||
|
{
|
||||||
|
OnDecorationDroppedOnStatue?.Invoke(eventData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Broadcast that a decoration was dropped outside the statue (animation starts)
|
||||||
|
/// </summary>
|
||||||
|
public static void BroadcastDecorationDroppedOut(DecorationEventData eventData)
|
||||||
|
{
|
||||||
|
OnDecorationDroppedOut?.Invoke(eventData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Broadcast that a decoration finished its drop-out animation
|
||||||
|
/// </summary>
|
||||||
|
public static void BroadcastDecorationFinishedDroppingOut(DecorationEventData eventData)
|
||||||
|
{
|
||||||
|
OnDecorationFinishedDroppingOut?.Invoke(eventData);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Event Handlers (Stubbed with Logs)
|
||||||
|
|
||||||
|
private void HandleDecorationTappedInGrid(DecorationEventData eventData)
|
||||||
|
{
|
||||||
|
Logging.Debug($"[DecorationEventsManager] Decoration tapped in grid: {eventData.DecorationData?.DecorationId}");
|
||||||
|
// TODO: Play tap SFX/VFX
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleDecorationTappedOnStatue(DecorationEventData eventData)
|
||||||
|
{
|
||||||
|
Logging.Debug($"[DecorationEventsManager] Decoration tapped on statue: {eventData.DecorationData?.DecorationId}");
|
||||||
|
// TODO: Play tap SFX/VFX (different from grid tap?)
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleDecorationStartedDragging(DecorationEventData eventData)
|
||||||
|
{
|
||||||
|
Logging.Debug($"[DecorationEventsManager] Decoration started dragging: {eventData.DecorationData?.DecorationId} (FromStatue: {eventData.FromStatue})");
|
||||||
|
// TODO: Play drag start SFX, maybe show drag VFX
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleDecorationFinishedDragging(DecorationEventData eventData)
|
||||||
|
{
|
||||||
|
Logging.Debug($"[DecorationEventsManager] Decoration finished dragging: {eventData.DecorationData?.DecorationId}");
|
||||||
|
// TODO: Play drag release SFX
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleDecorationDroppedOnStatue(DecorationEventData eventData)
|
||||||
|
{
|
||||||
|
Logging.Debug($"[DecorationEventsManager] Decoration dropped on statue: {eventData.DecorationData?.DecorationId}");
|
||||||
|
// TODO: Play success SFX, maybe show placement VFX
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleDecorationDroppedOut(DecorationEventData eventData)
|
||||||
|
{
|
||||||
|
Logging.Debug($"[DecorationEventsManager] Decoration dropped out (animation starting): {eventData.DecorationData?.DecorationId}");
|
||||||
|
// TODO: Play drop-out SFX (whoosh/disappear sound?)
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleDecorationFinishedDroppingOut(DecorationEventData eventData)
|
||||||
|
{
|
||||||
|
Logging.Debug($"[DecorationEventsManager] Decoration finished dropping out: {eventData.DecorationData?.DecorationId}");
|
||||||
|
// TODO: Play finish SFX (poof sound?), maybe show VFX
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 5c9796e0044a4fcd95b02a19925a6b2b
|
||||||
|
timeCreated: 1764248911
|
||||||
63
Assets/Scripts/Minigames/StatueDressup/IReadyNotifier.cs
Normal file
63
Assets/Scripts/Minigames/StatueDressup/IReadyNotifier.cs
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Minigames.StatueDressup
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interface for managers that load asynchronously and notify when ready.
|
||||||
|
/// Allows dependent components to safely access the manager via WhenReady callbacks.
|
||||||
|
/// </summary>
|
||||||
|
public interface IReadyNotifier
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// True when the manager has finished initialization and is ready to use
|
||||||
|
/// </summary>
|
||||||
|
bool IsReady { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event invoked when the manager becomes ready
|
||||||
|
/// </summary>
|
||||||
|
event Action OnReady;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Extension methods for IReadyNotifier to provide common callback behavior
|
||||||
|
/// </summary>
|
||||||
|
public static class ReadyNotifierExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Execute callback when ready. If already ready, executes immediately.
|
||||||
|
/// If not ready yet, subscribes to OnReady event and executes when fired.
|
||||||
|
/// </summary>
|
||||||
|
public static void WhenReady(this IReadyNotifier notifier, Action callback)
|
||||||
|
{
|
||||||
|
if (notifier == null)
|
||||||
|
{
|
||||||
|
Core.Logging.Warning("[ReadyNotifierExtensions] Notifier is null, cannot execute callback");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (callback == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (notifier.IsReady)
|
||||||
|
{
|
||||||
|
// Already ready - execute immediately
|
||||||
|
callback.Invoke();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Not ready yet - subscribe to event and auto-unsubscribe after invocation
|
||||||
|
Action handler = null;
|
||||||
|
handler = () =>
|
||||||
|
{
|
||||||
|
callback.Invoke();
|
||||||
|
notifier.OnReady -= handler; // Unsubscribe to prevent memory leaks
|
||||||
|
};
|
||||||
|
notifier.OnReady += handler;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: da5633d4a0f84ceeaca54bb2c542dca4
|
||||||
|
timeCreated: 1764244569
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
namespace Minigames.StatueDressup
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Default constants for StatueDressup minigame.
|
||||||
|
/// These serve as fallbacks when settings fail to load.
|
||||||
|
/// Prefer using settings configuration over these constants.
|
||||||
|
/// </summary>
|
||||||
|
public static class StatueDressupConstants
|
||||||
|
{
|
||||||
|
// Pagination
|
||||||
|
public const int DefaultMenuItemsPerPage = 20;
|
||||||
|
public const int DefaultGalleryItemsPerPage = 20;
|
||||||
|
|
||||||
|
// Animations
|
||||||
|
public const float DefaultAnimationDuration = 0.3f;
|
||||||
|
|
||||||
|
// Gallery/Photos - Performance Critical
|
||||||
|
// Note: These affect memory usage and should ideally come from settings
|
||||||
|
public const int DefaultThumbnailSize = 256;
|
||||||
|
public const int DefaultMaxCachedThumbnails = 50;
|
||||||
|
public const float DefaultEnlargedScale = 2.5f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 86c9225c5cc54b8b99b1964c393de5a3
|
||||||
|
timeCreated: 1764242098
|
||||||
154
docs/statue_minigame_primer.md
Normal file
154
docs/statue_minigame_primer.md
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
# Statue Decoration Minigame - Primer
|
||||||
|
|
||||||
|
A quick-start guide for designers and programmers working on the statue decoration minigame.
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
- [Overview](#overview)
|
||||||
|
- [Quick References](#quick-references)
|
||||||
|
- [Adding Audio/Visual Feedback](#adding-audiovisual-feedback)
|
||||||
|
- [Loading Decoration Data & Settings](#loading-decoration-data--settings)
|
||||||
|
- [Adding New Decorations](#adding-new-decorations)
|
||||||
|
- [Changing UI Layout](#changing-ui-layout)
|
||||||
|
- [Tweaking Behavior](#tweaking-behavior)
|
||||||
|
- [Photo Saving/Loading](#photo-savingloading)
|
||||||
|
- [Class Reference](#class-reference)
|
||||||
|
- [Controllers](#controllers)
|
||||||
|
- [Drag & Drop](#drag--drop)
|
||||||
|
- [Data & Events](#data--events)
|
||||||
|
- [Display](#display)
|
||||||
|
- [Settings](#settings)
|
||||||
|
- [Common Tasks](#common-tasks)
|
||||||
|
- [Known TODOs](#known-todos)
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
Players drag sticker decorations from a menu onto a statue, decorate it however they like, and take photos. Photos are saved to a gallery with decoration metadata so the statue can be restored in the town map miniature.
|
||||||
|
|
||||||
|
## Quick References
|
||||||
|
|
||||||
|
### Adding Audio/Visual Feedback
|
||||||
|
**Location:** `DecorationEventsManager.cs` in `Events/`
|
||||||
|
All decoration interactions broadcast events (tap, drag start, drag end, place, etc.). Subscribe to events or edit the stub handler methods to add your SFX/VFX. Just add a `DecorationEventsManager` component to the scene.
|
||||||
|
|
||||||
|
### Loading Decoration Data & Settings
|
||||||
|
**Location:** `DecorationDataManager.cs` in `Controllers/`
|
||||||
|
This singleton loads settings from GameManager, then loads all decoration sprites via Addressables. Everything happens automatically on scene start. Use `DecorationDataManager.WhenReady(() => { ... })` to wait for data before accessing.
|
||||||
|
|
||||||
|
### Adding New Decorations
|
||||||
|
**Location:** Create a `DecorationData` ScriptableObject in Unity
|
||||||
|
Set the sprite, ID, and name. Add it to the Addressables group specified in `StatueDressupSettings`. It'll appear in the menu automatically.
|
||||||
|
|
||||||
|
### Changing UI Layout
|
||||||
|
**Location:** `StatueDressupMinigame` scene
|
||||||
|
- Menu grid: `DecorationMenuController` → `ItemsContainer`
|
||||||
|
- Statue area: `StatueDecorationController` → `StatueImage` and `DecorationsParent`
|
||||||
|
- Photo gallery: `StatuePhotoGalleryController` → Grid and pagination UI
|
||||||
|
|
||||||
|
### Tweaking Behavior
|
||||||
|
**Location:** `StatueDressupSettings` ScriptableObject
|
||||||
|
Contains all tunable values: animation durations, menu items per page, gallery settings, drag thresholds, etc.
|
||||||
|
|
||||||
|
### Photo Saving/Loading
|
||||||
|
**Location:** `StatueDecorationController.cs` - `TakePhoto()` method
|
||||||
|
Photos are captured with metadata (decoration positions, scales, IDs). Use `PhotoManager` for save/load operations. Metadata is read by `StatueDecorationLoader` to restore decorations on the town map.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Class Reference
|
||||||
|
|
||||||
|
### Controllers
|
||||||
|
|
||||||
|
**`DecorationDataManager`**
|
||||||
|
- **What it does:** Loads settings and all decoration data from Addressables. Single source of truth for both.
|
||||||
|
- **When you might need it:** Accessing decoration sprites/data, checking if a decoration ID exists, waiting for data to be ready.
|
||||||
|
|
||||||
|
**`StatueDecorationController`**
|
||||||
|
- **What it does:** Main minigame controller - manages decoration placement, photo capture, and save/load of decoration state.
|
||||||
|
- **When you might need it:** Taking photos, getting/setting decoration placements, loading saved decorations, accessing statue UI references.
|
||||||
|
|
||||||
|
**`DecorationMenuController`**
|
||||||
|
- **What it does:** Manages the scrollable decoration picker menu with pagination and spawns draggable instances.
|
||||||
|
- **When you might need it:** Changing menu behavior, adding categories/filters, modifying how decorations are displayed.
|
||||||
|
|
||||||
|
**`StatuePhotoGalleryController`**
|
||||||
|
- **What it does:** Displays saved photos in a paginated grid with thumbnail caching and enlarged preview.
|
||||||
|
- **When you might need it:** Modifying gallery UI, changing thumbnail behavior, adding photo delete/share functionality.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Drag & Drop
|
||||||
|
|
||||||
|
**`DecorationDraggableInstance`**
|
||||||
|
- **What it does:** The actual draggable decoration instance that follows the cursor and can be placed on the statue.
|
||||||
|
- **When you might need it:** Changing drag behavior, adding visual effects during drag, modifying placement validation.
|
||||||
|
|
||||||
|
**`DecorationGridIcon`**
|
||||||
|
- **What it does:** Static menu icon that spawns a draggable instance when clicked/dragged.
|
||||||
|
- **When you might need it:** Adding icon animations, tooltips, or preview functionality to menu items.
|
||||||
|
|
||||||
|
**`DecorationDragContext`**
|
||||||
|
- **What it does:** Data container passed to draggable instances with all references and callbacks needed for dragging.
|
||||||
|
- **When you might need it:** Adding new data that draggables need during their lifecycle.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Data & Events
|
||||||
|
|
||||||
|
**`DecorationData`** (ScriptableObject)
|
||||||
|
- **What it does:** Defines a single decoration (sprite, ID, name, authored size).
|
||||||
|
- **When you might need it:** Creating new decorations or querying decoration properties.
|
||||||
|
|
||||||
|
**`DecorationPlacement`**
|
||||||
|
- **What it does:** Serializable data for a placed decoration (position, scale, rotation, sorting order).
|
||||||
|
- **When you might need it:** Saving/loading decoration state, modifying what gets persisted.
|
||||||
|
|
||||||
|
**`DecorationMetadata`**
|
||||||
|
- **What it does:** Complete metadata for all decorations on a photo (list of placements + coordinate system type).
|
||||||
|
- **When you might need it:** Working with photo save/load system, adding new metadata fields.
|
||||||
|
|
||||||
|
**`DecorationEventData`**
|
||||||
|
- **What it does:** Event payload containing decoration, instance GameObject, position, and context flags.
|
||||||
|
- **When you might need it:** Handling decoration events for SFX/VFX, adding new event data fields.
|
||||||
|
|
||||||
|
**`DecorationEventsManager`**
|
||||||
|
- **What it does:** Broadcasts and handles all decoration interaction events (tap, drag, place, etc.).
|
||||||
|
- **When you might need it:** Playing sounds/effects in response to decoration interactions, adding telemetry.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Display
|
||||||
|
|
||||||
|
**`StatueDecorationLoader`**
|
||||||
|
- **What it does:** Loads saved decoration metadata and spawns decorations on a statue (used in town map).
|
||||||
|
- **When you might need it:** Displaying decorations outside the minigame, fixing coordinate conversion bugs.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Settings
|
||||||
|
|
||||||
|
**`StatueDressupSettings`** (ScriptableObject in `Core/Settings`)
|
||||||
|
- **What it does:** All configuration values for the minigame (durations, counts, labels, thresholds).
|
||||||
|
- **When you might need it:** Tuning any minigame behavior without touching code.
|
||||||
|
|
||||||
|
**`StatueDressupConstants`**
|
||||||
|
- **What it does:** Fallback constant values if settings are missing.
|
||||||
|
- **When you might need it:** Setting default values or adding new configurable parameters.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Common Tasks
|
||||||
|
|
||||||
|
**Add a new decoration:**
|
||||||
|
Create `DecorationData` ScriptableObject → Set sprite/ID → Add to Addressables group
|
||||||
|
|
||||||
|
**Change drag feel:**
|
||||||
|
Edit `StatueDressupSettings` → Adjust `DragSnapThreshold` or animation durations
|
||||||
|
|
||||||
|
**Add sound to decoration tap:**
|
||||||
|
Edit `DecorationEventsManager.HandleDecorationTappedInGrid()` → Play your audio clip
|
||||||
|
|
||||||
|
**Change menu layout:**
|
||||||
|
Edit `StatueDressupSettings` → Adjust `ItemsPerPage` or edit menu prefab
|
||||||
|
|
||||||
|
**Debug save/load:**
|
||||||
|
Check `PhotoManager.SavePhoto()` and `StatueDecorationLoader.LoadAndDisplayDecorations()`
|
||||||
|
|
||||||
Reference in New Issue
Block a user