개요
아이소매트릭형태의 맵에서 카메라 범위를 제한
구현방법
선1과 선2의 교점이 있을경우 카메라의 이동을 제한
선1= 카메라의 현재 위치와 이동할려고 하는 위치를 연결한 선
선2= 맵의 경계선 (이미지의 Top 와 Right를 연결한 선)
교점= 선1과 선2이 만나는 지점
0. 이동 방법은 기존에 작성한 스크립트 활용
1. 맵 정보를 담을 클래스 작성
public class RhombusBounds
{
public float MinX { get; }
public float MinY { get; }
public float MaxX { get; }
public float MaxY { get; }
public RhombusBounds(float minX, float minY, float maxX, float maxY)
{
MinX = minX;
MinY = minY;
MaxX = maxX;
MaxY = maxY;
}
}
교점이 발생했을때의 제한 할 범위를 반환 할때 사용하기 위한 클래스
public class MapSize
{
public Vector3 Center { get; }
public float X { get; }
public float Y { get; }
public float MinX { get; }
public float MaxX { get; }
public float MinY { get; }
public float MaxY { get; }
public MapSize(Vector3 center, float sizeX, float sizeY)
{
// center
Center = center;
// size
X = sizeX;
Y = sizeY;
// half
var xHalf = X / 2;
var yHalf = Y / 2;
// x
MinX = center.x - xHalf;
MaxX = center.x + xHalf;
// y
MinY = center.y - yHalf;
MaxY = center.y + yHalf;
}
}
public class MapSizeIsometric : MapSize
{
public Vector3 Bottom { get; }
public Vector3 Top { get; }
public Vector3 Left { get; }
public Vector3 Right { get; }
public MapSizeIsometric(Vector3 center, float sizeX, float sizeY, float cellSizeX, float cellSizeY) : base(center, sizeX, sizeY)
{
// isometric point
Bottom = new Vector3(center.x, MinY * cellSizeY, center.z);
Top = new Vector3(center.x, MaxY * cellSizeY, center.z);
Left = new Vector3(MinX * cellSizeX, center.y, center.z);
Right = new Vector3(MaxX * cellSizeX, center.y, center.z);
}
}
맵에 대한 정보를 저장하기 위한 클래스
2. 변수 선언
// 변수 : 맵 크기
private MapSize _mapSize;
3. Start 함수
private void Start()
{
...
// 맵정보
_mapSize = new MapSizeIsometric(transform.position, 20f, 20f, 1f, 0.5f);
...
}
맵 정보
x=20f
y=20f
cellSizeX=1f
cellSizeY=0.5f
4. UpdateCameraPosition 함수 갱신
private void UpdateCameraPosition()
{
...
// 기존 소스: start
var targetPosition = new Vector3(targetX, targetY, currentPosition.z);
cameraTransform.position = Vector3.Lerp(currentPosition, targetPosition, 0.5f);
// 기존 소스: end
// 여기 부터 추가
// isometric limit
if (typeof(MapSizeIsometric) == _mapSize.GetType())
{
var rhombusRounds = GetRhombusRounds(targetPosition.x, targetPosition.y);
if (rhombusRounds != null)
{
targetX = Mathf.Clamp(targetPosition.x, rhombusRounds.MinX, rhombusRounds.MaxX);
targetY = Mathf.Clamp(targetPosition.y, rhombusRounds.MinY, rhombusRounds.MaxY);
var fixedPosition = new Vector3(targetX, targetY, transform.position.z);
cameraTransform.position = fixedPosition;
// 위치 보정이 일어난 만큼 스타트 위치를 보정
var fixPosition = new Vector3(targetX, targetY, currentPosition.z) - fixedPosition;
if (_userMoveInput)
{
fixPosition = new Vector2(Mathf.Abs(fixPosition.x) > Mathf.Epsilon ? fixPosition.x : 0f, Mathf.Abs(fixPosition.y) > Mathf.Epsilon ? fixPosition.y : 0f);
_startPosition -= fixPosition;
}
else
{
_directionForce -= fixPosition;
}
}
}
}
rhombusRounds != null: 교점이 존재할 경우
반환받은 범위로 카메라의 위치를 제한
5. GetRhombusRounds 작성
public RhombusBounds GetRhombusRounds(float targetX, float targetY)
{
var mapSize = (MapSizeIsometric)_mapSize;
Vector2 localPosition = transform.position - mapSize.Center;
var absPositionX = mapSize.Center.x + Mathf.Abs(localPosition.x);
var absPositionY = mapSize.Center.y + Mathf.Abs(localPosition.y);
var topRightIntersectionPosition = GetIntersectPosition(mapSize.Center, new Vector2(absPositionX, absPositionY), mapSize.Top, mapSize.Right);
if (topRightIntersectionPosition == Vector2.zero)
{
return null;
}
return new RhombusBounds(-topRightIntersectionPosition.x, -topRightIntersectionPosition.y,
topRightIntersectionPosition.x, topRightIntersectionPosition.y);
}
Vector2 localPosition = transform.position - mapSize.Center;
var absPositionX = mapSize.Center.x + Mathf.Abs(localPosition.x);
var absPositionY = mapSize.Center.y + Mathf.Abs(localPosition.y);
Top,Right를 이은 선과의 교점을 구하기 위해 절댓값으로 위치 변환
6. GetIntersectPosition 작성
private static Vector2 GetIntersectPosition(Vector2 aP1, Vector2 aP2, Vector2 bP1, Vector2 bP2)
{
var under = (bP2.y - bP1.y) * (aP2.x - aP1.x) - (bP2.x - bP1.x) * (aP2.y - aP1.y);
if (Mathf.Abs(under) < Mathf.Epsilon)
{
return Vector2.zero;
}
var t1 = (bP2.x - bP1.x) * (aP1.y - bP1.y) - (bP2.y - bP1.y) * (aP1.x - bP1.x);
var s1 = (aP2.x - aP1.x) * (aP1.y - bP1.y) - (aP2.y - aP1.y) * (aP1.x - bP1.x);
if (Mathf.Abs(t1) < Mathf.Epsilon && Mathf.Abs(s1) < Mathf.Epsilon)
{
return Vector2.zero;
}
var t2 = t1/under;
var s2 = s1/under;
if (t2 < 0f || t2 > 1.0f || s2 < 0f || s2 > 1f) {
return Vector2.zero;
}
var intersectionX = aP1.x + t2 * (aP2.x - aP1.x);
var intersectionY = aP1.y + t2 * (aP2.y - aP1.y);
return new Vector2(intersectionX, intersectionY);
}
교점 알고리즘 참고: http://www.gisdeveloper.co.kr/?p=89
'[Unity] > [Unity 2D]' 카테고리의 다른 글
[Unity 2D] 마우스 위치 기준으로 카메라 줌인 줌아웃 (Camera zoom in zoom out based on mouse position) (0) | 2023.07.22 |
---|---|
[Unity 2D] 드래그 카메라 이동 (drag camera move) (0) | 2023.07.22 |