Finalize capture taking
This commit is contained in:
committed by
Michal Pikulski
parent
5ad84ca3e8
commit
8d410b42d3
198
Assets/Scripts/Utils/ScreenSpaceUtility.cs
Normal file
198
Assets/Scripts/Utils/ScreenSpaceUtility.cs
Normal file
@@ -0,0 +1,198 @@
|
||||
using Core;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Utils
|
||||
{
|
||||
/// <summary>
|
||||
/// Utility methods for screen space and UI coordinate conversions
|
||||
/// </summary>
|
||||
public static class ScreenSpaceUtility
|
||||
{
|
||||
/// <summary>
|
||||
/// Convert RectTransform to screen space rect with center position.
|
||||
/// Useful for screenshot capture or screen-based calculations.
|
||||
/// </summary>
|
||||
/// <param name="rectTransform">RectTransform to convert</param>
|
||||
/// <param name="camera">Camera used for coordinate conversion (null = Camera.main)</param>
|
||||
/// <param name="clampToScreenBounds">If true, clamps the rect to visible screen area</param>
|
||||
/// <param name="returnCenterPosition">If true, returns center position; if false, returns bottom-left position</param>
|
||||
/// <returns>Screen space rect (position is center or bottom-left based on returnCenterPosition)</returns>
|
||||
public static Rect RectTransformToScreenRect(
|
||||
RectTransform rectTransform,
|
||||
Camera camera = null,
|
||||
bool clampToScreenBounds = true,
|
||||
bool returnCenterPosition = true)
|
||||
{
|
||||
if (rectTransform == null)
|
||||
{
|
||||
Logging.Error("[ScreenSpaceUtility] RectTransform is null!");
|
||||
return new Rect(Screen.width / 2f, Screen.height / 2f, 0, 0);
|
||||
}
|
||||
|
||||
if (camera == null) camera = Camera.main;
|
||||
|
||||
// Get world corners (0=bottom-left, 1=top-left, 2=top-right, 3=bottom-right)
|
||||
Vector3[] corners = new Vector3[4];
|
||||
rectTransform.GetWorldCorners(corners);
|
||||
|
||||
// Determine correct camera based on Canvas render mode
|
||||
Camera canvasCamera = GetCanvasCamera(rectTransform, camera);
|
||||
|
||||
// Convert corners to screen space
|
||||
Vector2 min = RectTransformUtility.WorldToScreenPoint(canvasCamera, corners[0]);
|
||||
Vector2 max = RectTransformUtility.WorldToScreenPoint(canvasCamera, corners[2]);
|
||||
|
||||
Logging.Debug($"[ScreenSpaceUtility] Canvas mode: {rectTransform.GetComponentInParent<Canvas>()?.renderMode}, Camera: {canvasCamera?.name ?? "null"}");
|
||||
Logging.Debug($"[ScreenSpaceUtility] Raw screen coords - min: {min}, max: {max}");
|
||||
|
||||
// Apply screen bounds clamping if requested
|
||||
if (clampToScreenBounds)
|
||||
{
|
||||
return ClampRectToScreenBounds(min, max, returnCenterPosition);
|
||||
}
|
||||
else
|
||||
{
|
||||
// No clamping - use raw values
|
||||
float width = Mathf.Abs(max.x - min.x);
|
||||
float height = Mathf.Abs(max.y - min.y);
|
||||
|
||||
if (returnCenterPosition)
|
||||
{
|
||||
float centerX = min.x + width / 2f;
|
||||
float centerY = min.y + height / 2f;
|
||||
return new Rect(centerX, centerY, width, height);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new Rect(min.x, min.y, width, height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the appropriate camera for UI coordinate conversion based on Canvas render mode
|
||||
/// </summary>
|
||||
/// <param name="rectTransform">RectTransform to find canvas for</param>
|
||||
/// <param name="fallbackCamera">Fallback camera if no canvas found</param>
|
||||
/// <returns>Camera to use for coordinate conversion (null for Overlay mode)</returns>
|
||||
public static Camera GetCanvasCamera(RectTransform rectTransform, Camera fallbackCamera = null)
|
||||
{
|
||||
Canvas canvas = rectTransform.GetComponentInParent<Canvas>();
|
||||
|
||||
if (canvas == null)
|
||||
{
|
||||
return fallbackCamera;
|
||||
}
|
||||
|
||||
switch (canvas.renderMode)
|
||||
{
|
||||
case RenderMode.ScreenSpaceOverlay:
|
||||
// For Screen Space - Overlay, use null (direct pixel coords)
|
||||
return null;
|
||||
|
||||
case RenderMode.ScreenSpaceCamera:
|
||||
// For Screen Space - Camera, use the canvas's worldCamera
|
||||
return canvas.worldCamera;
|
||||
|
||||
case RenderMode.WorldSpace:
|
||||
// For World Space, use canvas camera or fallback
|
||||
return canvas.worldCamera ?? fallbackCamera;
|
||||
|
||||
default:
|
||||
return fallbackCamera;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clamp rect coordinates to screen bounds and calculate final rect
|
||||
/// </summary>
|
||||
/// <param name="min">Bottom-left corner in screen space</param>
|
||||
/// <param name="max">Top-right corner in screen space</param>
|
||||
/// <param name="returnCenterPosition">If true, returns center position; if false, returns bottom-left</param>
|
||||
/// <returns>Clamped screen rect</returns>
|
||||
private static Rect ClampRectToScreenBounds(Vector2 min, Vector2 max, bool returnCenterPosition)
|
||||
{
|
||||
// Clamp to screen bounds
|
||||
float minX = Mathf.Max(0, min.x);
|
||||
float minY = Mathf.Max(0, min.y);
|
||||
float maxX = Mathf.Min(Screen.width, max.x);
|
||||
float maxY = Mathf.Min(Screen.height, max.y);
|
||||
|
||||
// Check if rect is completely outside screen bounds
|
||||
if (minX >= Screen.width || minY >= Screen.height || maxX <= 0 || maxY <= 0)
|
||||
{
|
||||
Logging.Warning("[ScreenSpaceUtility] RectTransform is completely outside screen bounds!");
|
||||
return new Rect(Screen.width / 2f, Screen.height / 2f, 0, 0);
|
||||
}
|
||||
|
||||
// Calculate dimensions from clamped bounds
|
||||
float width = maxX - minX;
|
||||
float height = maxY - minY;
|
||||
|
||||
// Validate dimensions
|
||||
if (width <= 0 || height <= 0)
|
||||
{
|
||||
Logging.Warning($"[ScreenSpaceUtility] Invalid dimensions after clamping: {width}x{height}");
|
||||
return new Rect(Screen.width / 2f, Screen.height / 2f, 100, 100); // Fallback small rect
|
||||
}
|
||||
|
||||
Logging.Debug($"[ScreenSpaceUtility] Clamped bounds - min: ({minX}, {minY}), max: ({maxX}, {maxY})");
|
||||
|
||||
if (returnCenterPosition)
|
||||
{
|
||||
// Calculate center position from clamped bounds
|
||||
float centerX = minX + width / 2f;
|
||||
float centerY = minY + height / 2f;
|
||||
|
||||
Logging.Debug($"[ScreenSpaceUtility] Final rect - center: ({centerX}, {centerY}), size: ({width}, {height})");
|
||||
return new Rect(centerX, centerY, width, height);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Return bottom-left position
|
||||
Logging.Debug($"[ScreenSpaceUtility] Final rect - position: ({minX}, {minY}), size: ({width}, {height})");
|
||||
return new Rect(minX, minY, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if a screen rect is completely outside screen bounds
|
||||
/// </summary>
|
||||
public static bool IsRectOutsideScreenBounds(Rect rect)
|
||||
{
|
||||
return rect.xMax < 0 || rect.xMin > Screen.width ||
|
||||
rect.yMax < 0 || rect.yMin > Screen.height;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the visible portion of a rect when clamped to screen bounds
|
||||
/// </summary>
|
||||
public static Rect GetVisibleScreenRect(Rect rect)
|
||||
{
|
||||
float minX = Mathf.Max(0, rect.xMin);
|
||||
float minY = Mathf.Max(0, rect.yMin);
|
||||
float maxX = Mathf.Min(Screen.width, rect.xMax);
|
||||
float maxY = Mathf.Min(Screen.height, rect.yMax);
|
||||
|
||||
float width = Mathf.Max(0, maxX - minX);
|
||||
float height = Mathf.Max(0, maxY - minY);
|
||||
|
||||
return new Rect(minX, minY, width, height);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculate the percentage of a rect that is visible on screen
|
||||
/// </summary>
|
||||
public static float GetVisiblePercentage(Rect rect)
|
||||
{
|
||||
if (rect.width <= 0 || rect.height <= 0) return 0f;
|
||||
|
||||
Rect visibleRect = GetVisibleScreenRect(rect);
|
||||
float totalArea = rect.width * rect.height;
|
||||
float visibleArea = visibleRect.width * visibleRect.height;
|
||||
|
||||
return visibleArea / totalArea;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
3
Assets/Scripts/Utils/ScreenSpaceUtility.cs.meta
Normal file
3
Assets/Scripts/Utils/ScreenSpaceUtility.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f9a38b4740894e6ea8c32d8f62bc5bd6
|
||||
timeCreated: 1764148562
|
||||
171
Assets/Scripts/Utils/TweenAnimationUtility.cs
Normal file
171
Assets/Scripts/Utils/TweenAnimationUtility.cs
Normal file
@@ -0,0 +1,171 @@
|
||||
using System;
|
||||
using Pixelplacement;
|
||||
using Pixelplacement.TweenSystem;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Utils
|
||||
{
|
||||
/// <summary>
|
||||
/// Common animation utilities extracted from CardAnimator pattern.
|
||||
/// Provides reusable tween animations for UI elements.
|
||||
/// </summary>
|
||||
public static class TweenAnimationUtility
|
||||
{
|
||||
#region Scale Animations
|
||||
|
||||
/// <summary>
|
||||
/// Animate scale to target value with ease in-out
|
||||
/// </summary>
|
||||
public static TweenBase AnimateScale(Transform transform, Vector3 targetScale, float duration, Action onComplete = null)
|
||||
{
|
||||
return Tween.LocalScale(transform, targetScale, duration, 0f, Tween.EaseInOut, completeCallback: onComplete);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pulse scale animation (scale up then back to original)
|
||||
/// </summary>
|
||||
public static void PulseScale(Transform transform, float pulseAmount = 1.1f, float duration = 0.2f, Action onComplete = null)
|
||||
{
|
||||
Vector3 originalScale = transform.localScale;
|
||||
Vector3 pulseScale = originalScale * pulseAmount;
|
||||
|
||||
Tween.LocalScale(transform, pulseScale, duration, 0f, Tween.EaseOutBack,
|
||||
completeCallback: () =>
|
||||
{
|
||||
Tween.LocalScale(transform, originalScale, duration, 0f, Tween.EaseInBack, completeCallback: onComplete);
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pop-in animation (scale from 0 to target with overshoot)
|
||||
/// </summary>
|
||||
public static TweenBase PopIn(Transform transform, Vector3 targetScale, float duration = 0.5f, Action onComplete = null)
|
||||
{
|
||||
transform.localScale = Vector3.zero;
|
||||
return Tween.LocalScale(transform, targetScale, duration, 0f, Tween.EaseOutBack, completeCallback: onComplete);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pop-out animation (scale from current to 0)
|
||||
/// </summary>
|
||||
public static TweenBase PopOut(Transform transform, float duration = 0.3f, Action onComplete = null)
|
||||
{
|
||||
return Tween.LocalScale(transform, Vector3.zero, duration, 0f, Tween.EaseInBack, completeCallback: onComplete);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Smooth scale transition with bounce
|
||||
/// </summary>
|
||||
public static TweenBase ScaleWithBounce(Transform transform, Vector3 targetScale, float duration, Action onComplete = null)
|
||||
{
|
||||
return Tween.LocalScale(transform, targetScale, duration, 0f, Tween.EaseOutBack, completeCallback: onComplete);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Position Animations
|
||||
|
||||
/// <summary>
|
||||
/// Animate anchored position (for RectTransform UI elements)
|
||||
/// </summary>
|
||||
public static TweenBase AnimateAnchoredPosition(RectTransform rectTransform, Vector2 targetPosition, float duration, Action onComplete = null)
|
||||
{
|
||||
return Tween.AnchoredPosition(rectTransform, targetPosition, duration, 0f, Tween.EaseInOut, completeCallback: onComplete);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Animate local position (for regular transforms)
|
||||
/// </summary>
|
||||
public static TweenBase AnimateLocalPosition(Transform transform, Vector3 targetPosition, float duration, Action onComplete = null)
|
||||
{
|
||||
return Tween.LocalPosition(transform, targetPosition, duration, 0f, Tween.EaseInOut, completeCallback: onComplete);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Move with bounce effect
|
||||
/// </summary>
|
||||
public static TweenBase MoveWithBounce(RectTransform rectTransform, Vector2 targetPosition, float duration, Action onComplete = null)
|
||||
{
|
||||
return Tween.AnchoredPosition(rectTransform, targetPosition, duration, 0f, Tween.EaseOutBack, completeCallback: onComplete);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Combined Hover Animations
|
||||
|
||||
/// <summary>
|
||||
/// Hover enter animation (lift and scale) for RectTransform
|
||||
/// </summary>
|
||||
public static void HoverEnter(RectTransform rectTransform, Vector2 originalPosition, float liftAmount = 20f,
|
||||
float scaleMultiplier = 1.05f, float duration = 0.2f, Action onComplete = null)
|
||||
{
|
||||
Vector2 targetPos = originalPosition + Vector2.up * liftAmount;
|
||||
|
||||
Tween.AnchoredPosition(rectTransform, targetPos, duration, 0f, Tween.EaseOutBack);
|
||||
Tween.LocalScale(rectTransform, Vector3.one * scaleMultiplier, duration, 0f, Tween.EaseOutBack, completeCallback: onComplete);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hover exit animation (return to original position and scale) for RectTransform
|
||||
/// </summary>
|
||||
public static void HoverExit(RectTransform rectTransform, Vector2 originalPosition, float duration = 0.2f, Action onComplete = null)
|
||||
{
|
||||
Tween.AnchoredPosition(rectTransform, originalPosition, duration, 0f, Tween.EaseInBack);
|
||||
Tween.LocalScale(rectTransform, Vector3.one, duration, 0f, Tween.EaseInBack, completeCallback: onComplete);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Glow pulse effect (scale up/down repeatedly)
|
||||
/// </summary>
|
||||
public static TweenBase StartGlowPulse(Transform transform, float pulseAmount = 1.1f, float duration = 0.8f)
|
||||
{
|
||||
Vector3 originalScale = transform.localScale;
|
||||
Vector3 pulseScale = originalScale * pulseAmount;
|
||||
|
||||
return Tween.LocalScale(transform, pulseScale, duration, 0f, Tween.EaseIn, Tween.LoopType.PingPong);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stop any active tweens on transform
|
||||
/// </summary>
|
||||
public static void StopTweens(Transform transform)
|
||||
{
|
||||
Tween.Cancel(transform.GetInstanceID());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Fade Animations
|
||||
|
||||
/// <summary>
|
||||
/// Fade CanvasGroup alpha
|
||||
/// </summary>
|
||||
public static TweenBase FadeCanvasGroup(CanvasGroup canvasGroup, float targetAlpha, float duration, Action onComplete = null)
|
||||
{
|
||||
return Tween.CanvasGroupAlpha(canvasGroup, targetAlpha, duration, 0f, Tween.EaseInOut, completeCallback: onComplete);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pop-out with fade - scale to 0 and fade out simultaneously
|
||||
/// </summary>
|
||||
public static void PopOutWithFade(Transform transform, CanvasGroup canvasGroup, float duration, Action onComplete = null)
|
||||
{
|
||||
// Scale to 0
|
||||
Tween.LocalScale(transform, Vector3.zero, duration, 0f, Tween.EaseInBack);
|
||||
|
||||
// Fade out simultaneously
|
||||
if (canvasGroup != null)
|
||||
{
|
||||
Tween.CanvasGroupAlpha(canvasGroup, 0f, duration, 0f, Tween.EaseInOut, completeCallback: onComplete);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If no canvas group, just call complete after scale
|
||||
Tween.LocalScale(transform, Vector3.zero, duration, 0f, Tween.EaseInBack, completeCallback: onComplete);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
3
Assets/Scripts/Utils/TweenAnimationUtility.cs.meta
Normal file
3
Assets/Scripts/Utils/TweenAnimationUtility.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: abd48147eff149508890fe2fa87b8421
|
||||
timeCreated: 1763745490
|
||||
Reference in New Issue
Block a user