Setup scene for the statue nonsense

This commit is contained in:
Michal Pikulski
2025-11-24 13:43:42 +01:00
parent e9a6f35ef5
commit 6a41fd3340
50 changed files with 3391 additions and 214 deletions

View File

@@ -172,6 +172,7 @@ namespace Core
var cardSystemSettings = SettingsProvider.Instance.LoadSettingsSynchronous<CardSystemSettings>();
var sortingGameSettings = SettingsProvider.Instance.LoadSettingsSynchronous<CardSortingSettings>();
var birdPooperSettings = SettingsProvider.Instance.LoadSettingsSynchronous<BirdPooperSettings>();
var statueDressupSettings = SettingsProvider.Instance.LoadSettingsSynchronous<StatueDressupSettings>();
// Register settings with service locator
if (playerSettings != null)
@@ -233,9 +234,20 @@ namespace Core
{
Debug.LogError("Failed to load BirdPooperSettings");
}
if (statueDressupSettings != null)
{
ServiceLocator.Register<IStatueDressupSettings>(statueDressupSettings);
Logging.Debug("StatueDressupSettings registered successfully");
}
else
{
Debug.LogError("Failed to load StatueDressupSettings");
}
// Log success
_settingsLoaded = playerSettings != null && interactionSettings != null && minigameSettings != null && cardSystemSettings != null && birdPooperSettings != null;
_settingsLoaded = playerSettings != null && interactionSettings != null && minigameSettings != null
&& cardSystemSettings != null && birdPooperSettings != null && statueDressupSettings != null;
if (_settingsLoaded)
{
Logging.Debug("All settings loaded and registered with ServiceLocator");

View File

@@ -160,4 +160,43 @@ namespace AppleHills.Core.Settings
// General Animation
float DefaultAnimationDuration { get; }
}
/// <summary>
/// Interface for statue dressup minigame settings
/// </summary>
public interface IStatueDressupSettings
{
// Decoration Display
Vector2 DefaultIconSize { get; }
Vector2 DefaultAuthoredSize { get; }
// Menu Configuration
int ItemsPerPage { get; }
int GridColumns { get; }
Vector2 GridSpacing { get; }
// Drag and Drop
float DragScaleTransitionDuration { get; }
float ReturnToMenuDuration { get; }
float MinOverlapPercentage { get; }
// Animation
float HoverScaleMultiplier { get; }
float HoverAnimationDuration { get; }
float PlacementAnimationDuration { get; }
// Photo Settings
string PhotoSaveKey { get; }
int PhotoQuality { get; }
bool CaptureFullScreen { get; }
// Rewards
int CardsRewardCount { get; }
bool AutoCompleteOnPhoto { get; }
// State Persistence
bool EnableStatePersistence { get; }
string StateSaveKey { get; }
int MaxSavedDecorations { get; }
}
}

View File

@@ -0,0 +1,146 @@
using AppleHills.Core.Settings;
using UnityEngine;
namespace Core.Settings
{
/// <summary>
/// Settings for the Mr. Cement Statue Decoration minigame
/// </summary>
[CreateAssetMenu(fileName = "StatueDressupSettings", menuName = "AppleHills/Settings/Statue Dressup", order = 7)]
public class StatueDressupSettings : BaseSettings, IStatueDressupSettings
{
[Header("Decoration Display")]
[Tooltip("Default icon size for decorations in the menu grid")]
[SerializeField] private Vector2 defaultIconSize = new Vector2(64f, 64f);
[Tooltip("Default full size for decorations when placed on statue")]
[SerializeField] private Vector2 defaultAuthoredSize = new Vector2(128f, 128f);
[Header("Menu Configuration")]
[Tooltip("Number of decoration items to display per page (2 columns x 5 rows = 10)")]
[SerializeField] private int itemsPerPage = 10;
[Tooltip("Number of columns in the decoration grid")]
[SerializeField] private int gridColumns = 2;
[Tooltip("Spacing between grid items")]
[SerializeField] private Vector2 gridSpacing = new Vector2(10f, 10f);
[Header("Drag and Drop")]
[Tooltip("Duration for icon to full size transition when dragging starts")]
[SerializeField] private float dragScaleTransitionDuration = 0.2f;
[Tooltip("Duration for return to menu animation")]
[SerializeField] private float returnToMenuDuration = 0.3f;
[Tooltip("Minimum overlap percentage required to place on statue (0-1)")]
[SerializeField] private float minOverlapPercentage = 0.1f;
[Header("Animation")]
[Tooltip("Scale multiplier for hover effect (1.0 = no change, 1.1 = 10% larger)")]
[SerializeField] private float hoverScaleMultiplier = 1.05f;
[Tooltip("Duration of hover animation")]
[SerializeField] private float hoverAnimationDuration = 0.2f;
[Tooltip("Duration for placement animation")]
[SerializeField] private float placementAnimationDuration = 0.15f;
[Header("Photo Settings")]
[Tooltip("PlayerPrefs key for saving the statue photo")]
[SerializeField] private string photoSaveKey = "MrCementStatuePhoto";
[Tooltip("Quality of the captured photo (1-100)")]
[SerializeField] private int photoQuality = 85;
[Tooltip("Whether to capture full screen or just statue area")]
[SerializeField] private bool captureFullScreen;
[Header("Rewards")]
[Tooltip("Number of Blokkemon cards awarded on completion")]
[SerializeField] private int cardsRewardCount = 3;
[Tooltip("Whether completion is automatic or requires confirmation")]
[SerializeField] private bool autoCompleteOnPhoto = true;
[Header("State Persistence")]
[Tooltip("Whether to save decoration positions between sessions")]
[SerializeField] private bool enableStatePersistence = true;
[Tooltip("PlayerPrefs key for saving decoration state")]
[SerializeField] private string stateSaveKey = "StatueDecorationState";
[Tooltip("Maximum number of decorations to save")]
[SerializeField] private int maxSavedDecorations = 50;
// IStatueDressupSettings implementation - Decoration Display
public Vector2 DefaultIconSize => defaultIconSize;
public Vector2 DefaultAuthoredSize => defaultAuthoredSize;
// IStatueDressupSettings implementation - Menu Configuration
public int ItemsPerPage => itemsPerPage;
public int GridColumns => gridColumns;
public Vector2 GridSpacing => gridSpacing;
// IStatueDressupSettings implementation - Drag and Drop
public float DragScaleTransitionDuration => dragScaleTransitionDuration;
public float ReturnToMenuDuration => returnToMenuDuration;
public float MinOverlapPercentage => minOverlapPercentage;
// IStatueDressupSettings implementation - Animation
public float HoverScaleMultiplier => hoverScaleMultiplier;
public float HoverAnimationDuration => hoverAnimationDuration;
public float PlacementAnimationDuration => placementAnimationDuration;
// IStatueDressupSettings implementation - Photo Settings
public string PhotoSaveKey => photoSaveKey;
public int PhotoQuality => photoQuality;
public bool CaptureFullScreen => captureFullScreen;
// IStatueDressupSettings implementation - Rewards
public int CardsRewardCount => cardsRewardCount;
public bool AutoCompleteOnPhoto => autoCompleteOnPhoto;
// IStatueDressupSettings implementation - State Persistence
public bool EnableStatePersistence => enableStatePersistence;
public string StateSaveKey => stateSaveKey;
public int MaxSavedDecorations => maxSavedDecorations;
public override void OnValidate()
{
base.OnValidate();
// Validate decoration display
defaultIconSize.x = Mathf.Max(16f, defaultIconSize.x);
defaultIconSize.y = Mathf.Max(16f, defaultIconSize.y);
defaultAuthoredSize.x = Mathf.Max(32f, defaultAuthoredSize.x);
defaultAuthoredSize.y = Mathf.Max(32f, defaultAuthoredSize.y);
// Validate menu configuration
itemsPerPage = Mathf.Max(1, itemsPerPage);
gridColumns = Mathf.Max(1, gridColumns);
gridSpacing.x = Mathf.Max(0f, gridSpacing.x);
gridSpacing.y = Mathf.Max(0f, gridSpacing.y);
// Validate drag and drop
dragScaleTransitionDuration = Mathf.Max(0.01f, dragScaleTransitionDuration);
returnToMenuDuration = Mathf.Max(0.01f, returnToMenuDuration);
minOverlapPercentage = Mathf.Clamp01(minOverlapPercentage);
// Validate animation
hoverScaleMultiplier = Mathf.Max(1f, hoverScaleMultiplier);
hoverAnimationDuration = Mathf.Max(0.01f, hoverAnimationDuration);
placementAnimationDuration = Mathf.Max(0.01f, placementAnimationDuration);
// Validate photo settings
photoQuality = Mathf.Clamp(photoQuality, 1, 100);
// Validate rewards
cardsRewardCount = Mathf.Max(0, cardsRewardCount);
// Validate state persistence
maxSavedDecorations = Mathf.Max(1, maxSavedDecorations);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4fcf232a64e34f489b874519cc96339e
timeCreated: 1763984221

View File

@@ -1,7 +1,9 @@
using System.Collections.Generic;
using Core;
using Core.Lifecycle;
using Minigames.StatueDressup.Data;
using Minigames.StatueDressup.DragDrop;
using UI.DragAndDrop.Core;
using UnityEngine;
using UnityEngine.UI;
@@ -10,13 +12,16 @@ namespace Minigames.StatueDressup.Controllers
/// <summary>
/// Manages the side menu with decoration items and pagination
/// </summary>
public class DecorationMenuController : MonoBehaviour
public class DecorationMenuController : ManagedBehaviour
{
[Header("References")]
[SerializeField] private DecorationItem itemPrefab;
[SerializeField] private Transform itemsContainer;
[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
[Header("Configuration")]
[SerializeField] private List<DecorationData> allDecorations = new List<DecorationData>();
@@ -25,22 +30,40 @@ namespace Minigames.StatueDressup.Controllers
[Header("Layout")]
[SerializeField] private GridLayoutGroup gridLayout;
private int _currentPage = 0;
private int _totalPages = 0;
private int _currentPage;
private int _totalPages;
private List<DecorationItem> _spawnedItems = new List<DecorationItem>();
private Dictionary<DecorationItem, DecorationData> _itemDataMapping = new Dictionary<DecorationItem, DecorationData>();
private AppleHills.Core.Settings.IStatueDressupSettings _settings;
// Properties
public int CurrentPage => _currentPage;
public int TotalPages => _totalPages;
private void Start()
/// <summary>
/// Early initialization - get settings reference
/// </summary>
internal override void OnManagedAwake()
{
Initialize();
base.OnManagedAwake();
// Get settings early
_settings = GameManager.GetSettingsObject<AppleHills.Core.Settings.IStatueDressupSettings>();
// Override itemsPerPage with settings value if available
if (_settings != null)
{
itemsPerPage = _settings.ItemsPerPage;
}
}
private void Initialize()
/// <summary>
/// Main initialization after all managers are ready
/// </summary>
internal override void OnManagedStart()
{
base.OnManagedStart();
Logging.Debug($"[DecorationMenuController] Initializing with {allDecorations.Count} decorations");
// Calculate total pages
@@ -105,6 +128,12 @@ namespace Minigames.StatueDressup.Controllers
DecorationItem item = Instantiate(itemPrefab, itemsContainer);
item.SetDecorationData(data);
// Set statue references for overlap detection
item.SetStatueArea(statueArea);
item.SetStatueParent(statueParent);
item.SetMenuParent(itemsContainer);
item.SetController(statueController);
// Store original position for return animation
if (item.RectTransform != null)
{
@@ -132,9 +161,6 @@ namespace Minigames.StatueDressup.Controllers
{
Logging.Debug($"[DecorationMenuController] Item picked up: {item.Data?.DecorationName}");
// Spawn replacement in menu slot
// This ensures menu always shows available items
DecorationData data = _itemDataMapping[item];
// We'll spawn replacement only if item is actually placed, not on pickup
}
}
@@ -146,10 +172,10 @@ namespace Minigames.StatueDressup.Controllers
{
if (draggable is DecorationItem item && _itemDataMapping.ContainsKey(item))
{
Logging.Debug($"[DecorationMenuController] Item dropped: {item.Data?.DecorationName}, slot={item.CurrentSlot?.name}");
Logging.Debug($"[DecorationMenuController] Item dropped: {item.Data?.DecorationName}, isPlacedOnStatue={item.IsPlacedOnStatue}");
// If item was placed on statue, spawn replacement in menu
if (item.CurrentSlot != null && !item.IsInMenu)
if (item.IsPlacedOnStatue && !item.IsInMenu)
{
DecorationData data = _itemDataMapping[item];
@@ -226,8 +252,13 @@ namespace Minigames.StatueDressup.Controllers
}
}
private void OnDestroy()
/// <summary>
/// Cleanup when menu controller is destroyed
/// </summary>
internal override void OnManagedDestroy()
{
base.OnManagedDestroy();
// Cleanup button listeners
if (nextPageButton != null)
{

View File

@@ -1,5 +1,6 @@
using System.Collections.Generic;
using Core;
using Core.Lifecycle;
using Minigames.StatueDressup.DragDrop;
using UnityEngine;
using UnityEngine.UI;
@@ -8,11 +9,13 @@ namespace Minigames.StatueDressup.Controllers
{
/// <summary>
/// Main controller for the Mr. Cement statue decoration minigame
/// Uses overlap-based placement instead of slots
/// </summary>
public class StatueDecorationController : MonoBehaviour
public class StatueDecorationController : ManagedBehaviour
{
[Header("References")]
[SerializeField] private StatueDecorationSlot[] statueSlots;
[SerializeField] private RectTransform statueArea; // Statue area for overlap detection
[SerializeField] private Transform statueParent; // Parent for placed decorations
[SerializeField] private DecorationMenuController menuController;
[SerializeField] private Button takePhotoButton;
[SerializeField] private GameObject statue;
@@ -24,16 +27,28 @@ namespace Minigames.StatueDressup.Controllers
[SerializeField] private RectTransform photoArea; // Area to capture
[SerializeField] private string photoSaveKey = "MrCementStatuePhoto";
private Dictionary<StatueDecorationSlot, DecorationItem> _placedDecorations = new Dictionary<StatueDecorationSlot, DecorationItem>();
private bool _minigameCompleted = false;
private List<DecorationItem> _placedDecorations = new List<DecorationItem>();
private bool _minigameCompleted;
private AppleHills.Core.Settings.IStatueDressupSettings _settings;
private void Start()
/// <summary>
/// Early initialization - get settings reference
/// </summary>
internal override void OnManagedAwake()
{
Initialize();
base.OnManagedAwake();
// Get settings early
_settings = GameManager.GetSettingsObject<AppleHills.Core.Settings.IStatueDressupSettings>();
}
private void Initialize()
/// <summary>
/// Main initialization after all managers are ready
/// </summary>
internal override void OnManagedStart()
{
base.OnManagedStart();
Logging.Debug("[StatueDecorationController] Initializing minigame");
// Setup photo button
@@ -42,13 +57,12 @@ namespace Minigames.StatueDressup.Controllers
takePhotoButton.onClick.AddListener(OnTakePhoto);
}
// Subscribe to slot occupation events
foreach (var slot in statueSlots)
// Subscribe to menu controller for tracking placed items
// Items will manage their own placement via overlap detection
if (menuController != null)
{
if (slot != null)
{
slot.OnOccupied += HandleDecorationPlaced;
}
// Menu controller will handle spawning replacements
Logging.Debug("[StatueDecorationController] Menu controller connected");
}
// Load saved state if exists
@@ -56,21 +70,32 @@ namespace Minigames.StatueDressup.Controllers
}
/// <summary>
/// Handle decoration placed in slot
/// Register a decoration as placed on statue
/// </summary>
private void HandleDecorationPlaced(DraggableObject draggable)
public void RegisterDecoration(DecorationItem decoration)
{
if (draggable is DecorationItem decoration)
if (decoration != null && !_placedDecorations.Contains(decoration))
{
var slot = decoration.CurrentSlot as StatueDecorationSlot;
if (slot != null)
{
_placedDecorations[slot] = decoration;
Logging.Debug($"[StatueDecorationController] Decoration placed: {decoration.Data?.DecorationName} in slot {slot.name}");
// Auto-save state
SaveStatueState();
}
_placedDecorations.Add(decoration);
Logging.Debug($"[StatueDecorationController] Decoration placed: {decoration.Data?.DecorationName}");
// Auto-save state
SaveStatueState();
}
}
/// <summary>
/// Unregister a decoration (when removed)
/// </summary>
public void UnregisterDecoration(DecorationItem decoration)
{
if (decoration != null && _placedDecorations.Contains(decoration))
{
_placedDecorations.Remove(decoration);
Logging.Debug($"[StatueDecorationController] Decoration removed: {decoration.Data?.DecorationName}");
// Auto-save state
SaveStatueState();
}
}
@@ -155,11 +180,11 @@ namespace Minigames.StatueDressup.Controllers
Logging.Debug($"[StatueDecorationController] Capturing area: {width}x{height} at ({min.x}, {min.y})");
// Capture the specified area
Texture2D screenshot = new Texture2D(width, height, TextureFormat.RGB24, false);
screenshot.ReadPixels(new Rect(min.x, min.y, width, height), 0, 0);
screenshot.Apply();
Texture2D areaScreenshot = new Texture2D(width, height, TextureFormat.RGB24, false);
areaScreenshot.ReadPixels(new Rect(min.x, min.y, width, height), 0, 0);
areaScreenshot.Apply();
return screenshot;
return areaScreenshot;
}
/// <summary>
@@ -171,7 +196,8 @@ namespace Minigames.StatueDressup.Controllers
// For now, save to PlayerPrefs as base64
byte[] bytes = photo.EncodeToPNG();
string base64 = System.Convert.ToBase64String(bytes);
PlayerPrefs.SetString(photoSaveKey, base64);
string saveKey = _settings?.PhotoSaveKey ?? photoSaveKey;
PlayerPrefs.SetString(saveKey, base64);
PlayerPrefs.Save();
Logging.Debug("[StatueDecorationController] Photo saved to album");
@@ -228,10 +254,18 @@ namespace Minigames.StatueDressup.Controllers
/// </summary>
private void SaveStatueState()
{
// TODO: Implement save system
// Save slot ID -> decoration ID mapping
// Check if persistence is enabled
if (_settings == null || !_settings.EnableStatePersistence)
{
Logging.Debug("[StatueDecorationController] State persistence disabled");
return;
}
Logging.Debug("[StatueDecorationController] State saved (TODO: implement persistence)");
// TODO: Implement save system
// Save decoration ID + position + rotation for each placed item
// Respect MaxSavedDecorations limit
Logging.Debug($"[StatueDecorationController] State saved to {_settings.StateSaveKey} (TODO: implement persistence)");
}
/// <summary>
@@ -239,28 +273,31 @@ namespace Minigames.StatueDressup.Controllers
/// </summary>
private void LoadStatueState()
{
// TODO: Implement load system
// Restore decorations to slots
// Check if persistence is enabled
if (_settings == null || !_settings.EnableStatePersistence)
{
Logging.Debug("[StatueDecorationController] State persistence disabled");
return;
}
Logging.Debug("[StatueDecorationController] State loaded (TODO: implement persistence)");
// TODO: Implement load system
// Restore decorations from saved state
Logging.Debug($"[StatueDecorationController] State loaded from {_settings.StateSaveKey} (TODO: implement persistence)");
}
private void OnDestroy()
/// <summary>
/// Cleanup when controller is destroyed
/// </summary>
internal override void OnManagedDestroy()
{
base.OnManagedDestroy();
// Cleanup button listener
if (takePhotoButton != null)
{
takePhotoButton.onClick.RemoveListener(OnTakePhoto);
}
// Cleanup slot listeners
foreach (var slot in statueSlots)
{
if (slot != null)
{
slot.OnOccupied -= HandleDecorationPlaced;
}
}
}
}
}

View File

@@ -29,7 +29,6 @@ namespace Minigames.StatueDressup.Data
public string DecorationId => decorationId;
public string DecorationName => decorationName;
public Sprite DecorationSprite => decorationSprite;
public DecorationCategory Category => category;
public Vector2 AuthoredSize => authoredSize;
public Vector2 IconSize => iconSize;
public bool IsUnlocked => isUnlocked;

View File

@@ -1,4 +1,5 @@
using Core;
using Minigames.StatueDressup.Controllers;
using Minigames.StatueDressup.Data;
using Minigames.StatueDressup.Utils;
using UI.DragAndDrop.Core;
@@ -8,7 +9,8 @@ using UnityEngine.UI;
namespace Minigames.StatueDressup.DragDrop
{
/// <summary>
/// Individual decoration item that can be dragged from menu to statue slots
/// Individual decoration item that can be dragged from menu to statue
/// Uses overlap detection instead of slot-based placement
/// </summary>
public class DecorationItem : DraggableObject
{
@@ -16,20 +18,38 @@ namespace Minigames.StatueDressup.DragDrop
[SerializeField] private DecorationData decorationData;
[SerializeField] private Image decorationImage;
[Header("Placement")]
[SerializeField] private RectTransform statueArea; // Reference to statue area for overlap check
private Vector2 _iconSize;
private Vector2 _authoredSize;
private Vector2 _originalMenuPosition;
private Vector2 _placedPosition; // Position when placed on statue
private bool _isInMenu = true;
private bool _isPlacedOnStatue = false;
private Transform _menuParent; // Original parent in menu
private Transform _statueParent; // Parent when placed on statue
private StatueDecorationController _controller; // Controller for registration
private AppleHills.Core.Settings.IStatueDressupSettings _settings; // Settings reference
// Properties
public DecorationData Data => decorationData;
public DecorationCategory Category => decorationData?.Category ?? DecorationCategory.Hats;
public bool IsInMenu => _isInMenu;
public bool IsPlacedOnStatue => _isPlacedOnStatue;
protected override void Initialize()
{
base.Initialize();
// Get settings
_settings = GameManager.GetSettingsObject<AppleHills.Core.Settings.IStatueDressupSettings>();
// Store menu parent
_menuParent = transform.parent;
// Find statue parent (will be set by controller)
// statueParent will be assigned externally
if (decorationData != null)
{
_iconSize = decorationData.IconSize;
@@ -83,35 +103,136 @@ namespace Minigames.StatueDressup.DragDrop
}
}
/// <summary>
/// Set statue area reference for overlap detection
/// </summary>
public void SetStatueArea(RectTransform statue)
{
statueArea = statue;
}
/// <summary>
/// Set statue parent for placing items
/// </summary>
public void SetStatueParent(Transform parent)
{
_statueParent = parent;
}
/// <summary>
/// Set controller for registration callbacks
/// </summary>
public void SetController(StatueDecorationController controller)
{
_controller = controller;
}
protected override void OnDragStartedHook()
{
Logging.Debug($"[DecorationItem] OnDragStarted: {decorationData?.DecorationName}");
// If picking up from statue, allow re-positioning
if (_isPlacedOnStatue)
{
_isPlacedOnStatue = false;
Logging.Debug($"[DecorationItem] Picking up from statue for re-positioning");
}
// Scale to authored size when dragging starts
if (RectTransform != null)
{
TweenAnimationUtility.AnimateScale(transform, Vector3.one, 0.2f);
// Animate size delta to authored size
// Smoothly transition from icon size to authored size
RectTransform.sizeDelta = _authoredSize;
float duration = _settings?.DragScaleTransitionDuration ?? 0.2f;
TweenAnimationUtility.AnimateScale(transform, Vector3.one, duration);
}
}
protected override void OnDragEndedHook()
{
Logging.Debug($"[DecorationItem] OnDragEnded: {decorationData?.DecorationName}, currentSlot={CurrentSlot?.name}");
Logging.Debug($"[DecorationItem] OnDragEnded: {decorationData?.DecorationName}");
// If not placed in a slot, return to menu
if (CurrentSlot == null)
// Check if overlapping with statue
if (IsOverlappingStatue())
{
ReturnToMenu();
PlaceOnStatue();
}
else
{
_isInMenu = false;
ReturnToMenu();
}
}
/// <summary>
/// Check if item overlaps with statue area
/// </summary>
private bool IsOverlappingStatue()
{
if (statueArea == null || RectTransform == null)
{
Logging.Warning($"[DecorationItem] Cannot check overlap - statueArea or RectTransform is null");
return false;
}
// Get bounds of this item in world space
Rect itemRect = GetWorldRect(RectTransform);
Rect statueRect = GetWorldRect(statueArea);
// Check for any overlap
bool overlaps = itemRect.Overlaps(statueRect);
Logging.Debug($"[DecorationItem] Overlap check: {decorationData?.DecorationName}, overlaps={overlaps}");
Logging.Debug($"[DecorationItem] Item rect: {itemRect}, Statue rect: {statueRect}");
return overlaps;
}
/// <summary>
/// Get world space rect for a RectTransform
/// </summary>
private Rect GetWorldRect(RectTransform rectTransform)
{
Vector3[] corners = new Vector3[4];
rectTransform.GetWorldCorners(corners);
Vector3 bottomLeft = corners[0];
Vector3 topRight = corners[2];
return new Rect(bottomLeft.x, bottomLeft.y, topRight.x - bottomLeft.x, topRight.y - bottomLeft.y);
}
/// <summary>
/// Place item on statue at current position
/// </summary>
private void PlaceOnStatue()
{
Logging.Debug($"[DecorationItem] Placing on statue: {decorationData?.DecorationName}");
_isInMenu = false;
_isPlacedOnStatue = true;
// Store current position
if (RectTransform != null)
{
_placedPosition = RectTransform.anchoredPosition;
}
// Move to statue parent if specified
if (_statueParent != null && transform.parent != _statueParent)
{
transform.SetParent(_statueParent, true); // Keep world position
}
// Register with controller
if (_controller != null)
{
_controller.RegisterDecoration(this);
}
// Keep authored size
// Position is already set by drag
}
/// <summary>
/// Return item to menu with animation
/// </summary>
@@ -119,21 +240,34 @@ namespace Minigames.StatueDressup.DragDrop
{
Logging.Debug($"[DecorationItem] Returning to menu: {decorationData?.DecorationName}");
// Unregister from controller if was placed on statue
if (_isPlacedOnStatue && _controller != null)
{
_controller.UnregisterDecoration(this);
}
_isInMenu = true;
_isPlacedOnStatue = false;
// Return to menu parent
if (_menuParent != null && transform.parent != _menuParent)
{
transform.SetParent(_menuParent, false); // Use local positioning
}
if (RectTransform != null)
{
// Animate back to icon size
RectTransform.sizeDelta = _iconSize;
TweenAnimationUtility.AnimateScale(transform, Vector3.one, 0.2f);
float scaleDuration = _settings?.DragScaleTransitionDuration ?? 0.2f;
TweenAnimationUtility.AnimateScale(transform, Vector3.one, scaleDuration);
// Animate back to original position
TweenAnimationUtility.AnimateAnchoredPosition(RectTransform, _originalMenuPosition, 0.3f);
float returnDuration = _settings?.ReturnToMenuDuration ?? 0.3f;
TweenAnimationUtility.AnimateAnchoredPosition(RectTransform, _originalMenuPosition, returnDuration);
}
}
/// <summary>
/// Set original menu position (called by menu controller)
/// </summary>
@@ -141,6 +275,14 @@ namespace Minigames.StatueDressup.DragDrop
{
_originalMenuPosition = position;
}
/// <summary>
/// Set menu parent (called by menu controller)
/// </summary>
public void SetMenuParent(Transform parent)
{
_menuParent = parent;
}
}
}

View File

@@ -13,7 +13,6 @@ namespace Minigames.StatueDressup.DragDrop
public class StatueDecorationSlot : DraggableSlot, IPointerEnterHandler, IPointerExitHandler
{
[Header("Slot Configuration")]
[SerializeField] private DecorationCategory allowedCategory;
[SerializeField] private bool isPermanent = true; // Can't remove once placed
[Header("Glow Effect")]
@@ -23,9 +22,7 @@ namespace Minigames.StatueDressup.DragDrop
private bool _isGlowing;
private Pixelplacement.TweenSystem.TweenBase _glowTween;
// Properties
public DecorationCategory AllowedCategory => allowedCategory;
public bool IsPermanent => isPermanent;
private void Start()
@@ -43,7 +40,7 @@ namespace Minigames.StatueDressup.DragDrop
if (eventData.pointerDrag != null)
{
var decoration = eventData.pointerDrag.GetComponent<DecorationItem>();
if (decoration != null && decoration.Category == allowedCategory && !IsOccupied)
if (decoration != null && !IsOccupied)
{
StartGlow();
}
@@ -100,19 +97,7 @@ namespace Minigames.StatueDressup.DragDrop
public new bool CanAccept(DraggableObject draggable)
{
// First check base conditions
if (!base.CanAccept(draggable))
return false;
// Then check category matching
if (draggable is DecorationItem decoration)
{
bool matches = decoration.Category == allowedCategory;
Logging.Debug($"[StatueDecorationSlot] CanAccept: {decoration.Data?.DecorationName}, " +
$"category={decoration.Category}, allowed={allowedCategory}, matches={matches}");
return matches;
}
return false;
return base.CanAccept(draggable);
}
private void OnDisable()

View File

@@ -122,7 +122,7 @@ namespace Minigames.StatueDressup.Utils
Vector3 originalScale = transform.localScale;
Vector3 pulseScale = originalScale * pulseAmount;
return Tween.LocalScale(transform, pulseScale, duration, 0f, Tween.EaseInOutSine, Tween.LoopType.PingPong);
return Tween.LocalScale(transform, pulseScale, duration, 0f, Tween.EaseIn, Tween.LoopType.PingPong);
}
/// <summary>

View File

@@ -235,7 +235,7 @@ namespace UI
case "Quarry":
currentUIMode = UIMode.Puzzle;
break;
case "DivingForPictures" or "CardQualityControl" or "BirdPoop":
case "DivingForPictures" or "CardQualityControl" or "BirdPoop" or "StatueDecoration":
currentUIMode = UIMode.Minigame;
break;
}