Update the statue game to include rotation etc.

This commit is contained in:
Michal Pikulski
2025-12-08 14:48:09 +01:00
parent fff50990f1
commit e338e28673
7 changed files with 2720 additions and 96 deletions

View 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");
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 7f3e2a1b9c4d5e6f7a8b9c0d1e2f3a4b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: