728x90
에셋으로 팔지만 물리지식이 있다면 간단하게 구현 가능하고 좀더 세밀하게 조정하여 에셋에 돈을 지불하는것을 방지할 수 있다
2D에 z축이 추가된 사항뿐이며 UI는 camera의 far을 넘어가게 되면 보이지 않게된다 (나는 이를 고려하지는 않았다)
코드를 바로 보면 이해가 될거다
using TMPro;
using UnityEngine;
using UnityEngine.UI;
public class Waypoint : MonoBehaviour
{
[Header("Image Settings")]
public Image screenOffImage;
public Image screenOnImage;
[Header("Transform")]
public Transform wayPointTarget;
public Transform playerTarget;
[Header("Util Settings")]
public Vector3 screenOnImageOffset;
public TMP_Text meter;
private float minX, maxX, minY, maxY;
private Vector3 screenCenter;
private void Start()
{
screenCenter = new Vector3(Screen.width / 2, Screen.height / 2, 0);
float halfWidth = screenOffImage.GetPixelAdjustedRect().width / 2;
float halfHeight = screenOffImage.GetPixelAdjustedRect().height / 2;
minX = halfWidth;
maxX = Screen.width - halfWidth;
minY = halfHeight;
maxY = Screen.height - halfHeight;
}
private void Update()
{
if (!wayPointTarget || !playerTarget || !Camera.main) return;
// 카메라가 Waypoint를 보고 있는지 체크
if (Vector3.Dot(wayPointTarget.position - playerTarget.position, playerTarget.forward) < 0)
{
screenOffImage.enabled = false;
return;
}
Vector3 screenPos = Camera.main.WorldToScreenPoint(wayPointTarget.position);
// 화면 안에 있는 경우
if (screenPos.x >= 0 && screenPos.x <= Screen.width && screenPos.y >= 0 && screenPos.y <= Screen.height)
{
ScreenOn(screenPos);
}
else
{
ScreenOff(ClampToScreenBounds(screenPos));
}
}
private Vector3 ClampToScreenBounds(Vector3 screenPos)
{
Vector3 dir = screenPos - screenCenter;
float dirSlope = dir.y / dir.x;
float screenSlope = screenCenter.y / screenCenter.x;
if (Mathf.Abs(dirSlope) > screenSlope)
{
screenPos.y = dir.y > 0 ? maxY : minY;
screenPos.x = screenCenter.x + (screenPos.y - screenCenter.y) / dirSlope;
}
else
{
screenPos.x = dir.x > 0 ? maxX : minX;
screenPos.y = screenCenter.y + (screenPos.x - screenCenter.x) * dirSlope;
}
return new Vector3(
Mathf.Clamp(screenPos.x, minX, maxX),
Mathf.Clamp(screenPos.y, minY, maxY),
screenPos.z
);
}
private void ScreenOn(Vector3 position)
{
screenOnImage.gameObject.SetActive(true);
meter.gameObject.SetActive(true);
screenOffImage.gameObject.SetActive(false);
screenOnImage.transform.position = position + screenOnImageOffset;
meter.text = $"{Vector3.Distance(playerTarget.position, wayPointTarget.position):F1}m";
}
private void ScreenOff(Vector3 position)
{
screenOnImage.gameObject.SetActive(false);
meter.gameObject.SetActive(false);
screenOffImage.gameObject.SetActive(true);
screenOffImage.transform.position = position;
Vector3 direction = position - screenCenter;
screenOffImage.transform.rotation = Quaternion.Euler(0, 0, Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg);
}
}
728x90
'2025 > Unity' 카테고리의 다른 글
Unity - MCP 사용해보기 (0) | 2025.04.03 |
---|---|
[Unity] tool 만들기 아코디언 메뉴 (0) | 2025.03.01 |
[Unity] UI - 아코디언 메뉴 만드는 방법 <펼치고 접기> (0) | 2025.03.01 |
UnityEditor : 스크립터블오브젝트 <-> json 상호 변환기 (0) | 2025.02.25 |
unity - 2022ver 타임라인 녹화 오류 버그 (0) | 2025.02.23 |