Screenshots in Diving Minigame
This commit is contained in:
@@ -57,8 +57,11 @@ namespace Utils
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for UI to hide
|
||||
// Wait for UI to hide and render to complete
|
||||
yield return new WaitForEndOfFrame();
|
||||
yield return null; // Wait one more frame for good measure
|
||||
|
||||
Logging.Debug($"[PhotoManager] About to capture. CaptureArea: {captureArea.name}");
|
||||
|
||||
// Capture photo
|
||||
bool captureComplete = false;
|
||||
@@ -68,6 +71,7 @@ namespace Utils
|
||||
{
|
||||
capturedPhoto = texture;
|
||||
captureComplete = true;
|
||||
Logging.Debug($"[PhotoManager] Capture callback received. Texture: {(texture != null ? $"{texture.width}x{texture.height}" : "NULL")}");
|
||||
}, mainCamera, clampToScreenBounds);
|
||||
|
||||
// Wait for capture to complete
|
||||
@@ -129,6 +133,12 @@ namespace Utils
|
||||
|
||||
if (mainCamera == null) mainCamera = Camera.main;
|
||||
|
||||
// Debug: Log RectTransform details
|
||||
Logging.Debug($"[PhotoManager] CaptureArea RectTransform: {captureArea.name}");
|
||||
Logging.Debug($"[PhotoManager] CaptureArea anchoredPosition: {captureArea.anchoredPosition}");
|
||||
Logging.Debug($"[PhotoManager] CaptureArea sizeDelta: {captureArea.sizeDelta}");
|
||||
Logging.Debug($"[PhotoManager] CaptureArea rect: {captureArea.rect}");
|
||||
|
||||
// Use ScreenSpaceUtility to convert RectTransform to screen rect
|
||||
Rect screenRect = ScreenSpaceUtility.RectTransformToScreenRect(
|
||||
captureArea,
|
||||
@@ -138,6 +148,15 @@ namespace Utils
|
||||
);
|
||||
|
||||
Logging.Debug($"[PhotoManager] Capturing area: pos={screenRect.position}, size={screenRect.size}");
|
||||
Logging.Debug($"[PhotoManager] Screen dimensions: {Screen.width}x{Screen.height}");
|
||||
|
||||
// Validate screenRect
|
||||
if (screenRect.width <= 0 || screenRect.height <= 0)
|
||||
{
|
||||
Logging.Error($"[PhotoManager] Invalid screen rect calculated! width={screenRect.width}, height={screenRect.height}");
|
||||
onComplete?.Invoke(null);
|
||||
return;
|
||||
}
|
||||
|
||||
// Use Screenshot Helper's Capture method
|
||||
ScreenshotHelper.Instance.Capture(
|
||||
|
||||
3
Assets/Scripts/Utils/UI.meta
Normal file
3
Assets/Scripts/Utils/UI.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6b23cacf87f94639aad3b8e25b596ac3
|
||||
timeCreated: 1766012758
|
||||
217
Assets/Scripts/Utils/UI/ScreenshotFlyawayAnimation.cs
Normal file
217
Assets/Scripts/Utils/UI/ScreenshotFlyawayAnimation.cs
Normal file
@@ -0,0 +1,217 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using Pixelplacement;
|
||||
|
||||
namespace Utils.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// UI component that animates a screenshot flying away and disappearing.
|
||||
/// Uses Pixelplacement Tween library for smooth animations with curves.
|
||||
/// Attach to a UI prefab with frame (Image) and picture (Image) components.
|
||||
/// </summary>
|
||||
public class ScreenshotFlyawayAnimation : MonoBehaviour
|
||||
{
|
||||
[Header("UI Components")]
|
||||
[SerializeField] private Image _frame;
|
||||
[SerializeField] private Image _picture;
|
||||
|
||||
[Header("Animation Settings")]
|
||||
[Tooltip("Target offset from starting position (in UI space)")]
|
||||
[SerializeField] private Vector2 _targetOffset = new Vector2(0, 300f);
|
||||
|
||||
[Tooltip("Number of full rotations during animation")]
|
||||
[SerializeField] private float _spinRotations = 2f;
|
||||
|
||||
[Tooltip("Duration of the entire animation in seconds")]
|
||||
[SerializeField] private float _duration = 1.5f;
|
||||
|
||||
[Tooltip("Movement curve for position animation")]
|
||||
[SerializeField] private AnimationCurve _moveCurve = AnimationCurve.EaseInOut(0, 0, 1, 1);
|
||||
|
||||
[Tooltip("Scale curve for shrinking animation")]
|
||||
[SerializeField] private AnimationCurve _scaleCurve = AnimationCurve.EaseInOut(0, 1, 1, 0);
|
||||
|
||||
[Tooltip("Rotation curve for spinning animation")]
|
||||
[SerializeField] private AnimationCurve _rotationCurve = AnimationCurve.Linear(0, 0, 1, 1);
|
||||
|
||||
private RectTransform _rectTransform;
|
||||
private bool _isAnimating;
|
||||
private Transform _targetTransform; // Target to fly toward (optional)
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_rectTransform = GetComponent<RectTransform>();
|
||||
|
||||
// Hide initially - will be shown when animation plays
|
||||
gameObject.SetActive(false);
|
||||
|
||||
// Validate components
|
||||
if (_frame == null)
|
||||
{
|
||||
Debug.LogWarning("[ScreenshotFlyawayAnimation] Frame image not assigned!");
|
||||
}
|
||||
|
||||
if (_picture == null)
|
||||
{
|
||||
Debug.LogWarning("[ScreenshotFlyawayAnimation] Picture image not assigned!");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start the flyaway animation with the captured screenshot texture.
|
||||
/// Unparents to root canvas to survive viewfinder destruction.
|
||||
/// </summary>
|
||||
/// <param name="photo">The screenshot texture to display</param>
|
||||
/// <param name="target">Optional target transform to fly toward (if null, uses _targetOffset)</param>
|
||||
public void PlayAnimation(Texture2D photo, Transform target = null)
|
||||
{
|
||||
if (_isAnimating)
|
||||
{
|
||||
Debug.LogWarning("[ScreenshotFlyawayAnimation] Animation already playing!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (photo == null)
|
||||
{
|
||||
Debug.LogError("[ScreenshotFlyawayAnimation] Photo texture is null!");
|
||||
Destroy(gameObject);
|
||||
return;
|
||||
}
|
||||
|
||||
// Store target for StartAnimation
|
||||
_targetTransform = target;
|
||||
|
||||
// Show the GameObject before playing animation
|
||||
gameObject.SetActive(true);
|
||||
|
||||
// Unparent to root canvas to survive viewfinder destruction
|
||||
Canvas rootCanvas = GetComponentInParent<Canvas>();
|
||||
if (rootCanvas != null)
|
||||
{
|
||||
rootCanvas = rootCanvas.rootCanvas;
|
||||
transform.SetParent(rootCanvas.transform, worldPositionStays: true);
|
||||
}
|
||||
|
||||
// Assign texture to picture image
|
||||
if (_picture != null)
|
||||
{
|
||||
Sprite photoSprite = Sprite.Create(
|
||||
photo,
|
||||
new Rect(0, 0, photo.width, photo.height),
|
||||
new Vector2(0.5f, 0.5f)
|
||||
);
|
||||
_picture.sprite = photoSprite;
|
||||
}
|
||||
|
||||
_isAnimating = true;
|
||||
StartAnimation();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execute the animation using Pixelplacement Tween
|
||||
/// </summary>
|
||||
private void StartAnimation()
|
||||
{
|
||||
if (_rectTransform == null) return;
|
||||
|
||||
// Get starting position
|
||||
Vector2 startPosition = _rectTransform.anchoredPosition;
|
||||
Vector2 endPosition;
|
||||
|
||||
// Calculate end position based on target or offset
|
||||
if (_targetTransform != null)
|
||||
{
|
||||
// Convert target world position to local anchored position
|
||||
RectTransform targetRect = _targetTransform as RectTransform;
|
||||
if (targetRect != null && _rectTransform.parent is RectTransform parentRect)
|
||||
{
|
||||
// Convert target's position to parent's local space
|
||||
Vector2 targetLocalPos;
|
||||
RectTransformUtility.ScreenPointToLocalPointInRectangle(
|
||||
parentRect,
|
||||
RectTransformUtility.WorldToScreenPoint(null, targetRect.position),
|
||||
null,
|
||||
out targetLocalPos
|
||||
);
|
||||
endPosition = targetLocalPos;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fallback: use offset if conversion fails
|
||||
endPosition = startPosition + _targetOffset;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use offset if no target provided
|
||||
endPosition = startPosition + _targetOffset;
|
||||
}
|
||||
|
||||
// Start rotation at 0
|
||||
Vector3 startRotation = Vector3.zero;
|
||||
Vector3 endRotation = new Vector3(0, 0, 360f * _spinRotations);
|
||||
|
||||
// Start scale at 1
|
||||
Vector3 startScale = Vector3.one;
|
||||
Vector3 endScale = Vector3.zero;
|
||||
|
||||
// Animate position using AnchoredPosition for UI
|
||||
Tween.AnchoredPosition(
|
||||
_rectTransform,
|
||||
startPosition,
|
||||
endPosition,
|
||||
_duration,
|
||||
0f, // no delay
|
||||
_moveCurve,
|
||||
Tween.LoopType.None,
|
||||
null, // no start callback
|
||||
OnAnimationComplete // complete callback
|
||||
);
|
||||
|
||||
// Animate scale
|
||||
Tween.LocalScale(
|
||||
transform,
|
||||
startScale,
|
||||
endScale,
|
||||
_duration,
|
||||
0f,
|
||||
_scaleCurve
|
||||
);
|
||||
|
||||
// Animate rotation (Z-axis spin)
|
||||
Tween.Rotation(
|
||||
transform,
|
||||
Quaternion.Euler(startRotation),
|
||||
Quaternion.Euler(endRotation),
|
||||
_duration,
|
||||
0f,
|
||||
_rotationCurve,
|
||||
Tween.LoopType.None,
|
||||
null,
|
||||
null,
|
||||
true // obey timescale
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when animation completes - destroy the GameObject
|
||||
/// </summary>
|
||||
private void OnAnimationComplete()
|
||||
{
|
||||
_isAnimating = false;
|
||||
|
||||
// Clean up sprite to avoid memory leak
|
||||
if (_picture != null && _picture.sprite != null)
|
||||
{
|
||||
Sprite sprite = _picture.sprite;
|
||||
_picture.sprite = null;
|
||||
Destroy(sprite.texture);
|
||||
Destroy(sprite);
|
||||
}
|
||||
|
||||
// Destroy the animation GameObject
|
||||
Destroy(gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5600bf58913e468e883989b2cca4b0a8
|
||||
timeCreated: 1766012758
|
||||
Reference in New Issue
Block a user