Add pinch controls to statue dressup game
This commit is contained in:
@@ -1,8 +1,8 @@
|
|||||||
using UnityEngine;
|
using Minigames.TrashMaze.Objects;
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
using Minigames.TrashMaze.Objects;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace Minigames.TrashMaze.Editor
|
namespace Editor.CustomEditorsAndDrawers
|
||||||
{
|
{
|
||||||
[CustomEditor(typeof(RevealableObject))]
|
[CustomEditor(typeof(RevealableObject))]
|
||||||
public class RevealableObjectEditor : UnityEditor.Editor
|
public class RevealableObjectEditor : UnityEditor.Editor
|
||||||
File diff suppressed because one or more lines are too long
@@ -2010,6 +2010,7 @@ Transform:
|
|||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
--- !u!212 &831113526
|
--- !u!212 &831113526
|
||||||
SpriteRenderer:
|
SpriteRenderer:
|
||||||
|
serializedVersion: 2
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
m_PrefabInstance: {fileID: 0}
|
m_PrefabInstance: {fileID: 0}
|
||||||
@@ -2055,6 +2056,7 @@ SpriteRenderer:
|
|||||||
m_SortingLayerID: 0
|
m_SortingLayerID: 0
|
||||||
m_SortingLayer: 0
|
m_SortingLayer: 0
|
||||||
m_SortingOrder: 1
|
m_SortingOrder: 1
|
||||||
|
m_MaskInteraction: 0
|
||||||
m_Sprite: {fileID: -9176826819293939900, guid: 7b00cd0000ef4424985cd21fb4f197ee, type: 3}
|
m_Sprite: {fileID: -9176826819293939900, guid: 7b00cd0000ef4424985cd21fb4f197ee, type: 3}
|
||||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||||
m_FlipX: 0
|
m_FlipX: 0
|
||||||
@@ -2064,7 +2066,6 @@ SpriteRenderer:
|
|||||||
m_AdaptiveModeThreshold: 0.5
|
m_AdaptiveModeThreshold: 0.5
|
||||||
m_SpriteTileMode: 0
|
m_SpriteTileMode: 0
|
||||||
m_WasSpriteAssigned: 1
|
m_WasSpriteAssigned: 1
|
||||||
m_MaskInteraction: 0
|
|
||||||
m_SpriteSortPoint: 0
|
m_SpriteSortPoint: 0
|
||||||
--- !u!1 &948124904
|
--- !u!1 &948124904
|
||||||
GameObject:
|
GameObject:
|
||||||
@@ -6571,6 +6572,10 @@ PrefabInstance:
|
|||||||
propertyPath: maxSpeed
|
propertyPath: maxSpeed
|
||||||
value: 15
|
value: 15
|
||||||
objectReference: {fileID: 0}
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 7852204877518954380, guid: 8ac0210dbf9d7754e9526d6d5c214f49, type: 3}
|
||||||
|
propertyPath: maxAcceleration
|
||||||
|
value: 1000
|
||||||
|
objectReference: {fileID: 0}
|
||||||
m_RemovedComponents: []
|
m_RemovedComponents: []
|
||||||
m_RemovedGameObjects: []
|
m_RemovedGameObjects: []
|
||||||
m_AddedGameObjects: []
|
m_AddedGameObjects: []
|
||||||
|
|||||||
@@ -228,6 +228,10 @@ namespace AppleHills.Core.Settings
|
|||||||
bool EnableStatePersistence { get; }
|
bool EnableStatePersistence { get; }
|
||||||
string StateSaveKey { get; }
|
string StateSaveKey { get; }
|
||||||
int MaxSavedDecorations { get; }
|
int MaxSavedDecorations { get; }
|
||||||
|
|
||||||
|
// Pinch Controls
|
||||||
|
float MinDecorationScale { get; }
|
||||||
|
float MaxDecorationScale { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -90,6 +90,13 @@ namespace Core.Settings
|
|||||||
[Tooltip("Maximum number of decorations to save")]
|
[Tooltip("Maximum number of decorations to save")]
|
||||||
[SerializeField] private int maxSavedDecorations = 50;
|
[SerializeField] private int maxSavedDecorations = 50;
|
||||||
|
|
||||||
|
[Header("Pinch Controls")]
|
||||||
|
[Tooltip("Minimum scale for decorations when using pinch controls")]
|
||||||
|
[SerializeField] private float minDecorationScale = 0.1f;
|
||||||
|
|
||||||
|
[Tooltip("Maximum scale for decorations when using pinch controls")]
|
||||||
|
[SerializeField] private float maxDecorationScale = 2.0f;
|
||||||
|
|
||||||
// IStatueDressupSettings implementation - Decoration Display
|
// IStatueDressupSettings implementation - Decoration Display
|
||||||
public Vector2 DefaultAuthoredSize => defaultAuthoredSize;
|
public Vector2 DefaultAuthoredSize => defaultAuthoredSize;
|
||||||
|
|
||||||
@@ -136,6 +143,10 @@ namespace Core.Settings
|
|||||||
public string StateSaveKey => stateSaveKey;
|
public string StateSaveKey => stateSaveKey;
|
||||||
public int MaxSavedDecorations => maxSavedDecorations;
|
public int MaxSavedDecorations => maxSavedDecorations;
|
||||||
|
|
||||||
|
// IStatueDressupSettings implementation - Pinch Controls
|
||||||
|
public float MinDecorationScale => minDecorationScale;
|
||||||
|
public float MaxDecorationScale => maxDecorationScale;
|
||||||
|
|
||||||
public override void OnValidate()
|
public override void OnValidate()
|
||||||
{
|
{
|
||||||
base.OnValidate();
|
base.OnValidate();
|
||||||
@@ -168,6 +179,10 @@ namespace Core.Settings
|
|||||||
|
|
||||||
// Validate state persistence
|
// Validate state persistence
|
||||||
maxSavedDecorations = Mathf.Max(1, maxSavedDecorations);
|
maxSavedDecorations = Mathf.Max(1, maxSavedDecorations);
|
||||||
|
|
||||||
|
// Validate pinch controls
|
||||||
|
minDecorationScale = Mathf.Max(0.01f, minDecorationScale);
|
||||||
|
maxDecorationScale = Mathf.Max(minDecorationScale + 0.1f, maxDecorationScale);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,32 +1,33 @@
|
|||||||
using Core.SaveLoad;
|
using Core.SaveLoad;
|
||||||
using UnityEditor.Animations;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using System.Collections;
|
|
||||||
|
|
||||||
public class FrakkeAnimEventTrigger : MonoBehaviour
|
namespace DamianExperiments.Dump
|
||||||
{
|
{
|
||||||
[Header("Frakke Crashing References")]
|
public class FrakkeAnimEventTrigger : MonoBehaviour
|
||||||
public AppleMachine FrakkeSMRef;
|
|
||||||
public GameObject stateToChangeToAfterCrashing;
|
|
||||||
|
|
||||||
[Header("Fence Breaking References")]
|
|
||||||
public AppleMachine FenceSMRef;
|
|
||||||
public GameObject FenceStateToSet;
|
|
||||||
|
|
||||||
public void OnFrakkeCrashEnded()
|
|
||||||
{
|
{
|
||||||
FrakkeSMRef.ChangeState(stateToChangeToAfterCrashing);
|
[Header("Frakke Crashing References")]
|
||||||
}
|
public AppleMachine FrakkeSMRef;
|
||||||
|
public GameObject stateToChangeToAfterCrashing;
|
||||||
|
|
||||||
public void OnFenceBroken()
|
[Header("Fence Breaking References")]
|
||||||
{
|
public AppleMachine FenceSMRef;
|
||||||
if (FenceSMRef != null)
|
public GameObject FenceStateToSet;
|
||||||
|
|
||||||
|
public void OnFrakkeCrashEnded()
|
||||||
{
|
{
|
||||||
FenceSMRef.ChangeState(FenceStateToSet);
|
FrakkeSMRef.ChangeState(stateToChangeToAfterCrashing);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
public void OnFenceBroken()
|
||||||
{
|
{
|
||||||
Debug.LogWarning("FrakkeRevUpCrashBehaviour: FenceSMRef is not assigned.");
|
if (FenceSMRef != null)
|
||||||
|
{
|
||||||
|
FenceSMRef.ChangeState(FenceStateToSet);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.LogWarning("FrakkeRevUpCrashBehaviour: FenceSMRef is not assigned.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,20 @@
|
|||||||
using Core.SaveLoad;
|
|
||||||
using UnityEditor.Animations;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
public class FrakkeCrashedBehaviour : MonoBehaviour
|
namespace DamianExperiments.Dump
|
||||||
{
|
{
|
||||||
public Animator FrakkeAnimControllerRef;
|
public class FrakkeCrashedBehaviour : MonoBehaviour
|
||||||
|
|
||||||
|
|
||||||
private void OnEnable()
|
|
||||||
{
|
{
|
||||||
if (FrakkeAnimControllerRef != null)
|
public Animator FrakkeAnimControllerRef;
|
||||||
{
|
|
||||||
FrakkeAnimControllerRef.SetTrigger("Crashes");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
private void OnEnable()
|
||||||
|
{
|
||||||
|
if (FrakkeAnimControllerRef != null)
|
||||||
|
{
|
||||||
|
FrakkeAnimControllerRef.SetTrigger("Crashes");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
using Core.SaveLoad;
|
|
||||||
using UnityEditor.Animations;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using System.Collections;
|
|
||||||
|
|
||||||
public class FrakkeRevUpCrashBehaviour : MonoBehaviour
|
namespace DamianExperiments.Dump
|
||||||
{
|
{
|
||||||
public Animator FrakkeAnimControllerRef;
|
public class FrakkeRevUpCrashBehaviour : MonoBehaviour
|
||||||
|
|
||||||
private void OnEnable()
|
|
||||||
{
|
{
|
||||||
if (FrakkeAnimControllerRef != null)
|
public Animator FrakkeAnimControllerRef;
|
||||||
|
|
||||||
|
private void OnEnable()
|
||||||
{
|
{
|
||||||
FrakkeAnimControllerRef.SetTrigger("SpeedsOff");
|
if (FrakkeAnimControllerRef != null)
|
||||||
|
{
|
||||||
|
FrakkeAnimControllerRef.SetTrigger("SpeedsOff");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -285,7 +285,7 @@ namespace Input
|
|||||||
};
|
};
|
||||||
|
|
||||||
var results = new System.Collections.Generic.List<RaycastResult>();
|
var results = new System.Collections.Generic.List<RaycastResult>();
|
||||||
EventSystem.current.RaycastAll(eventData, results);
|
EventSystem.current.RaycastAll(eventData, results);
|
||||||
|
|
||||||
foreach (var result in results)
|
foreach (var result in results)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -26,9 +26,8 @@ namespace Minigames.StatueDressup.Controllers
|
|||||||
[SerializeField] private GameObject statue;
|
[SerializeField] private GameObject statue;
|
||||||
[SerializeField] private DecorationDraggableInstance draggablePrefab; // Prefab for spawning decorations
|
[SerializeField] private DecorationDraggableInstance draggablePrefab; // Prefab for spawning decorations
|
||||||
|
|
||||||
[Header("Edit UI")]
|
[Header("Pinch Controls")]
|
||||||
[SerializeField] private UI.DecorationEditUI editUIPrefab; // Prefab for edit UI
|
private UI.DecorationPinchController _pinchControllerInstance;
|
||||||
private UI.DecorationEditUI _editUIInstance;
|
|
||||||
|
|
||||||
[Header("UI Pages")]
|
[Header("UI Pages")]
|
||||||
[SerializeField] private UI.PlayAreaPage playAreaPage;
|
[SerializeField] private UI.PlayAreaPage playAreaPage;
|
||||||
@@ -460,35 +459,37 @@ namespace Minigames.StatueDressup.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Show edit UI for a placed decoration
|
/// Show pinch controls for a placed decoration
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void ShowEditUI(DecorationDraggableInstance decoration)
|
public void ShowEditUI(DecorationDraggableInstance decoration)
|
||||||
{
|
{
|
||||||
if (decoration == null)
|
if (decoration == null)
|
||||||
{
|
{
|
||||||
Logging.Warning("[StatueDecorationController] Cannot show edit UI - decoration is null");
|
Logging.Warning("[StatueDecorationController] Cannot show pinch controls - decoration is null");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create edit UI instance if needed
|
// Create pinch controller instance if needed
|
||||||
if (_editUIInstance == null)
|
if (_pinchControllerInstance == null)
|
||||||
{
|
{
|
||||||
if (editUIPrefab == null)
|
// Find canvas transform
|
||||||
{
|
|
||||||
Logging.Error("[StatueDecorationController] Edit UI prefab is not assigned!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Instantiate as child of canvas (find appropriate parent)
|
|
||||||
Transform canvasTransform = statueArea != null ? statueArea.root : transform.root;
|
Transform canvasTransform = statueArea != null ? statueArea.root : transform.root;
|
||||||
_editUIInstance = Instantiate(editUIPrefab, canvasTransform);
|
|
||||||
_editUIInstance.transform.SetAsLastSibling(); // Ensure it's on top
|
|
||||||
|
|
||||||
Logging.Debug("[StatueDecorationController] Created edit UI instance");
|
// Create new GameObject with DecorationPinchController component
|
||||||
|
GameObject pinchControllerObj = new GameObject("DecorationPinchController");
|
||||||
|
pinchControllerObj.transform.SetParent(canvasTransform, false);
|
||||||
|
|
||||||
|
// Add the component (it will auto-create RectTransform, Image, CanvasGroup, PinchGestureHandler in Awake)
|
||||||
|
_pinchControllerInstance = pinchControllerObj.AddComponent<UI.DecorationPinchController>();
|
||||||
|
|
||||||
|
// Ensure it's on top
|
||||||
|
pinchControllerObj.transform.SetAsLastSibling();
|
||||||
|
|
||||||
|
Logging.Debug("[StatueDecorationController] Created pinch controller instance dynamically");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show the UI
|
// Show the pinch controls
|
||||||
_editUIInstance.Show(decoration);
|
_pinchControllerInstance.Show(decoration);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1,288 +0,0 @@
|
|||||||
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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 7f3e2a1b9c4d5e6f7a8b9c0d1e2f3a4b
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
|
|
||||||
@@ -0,0 +1,266 @@
|
|||||||
|
using Core;
|
||||||
|
using Minigames.StatueDressup.Controllers;
|
||||||
|
using Minigames.StatueDressup.DragDrop;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.UI;
|
||||||
|
|
||||||
|
namespace Minigames.StatueDressup.UI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Manages pinch-to-scale and pinch-to-rotate controls for placed decorations.
|
||||||
|
/// Shows a semi-transparent backdrop and listens for pinch gestures.
|
||||||
|
/// Tap anywhere to dismiss and save changes.
|
||||||
|
/// </summary>
|
||||||
|
public class DecorationPinchController : MonoBehaviour
|
||||||
|
{
|
||||||
|
[Header("UI References")]
|
||||||
|
[SerializeField] private PinchGestureHandler gestureHandler;
|
||||||
|
[SerializeField] private CanvasGroup backdropCanvasGroup;
|
||||||
|
[SerializeField] private Image backdropImage;
|
||||||
|
|
||||||
|
[Header("Backdrop Settings")]
|
||||||
|
[SerializeField] private Color backdropColor = new Color(0f, 0f, 0f, 0.5f);
|
||||||
|
[Tooltip("Sort order for the active decoration to render above backdrop")]
|
||||||
|
[SerializeField] private int activeDecorationSortOrder = 100;
|
||||||
|
|
||||||
|
private DecorationDraggableInstance _targetDecoration;
|
||||||
|
private AppleHills.Core.Settings.IStatueDressupSettings _settings;
|
||||||
|
private bool _isInitialized;
|
||||||
|
|
||||||
|
// Canvas management for rendering order
|
||||||
|
private Canvas _temporaryDecorationCanvas;
|
||||||
|
private int _backdropSortOrder;
|
||||||
|
private void Awake()
|
||||||
|
{
|
||||||
|
// Ensure components exist
|
||||||
|
if (gestureHandler == null)
|
||||||
|
{
|
||||||
|
gestureHandler = GetComponentInChildren<PinchGestureHandler>();
|
||||||
|
if (gestureHandler == null)
|
||||||
|
{
|
||||||
|
// Create gesture handler if not found
|
||||||
|
GameObject handlerObj = new GameObject("PinchGestureHandler");
|
||||||
|
handlerObj.transform.SetParent(transform, false);
|
||||||
|
gestureHandler = handlerObj.AddComponent<PinchGestureHandler>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (backdropCanvasGroup == null)
|
||||||
|
{
|
||||||
|
backdropCanvasGroup = GetComponent<CanvasGroup>();
|
||||||
|
if (backdropCanvasGroup == null)
|
||||||
|
{
|
||||||
|
backdropCanvasGroup = gameObject.AddComponent<CanvasGroup>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (backdropImage == null)
|
||||||
|
{
|
||||||
|
backdropImage = GetComponent<Image>();
|
||||||
|
if (backdropImage == null)
|
||||||
|
{
|
||||||
|
backdropImage = gameObject.AddComponent<Image>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure backdrop
|
||||||
|
backdropImage.color = backdropColor;
|
||||||
|
backdropImage.raycastTarget = true;
|
||||||
|
|
||||||
|
// Ensure fullscreen
|
||||||
|
RectTransform rectTransform = GetComponent<RectTransform>();
|
||||||
|
if (rectTransform != null)
|
||||||
|
{
|
||||||
|
rectTransform.anchorMin = Vector2.zero;
|
||||||
|
rectTransform.anchorMax = Vector2.one;
|
||||||
|
rectTransform.offsetMin = Vector2.zero;
|
||||||
|
rectTransform.offsetMax = Vector2.zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subscribe to gesture events
|
||||||
|
if (gestureHandler != null)
|
||||||
|
{
|
||||||
|
gestureHandler.OnPinchScale += HandlePinchScale;
|
||||||
|
gestureHandler.OnPinchRotate += HandlePinchRotate;
|
||||||
|
gestureHandler.OnDismissTap += HandleDismiss;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load settings
|
||||||
|
_settings = DecorationDataManager.Instance?.Settings;
|
||||||
|
|
||||||
|
// Get backdrop's canvas sort order for reference
|
||||||
|
Canvas backdropCanvas = GetComponentInParent<Canvas>();
|
||||||
|
if (backdropCanvas != null)
|
||||||
|
{
|
||||||
|
_backdropSortOrder = backdropCanvas.sortingOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start hidden
|
||||||
|
gameObject.SetActive(false);
|
||||||
|
|
||||||
|
_isInitialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDestroy()
|
||||||
|
{
|
||||||
|
// Unsubscribe from gesture events
|
||||||
|
if (gestureHandler != null)
|
||||||
|
{
|
||||||
|
gestureHandler.OnPinchScale -= HandlePinchScale;
|
||||||
|
gestureHandler.OnPinchRotate -= HandlePinchRotate;
|
||||||
|
gestureHandler.OnDismissTap -= HandleDismiss;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Show pinch controls for the given decoration
|
||||||
|
/// </summary>
|
||||||
|
public void Show(DecorationDraggableInstance decoration)
|
||||||
|
{
|
||||||
|
if (!_isInitialized)
|
||||||
|
{
|
||||||
|
Logging.Error("[DecorationPinchController] Attempted to show before initialization!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (decoration == null)
|
||||||
|
{
|
||||||
|
Logging.Error("[DecorationPinchController] Cannot show pinch controller - decoration is null!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_targetDecoration = decoration;
|
||||||
|
|
||||||
|
// Add temporary Canvas component to decoration to control render order
|
||||||
|
_temporaryDecorationCanvas = decoration.gameObject.GetComponent<Canvas>();
|
||||||
|
if (_temporaryDecorationCanvas == null)
|
||||||
|
{
|
||||||
|
_temporaryDecorationCanvas = decoration.gameObject.AddComponent<Canvas>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure canvas to override sorting and render above backdrop
|
||||||
|
_temporaryDecorationCanvas.overrideSorting = true;
|
||||||
|
_temporaryDecorationCanvas.sortingOrder = _backdropSortOrder + activeDecorationSortOrder;
|
||||||
|
|
||||||
|
// Disable decoration raycasts during editing
|
||||||
|
CanvasGroup decorationCanvasGroup = decoration.GetComponent<CanvasGroup>();
|
||||||
|
if (decorationCanvasGroup != null)
|
||||||
|
{
|
||||||
|
decorationCanvasGroup.blocksRaycasts = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show UI
|
||||||
|
gameObject.SetActive(true);
|
||||||
|
|
||||||
|
if (backdropCanvasGroup != null)
|
||||||
|
{
|
||||||
|
backdropCanvasGroup.alpha = 1f;
|
||||||
|
backdropCanvasGroup.blocksRaycasts = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Activate gesture detection
|
||||||
|
if (gestureHandler != null)
|
||||||
|
{
|
||||||
|
gestureHandler.Activate();
|
||||||
|
}
|
||||||
|
|
||||||
|
Logging.Debug($"[DecorationPinchController] Showing pinch controls for: {decoration.Data?.DecorationName}");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Hide pinch controls
|
||||||
|
/// </summary>
|
||||||
|
public void Hide()
|
||||||
|
{
|
||||||
|
if (_targetDecoration != null)
|
||||||
|
{
|
||||||
|
// Remove temporary Canvas component to restore original rendering
|
||||||
|
if (_temporaryDecorationCanvas != null)
|
||||||
|
{
|
||||||
|
Destroy(_temporaryDecorationCanvas);
|
||||||
|
_temporaryDecorationCanvas = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Re-enable decoration raycasts
|
||||||
|
CanvasGroup decorationCanvasGroup = _targetDecoration.GetComponent<CanvasGroup>();
|
||||||
|
if (decorationCanvasGroup != null)
|
||||||
|
{
|
||||||
|
decorationCanvasGroup.blocksRaycasts = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deactivate gesture detection
|
||||||
|
if (gestureHandler != null)
|
||||||
|
{
|
||||||
|
gestureHandler.Deactivate();
|
||||||
|
}
|
||||||
|
|
||||||
|
_targetDecoration = null;
|
||||||
|
gameObject.SetActive(false);
|
||||||
|
|
||||||
|
Logging.Debug("[DecorationPinchController] Pinch controls hidden");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handle pinch scale gesture
|
||||||
|
/// </summary>
|
||||||
|
private void HandlePinchScale(float scaleDelta)
|
||||||
|
{
|
||||||
|
if (_targetDecoration == null || _settings == null) return;
|
||||||
|
|
||||||
|
// Get current scale
|
||||||
|
Vector3 currentScale = _targetDecoration.transform.localScale;
|
||||||
|
float newScaleValue = currentScale.x + scaleDelta;
|
||||||
|
|
||||||
|
// Clamp to settings constraints
|
||||||
|
newScaleValue = Mathf.Clamp(newScaleValue, _settings.MinDecorationScale, _settings.MaxDecorationScale);
|
||||||
|
|
||||||
|
// Apply uniform scale
|
||||||
|
_targetDecoration.transform.localScale = Vector3.one * newScaleValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handle pinch rotate gesture
|
||||||
|
/// </summary>
|
||||||
|
private void HandlePinchRotate(float angleDelta)
|
||||||
|
{
|
||||||
|
if (_targetDecoration == null) return;
|
||||||
|
|
||||||
|
// Get current rotation
|
||||||
|
Vector3 currentRotation = _targetDecoration.transform.localEulerAngles;
|
||||||
|
|
||||||
|
// Apply rotation delta (Z-axis only for 2D)
|
||||||
|
float newZRotation = currentRotation.z + angleDelta;
|
||||||
|
|
||||||
|
// Normalize to -180 to 180 range for cleaner values
|
||||||
|
while (newZRotation > 180f) newZRotation -= 360f;
|
||||||
|
while (newZRotation < -180f) newZRotation += 360f;
|
||||||
|
|
||||||
|
_targetDecoration.transform.localEulerAngles = new Vector3(0f, 0f, newZRotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handle dismiss tap - save and close
|
||||||
|
/// </summary>
|
||||||
|
private void HandleDismiss()
|
||||||
|
{
|
||||||
|
if (_targetDecoration != null)
|
||||||
|
{
|
||||||
|
// Trigger auto-save through the controller
|
||||||
|
var controller = Controllers.StatueDecorationController.Instance;
|
||||||
|
if (controller != null)
|
||||||
|
{
|
||||||
|
// The decoration is already registered, but we need to trigger a save
|
||||||
|
// We can force this by unregistering and re-registering
|
||||||
|
controller.UnregisterDecoration(_targetDecoration);
|
||||||
|
controller.RegisterDecoration(_targetDecoration);
|
||||||
|
|
||||||
|
Logging.Debug("[DecorationPinchController] Changes saved on dismissal");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 1c8a81e283ec41b7b257c0a6824d32cf
|
||||||
|
timeCreated: 1765369467
|
||||||
212
Assets/Scripts/Minigames/StatueDressup/UI/PinchGestureHandler.cs
Normal file
212
Assets/Scripts/Minigames/StatueDressup/UI/PinchGestureHandler.cs
Normal file
@@ -0,0 +1,212 @@
|
|||||||
|
using System;
|
||||||
|
using Core;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.InputSystem;
|
||||||
|
using UnityEngine.InputSystem.EnhancedTouch;
|
||||||
|
using Touch = UnityEngine.InputSystem.EnhancedTouch.Touch;
|
||||||
|
|
||||||
|
namespace Minigames.StatueDressup.UI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Detects and processes pinch gestures for scaling and rotation using Unity's new Input System (EnhancedTouch).
|
||||||
|
/// Also detects single-tap dismissal and provides keyboard shortcuts for editor testing.
|
||||||
|
/// </summary>
|
||||||
|
public class PinchGestureHandler : MonoBehaviour
|
||||||
|
{
|
||||||
|
[Header("Gesture Settings")]
|
||||||
|
[Tooltip("Minimum distance change to register as pinch scale gesture")]
|
||||||
|
[SerializeField] private float minPinchDistance = 10f;
|
||||||
|
|
||||||
|
[Tooltip("Sensitivity multiplier for scale changes")]
|
||||||
|
[SerializeField] private float scaleSensitivity = 0.01f;
|
||||||
|
|
||||||
|
[Tooltip("Sensitivity multiplier for rotation changes")]
|
||||||
|
[SerializeField] private float rotationSensitivity = 1.0f;
|
||||||
|
|
||||||
|
[Header("Editor Testing (Keyboard)")]
|
||||||
|
[Tooltip("Keyboard rotation speed in degrees per second")]
|
||||||
|
[SerializeField] private float keyboardRotationSpeed = 90f;
|
||||||
|
|
||||||
|
[Tooltip("Keyboard scale speed per second")]
|
||||||
|
[SerializeField] private float keyboardScaleSpeed = 0.5f;
|
||||||
|
|
||||||
|
// Events
|
||||||
|
public event Action<float> OnPinchScale;
|
||||||
|
public event Action<float> OnPinchRotate;
|
||||||
|
public event Action OnDismissTap;
|
||||||
|
|
||||||
|
private bool _isActive;
|
||||||
|
private float _previousDistance;
|
||||||
|
private float _previousAngle;
|
||||||
|
private double _touchStartTime;
|
||||||
|
private bool _wasTouchTracked;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Activate gesture detection
|
||||||
|
/// </summary>
|
||||||
|
public void Activate()
|
||||||
|
{
|
||||||
|
_isActive = true;
|
||||||
|
_previousDistance = 0f;
|
||||||
|
_previousAngle = 0f;
|
||||||
|
_wasTouchTracked = false;
|
||||||
|
|
||||||
|
// Enable enhanced touch support for new Input System
|
||||||
|
if (!EnhancedTouchSupport.enabled)
|
||||||
|
{
|
||||||
|
EnhancedTouchSupport.Enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
Logging.Debug("[PinchGestureHandler] Activated");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Deactivate gesture detection
|
||||||
|
/// </summary>
|
||||||
|
public void Deactivate()
|
||||||
|
{
|
||||||
|
_isActive = false;
|
||||||
|
Logging.Debug("[PinchGestureHandler] Deactivated");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Update()
|
||||||
|
{
|
||||||
|
if (!_isActive) return;
|
||||||
|
|
||||||
|
// Handle touch input (mobile) - using new Input System
|
||||||
|
if (Touch.activeTouches.Count > 0)
|
||||||
|
{
|
||||||
|
HandleTouchInput();
|
||||||
|
}
|
||||||
|
// Handle keyboard input (editor testing)
|
||||||
|
else if (Application.isEditor)
|
||||||
|
{
|
||||||
|
HandleKeyboardInput();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Process touch input for pinch gestures and single-tap dismissal
|
||||||
|
/// </summary>
|
||||||
|
private void HandleTouchInput()
|
||||||
|
{
|
||||||
|
var activeTouches = Touch.activeTouches;
|
||||||
|
|
||||||
|
// Single tap for dismissal
|
||||||
|
if (activeTouches.Count == 1)
|
||||||
|
{
|
||||||
|
Touch touch = activeTouches[0];
|
||||||
|
|
||||||
|
// Track touch start time
|
||||||
|
if (touch.phase == UnityEngine.InputSystem.TouchPhase.Began)
|
||||||
|
{
|
||||||
|
_touchStartTime = touch.startTime;
|
||||||
|
_wasTouchTracked = true;
|
||||||
|
}
|
||||||
|
// Detect tap (touch began and ended quickly - within 0.3 seconds)
|
||||||
|
else if (touch.phase == UnityEngine.InputSystem.TouchPhase.Ended && _wasTouchTracked)
|
||||||
|
{
|
||||||
|
double touchDuration = Time.timeAsDouble - _touchStartTime;
|
||||||
|
if (touchDuration < 0.3)
|
||||||
|
{
|
||||||
|
Logging.Debug("[PinchGestureHandler] Single tap detected for dismissal");
|
||||||
|
OnDismissTap?.Invoke();
|
||||||
|
}
|
||||||
|
_wasTouchTracked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Two-finger pinch for scale and rotation
|
||||||
|
else if (activeTouches.Count == 2)
|
||||||
|
{
|
||||||
|
Touch touch0 = activeTouches[0];
|
||||||
|
Touch touch1 = activeTouches[1];
|
||||||
|
|
||||||
|
// Calculate current positions and distance
|
||||||
|
Vector2 currentTouch0 = touch0.screenPosition;
|
||||||
|
Vector2 currentTouch1 = touch1.screenPosition;
|
||||||
|
float currentDistance = Vector2.Distance(currentTouch0, currentTouch1);
|
||||||
|
float currentAngle = Mathf.Atan2(currentTouch1.y - currentTouch0.y, currentTouch1.x - currentTouch0.x) * Mathf.Rad2Deg;
|
||||||
|
|
||||||
|
// Initialize on first frame of pinch
|
||||||
|
if (touch0.phase == UnityEngine.InputSystem.TouchPhase.Began || touch1.phase == UnityEngine.InputSystem.TouchPhase.Began)
|
||||||
|
{
|
||||||
|
_previousDistance = currentDistance;
|
||||||
|
_previousAngle = currentAngle;
|
||||||
|
Logging.Debug("[PinchGestureHandler] Pinch gesture started");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process pinch scale (distance change)
|
||||||
|
if (touch0.phase == UnityEngine.InputSystem.TouchPhase.Moved || touch1.phase == UnityEngine.InputSystem.TouchPhase.Moved)
|
||||||
|
{
|
||||||
|
if (_previousDistance > minPinchDistance)
|
||||||
|
{
|
||||||
|
float distanceDelta = currentDistance - _previousDistance;
|
||||||
|
float scaleDelta = distanceDelta * scaleSensitivity;
|
||||||
|
|
||||||
|
if (Mathf.Abs(scaleDelta) > 0.001f)
|
||||||
|
{
|
||||||
|
OnPinchScale?.Invoke(scaleDelta);
|
||||||
|
Logging.Debug($"[PinchGestureHandler] Scale delta: {scaleDelta:F3}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process pinch rotation (angle change)
|
||||||
|
float angleDelta = Mathf.DeltaAngle(_previousAngle, currentAngle) * rotationSensitivity;
|
||||||
|
|
||||||
|
if (Mathf.Abs(angleDelta) > 0.5f)
|
||||||
|
{
|
||||||
|
OnPinchRotate?.Invoke(angleDelta);
|
||||||
|
Logging.Debug($"[PinchGestureHandler] Rotation delta: {angleDelta:F1}°");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update previous values
|
||||||
|
_previousDistance = currentDistance;
|
||||||
|
_previousAngle = currentAngle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Process keyboard input for editor testing
|
||||||
|
/// Q/E for rotation, +/- for scale, Escape for dismissal
|
||||||
|
/// </summary>
|
||||||
|
private void HandleKeyboardInput()
|
||||||
|
{
|
||||||
|
var keyboard = Keyboard.current;
|
||||||
|
if (keyboard == null) return;
|
||||||
|
|
||||||
|
// Rotation with Q/E
|
||||||
|
if (keyboard.qKey.isPressed)
|
||||||
|
{
|
||||||
|
float rotateDelta = -keyboardRotationSpeed * Time.deltaTime;
|
||||||
|
OnPinchRotate?.Invoke(rotateDelta);
|
||||||
|
}
|
||||||
|
else if (keyboard.eKey.isPressed)
|
||||||
|
{
|
||||||
|
float rotateDelta = keyboardRotationSpeed * Time.deltaTime;
|
||||||
|
OnPinchRotate?.Invoke(rotateDelta);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scale with +/- (equals key is where + is on keyboard)
|
||||||
|
if (keyboard.equalsKey.isPressed || keyboard.numpadPlusKey.isPressed)
|
||||||
|
{
|
||||||
|
float scaleDelta = keyboardScaleSpeed * Time.deltaTime;
|
||||||
|
OnPinchScale?.Invoke(scaleDelta);
|
||||||
|
}
|
||||||
|
else if (keyboard.minusKey.isPressed || keyboard.numpadMinusKey.isPressed)
|
||||||
|
{
|
||||||
|
float scaleDelta = -keyboardScaleSpeed * Time.deltaTime;
|
||||||
|
OnPinchScale?.Invoke(scaleDelta);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dismissal with Escape or Space
|
||||||
|
if (keyboard.escapeKey.wasPressedThisFrame || keyboard.spaceKey.wasPressedThisFrame)
|
||||||
|
{
|
||||||
|
Logging.Debug("[PinchGestureHandler] Keyboard dismissal detected");
|
||||||
|
OnDismissTap?.Invoke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: daa669f49a29434a927eafbd291e251f
|
||||||
|
timeCreated: 1765369442
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 3a935f5e791c46df8920c2c33f1c24c0
|
|
||||||
timeCreated: 1765361215
|
|
||||||
@@ -25,11 +25,12 @@ MonoBehaviour:
|
|||||||
useRigidbody: 0
|
useRigidbody: 0
|
||||||
defaultHoldMovementMode: 1
|
defaultHoldMovementMode: 1
|
||||||
followerMovement:
|
followerMovement:
|
||||||
followDistance: 1.5
|
followDistance: 5
|
||||||
manualMoveSmooth: 8
|
manualMoveSmooth: 1
|
||||||
thresholdFar: 2.5
|
thresholdFar: 10
|
||||||
thresholdNear: 0.5
|
thresholdNear: 3
|
||||||
stopThreshold: 0.1
|
stopThreshold: 0.1
|
||||||
followUpdateInterval: 0.1
|
followUpdateInterval: 0.1
|
||||||
followerSpeedMultiplier: 1.2
|
followerSpeedMultiplier: 0.9
|
||||||
heldIconDisplayHeight: 2
|
heldIconDisplayHeight: 2
|
||||||
|
trashMazeVisionRadius: 8
|
||||||
|
|||||||
@@ -72,3 +72,5 @@ MonoBehaviour:
|
|||||||
enableStatePersistence: 1
|
enableStatePersistence: 1
|
||||||
stateSaveKey: StatueDecorationState
|
stateSaveKey: StatueDecorationState
|
||||||
maxSavedDecorations: 50
|
maxSavedDecorations: 50
|
||||||
|
minDecorationScale: 0.1
|
||||||
|
maxDecorationScale: 2
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ PlayerSettings:
|
|||||||
loadStoreDebugModeEnabled: 0
|
loadStoreDebugModeEnabled: 0
|
||||||
visionOSBundleVersion: 1.0
|
visionOSBundleVersion: 1.0
|
||||||
tvOSBundleVersion: 1.0
|
tvOSBundleVersion: 1.0
|
||||||
bundleVersion: 0.6
|
bundleVersion: 0.7
|
||||||
preloadedAssets: []
|
preloadedAssets: []
|
||||||
metroInputSource: 0
|
metroInputSource: 0
|
||||||
wsaTransparentSwapchain: 0
|
wsaTransparentSwapchain: 0
|
||||||
@@ -177,7 +177,7 @@ PlayerSettings:
|
|||||||
iPhone: 0
|
iPhone: 0
|
||||||
tvOS: 0
|
tvOS: 0
|
||||||
overrideDefaultApplicationIdentifier: 1
|
overrideDefaultApplicationIdentifier: 1
|
||||||
AndroidBundleVersionCode: 2
|
AndroidBundleVersionCode: 3
|
||||||
AndroidMinSdkVersion: 25
|
AndroidMinSdkVersion: 25
|
||||||
AndroidTargetSdkVersion: 0
|
AndroidTargetSdkVersion: 0
|
||||||
AndroidPreferredInstallLocation: 1
|
AndroidPreferredInstallLocation: 1
|
||||||
|
|||||||
Reference in New Issue
Block a user