Working visual part

This commit is contained in:
Michal Pikulski
2025-11-06 13:18:39 +01:00
parent 95daea8d34
commit 4e0c9cb4c4
47 changed files with 5585 additions and 218 deletions

View File

@@ -21,6 +21,8 @@ namespace UI.CardSystem
[Header("Booster Pack UI")]
[SerializeField] private GameObject[] boosterPackButtons;
[SerializeField] private BoosterOpeningPage boosterOpeningPage;
private Input.InputMode _previousInputMode;
private void Awake()
{
@@ -122,6 +124,13 @@ namespace UI.CardSystem
else
{
// Already on page 0 or no book reference, exit
// Restore input mode before popping
if (Input.InputManager.Instance != null)
{
Input.InputManager.Instance.SetInputMode(_previousInputMode);
Debug.Log($"[AlbumViewPage] Restored input mode to {_previousInputMode} on exit");
}
if (UIPageController.Instance != null)
{
UIPageController.Instance.PopPage();
@@ -160,6 +169,27 @@ namespace UI.CardSystem
UIPageController.Instance.PushPage(boosterOpeningPage);
}
}
public override void TransitionIn()
{
// Only store and switch input mode if this is the first time entering
// (when _previousInputMode hasn't been set yet)
if (Input.InputManager.Instance != null && _previousInputMode == default(Input.InputMode))
{
// Store the current input mode before switching
_previousInputMode = Input.InputMode.GameAndUI;
Input.InputManager.Instance.SetInputMode(Input.InputMode.UI);
Debug.Log("[AlbumViewPage] Switched to UI-only input mode on first entry");
}
base.TransitionIn();
}
public override void TransitionOut()
{
// Don't restore input mode here - only restore when actually exiting (in OnExitButtonClicked)
base.TransitionOut();
}
protected override void DoTransitionIn(System.Action onComplete)
{

View File

@@ -111,6 +111,8 @@ namespace UI.CardSystem
/// </summary>
private void InitializeBoosterDisplay()
{
Debug.Log($"[BoosterOpeningPage] InitializeBoosterDisplay called with {_availableBoosterCount} boosters available");
if (boosterPackInstances == null || boosterPackInstances.Length == 0)
{
Debug.LogWarning("BoosterOpeningPage: No booster pack instances assigned!");
@@ -120,12 +122,16 @@ namespace UI.CardSystem
// Calculate how many boosters to show (capped by array size)
int visibleCount = Mathf.Min(_availableBoosterCount, boosterPackInstances.Length);
Debug.Log($"[BoosterOpeningPage] Will show {visibleCount} boosters out of {boosterPackInstances.Length} instances");
// Show/hide boosters and assign to slots
for (int i = 0; i < boosterPackInstances.Length; i++)
{
if (boosterPackInstances[i] == null) continue;
bool shouldShow = i < visibleCount;
Debug.Log($"[BoosterOpeningPage] Booster {i} ({boosterPackInstances[i].name}): shouldShow={shouldShow}, position={boosterPackInstances[i].transform.position}");
boosterPackInstances[i].SetActive(shouldShow);
if (shouldShow)
@@ -147,9 +153,22 @@ namespace UI.CardSystem
DraggableSlot slot = bottomRightSlots.GetSlotAtIndex(i);
if (slot != null)
{
Debug.Log($"[BoosterOpeningPage] Assigning booster {i} to slot {slot.name} at {slot.transform.position}");
booster.AssignToSlot(slot, false);
}
else
{
Debug.LogWarning($"[BoosterOpeningPage] Slot {i} is null in bottomRightSlots!");
}
}
else
{
Debug.LogWarning($"[BoosterOpeningPage] No slot available for booster {i}. bottomRightSlots={bottomRightSlots}, SlotCount={bottomRightSlots?.SlotCount}");
}
}
else
{
Debug.LogWarning($"[BoosterOpeningPage] Booster {i} has no BoosterPackDraggable component!");
}
}
}
@@ -158,6 +177,11 @@ namespace UI.CardSystem
if (centerOpeningSlot != null)
{
centerOpeningSlot.OnOccupied += OnBoosterPlacedInCenter;
Debug.Log($"[BoosterOpeningPage] Subscribed to center slot {centerOpeningSlot.name} at {centerOpeningSlot.transform.position}");
}
else
{
Debug.LogWarning("[BoosterOpeningPage] centerOpeningSlot is null!");
}
}

View File

@@ -12,8 +12,8 @@ namespace UI.DragAndDrop.Core
/// Handles drag logic, slot snapping, and events.
/// Spawns and manages a separate DraggableVisual for rendering.
/// Touch-compatible via Unity's pointer event system.
/// Note: Optionally uses Image or CanvasGroup for automatic raycast toggling during drag.
/// </summary>
[RequireComponent(typeof(Image))]
public abstract class DraggableObject : MonoBehaviour,
IBeginDragHandler, IDragHandler, IEndDragHandler,
IPointerEnterHandler, IPointerExitHandler,
@@ -25,9 +25,7 @@ namespace UI.DragAndDrop.Core
[SerializeField] protected float snapDuration = 0.3f;
[Header("Visual")]
[SerializeField] protected GameObject visualPrefab;
[SerializeField] protected bool instantiateVisual = true;
[SerializeField] protected Transform visualParent;
[SerializeField] protected DraggableVisual visual;
[Header("Selection")]
[SerializeField] protected bool isSelectable = true;
@@ -42,6 +40,7 @@ namespace UI.DragAndDrop.Core
// References
protected Canvas _canvas;
protected Image _imageComponent;
protected CanvasGroup _canvasGroup;
protected GraphicRaycaster _raycaster;
protected DraggableSlot _currentSlot;
protected DraggableVisual _visualInstance;
@@ -72,20 +71,36 @@ namespace UI.DragAndDrop.Core
public Vector3 WorldPosition => transform.position;
public RectTransform RectTransform => transform as RectTransform;
protected virtual void Start()
protected virtual void Awake()
{
Initialize();
}
protected virtual void Initialize()
{
Debug.Log($"[DraggableObject] Initializing {name} at world pos {transform.position}, local pos {transform.localPosition}, parent: {(transform.parent != null ? transform.parent.name : "NULL")}");
_canvas = GetComponentInParent<Canvas>();
Debug.Log($"[DraggableObject] {name} found canvas: {(_canvas != null ? _canvas.name : "NULL")}, canvas pos: {(_canvas != null ? _canvas.transform.position.ToString() : "N/A")}");
_imageComponent = GetComponent<Image>();
_canvasGroup = GetComponent<CanvasGroup>();
_raycaster = _canvas?.GetComponent<GraphicRaycaster>();
if (instantiateVisual && visualPrefab != null)
// Use assigned visual, or find in children recursively if not assigned
if (visual != null)
{
SpawnVisual();
_visualInstance = visual;
}
else
{
_visualInstance = GetComponentInChildren<DraggableVisual>(true);
}
// Initialize the visual if found
if (_visualInstance != null)
{
_visualInstance.Initialize(this);
}
// If we're already in a slot, register with it
@@ -96,18 +111,6 @@ namespace UI.DragAndDrop.Core
}
}
protected virtual void SpawnVisual()
{
Transform parent = visualParent != null ? visualParent : _canvas.transform;
GameObject visualObj = Instantiate(visualPrefab, parent);
_visualInstance = visualObj.GetComponent<DraggableVisual>();
if (_visualInstance != null)
{
_visualInstance.Initialize(this);
}
}
protected virtual void Update()
{
if (_isDragging && smoothMovement)
@@ -130,6 +133,10 @@ namespace UI.DragAndDrop.Core
protected virtual void ClampToScreen()
{
// Skip clamping for ScreenSpaceOverlay - it doesn't use world coordinates
if (_canvas != null && _canvas.renderMode == RenderMode.ScreenSpaceOverlay)
return;
if (Camera.main == null || RectTransform == null)
return;
@@ -166,6 +173,8 @@ namespace UI.DragAndDrop.Core
_raycaster.enabled = false;
if (_imageComponent != null)
_imageComponent.raycastTarget = false;
if (_canvasGroup != null)
_canvasGroup.blocksRaycasts = false;
// Notify current slot we're leaving
if (_currentSlot != null)
@@ -202,6 +211,8 @@ namespace UI.DragAndDrop.Core
_raycaster.enabled = true;
if (_imageComponent != null)
_imageComponent.raycastTarget = true;
if (_canvasGroup != null)
_canvasGroup.blocksRaycasts = true;
// Find closest slot and snap
FindAndSnapToSlot();
@@ -323,6 +334,8 @@ namespace UI.DragAndDrop.Core
if (slot == null)
return;
Debug.Log($"[DraggableObject] Assigning {name} to slot {slot.name}, animate={animate}, current pos={transform.position}, slot pos={slot.transform.position}");
DraggableSlot previousSlot = _currentSlot;
_currentSlot = slot;
@@ -336,6 +349,8 @@ namespace UI.DragAndDrop.Core
{
transform.SetParent(slot.transform);
transform.localPosition = _isSelected ? new Vector3(0, selectionOffset, 0) : Vector3.zero;
transform.localRotation = Quaternion.identity;
Debug.Log($"[DraggableObject] {name} assigned to slot {slot.name}, new world pos={transform.position}, local pos={transform.localPosition}");
}
OnSlotChanged?.Invoke(this, slot);
@@ -352,10 +367,12 @@ namespace UI.DragAndDrop.Core
if (RectTransform != null)
{
Tween.LocalPosition(RectTransform, targetLocalPos, snapDuration, 0f, Tween.EaseOutBack);
Tween.LocalRotation(transform, Quaternion.identity, snapDuration, 0f, Tween.EaseOutBack);
}
else
{
transform.localPosition = targetLocalPos;
transform.localRotation = Quaternion.identity;
}
}

View File

@@ -10,16 +10,24 @@ namespace UI.DragAndDrop.Core
/// </summary>
public class DraggableSlot : MonoBehaviour
{
public enum OccupantSizeMode
{
None, // Don't modify occupant size
MatchSlotSize, // Set occupant RectTransform size to match slot size
Scale // Apply scale multiplier to occupant
}
[Header("Slot Settings")]
[SerializeField] private int slotIndex;
[SerializeField] private bool isLocked;
[SerializeField] private bool hideImageOnPlay = false;
[Header("Type Filtering")]
[SerializeField] private bool filterByType;
[SerializeField] private string[] allowedTypeNames;
[Header("Scale Control")]
[SerializeField] private bool applyScaleToOccupant = false;
[Header("Occupant Size Control")]
[SerializeField] private OccupantSizeMode occupantSizeMode = OccupantSizeMode.None;
[SerializeField] private Vector3 occupantScale = Vector3.one;
[SerializeField] private float scaleTransitionDuration = 0.3f;
@@ -37,6 +45,18 @@ namespace UI.DragAndDrop.Core
public Vector3 WorldPosition => transform.position;
public RectTransform RectTransform => transform as RectTransform;
private void Start()
{
if (hideImageOnPlay)
{
UnityEngine.UI.Image image = GetComponent<UnityEngine.UI.Image>();
if (image != null)
{
Destroy(image);
}
}
}
/// <summary>
/// Attempt to occupy this slot with a draggable object
/// </summary>
@@ -54,10 +74,27 @@ namespace UI.DragAndDrop.Core
_occupant = draggable;
draggable.transform.SetParent(transform);
// Apply scale if configured
if (applyScaleToOccupant)
// Apply size modification based on mode
switch (occupantSizeMode)
{
Tween.LocalScale(draggable.transform, occupantScale, scaleTransitionDuration, 0f, Tween.EaseOutBack);
case OccupantSizeMode.MatchSlotSize:
if (draggable.RectTransform != null && RectTransform != null)
{
Vector2 targetSize = RectTransform.sizeDelta;
Tween.Value(draggable.RectTransform.sizeDelta, targetSize,
(val) => draggable.RectTransform.sizeDelta = val,
scaleTransitionDuration, 0f, Tween.EaseOutBack);
}
break;
case OccupantSizeMode.Scale:
Tween.LocalScale(draggable.transform, occupantScale, scaleTransitionDuration, 0f, Tween.EaseOutBack);
break;
case OccupantSizeMode.None:
default:
// Don't modify size
break;
}
OnOccupied?.Invoke(draggable);

View File

@@ -56,11 +56,12 @@ namespace UI.DragAndDrop.Core
{
_parentDraggable = parent;
// Get or add required components
Canvas parentCanvas = parent.GetComponentInParent<Canvas>();
Debug.Log($"[DraggableVisual] Initializing visual for {parent.name} at world pos {parent.transform.position}, parent canvas: {(parentCanvas != null ? parentCanvas.name + " (renderMode: " + parentCanvas.renderMode + ")" : "NULL")}");
// Get components if assigned (don't auto-create Canvas to avoid Unity's auto-reparenting)
if (canvas == null)
canvas = GetComponent<Canvas>();
if (canvas == null)
canvas = gameObject.AddComponent<Canvas>();
if (canvasGroup == null)
canvasGroup = GetComponent<CanvasGroup>();
@@ -74,6 +75,8 @@ namespace UI.DragAndDrop.Core
transform.position = parent.transform.position;
_lastPosition = transform.position;
Debug.Log($"[DraggableVisual] Visual {name} initialized at world pos {transform.position}, local pos {transform.localPosition}, parent at world pos {parent.transform.position}, local pos {parent.transform.localPosition}");
_isInitialized = true;
OnInitialized();
@@ -127,6 +130,12 @@ namespace UI.DragAndDrop.Core
Vector3 targetPosition = GetTargetPosition();
// Debug log if position is drastically different (likely a clustering issue)
if (Vector3.Distance(transform.position, targetPosition) > 500f)
{
Debug.LogWarning($"[DraggableVisual] Large position delta detected! Visual {name} at {transform.position}, target {targetPosition}, parent {_parentDraggable.name} at {_parentDraggable.transform.position}");
}
if (useFollowDelay)
{
transform.position = Vector3.Lerp(transform.position, targetPosition, followSpeed * Time.deltaTime);

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4b9473a4ece8425d97676fe7630d25ac
timeCreated: 1762428015

View File

@@ -0,0 +1,95 @@
using UnityEditor;
using UnityEngine;
using UI.DragAndDrop.Core;
namespace UI.DragAndDrop.Editor
{
[CustomEditor(typeof(DraggableObject), true)]
public class DraggableObjectEditor : UnityEditor.Editor
{
public override void OnInspectorGUI()
{
DrawDefaultInspector();
DraggableObject draggable = (DraggableObject)target;
// Only show button in edit mode
if (!Application.isPlaying)
{
EditorGUILayout.Space();
EditorGUILayout.LabelField("Editor Tools", EditorStyles.boldLabel);
if (GUILayout.Button("Snap to Parent Slot"))
{
SnapToParentSlot(draggable);
}
}
}
private void SnapToParentSlot(DraggableObject draggable)
{
// Find parent slot
DraggableSlot parentSlot = draggable.GetComponentInParent<DraggableSlot>();
if (parentSlot == null)
{
Debug.LogWarning("No parent DraggableSlot found!");
return;
}
Undo.RecordObject(draggable.transform, "Snap to Parent Slot");
// Reset position and rotation
draggable.transform.localPosition = Vector3.zero;
draggable.transform.localRotation = Quaternion.identity;
// Apply slot's size mode
RectTransform draggableRect = draggable.GetComponent<RectTransform>();
RectTransform slotRect = parentSlot.GetComponent<RectTransform>();
if (draggableRect != null && slotRect != null)
{
// Use reflection to access private fields
System.Reflection.FieldInfo modeField = typeof(DraggableSlot).GetField("occupantSizeMode",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
System.Reflection.FieldInfo scaleField = typeof(DraggableSlot).GetField("occupantScale",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
if (modeField != null && scaleField != null)
{
var sizeMode = modeField.GetValue(parentSlot);
var occupantScale = (Vector3)scaleField.GetValue(parentSlot);
// Get enum type
System.Type enumType = sizeMode.GetType();
string modeName = System.Enum.GetName(enumType, sizeMode);
Undo.RecordObject(draggableRect, "Apply Slot Size Mode");
switch (modeName)
{
case "MatchSlotSize":
draggableRect.sizeDelta = slotRect.sizeDelta;
draggableRect.localScale = Vector3.one;
Debug.Log($"Matched slot size: {slotRect.sizeDelta}");
break;
case "Scale":
draggableRect.localScale = occupantScale;
Debug.Log($"Applied scale: {occupantScale}");
break;
case "None":
default:
// Keep current size
break;
}
}
}
EditorUtility.SetDirty(draggable.gameObject);
Debug.Log($"Snapped {draggable.name} to parent slot {parentSlot.name}");
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 290619d598ef4b199862482abc7188a3
timeCreated: 1762428015

View File

@@ -5,16 +5,16 @@ public class ScrapbookController : MonoBehaviour
{
private void OnEnable()
{
InputManager.Instance.SetInputMode(InputMode.UI);
// InputManager.Instance.SetInputMode(InputMode.UI);
}
private void OnDisable()
{
InputManager.Instance.SetInputMode (InputMode.Game);
// InputManager.Instance.SetInputMode (InputMode.Game);
}
public void DebugClick()
{
Debug.Log("Yey I was clicked!");
// Debug.Log("Yey I was clicked!");
}
}