Update the statue game to include rotation etc.
This commit is contained in:
288
Assets/Scripts/Minigames/StatueDressup/UI/DecorationEditUI.cs
Normal file
288
Assets/Scripts/Minigames/StatueDressup/UI/DecorationEditUI.cs
Normal file
@@ -0,0 +1,288 @@
|
||||
using Core;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using Minigames.StatueDressup.DragDrop;
|
||||
|
||||
namespace Minigames.StatueDressup.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// UI panel for editing a placed decoration's scale and rotation.
|
||||
/// Shows sliders for scale (0.1x - 2x) and rotation (-180° to 180°).
|
||||
/// Changes are applied immediately to the decoration's transform.
|
||||
/// </summary>
|
||||
public class DecorationEditUI : MonoBehaviour
|
||||
{
|
||||
[Header("UI References")]
|
||||
[SerializeField] private Slider scaleSlider;
|
||||
[SerializeField] private Slider rotationSlider;
|
||||
[SerializeField] private Button confirmButton;
|
||||
[SerializeField] private Button resetButton;
|
||||
[SerializeField] private CanvasGroup canvasGroup;
|
||||
|
||||
[Header("Slider Ranges")]
|
||||
[SerializeField] private float minScale = 0.1f;
|
||||
[SerializeField] private float maxScale = 2.0f;
|
||||
[SerializeField] private float minRotation = -180f;
|
||||
[SerializeField] private float maxRotation = 180f;
|
||||
|
||||
private DecorationDraggableInstance _targetDecoration;
|
||||
private RectTransform _rectTransform;
|
||||
private float _originalRotation;
|
||||
private bool _isInitialized;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
// Get RectTransform
|
||||
_rectTransform = GetComponent<RectTransform>();
|
||||
|
||||
// Ensure canvas group exists
|
||||
if (canvasGroup == null)
|
||||
{
|
||||
canvasGroup = GetComponent<CanvasGroup>();
|
||||
if (canvasGroup == null)
|
||||
{
|
||||
canvasGroup = gameObject.AddComponent<CanvasGroup>();
|
||||
}
|
||||
}
|
||||
|
||||
// Setup slider ranges
|
||||
if (scaleSlider != null)
|
||||
{
|
||||
scaleSlider.minValue = minScale;
|
||||
scaleSlider.maxValue = maxScale;
|
||||
scaleSlider.onValueChanged.AddListener(OnScaleChanged);
|
||||
}
|
||||
|
||||
if (rotationSlider != null)
|
||||
{
|
||||
rotationSlider.minValue = minRotation;
|
||||
rotationSlider.maxValue = maxRotation;
|
||||
rotationSlider.onValueChanged.AddListener(OnRotationChanged);
|
||||
}
|
||||
|
||||
// Setup buttons
|
||||
if (confirmButton != null)
|
||||
{
|
||||
confirmButton.onClick.AddListener(OnConfirm);
|
||||
}
|
||||
|
||||
if (resetButton != null)
|
||||
{
|
||||
resetButton.onClick.AddListener(OnReset);
|
||||
}
|
||||
|
||||
// Start hidden
|
||||
gameObject.SetActive(false);
|
||||
|
||||
_isInitialized = true;
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
// Clean up listeners
|
||||
if (scaleSlider != null)
|
||||
{
|
||||
scaleSlider.onValueChanged.RemoveListener(OnScaleChanged);
|
||||
}
|
||||
|
||||
if (rotationSlider != null)
|
||||
{
|
||||
rotationSlider.onValueChanged.RemoveListener(OnRotationChanged);
|
||||
}
|
||||
|
||||
if (confirmButton != null)
|
||||
{
|
||||
confirmButton.onClick.RemoveListener(OnConfirm);
|
||||
}
|
||||
|
||||
if (resetButton != null)
|
||||
{
|
||||
resetButton.onClick.RemoveListener(OnReset);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Show the edit UI for the given decoration
|
||||
/// </summary>
|
||||
public void Show(DecorationDraggableInstance decoration)
|
||||
{
|
||||
if (!_isInitialized)
|
||||
{
|
||||
Logging.Error("[DecorationEditUI] Attempted to show before initialization!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (decoration == null)
|
||||
{
|
||||
Logging.Error("[DecorationEditUI] Cannot show edit UI - decoration is null!");
|
||||
return;
|
||||
}
|
||||
|
||||
_targetDecoration = decoration;
|
||||
|
||||
// Store original rotation for reference
|
||||
_originalRotation = decoration.transform.localEulerAngles.z;
|
||||
|
||||
// Normalize rotation to -180 to 180 range
|
||||
if (_originalRotation > 180f)
|
||||
{
|
||||
_originalRotation -= 360f;
|
||||
}
|
||||
|
||||
// Initialize sliders from current transform values
|
||||
if (scaleSlider != null)
|
||||
{
|
||||
// Use X component for uniform scale
|
||||
float currentScale = decoration.transform.localScale.x;
|
||||
scaleSlider.value = Mathf.Clamp(currentScale, minScale, maxScale);
|
||||
}
|
||||
|
||||
if (rotationSlider != null)
|
||||
{
|
||||
rotationSlider.value = Mathf.Clamp(_originalRotation, minRotation, maxRotation);
|
||||
}
|
||||
|
||||
// Disable decoration raycasts during editing
|
||||
CanvasGroup decorationCanvasGroup = decoration.GetComponent<CanvasGroup>();
|
||||
if (decorationCanvasGroup != null)
|
||||
{
|
||||
decorationCanvasGroup.blocksRaycasts = false;
|
||||
}
|
||||
|
||||
// Position UI centered over the decoration (context menu style)
|
||||
PositionOverDecoration(decoration);
|
||||
|
||||
// Show UI immediately
|
||||
gameObject.SetActive(true);
|
||||
|
||||
if (canvasGroup != null)
|
||||
{
|
||||
canvasGroup.alpha = 1f;
|
||||
}
|
||||
|
||||
Logging.Debug($"[DecorationEditUI] Showing edit UI for: {decoration.Data?.DecorationName}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Position the UI centered over the decoration (context menu style)
|
||||
/// </summary>
|
||||
private void PositionOverDecoration(DecorationDraggableInstance decoration)
|
||||
{
|
||||
if (_rectTransform == null || decoration == null) return;
|
||||
|
||||
// Get decoration's world position
|
||||
Vector3 decorationWorldPos = decoration.transform.position;
|
||||
|
||||
// Convert to canvas space if using screen space overlay
|
||||
Canvas canvas = GetComponentInParent<Canvas>();
|
||||
if (canvas != null && canvas.renderMode == RenderMode.ScreenSpaceOverlay)
|
||||
{
|
||||
// For overlay canvas, world position is already correct
|
||||
_rectTransform.position = decorationWorldPos;
|
||||
}
|
||||
else if (canvas != null)
|
||||
{
|
||||
// For other canvas modes, convert properly
|
||||
RectTransformUtility.ScreenPointToLocalPointInRectangle(
|
||||
canvas.transform as RectTransform,
|
||||
RectTransformUtility.WorldToScreenPoint(canvas.worldCamera, decorationWorldPos),
|
||||
canvas.worldCamera,
|
||||
out Vector2 localPoint
|
||||
);
|
||||
_rectTransform.localPosition = localPoint;
|
||||
}
|
||||
|
||||
Logging.Debug($"[DecorationEditUI] Positioned at decoration location: {decorationWorldPos}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hide the edit UI
|
||||
/// </summary>
|
||||
public void Hide()
|
||||
{
|
||||
if (_targetDecoration != null)
|
||||
{
|
||||
// Re-enable decoration raycasts
|
||||
CanvasGroup decorationCanvasGroup = _targetDecoration.GetComponent<CanvasGroup>();
|
||||
if (decorationCanvasGroup != null)
|
||||
{
|
||||
decorationCanvasGroup.blocksRaycasts = true;
|
||||
}
|
||||
}
|
||||
|
||||
_targetDecoration = null;
|
||||
gameObject.SetActive(false);
|
||||
|
||||
Logging.Debug("[DecorationEditUI] Edit UI hidden");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle scale slider change
|
||||
/// </summary>
|
||||
private void OnScaleChanged(float value)
|
||||
{
|
||||
if (_targetDecoration == null) return;
|
||||
|
||||
// Apply uniform scale (X, Y, Z all the same)
|
||||
_targetDecoration.transform.localScale = Vector3.one * value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle rotation slider change
|
||||
/// </summary>
|
||||
private void OnRotationChanged(float value)
|
||||
{
|
||||
if (_targetDecoration == null) return;
|
||||
|
||||
// Apply Z rotation only
|
||||
_targetDecoration.transform.localEulerAngles = new Vector3(0f, 0f, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle confirm button - save changes and close
|
||||
/// </summary>
|
||||
private void OnConfirm()
|
||||
{
|
||||
if (_targetDecoration != null)
|
||||
{
|
||||
// Trigger auto-save through the controller
|
||||
var controller = Controllers.StatueDecorationController.Instance;
|
||||
if (controller != null)
|
||||
{
|
||||
// The controller's RegisterDecoration already triggers SaveStatueState
|
||||
// Since the decoration is already registered, we just need to trigger a save
|
||||
// This happens automatically on the next RegisterDecoration/UnregisterDecoration call
|
||||
Logging.Debug("[DecorationEditUI] Changes confirmed - will be auto-saved");
|
||||
}
|
||||
}
|
||||
|
||||
Hide();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle reset button - restore original values
|
||||
/// </summary>
|
||||
private void OnReset()
|
||||
{
|
||||
if (_targetDecoration == null) return;
|
||||
|
||||
// Reset to authored size (scale 1.0) and 0 rotation
|
||||
float defaultScale = 1.0f;
|
||||
float defaultRotation = 0f;
|
||||
|
||||
if (scaleSlider != null)
|
||||
{
|
||||
scaleSlider.value = defaultScale;
|
||||
}
|
||||
|
||||
if (rotationSlider != null)
|
||||
{
|
||||
rotationSlider.value = defaultRotation;
|
||||
}
|
||||
|
||||
// Values are applied through the slider callbacks
|
||||
Logging.Debug("[DecorationEditUI] Reset to defaults");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7f3e2a1b9c4d5e6f7a8b9c0d1e2f3a4b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
||||
Reference in New Issue
Block a user