창 올라타기
This commit is contained in:
75
Assets/02_Scripts/Character/CharacterScreenBounds.cs
Normal file
75
Assets/02_Scripts/Character/CharacterScreenBounds.cs
Normal file
@@ -0,0 +1,75 @@
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// 캐릭터가 화면 밖으로 나가 잘리지 않도록 화면 좌표를 제한한다.
|
||||
///
|
||||
/// 드래그와 창 올라타기 양쪽에서 쓴다. 캐릭터를 화면 가장자리 창의 타이틀바에
|
||||
/// 올려놓을 때도 같은 제한이 필요하기 때문에 별도 유틸로 분리했다.
|
||||
///
|
||||
/// 캐릭터는 고정된 깊이 평면 위에서만 움직이므로, 화면상 크기는 드래그 중에
|
||||
/// 변하지 않는다. 그래서 시작할 때 한 번만 재면 된다.
|
||||
/// </summary>
|
||||
public static class CharacterScreenBounds
|
||||
{
|
||||
/// <summary>
|
||||
/// 캐릭터 원점(transform.position) 기준으로, 화면상 어디까지 뻗어 있는지 잰다.
|
||||
/// 반환되는 offMin/offMax 는 원점의 화면 좌표에 대한 상대 오프셋이다.
|
||||
/// </summary>
|
||||
public static bool TryMeasure(Camera cam, Transform character, out Vector2 offMin, out Vector2 offMax)
|
||||
{
|
||||
offMin = offMax = Vector2.zero;
|
||||
if (cam == null || character == null) return false;
|
||||
|
||||
var renderers = character.GetComponentsInChildren<Renderer>(true);
|
||||
if (renderers.Length == 0) return false;
|
||||
|
||||
Bounds world = renderers[0].bounds;
|
||||
for (int i = 1; i < renderers.Length; i++) world.Encapsulate(renderers[i].bounds);
|
||||
|
||||
Vector3 c = world.center;
|
||||
Vector3 e = world.extents;
|
||||
|
||||
// AABB 를 화면에 투영하면 축 정렬이 깨지므로 8개 꼭짓점을 모두 변환해 감싼다.
|
||||
var min = new Vector2(float.MaxValue, float.MaxValue);
|
||||
var max = new Vector2(float.MinValue, float.MinValue);
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
var corner = new Vector3(
|
||||
c.x + ((i & 1) == 0 ? -e.x : e.x),
|
||||
c.y + ((i & 2) == 0 ? -e.y : e.y),
|
||||
c.z + ((i & 4) == 0 ? -e.z : e.z));
|
||||
|
||||
Vector3 sp = cam.WorldToScreenPoint(corner);
|
||||
min = Vector2.Min(min, sp);
|
||||
max = Vector2.Max(max, sp);
|
||||
}
|
||||
|
||||
Vector2 origin = cam.WorldToScreenPoint(character.position);
|
||||
offMin = min - origin;
|
||||
offMax = max - origin;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 캐릭터 원점의 화면 좌표를, 캐릭터 전체가 화면 안에 들어오도록 제한한다.
|
||||
/// </summary>
|
||||
/// <param name="margin">가장자리에서 추가로 띄울 여백(픽셀)</param>
|
||||
public static Vector2 Clamp(Vector2 origin, Vector2 offMin, Vector2 offMax, float margin = 0f)
|
||||
{
|
||||
return new Vector2(
|
||||
ClampAxis(origin.x, offMin.x, offMax.x, Screen.width, margin),
|
||||
ClampAxis(origin.y, offMin.y, offMax.y, Screen.height, margin));
|
||||
}
|
||||
|
||||
static float ClampAxis(float value, float offMin, float offMax, float screenSize, float margin)
|
||||
{
|
||||
float lo = margin - offMin;
|
||||
float hi = screenSize - margin - offMax;
|
||||
|
||||
// 캐릭터가 화면보다 큰 경우 범위가 뒤집힌다. 그때는 가운데로 보낸다.
|
||||
if (lo > hi) return (lo + hi) * 0.5f;
|
||||
|
||||
return Mathf.Clamp(value, lo, hi);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user