2025-11-07 15:38:31 +00:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections;
|
2025-11-10 13:03:36 +01:00
|
|
|
|
using Core;
|
2025-11-07 15:38:31 +00:00
|
|
|
|
using Data.CardSystem;
|
|
|
|
|
|
using Pixelplacement;
|
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
using UnityEngine.UI;
|
|
|
|
|
|
|
|
|
|
|
|
namespace UI.CardSystem
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
2025-12-15 11:59:40 +01:00
|
|
|
|
/// UI component for granting booster packs from minigames.
|
|
|
|
|
|
/// Supports awarding 1 to N booster packs with visual animations.
|
|
|
|
|
|
/// Shows up to 3 booster packs visually. For more than 3, duplicates the first pack and tweens them sequentially.
|
2025-11-07 15:38:31 +00:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
public class MinigameBoosterGiver : MonoBehaviour
|
|
|
|
|
|
{
|
|
|
|
|
|
public static MinigameBoosterGiver Instance { get; private set; }
|
|
|
|
|
|
|
|
|
|
|
|
[Header("Visual References")]
|
|
|
|
|
|
[SerializeField] private GameObject visualContainer;
|
2025-12-15 11:59:40 +01:00
|
|
|
|
[SerializeField] private RectTransform[] boosterImages; // Up to 3 booster pack visuals
|
|
|
|
|
|
[SerializeField] private RectTransform glowImage; // Single glow effect for all boosters
|
2025-11-07 15:38:31 +00:00
|
|
|
|
[SerializeField] private Button continueButton;
|
|
|
|
|
|
|
|
|
|
|
|
[Header("Animation Settings")]
|
|
|
|
|
|
[SerializeField] private float hoverAmount = 20f;
|
|
|
|
|
|
[SerializeField] private float hoverDuration = 1.5f;
|
|
|
|
|
|
[SerializeField] private float glowPulseMax = 1.1f;
|
|
|
|
|
|
[SerializeField] private float glowPulseDuration = 1.2f;
|
|
|
|
|
|
|
|
|
|
|
|
[Header("Disappear Animation")]
|
|
|
|
|
|
[SerializeField] private Vector2 targetBottomLeftOffset = new Vector2(100f, 100f);
|
2025-12-15 11:59:40 +01:00
|
|
|
|
[SerializeField] private float tweenDuration = 0.8f;
|
|
|
|
|
|
[SerializeField] private float delayBetweenTweens = 0.2f;
|
2025-11-07 15:38:31 +00:00
|
|
|
|
[SerializeField] private float disappearScale = 0.2f;
|
|
|
|
|
|
|
2025-12-15 11:59:40 +01:00
|
|
|
|
private Vector3[] _boosterInitialPositions;
|
|
|
|
|
|
private Vector3[] _boosterInitialScales;
|
2025-11-07 15:38:31 +00:00
|
|
|
|
private Vector3 _glowInitialScale;
|
|
|
|
|
|
private Coroutine _currentSequence;
|
|
|
|
|
|
private Action _onCompleteCallback;
|
2025-12-15 11:59:40 +01:00
|
|
|
|
private int _totalPackCount = 1;
|
2025-11-07 15:38:31 +00:00
|
|
|
|
|
|
|
|
|
|
private void Awake()
|
|
|
|
|
|
{
|
|
|
|
|
|
// Singleton pattern
|
|
|
|
|
|
if (Instance != null && Instance != this)
|
|
|
|
|
|
{
|
2025-11-10 13:03:36 +01:00
|
|
|
|
Logging.Warning("[MinigameBoosterGiver] Duplicate instance found. Destroying.");
|
2025-11-07 15:38:31 +00:00
|
|
|
|
Destroy(gameObject);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Instance = this;
|
|
|
|
|
|
|
2025-12-15 11:59:40 +01:00
|
|
|
|
// Cache initial values for all booster images
|
|
|
|
|
|
if (boosterImages != null && boosterImages.Length > 0)
|
2025-11-07 15:38:31 +00:00
|
|
|
|
{
|
2025-12-15 11:59:40 +01:00
|
|
|
|
_boosterInitialPositions = new Vector3[boosterImages.Length];
|
|
|
|
|
|
_boosterInitialScales = new Vector3[boosterImages.Length];
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < boosterImages.Length; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (boosterImages[i] != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
_boosterInitialPositions[i] = boosterImages[i].localPosition;
|
|
|
|
|
|
_boosterInitialScales[i] = boosterImages[i].localScale;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-11-07 15:38:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (glowImage != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
_glowInitialScale = glowImage.localScale;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Setup button listener
|
|
|
|
|
|
if (continueButton != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
continueButton.onClick.AddListener(OnContinueClicked);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Start hidden
|
|
|
|
|
|
if (visualContainer != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
visualContainer.SetActive(false);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-15 11:59:40 +01:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Initialize the booster giver with a specific pack count.
|
|
|
|
|
|
/// Shows up to 3 booster visuals based on count.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="packCount">Number of booster packs to grant</param>
|
|
|
|
|
|
public void Initialize(int packCount)
|
|
|
|
|
|
{
|
|
|
|
|
|
_totalPackCount = Mathf.Max(1, packCount);
|
|
|
|
|
|
|
|
|
|
|
|
// Show up to 3 booster visuals
|
|
|
|
|
|
int visualCount = Mathf.Min(_totalPackCount, boosterImages.Length);
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < boosterImages.Length; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
bool shouldShow = i < visualCount;
|
|
|
|
|
|
if (boosterImages[i] != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
boosterImages[i].gameObject.SetActive(shouldShow);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Logging.Debug($"[MinigameBoosterGiver] Initialized with {_totalPackCount} packs, showing {visualCount} visuals");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-07 15:38:31 +00:00
|
|
|
|
private void OnDestroy()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (Instance == this)
|
|
|
|
|
|
{
|
|
|
|
|
|
Instance = null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (continueButton != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
continueButton.onClick.RemoveListener(OnContinueClicked);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Public API to give a booster pack. Displays UI, starts animations, and waits for user interaction.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="onComplete">Optional callback when the sequence completes and pack is granted</param>
|
|
|
|
|
|
public void GiveBooster(Action onComplete = null)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_currentSequence != null)
|
|
|
|
|
|
{
|
2025-11-10 13:03:36 +01:00
|
|
|
|
Logging.Warning("[MinigameBoosterGiver] Already running a sequence. Ignoring new request.");
|
2025-11-07 15:38:31 +00:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_onCompleteCallback = onComplete;
|
|
|
|
|
|
_currentSequence = StartCoroutine(GiveBoosterSequence());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private IEnumerator GiveBoosterSequence()
|
|
|
|
|
|
{
|
|
|
|
|
|
// Show the visual
|
|
|
|
|
|
if (visualContainer != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
visualContainer.SetActive(true);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-15 11:59:40 +01:00
|
|
|
|
// Reset positions and scales for visible boosters
|
|
|
|
|
|
int visualCount = Mathf.Min(_totalPackCount, boosterImages.Length);
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < visualCount; i++)
|
2025-11-07 15:38:31 +00:00
|
|
|
|
{
|
2025-12-15 11:59:40 +01:00
|
|
|
|
if (boosterImages[i] != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
boosterImages[i].localPosition = _boosterInitialPositions[i];
|
|
|
|
|
|
boosterImages[i].localScale = _boosterInitialScales[i];
|
|
|
|
|
|
}
|
2025-11-07 15:38:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-15 11:59:40 +01:00
|
|
|
|
// Reset glow scale
|
2025-11-07 15:38:31 +00:00
|
|
|
|
if (glowImage != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
glowImage.localScale = _glowInitialScale;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Enable the continue button
|
|
|
|
|
|
if (continueButton != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
continueButton.interactable = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-15 11:59:40 +01:00
|
|
|
|
// Start idle hovering animation on all visible boosters (ping-pong)
|
|
|
|
|
|
for (int i = 0; i < visualCount; i++)
|
2025-11-07 15:38:31 +00:00
|
|
|
|
{
|
2025-12-15 11:59:40 +01:00
|
|
|
|
if (boosterImages[i] != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Vector3 hoverTarget = _boosterInitialPositions[i] + Vector3.up * hoverAmount;
|
|
|
|
|
|
Tween.LocalPosition(boosterImages[i], hoverTarget, hoverDuration, 0f, Tween.EaseLinear, Tween.LoopType.PingPong);
|
|
|
|
|
|
}
|
2025-11-07 15:38:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-15 11:59:40 +01:00
|
|
|
|
// Start pulsing animation on the single glow (ping-pong scale)
|
2025-11-07 15:38:31 +00:00
|
|
|
|
if (glowImage != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Vector3 glowPulseScale = _glowInitialScale * glowPulseMax;
|
|
|
|
|
|
Tween.LocalScale(glowImage, glowPulseScale, glowPulseDuration, 0f, Tween.EaseOut, Tween.LoopType.PingPong);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Wait for button click (handled by OnContinueClicked)
|
|
|
|
|
|
yield return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void OnContinueClicked()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_currentSequence == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
return; // Not in a sequence
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-15 11:59:40 +01:00
|
|
|
|
// Disable and hide button to prevent double-clicks
|
2025-11-07 15:38:31 +00:00
|
|
|
|
if (continueButton != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
continueButton.interactable = false;
|
2025-12-15 11:59:40 +01:00
|
|
|
|
continueButton.gameObject.SetActive(false);
|
2025-11-07 15:38:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-15 11:59:40 +01:00
|
|
|
|
// Start moving all boosters to backpack
|
|
|
|
|
|
StartCoroutine(MoveAllBoostersToBackpack());
|
2025-11-07 15:38:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-15 11:59:40 +01:00
|
|
|
|
private IEnumerator MoveAllBoostersToBackpack()
|
2025-11-07 15:38:31 +00:00
|
|
|
|
{
|
2025-11-10 10:41:38 +01:00
|
|
|
|
// Show scrapbook button temporarily using HUD visibility context
|
|
|
|
|
|
PlayerHudManager.HudVisibilityContext hudContext = null;
|
2025-12-15 11:59:40 +01:00
|
|
|
|
GameObject scrapbookButton = PlayerHudManager.Instance?.GetScrabookButton();
|
2025-11-10 10:41:38 +01:00
|
|
|
|
|
|
|
|
|
|
if (scrapbookButton != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
hudContext = PlayerHudManager.Instance.ShowElementTemporarily(scrapbookButton);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2025-11-10 13:03:36 +01:00
|
|
|
|
Logging.Warning("[MinigameBoosterGiver] Scrapbook button not found in PlayerHudManager.");
|
2025-11-10 10:41:38 +01:00
|
|
|
|
}
|
2025-11-07 15:38:31 +00:00
|
|
|
|
|
2025-12-15 11:59:40 +01:00
|
|
|
|
// Calculate target position once
|
|
|
|
|
|
Vector3 targetPosition = GetTargetPosition(scrapbookButton);
|
2025-11-10 10:41:38 +01:00
|
|
|
|
|
2025-12-15 11:59:40 +01:00
|
|
|
|
int remaining = _totalPackCount;
|
|
|
|
|
|
int visualCount = Mathf.Min(_totalPackCount, boosterImages.Length);
|
|
|
|
|
|
|
|
|
|
|
|
// Stop and fade out the single glow immediately
|
|
|
|
|
|
if (glowImage != null)
|
2025-11-07 15:38:31 +00:00
|
|
|
|
{
|
2025-12-15 11:59:40 +01:00
|
|
|
|
Tween.Stop(glowImage.GetInstanceID());
|
|
|
|
|
|
Tween.LocalScale(glowImage, Vector3.zero, tweenDuration * 0.5f, 0f, Tween.EaseInBack);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Phase 1: Animate duplicates for packs above 3 (if any)
|
|
|
|
|
|
int duplicatesToAnimate = Mathf.Max(0, _totalPackCount - 3);
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < duplicatesToAnimate; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Spawn duplicate at the first booster's current position
|
|
|
|
|
|
if (boosterImages.Length > 0 && boosterImages[0] != null)
|
2025-11-10 10:41:38 +01:00
|
|
|
|
{
|
2025-12-15 11:59:40 +01:00
|
|
|
|
StartCoroutine(TweenPackToBackpack(boosterImages[0], targetPosition, isDuplicate: true));
|
2025-11-10 10:41:38 +01:00
|
|
|
|
}
|
2025-12-15 11:59:40 +01:00
|
|
|
|
|
|
|
|
|
|
remaining--;
|
|
|
|
|
|
|
|
|
|
|
|
// Wait for stagger delay before next
|
|
|
|
|
|
if (i < duplicatesToAnimate - 1 || remaining > 0)
|
2025-11-10 10:41:38 +01:00
|
|
|
|
{
|
2025-12-15 11:59:40 +01:00
|
|
|
|
yield return new WaitForSeconds(delayBetweenTweens);
|
2025-11-10 10:41:38 +01:00
|
|
|
|
}
|
2025-11-07 15:38:31 +00:00
|
|
|
|
}
|
2025-12-15 11:59:40 +01:00
|
|
|
|
|
|
|
|
|
|
// Phase 2: Animate the actual visible packs (up to 3)
|
|
|
|
|
|
for (int i = 0; i < visualCount && i < remaining; i++)
|
2025-11-07 15:38:31 +00:00
|
|
|
|
{
|
2025-12-15 11:59:40 +01:00
|
|
|
|
if (boosterImages[i] != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Stop hover animations first
|
|
|
|
|
|
Tween.Stop(boosterImages[i].GetInstanceID());
|
|
|
|
|
|
|
|
|
|
|
|
// Tween the actual booster
|
|
|
|
|
|
StartCoroutine(TweenPackToBackpack(boosterImages[i], targetPosition, isDuplicate: false));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Wait for stagger delay before next (except after last one)
|
|
|
|
|
|
if (i < visualCount - 1 && i < remaining - 1)
|
|
|
|
|
|
{
|
|
|
|
|
|
yield return new WaitForSeconds(delayBetweenTweens);
|
|
|
|
|
|
}
|
2025-11-07 15:38:31 +00:00
|
|
|
|
}
|
2025-12-15 11:59:40 +01:00
|
|
|
|
|
|
|
|
|
|
// Wait for the last tween to complete
|
|
|
|
|
|
yield return new WaitForSeconds(tweenDuration);
|
|
|
|
|
|
|
|
|
|
|
|
// Grant all booster packs at once
|
2025-11-07 15:38:31 +00:00
|
|
|
|
if (CardSystemManager.Instance != null)
|
|
|
|
|
|
{
|
2025-12-15 11:59:40 +01:00
|
|
|
|
CardSystemManager.Instance.AddBoosterPack(_totalPackCount);
|
|
|
|
|
|
Logging.Debug($"[MinigameBoosterGiver] Granted {_totalPackCount} booster pack(s)!");
|
2025-11-07 15:38:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2025-12-15 11:59:40 +01:00
|
|
|
|
Logging.Warning("[MinigameBoosterGiver] CardSystemManager not found, cannot grant booster packs.");
|
2025-11-07 15:38:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-10 10:41:38 +01:00
|
|
|
|
// Hide scrapbook button by disposing the context
|
|
|
|
|
|
hudContext?.Dispose();
|
|
|
|
|
|
|
2025-12-15 11:59:40 +01:00
|
|
|
|
// Hide the visual container
|
2025-11-07 15:38:31 +00:00
|
|
|
|
if (visualContainer != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
visualContainer.SetActive(false);
|
|
|
|
|
|
}
|
2025-12-15 11:59:40 +01:00
|
|
|
|
|
|
|
|
|
|
// Show button again for next use
|
|
|
|
|
|
if (continueButton != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
continueButton.gameObject.SetActive(true);
|
|
|
|
|
|
}
|
2025-11-07 15:38:31 +00:00
|
|
|
|
|
|
|
|
|
|
// Invoke completion callback
|
|
|
|
|
|
_onCompleteCallback?.Invoke();
|
|
|
|
|
|
_onCompleteCallback = null;
|
|
|
|
|
|
|
|
|
|
|
|
// Clear sequence reference
|
|
|
|
|
|
_currentSequence = null;
|
|
|
|
|
|
}
|
2025-12-15 11:59:40 +01:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Generic method to tween a booster pack to the backpack button.
|
|
|
|
|
|
/// Handles both duplicates (instantiated clones) and actual booster visuals.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private IEnumerator TweenPackToBackpack(RectTransform sourceRect, Vector3 targetPosition, bool isDuplicate)
|
|
|
|
|
|
{
|
|
|
|
|
|
RectTransform packToAnimate;
|
|
|
|
|
|
|
|
|
|
|
|
if (isDuplicate)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Create a clone at the source position
|
|
|
|
|
|
GameObject clone = Instantiate(sourceRect.gameObject, sourceRect.parent);
|
|
|
|
|
|
packToAnimate = clone.GetComponent<RectTransform>();
|
|
|
|
|
|
|
|
|
|
|
|
if (packToAnimate != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
packToAnimate.localPosition = sourceRect.localPosition;
|
|
|
|
|
|
packToAnimate.localScale = sourceRect.localScale;
|
|
|
|
|
|
packToAnimate.gameObject.SetActive(true);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
packToAnimate = sourceRect;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (packToAnimate == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
yield break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Tween to target position
|
|
|
|
|
|
Tween.LocalPosition(packToAnimate, targetPosition, tweenDuration, 0f, Tween.EaseInBack);
|
|
|
|
|
|
|
|
|
|
|
|
// Scale down
|
|
|
|
|
|
Vector3 targetScale = packToAnimate.localScale * disappearScale;
|
|
|
|
|
|
Tween.LocalScale(packToAnimate, targetScale, tweenDuration, 0f, Tween.EaseInBack);
|
|
|
|
|
|
|
|
|
|
|
|
// Don't wait here - let animations overlap
|
|
|
|
|
|
// Hide/destroy the booster after tween completes (duplicate or not)
|
|
|
|
|
|
// Since we destroy the entire UI instance anyway, just clean up visual artifacts
|
|
|
|
|
|
yield return new WaitForSeconds(tweenDuration);
|
|
|
|
|
|
|
|
|
|
|
|
if (packToAnimate != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
packToAnimate.gameObject.SetActive(false);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
yield break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Get the target position for the booster pack animation (scrapbook button or fallback).
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private Vector3 GetTargetPosition(GameObject scrapbookButton)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (scrapbookButton != null && boosterImages.Length > 0 && boosterImages[0] != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
RectTransform scrapbookRect = scrapbookButton.GetComponent<RectTransform>();
|
|
|
|
|
|
if (scrapbookRect != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Convert scrapbook button's world position to local position relative to booster's parent
|
|
|
|
|
|
Canvas canvas = GetComponentInParent<Canvas>();
|
|
|
|
|
|
if (canvas != null && canvas.renderMode == RenderMode.ScreenSpaceOverlay)
|
|
|
|
|
|
{
|
|
|
|
|
|
// For overlay canvas, convert screen position to local position
|
|
|
|
|
|
Vector2 screenPos = RectTransformUtility.WorldToScreenPoint(null, scrapbookRect.position);
|
|
|
|
|
|
RectTransformUtility.ScreenPointToLocalPointInRectangle(
|
|
|
|
|
|
boosterImages[0].parent as RectTransform,
|
|
|
|
|
|
screenPos,
|
|
|
|
|
|
null,
|
|
|
|
|
|
out Vector2 localPoint);
|
|
|
|
|
|
return localPoint;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
// For world space or camera canvas
|
|
|
|
|
|
return boosterImages[0].parent.InverseTransformPoint(scrapbookRect.position);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Fallback position
|
|
|
|
|
|
return GetFallbackPosition();
|
|
|
|
|
|
}
|
2025-11-10 10:41:38 +01:00
|
|
|
|
|
|
|
|
|
|
private Vector3 GetFallbackPosition()
|
|
|
|
|
|
{
|
|
|
|
|
|
RectTransform canvasRect = GetComponentInParent<Canvas>()?.GetComponent<RectTransform>();
|
|
|
|
|
|
if (canvasRect != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Convert bottom-left corner with offset to local position
|
|
|
|
|
|
Vector2 bottomLeft = new Vector2(-canvasRect.rect.width / 2f, -canvasRect.rect.height / 2f);
|
|
|
|
|
|
return bottomLeft + targetBottomLeftOffset;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
// Ultimate fallback if no canvas found
|
2025-12-15 11:59:40 +01:00
|
|
|
|
if (boosterImages.Length > 0 && _boosterInitialPositions != null && _boosterInitialPositions.Length > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
return _boosterInitialPositions[0] + new Vector3(-500f, -500f, 0f);
|
|
|
|
|
|
}
|
|
|
|
|
|
return new Vector3(-500f, -500f, 0f);
|
2025-11-10 10:41:38 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-11-07 15:38:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|