FInalize first pass over cement decoration game
This commit is contained in:
@@ -3,7 +3,6 @@ using Core;
|
||||
using Core.Lifecycle;
|
||||
using Minigames.StatueDressup.Data;
|
||||
using Minigames.StatueDressup.DragDrop;
|
||||
using UI.DragAndDrop.Core;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
@@ -15,21 +14,21 @@ namespace Minigames.StatueDressup.Controllers
|
||||
public class DecorationMenuController : ManagedBehaviour
|
||||
{
|
||||
[Header("References")]
|
||||
[SerializeField] private DecorationItem itemPrefab;
|
||||
[SerializeField] private DecorationGridIcon iconPrefab;
|
||||
[SerializeField] private DecorationDraggableInstance draggablePrefab;
|
||||
[SerializeField] private Transform itemsContainer;
|
||||
[SerializeField] private Transform draggableContainer; // Parent for spawned draggables
|
||||
[SerializeField] private Button nextPageButton;
|
||||
[SerializeField] private Button previousPageButton;
|
||||
[SerializeField] private RectTransform statueArea; // For overlap detection
|
||||
[SerializeField] private Transform statueParent; // Parent for placed decorations
|
||||
[SerializeField] private StatueDecorationController statueController; // Controller for registration
|
||||
[SerializeField] private Image statueOutline; // Outline image shown during drag to indicate valid drop area
|
||||
|
||||
[Header("Layout")]
|
||||
[SerializeField] private GridLayoutGroup gridLayout;
|
||||
|
||||
private int _currentPage;
|
||||
private int _totalPages;
|
||||
private List<DecorationItem> _spawnedItems = new List<DecorationItem>();
|
||||
private Dictionary<DecorationItem, DecorationData> _itemDataMapping = new Dictionary<DecorationItem, DecorationData>();
|
||||
private List<DecorationGridIcon> _spawnedIcons = new List<DecorationGridIcon>();
|
||||
private AppleHills.Core.Settings.IStatueDressupSettings _settings;
|
||||
|
||||
// Properties
|
||||
@@ -65,6 +64,12 @@ namespace Minigames.StatueDressup.Controllers
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure outline starts hidden
|
||||
if (statueOutline != null)
|
||||
{
|
||||
statueOutline.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
var allDecorations = _settings.AllDecorations;
|
||||
int itemsPerPage = _settings.ItemsPerPage;
|
||||
|
||||
@@ -101,7 +106,7 @@ namespace Minigames.StatueDressup.Controllers
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Populate the current page with decoration items
|
||||
/// Populate the current page with decoration icons
|
||||
/// </summary>
|
||||
private void PopulateCurrentPage()
|
||||
{
|
||||
@@ -118,19 +123,19 @@ namespace Minigames.StatueDressup.Controllers
|
||||
|
||||
Logging.Debug($"[DecorationMenuController] Populating page {_currentPage + 1}/{_totalPages}");
|
||||
|
||||
// Clear existing items
|
||||
ClearItems();
|
||||
// Clear existing icons
|
||||
ClearIcons();
|
||||
|
||||
// Calculate range for current page
|
||||
int startIndex = _currentPage * itemsPerPage;
|
||||
int endIndex = Mathf.Min(startIndex + itemsPerPage, allDecorations.Count);
|
||||
|
||||
Logging.Debug($"[DecorationMenuController] Spawning items {startIndex} to {endIndex - 1}");
|
||||
Logging.Debug($"[DecorationMenuController] Spawning icons {startIndex} to {endIndex - 1}");
|
||||
|
||||
// Spawn items for this page
|
||||
// Spawn icons for this page
|
||||
for (int i = startIndex; i < endIndex; i++)
|
||||
{
|
||||
SpawnDecorationItem(allDecorations[i]);
|
||||
SpawnGridIcon(allDecorations[i]);
|
||||
}
|
||||
|
||||
// Update button states
|
||||
@@ -138,99 +143,126 @@ namespace Minigames.StatueDressup.Controllers
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Spawn a decoration item in the menu
|
||||
/// Spawn a grid icon in the menu
|
||||
/// </summary>
|
||||
private void SpawnDecorationItem(DecorationData data)
|
||||
private void SpawnGridIcon(DecorationData data)
|
||||
{
|
||||
if (itemPrefab == null || itemsContainer == null)
|
||||
if (iconPrefab == null || itemsContainer == null)
|
||||
{
|
||||
Logging.Warning("[DecorationMenuController] Missing prefab or container");
|
||||
Logging.Warning("[DecorationMenuController] Missing icon prefab or container");
|
||||
return;
|
||||
}
|
||||
|
||||
DecorationItem item = Instantiate(itemPrefab, itemsContainer);
|
||||
item.SetDecorationData(data);
|
||||
DecorationGridIcon icon = Instantiate(iconPrefab, itemsContainer);
|
||||
icon.Initialize(data, this);
|
||||
|
||||
// Set statue references for overlap detection
|
||||
item.SetStatueArea(statueArea);
|
||||
item.SetStatueParent(statueParent);
|
||||
item.SetMenuParent(itemsContainer);
|
||||
item.SetController(statueController);
|
||||
_spawnedIcons.Add(icon);
|
||||
|
||||
// Store original position for return animation
|
||||
if (item.RectTransform != null)
|
||||
{
|
||||
// Force layout update to get correct position
|
||||
Canvas.ForceUpdateCanvases();
|
||||
item.SetOriginalMenuPosition(item.RectTransform.anchoredPosition);
|
||||
}
|
||||
|
||||
// Subscribe to drag events
|
||||
item.OnDragStarted += HandleItemPickedUp;
|
||||
item.OnDragEnded += HandleItemDropped;
|
||||
|
||||
_spawnedItems.Add(item);
|
||||
_itemDataMapping[item] = data;
|
||||
|
||||
Logging.Debug($"[DecorationMenuController] Spawned: {data.DecorationName} at position {item.RectTransform?.anchoredPosition}");
|
||||
Logging.Debug($"[DecorationMenuController] Spawned icon: {data.DecorationName}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle item picked up from menu
|
||||
/// Factory method: Spawn a draggable instance at cursor position
|
||||
/// Called by DecorationGridIcon when drag starts
|
||||
/// </summary>
|
||||
private void HandleItemPickedUp(DraggableObject draggable)
|
||||
public DecorationDraggableInstance SpawnDraggableInstance(DecorationData data, Vector3 screenPosition)
|
||||
{
|
||||
if (draggable is DecorationItem item && _itemDataMapping.ContainsKey(item))
|
||||
if (draggablePrefab == null || statueController == null)
|
||||
{
|
||||
Logging.Debug($"[DecorationMenuController] Item picked up: {item.Data?.DecorationName}");
|
||||
Logging.Warning("[DecorationMenuController] Missing draggable prefab or statue controller");
|
||||
return null;
|
||||
}
|
||||
|
||||
// Show statue outline
|
||||
ShowStatueOutline();
|
||||
|
||||
// Determine parent - use draggableContainer if set, otherwise itemsContainer's parent
|
||||
Transform parent = draggableContainer != null ? draggableContainer : itemsContainer.parent;
|
||||
|
||||
// Spawn draggable instance
|
||||
DecorationDraggableInstance instance = Instantiate(draggablePrefab, parent);
|
||||
|
||||
// Get outline RectTransform for overlap detection
|
||||
RectTransform outlineRect = statueOutline != null ? statueOutline.rectTransform : null;
|
||||
|
||||
// Initialize with references
|
||||
instance.Initialize(
|
||||
data,
|
||||
outlineRect,
|
||||
statueController.StatueParent,
|
||||
statueController,
|
||||
_settings,
|
||||
OnDraggableFinished
|
||||
);
|
||||
|
||||
// Position at cursor (in local space)
|
||||
Canvas canvas = GetComponentInParent<Canvas>();
|
||||
if (canvas != null)
|
||||
{
|
||||
RectTransformUtility.ScreenPointToLocalPointInRectangle(
|
||||
canvas.transform as RectTransform,
|
||||
screenPosition,
|
||||
canvas.worldCamera,
|
||||
out Vector2 localPoint);
|
||||
|
||||
// We'll spawn replacement only if item is actually placed, not on pickup
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle item dropped (either placed on statue or returned to menu)
|
||||
/// </summary>
|
||||
private void HandleItemDropped(DraggableObject draggable)
|
||||
{
|
||||
if (draggable is DecorationItem item && _itemDataMapping.ContainsKey(item))
|
||||
{
|
||||
Logging.Debug($"[DecorationMenuController] Item dropped: {item.Data?.DecorationName}, isPlacedOnStatue={item.IsPlacedOnStatue}");
|
||||
|
||||
// If item was placed on statue, spawn replacement in menu
|
||||
if (item.IsPlacedOnStatue && !item.IsInMenu)
|
||||
RectTransform instanceRect = instance.GetComponent<RectTransform>();
|
||||
if (instanceRect != null)
|
||||
{
|
||||
DecorationData data = _itemDataMapping[item];
|
||||
|
||||
// Remove original from tracking
|
||||
_spawnedItems.Remove(item);
|
||||
_itemDataMapping.Remove(item);
|
||||
|
||||
// Spawn replacement
|
||||
SpawnDecorationItem(data);
|
||||
|
||||
Logging.Debug($"[DecorationMenuController] Spawned replacement for: {data.DecorationName}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear all spawned items
|
||||
/// </summary>
|
||||
private void ClearItems()
|
||||
{
|
||||
foreach (var item in _spawnedItems)
|
||||
{
|
||||
if (item != null)
|
||||
{
|
||||
item.OnDragStarted -= HandleItemPickedUp;
|
||||
item.OnDragEnded -= HandleItemDropped;
|
||||
Destroy(item.gameObject);
|
||||
instanceRect.localPosition = localPoint;
|
||||
}
|
||||
}
|
||||
|
||||
_spawnedItems.Clear();
|
||||
_itemDataMapping.Clear();
|
||||
Logging.Debug($"[DecorationMenuController] Spawned draggable instance: {data.DecorationName}");
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Show the statue outline to indicate valid drop area
|
||||
/// </summary>
|
||||
private void ShowStatueOutline()
|
||||
{
|
||||
if (statueOutline != null)
|
||||
{
|
||||
statueOutline.gameObject.SetActive(true);
|
||||
Logging.Debug("[DecorationMenuController] Statue outline shown");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hide the statue outline after drag ends
|
||||
/// </summary>
|
||||
private void HideStatueOutline()
|
||||
{
|
||||
if (statueOutline != null)
|
||||
{
|
||||
statueOutline.gameObject.SetActive(false);
|
||||
Logging.Debug("[DecorationMenuController] Statue outline hidden");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Callback from DecorationDraggableInstance when drag finishes
|
||||
/// </summary>
|
||||
private void OnDraggableFinished()
|
||||
{
|
||||
HideStatueOutline();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear all spawned icons
|
||||
/// </summary>
|
||||
private void ClearIcons()
|
||||
{
|
||||
foreach (var icon in _spawnedIcons)
|
||||
{
|
||||
if (icon != null)
|
||||
{
|
||||
Destroy(icon.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
_spawnedIcons.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -293,8 +325,8 @@ namespace Minigames.StatueDressup.Controllers
|
||||
previousPageButton.onClick.RemoveListener(OnPreviousPage);
|
||||
}
|
||||
|
||||
// Cleanup item listeners
|
||||
ClearItems();
|
||||
// Cleanup icons
|
||||
ClearIcons();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,10 +27,13 @@ namespace Minigames.StatueDressup.Controllers
|
||||
[SerializeField] private RectTransform photoArea; // Area to capture
|
||||
[SerializeField] private string photoSaveKey = "MrCementStatuePhoto";
|
||||
|
||||
private List<DecorationItem> _placedDecorations = new List<DecorationItem>();
|
||||
private List<DecorationDraggableInstance> _placedDecorations = new List<DecorationDraggableInstance>();
|
||||
private bool _minigameCompleted;
|
||||
private AppleHills.Core.Settings.IStatueDressupSettings _settings;
|
||||
|
||||
// Public property for menu controller
|
||||
public Transform StatueParent => statueParent;
|
||||
|
||||
/// <summary>
|
||||
/// Early initialization - get settings reference
|
||||
/// </summary>
|
||||
@@ -72,7 +75,7 @@ namespace Minigames.StatueDressup.Controllers
|
||||
/// <summary>
|
||||
/// Register a decoration as placed on statue
|
||||
/// </summary>
|
||||
public void RegisterDecoration(DecorationItem decoration)
|
||||
public void RegisterDecoration(DecorationDraggableInstance decoration)
|
||||
{
|
||||
if (decoration != null && !_placedDecorations.Contains(decoration))
|
||||
{
|
||||
@@ -87,7 +90,7 @@ namespace Minigames.StatueDressup.Controllers
|
||||
/// <summary>
|
||||
/// Unregister a decoration (when removed)
|
||||
/// </summary>
|
||||
public void UnregisterDecoration(DecorationItem decoration)
|
||||
public void UnregisterDecoration(DecorationDraggableInstance decoration)
|
||||
{
|
||||
if (decoration != null && _placedDecorations.Contains(decoration))
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user