#nullable enable
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using UVC.Core;
using UVC.Extention;
using UVC.UI.Modal;
namespace UVC.Factory.Modal
{
///
/// 3D 객체를 따라다니며 정보를 표시하는 UI 창입니다.
/// 이 컴포넌트는 World Space Canvas 내의 UI 요소에 추가되어야 합니다.
///
public class InfoWindow : SingletonScene
{
[Tooltip("Label 정보 텍스트를 표시할 UI 요소")]
[SerializeField]
private TextMeshProUGUI text;
[Tooltip("정보 창을 닫는 버튼")]
[SerializeField]
private Button closeButton;
[Tooltip("정보 창의 내용을 클립보드에 복사할 버튼")]
[SerializeField]
private Button copyButton;
[Tooltip("UI가 객체를 가리지 않도록 할 월드 좌표계 오프셋")]
[SerializeField]
private Vector2 screenOffset = new Vector2(10f, 10f);
[Tooltip("UI가 객체를 가리지 않도록 할 메뉴바 높이")]
[SerializeField]
private float menuBarHeight = 70f;
// 정보 창이 따라다닐 3D 객체의 Transform
private Transform? target;
private string message = string.Empty;
///
/// 정보 창이 현재 화면에 표시되고 있는지 여부를 반환합니다.
///
public bool IsVisible => gameObject.activeSelf;
private RectTransform? rectTransform;
protected override void Awake()
{
base.Awake();
rectTransform = GetComponent();
// 닫기 버튼이 할당되었으면 클릭 이벤트를 연결합니다.
if (closeButton != null)
{
closeButton.onClick.AddListener(Hide);
}
if (copyButton != null)
{
copyButton.onClick.AddListener(CopyToClipboard);
}
// 처음에는 정보 창을 숨깁니다.
if (gameObject.activeSelf)
{
Hide();
}
}
private void CopyToClipboard()
{
// 클립보드에 현재 메시지를 복사합니다.
if (!string.IsNullOrEmpty(message))
{
GUIUtility.systemCopyBuffer = message;
Toast.Show("정보가 클립보드에 복사되었습니다.", 2f, 0.5f);
}
}
private void LateUpdate()
{
// target이 설정되어 있고 활성화 상태일 때만 위치와 방향을 업데이트합니다.
if (target != null && gameObject.activeSelf && Camera.main != null)
{
// 타겟의 렌더러 또는 콜라이더를 가져와 화면 상의 크기를 계산
Bounds bounds = new Bounds(target.position, Vector3.one);
Renderer? renderer = target.GetComponent();
Collider? collider = target.GetComponent();
// 렌더러가 있으면 렌더러의 바운드를, 없으면 콜라이더의 바운드를 사용
if (renderer != null)
{
bounds = renderer.bounds;
}
else if (collider != null)
{
bounds = collider.bounds;
}
// 바운드의 오른쪽 지점을 월드 좌표로 계산
Vector3 rightPoint = bounds.center + new Vector3(bounds.extents.x, 0, 0);
// 바운드의 오른쪽 지점을 스크린 좌표로 변환
Vector3 screenPosRight = Camera.main.WorldToScreenPoint(rightPoint);
// 추가 오프셋 적용
screenPosRight.x += screenOffset.x;
screenPosRight.y += screenOffset.y;
// 메뉴바 영역 고려 및 화면 밖으로 나가지 않도록 제한
screenPosRight.x = Mathf.Clamp(screenPosRight.x, 0, Screen.width - rectTransform!.rect.width);
screenPosRight.y = Mathf.Clamp(screenPosRight.y, rectTransform!.rect.height, Screen.height - menuBarHeight);
// RectTransform을 사용하여 UI 위치 설정
// 캔버스의 렌더링 모드에 따라 다르게 처리
Canvas canvas = GetComponentInParent