Finalize capture taking
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -318,6 +318,42 @@ CanvasRenderer:
|
|||||||
m_PrefabAsset: {fileID: 0}
|
m_PrefabAsset: {fileID: 0}
|
||||||
m_GameObject: {fileID: 37633365}
|
m_GameObject: {fileID: 37633365}
|
||||||
m_CullTransparentMesh: 1
|
m_CullTransparentMesh: 1
|
||||||
|
--- !u!1 &61401515
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 61401516}
|
||||||
|
m_Layer: 5
|
||||||
|
m_Name: PhotoGallery
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!224 &61401516
|
||||||
|
RectTransform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 61401515}
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children:
|
||||||
|
- {fileID: 1612917661}
|
||||||
|
m_Father: {fileID: 1217454518}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
m_AnchorMin: {x: 0, y: 0}
|
||||||
|
m_AnchorMax: {x: 1, y: 1}
|
||||||
|
m_AnchoredPosition: {x: 0, y: 0}
|
||||||
|
m_SizeDelta: {x: 0, y: 0}
|
||||||
|
m_Pivot: {x: 0.5, y: 0.5}
|
||||||
--- !u!1 &65358844
|
--- !u!1 &65358844
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
@@ -1274,6 +1310,7 @@ RectTransform:
|
|||||||
m_ConstrainProportionsScale: 0
|
m_ConstrainProportionsScale: 0
|
||||||
m_Children:
|
m_Children:
|
||||||
- {fileID: 1443594949}
|
- {fileID: 1443594949}
|
||||||
|
- {fileID: 61401516}
|
||||||
m_Father: {fileID: 0}
|
m_Father: {fileID: 0}
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
m_AnchorMin: {x: 0, y: 0}
|
m_AnchorMin: {x: 0, y: 0}
|
||||||
@@ -1508,6 +1545,141 @@ Transform:
|
|||||||
m_Children: []
|
m_Children: []
|
||||||
m_Father: {fileID: 0}
|
m_Father: {fileID: 0}
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!1 &1612917660
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 1612917661}
|
||||||
|
- component: {fileID: 1612917665}
|
||||||
|
- component: {fileID: 1612917664}
|
||||||
|
- component: {fileID: 1612917663}
|
||||||
|
- component: {fileID: 1612917662}
|
||||||
|
m_Layer: 5
|
||||||
|
m_Name: Button
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!224 &1612917661
|
||||||
|
RectTransform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1612917660}
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 61401516}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
m_AnchorMin: {x: 1, y: 1}
|
||||||
|
m_AnchorMax: {x: 1, y: 1}
|
||||||
|
m_AnchoredPosition: {x: -75, y: -75}
|
||||||
|
m_SizeDelta: {x: 172.83276, y: 0}
|
||||||
|
m_Pivot: {x: 1, y: 1}
|
||||||
|
--- !u!114 &1612917662
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1612917660}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 86710e43de46f6f4bac7c8e50813a599, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.AspectRatioFitter
|
||||||
|
m_AspectMode: 1
|
||||||
|
m_AspectRatio: 0.964
|
||||||
|
--- !u!114 &1612917663
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1612917660}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Button
|
||||||
|
m_Navigation:
|
||||||
|
m_Mode: 3
|
||||||
|
m_WrapAround: 0
|
||||||
|
m_SelectOnUp: {fileID: 0}
|
||||||
|
m_SelectOnDown: {fileID: 0}
|
||||||
|
m_SelectOnLeft: {fileID: 0}
|
||||||
|
m_SelectOnRight: {fileID: 0}
|
||||||
|
m_Transition: 1
|
||||||
|
m_Colors:
|
||||||
|
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
|
||||||
|
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
|
||||||
|
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
|
||||||
|
m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
|
||||||
|
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
|
||||||
|
m_ColorMultiplier: 1
|
||||||
|
m_FadeDuration: 0.1
|
||||||
|
m_SpriteState:
|
||||||
|
m_HighlightedSprite: {fileID: 0}
|
||||||
|
m_PressedSprite: {fileID: 0}
|
||||||
|
m_SelectedSprite: {fileID: 0}
|
||||||
|
m_DisabledSprite: {fileID: 0}
|
||||||
|
m_AnimationTriggers:
|
||||||
|
m_NormalTrigger: Normal
|
||||||
|
m_HighlightedTrigger: Highlighted
|
||||||
|
m_PressedTrigger: Pressed
|
||||||
|
m_SelectedTrigger: Selected
|
||||||
|
m_DisabledTrigger: Disabled
|
||||||
|
m_Interactable: 1
|
||||||
|
m_TargetGraphic: {fileID: 1612917664}
|
||||||
|
m_OnClick:
|
||||||
|
m_PersistentCalls:
|
||||||
|
m_Calls: []
|
||||||
|
--- !u!114 &1612917664
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1612917660}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Image
|
||||||
|
m_Material: {fileID: 0}
|
||||||
|
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||||
|
m_RaycastTarget: 1
|
||||||
|
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
m_Maskable: 1
|
||||||
|
m_OnCullStateChanged:
|
||||||
|
m_PersistentCalls:
|
||||||
|
m_Calls: []
|
||||||
|
m_Sprite: {fileID: 1917382497509789248, guid: 8d568408ea5f183458e17af541af2d8e, type: 3}
|
||||||
|
m_Type: 0
|
||||||
|
m_PreserveAspect: 0
|
||||||
|
m_FillCenter: 1
|
||||||
|
m_FillMethod: 4
|
||||||
|
m_FillAmount: 1
|
||||||
|
m_FillClockwise: 1
|
||||||
|
m_FillOrigin: 0
|
||||||
|
m_UseSpriteMesh: 0
|
||||||
|
m_PixelsPerUnitMultiplier: 1
|
||||||
|
--- !u!222 &1612917665
|
||||||
|
CanvasRenderer:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1612917660}
|
||||||
|
m_CullTransparentMesh: 1
|
||||||
--- !u!1 &1647993457
|
--- !u!1 &1647993457
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
@@ -1543,7 +1715,7 @@ MonoBehaviour:
|
|||||||
takePhotoButton: {fileID: 37633367}
|
takePhotoButton: {fileID: 37633367}
|
||||||
statue: {fileID: 1078270173}
|
statue: {fileID: 1078270173}
|
||||||
uiElementsToHideForPhoto: []
|
uiElementsToHideForPhoto: []
|
||||||
photoArea: {fileID: 0}
|
photoArea: {fileID: 65358845}
|
||||||
photoSaveKey: MrCementStatuePhoto
|
photoSaveKey: MrCementStatuePhoto
|
||||||
--- !u!4 &1647993459
|
--- !u!4 &1647993459
|
||||||
Transform:
|
Transform:
|
||||||
|
|||||||
@@ -57,7 +57,8 @@ namespace Minigames.StatueDressup.Controllers
|
|||||||
// Setup photo button
|
// Setup photo button
|
||||||
if (takePhotoButton != null)
|
if (takePhotoButton != null)
|
||||||
{
|
{
|
||||||
takePhotoButton.onClick.AddListener(OnTakePhoto);
|
// TODO: Remove comment when ready
|
||||||
|
// takePhotoButton.onClick.AddListener(OnTakePhoto);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Subscribe to menu controller for tracking placed items
|
// Subscribe to menu controller for tracking placed items
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using Minigames.StatueDressup.Utils;
|
|||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.EventSystems;
|
using UnityEngine.EventSystems;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
|
using Utils;
|
||||||
|
|
||||||
namespace Minigames.StatueDressup.DragDrop
|
namespace Minigames.StatueDressup.DragDrop
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
|
||||||
using Core;
|
using Core;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using SDev;
|
using SDev;
|
||||||
|
using ScreenUtils = Utils.ScreenSpaceUtility;
|
||||||
|
|
||||||
namespace Minigames.StatueDressup.Utils
|
namespace Minigames.StatueDressup.Utils
|
||||||
{
|
{
|
||||||
@@ -15,15 +15,15 @@ namespace Minigames.StatueDressup.Utils
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static class StatuePhotoManager
|
public static class StatuePhotoManager
|
||||||
{
|
{
|
||||||
private const string PHOTO_FOLDER = "StatuePhotos";
|
private const string PhotoFolder = "StatuePhotos";
|
||||||
private const string PHOTO_PREFIX = "MrCementStatue_";
|
private const string PhotoPrefix = "MrCementStatue_";
|
||||||
private const string METADATA_KEY_PREFIX = "StatuePhoto_Meta_";
|
private const string MetadataKeyPrefix = "StatuePhoto_Meta_";
|
||||||
private const string PHOTO_INDEX_KEY = "StatuePhoto_Index";
|
private const string PhotoIndexKey = "StatuePhoto_Index";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Photo metadata stored in PlayerPrefs
|
/// Photo metadata stored in PlayerPrefs
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[System.Serializable]
|
[Serializable]
|
||||||
public class PhotoMetadata
|
public class PhotoMetadata
|
||||||
{
|
{
|
||||||
public string photoId;
|
public string photoId;
|
||||||
@@ -40,7 +40,12 @@ namespace Minigames.StatueDressup.Utils
|
|||||||
/// <param name="captureArea">RectTransform defining the capture region</param>
|
/// <param name="captureArea">RectTransform defining the capture region</param>
|
||||||
/// <param name="onComplete">Callback with captured Texture2D</param>
|
/// <param name="onComplete">Callback with captured Texture2D</param>
|
||||||
/// <param name="mainCamera">Camera used for coordinate conversion (null = Camera.main)</param>
|
/// <param name="mainCamera">Camera used for coordinate conversion (null = Camera.main)</param>
|
||||||
public static void CaptureAreaPhoto(RectTransform captureArea, Action<Texture2D> onComplete, Camera mainCamera = null)
|
/// <param name="clampToScreenBounds">If true, clamps capture area to visible screen bounds</param>
|
||||||
|
public static void CaptureAreaPhoto(
|
||||||
|
RectTransform captureArea,
|
||||||
|
Action<Texture2D> onComplete,
|
||||||
|
Camera mainCamera = null,
|
||||||
|
bool clampToScreenBounds = true)
|
||||||
{
|
{
|
||||||
if (captureArea == null)
|
if (captureArea == null)
|
||||||
{
|
{
|
||||||
@@ -51,8 +56,14 @@ namespace Minigames.StatueDressup.Utils
|
|||||||
|
|
||||||
if (mainCamera == null) mainCamera = Camera.main;
|
if (mainCamera == null) mainCamera = Camera.main;
|
||||||
|
|
||||||
// Get screen rect from RectTransform
|
// Use ScreenSpaceUtility to convert RectTransform to screen rect
|
||||||
Rect screenRect = GetScreenRectFromRectTransform(captureArea, mainCamera);
|
// returnCenterPosition = true because ScreenshotHelper expects center position
|
||||||
|
Rect screenRect = ScreenUtils.RectTransformToScreenRect(
|
||||||
|
captureArea,
|
||||||
|
mainCamera,
|
||||||
|
clampToScreenBounds,
|
||||||
|
returnCenterPosition: true
|
||||||
|
);
|
||||||
|
|
||||||
Logging.Debug($"[StatuePhotoManager] Capturing area: pos={screenRect.position}, size={screenRect.size}");
|
Logging.Debug($"[StatuePhotoManager] Capturing area: pos={screenRect.position}, size={screenRect.size}");
|
||||||
|
|
||||||
@@ -60,7 +71,7 @@ namespace Minigames.StatueDressup.Utils
|
|||||||
ScreenshotHelper.Instance.Capture(
|
ScreenshotHelper.Instance.Capture(
|
||||||
screenRect.position,
|
screenRect.position,
|
||||||
screenRect.size,
|
screenRect.size,
|
||||||
(Texture2D texture) =>
|
(texture) =>
|
||||||
{
|
{
|
||||||
if (texture != null)
|
if (texture != null)
|
||||||
{
|
{
|
||||||
@@ -75,24 +86,7 @@ namespace Minigames.StatueDressup.Utils
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Convert RectTransform world corners to screen space rect
|
|
||||||
/// </summary>
|
|
||||||
private static Rect GetScreenRectFromRectTransform(RectTransform rectTransform, Camera camera)
|
|
||||||
{
|
|
||||||
Vector3[] corners = new Vector3[4];
|
|
||||||
rectTransform.GetWorldCorners(corners);
|
|
||||||
|
|
||||||
Vector2 min = RectTransformUtility.WorldToScreenPoint(camera, corners[0]);
|
|
||||||
Vector2 max = RectTransformUtility.WorldToScreenPoint(camera, corners[2]);
|
|
||||||
|
|
||||||
// Ensure positive dimensions
|
|
||||||
float width = Mathf.Abs(max.x - min.x);
|
|
||||||
float height = Mathf.Abs(max.y - min.y);
|
|
||||||
|
|
||||||
return new Rect(min.x, min.y, width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@@ -115,13 +109,13 @@ namespace Minigames.StatueDressup.Utils
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Generate unique photo ID
|
// Generate unique photo ID
|
||||||
string photoId = $"{PHOTO_PREFIX}{DateTime.Now.Ticks}";
|
string photoId = $"{PhotoPrefix}{DateTime.Now.Ticks}";
|
||||||
|
|
||||||
// Save texture using FileSaveUtil
|
// Save texture using FileSaveUtil
|
||||||
string savedPath = FileSaveUtil.Instance.SaveTextureAsPNG(
|
string savedPath = FileSaveUtil.Instance.SaveTextureAsPNG(
|
||||||
photo,
|
photo,
|
||||||
FileSaveUtil.AppPath.PersistentDataPath,
|
FileSaveUtil.AppPath.PersistentDataPath,
|
||||||
PHOTO_FOLDER,
|
PhotoFolder,
|
||||||
photoId
|
photoId
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -232,7 +226,7 @@ namespace Minigames.StatueDressup.Utils
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static List<string> GetAllPhotoIds()
|
public static List<string> GetAllPhotoIds()
|
||||||
{
|
{
|
||||||
string indexJson = PlayerPrefs.GetString(PHOTO_INDEX_KEY, "[]");
|
string indexJson = PlayerPrefs.GetString(PhotoIndexKey, "[]");
|
||||||
List<string> photoIds = JsonUtility.FromJson<PhotoIdList>(WrapJsonArray(indexJson))?.ids ?? new List<string>();
|
List<string> photoIds = JsonUtility.FromJson<PhotoIdList>(WrapJsonArray(indexJson))?.ids ?? new List<string>();
|
||||||
|
|
||||||
// Sort by timestamp descending (newest first)
|
// Sort by timestamp descending (newest first)
|
||||||
@@ -328,7 +322,7 @@ namespace Minigames.StatueDressup.Utils
|
|||||||
|
|
||||||
public static string GetPhotoDirectory()
|
public static string GetPhotoDirectory()
|
||||||
{
|
{
|
||||||
return Path.Combine(Application.persistentDataPath, PHOTO_FOLDER);
|
return Path.Combine(Application.persistentDataPath, PhotoFolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetPhotoFilePath(string photoId)
|
private static string GetPhotoFilePath(string photoId)
|
||||||
@@ -339,19 +333,19 @@ namespace Minigames.StatueDressup.Utils
|
|||||||
private static void SaveMetadata(PhotoMetadata metadata)
|
private static void SaveMetadata(PhotoMetadata metadata)
|
||||||
{
|
{
|
||||||
string json = JsonUtility.ToJson(metadata);
|
string json = JsonUtility.ToJson(metadata);
|
||||||
PlayerPrefs.SetString(METADATA_KEY_PREFIX + metadata.photoId, json);
|
PlayerPrefs.SetString(MetadataKeyPrefix + metadata.photoId, json);
|
||||||
PlayerPrefs.Save();
|
PlayerPrefs.Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static PhotoMetadata LoadMetadata(string photoId)
|
private static PhotoMetadata LoadMetadata(string photoId)
|
||||||
{
|
{
|
||||||
string json = PlayerPrefs.GetString(METADATA_KEY_PREFIX + photoId, null);
|
string json = PlayerPrefs.GetString(MetadataKeyPrefix + photoId, null);
|
||||||
return string.IsNullOrEmpty(json) ? null : JsonUtility.FromJson<PhotoMetadata>(json);
|
return string.IsNullOrEmpty(json) ? null : JsonUtility.FromJson<PhotoMetadata>(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void DeleteMetadata(string photoId)
|
private static void DeleteMetadata(string photoId)
|
||||||
{
|
{
|
||||||
PlayerPrefs.DeleteKey(METADATA_KEY_PREFIX + photoId);
|
PlayerPrefs.DeleteKey(MetadataKeyPrefix + photoId);
|
||||||
PlayerPrefs.Save();
|
PlayerPrefs.Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -377,7 +371,7 @@ namespace Minigames.StatueDressup.Utils
|
|||||||
private static void SavePhotoIndex(List<string> photoIds)
|
private static void SavePhotoIndex(List<string> photoIds)
|
||||||
{
|
{
|
||||||
string json = JsonUtility.ToJson(new PhotoIdList { ids = photoIds });
|
string json = JsonUtility.ToJson(new PhotoIdList { ids = photoIds });
|
||||||
PlayerPrefs.SetString(PHOTO_INDEX_KEY, json);
|
PlayerPrefs.SetString(PhotoIndexKey, json);
|
||||||
PlayerPrefs.Save();
|
PlayerPrefs.Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -387,7 +381,7 @@ namespace Minigames.StatueDressup.Utils
|
|||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
[System.Serializable]
|
[Serializable]
|
||||||
private class PhotoIdList
|
private class PhotoIdList
|
||||||
{
|
{
|
||||||
public List<string> ids = new List<string>();
|
public List<string> ids = new List<string>();
|
||||||
|
|||||||
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
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
using Pixelplacement;
|
using System;
|
||||||
|
using Pixelplacement;
|
||||||
using Pixelplacement.TweenSystem;
|
using Pixelplacement.TweenSystem;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Minigames.StatueDressup.Utils
|
namespace Utils
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Common animation utilities extracted from CardAnimator pattern.
|
/// Common animation utilities extracted from CardAnimator pattern.
|
||||||
Reference in New Issue
Block a user