배경이 무한으로 생성되는 게임. 본적 있죠? 없다고 하더라도 잘 생각해보세요.. 하다못해 하늘 배경이라도 계속 이어졌을겁니다.
이제 기억 나시나요? 마리오가 이동하는 지형 지물은 병견되어도 뒷 배경은 계속 이어지죠? 이것을 배경 스크롤링이라 부르더군요. 저는 이를 활용해서 좌우로 이동하는 레일이 무한으로 이어지도록 코드를 작성 할 것입니다.
스크롤링 적용하기
Unity 엔진
윗 레일은 좌측으로, 아래 레일은 우측으로 이동 할 것입니다.
레일은 여러개를 만들어서 이어지도록 배치해줍니다. 저는 위처럼 4개의 레일을 차례대로 이어줬습니다.
스크립트
코드 전문은 다음과 같습니다.
public class Scrolling : MonoBehaviour
{
[SerializeField] private Transform[] scrollingSprites; // 스크롤할 스프라이트 배열
[SerializeField] private bool isLeft;
private float leftPosX; // 왼쪽 끝 위치
private float rightPosX; // 오른쪽 끝 위치
private float xScreenHalfSize; // 화면의 X좌표 절반
private void Start()
{
// 화면의 절반 크기 계산
float yScreenHalfSize = Camera.main.orthographicSize;
xScreenHalfSize = yScreenHalfSize * Camera.main.aspect; // 세로 절반 * 종횡비(비율)
if(isLeft)
{
// 왼쪽과 오른쪽 끝 위치 계산
leftPosX = -xScreenHalfSize;
rightPosX = xScreenHalfSize * 2 * (scrollingSprites.Length - 1); // 모든 스프라이트를 고려한 오른쪽 끝 위치
}
else
{
// 오른쪽과 왼쪽 끝 위치 계산
rightPosX = xScreenHalfSize * 2;
leftPosX = -xScreenHalfSize * (scrollingSprites.Length);
}
}
private void Update()
{
// 스프라이트 이동
for (int i = 0; i < scrollingSprites.Length; i++)
{
if(isLeft)
{
// 왼쪽 끝을 넘어가면 오른쪽 끝으로 이동
if (scrollingSprites[i].position.x < leftPosX * 2)
{
Vector3 nextPos = scrollingSprites[i].position;
nextPos.x += rightPosX; // 오른쪽 끝으로 이동
scrollingSprites[i].position = nextPos;
}
}
else
{
// 오른쪽 끝을 넘어가면 왼쪽 끝으로 이동
if (scrollingSprites[i].position.x > rightPosX * 1.5)
{
Vector3 nextPos = scrollingSprites[i].position;
nextPos.x += leftPosX; // 왼쪽 끝으로 이동
scrollingSprites[i].position = nextPos;
}
}
}
}
}
하나씩 설명해보겠습니다.
[SerializeField] private Transform[] scrollingSprites; // 스크롤할 스프라이트 배열
[SerializeField] private bool isLeft;
private float leftPosX; // 왼쪽 끝 위치
private float rightPosX; // 오른쪽 끝 위치
private float xScreenHalfSize; // 화면의 X좌표 절반
scrollingSprites : 배치해둔 레일을 배열로 assign
isLeft : 왼쪽으로 이동하는 레일인지, 오른쪽으로 이동하는 레일인지 구분
private void Start()
{
// 화면의 절반 크기 계산
float yScreenHalfSize = Camera.main.orthographicSize;
xScreenHalfSize = yScreenHalfSize * Camera.main.aspect; // 세로 절반 * 종횡비(비율)
if(isLeft)
{
// 왼쪽과 오른쪽 끝 위치 계산
leftPosX = -xScreenHalfSize;
rightPosX = xScreenHalfSize * 2 * (scrollingSprites.Length - 1); // 모든 스프라이트를 고려한 오른쪽 끝 위치
}
else
{
// 오른쪽과 왼쪽 끝 위치 계산
rightPosX = xScreenHalfSize * 2;
leftPosX = -xScreenHalfSize * (scrollingSprites.Length + 1);
}
}
camera.main.orthographicSize : 카메라가 비추는 화면의 절반 크기(Y)를 반환
xScreenHalfSize : 절반 크기인 Y와 화면의 비율을 곱하여 절반 크기의 X를 구함
leftPosX : 가로 절반의 크기에서 왼쪽 제일 끝으로 가려면 -가로 절반의 크기
rightPosX : 가로의 절반 크기에서 오른쪽 끝으로 가려면 +가로 절반 크기 * (스프라이트 개수 -1 만큼)
저는 여기서 왜? 라는 생각이 들었습니다. 왼쪽은 절반에서 이동한 만큼을 그대로 적용하면서 오른쪽은 절반 * 2를 해줘야하지? 찾아보니 좌표계의 특성이라는 문제점이 있었습니다(자료 찾고 이해하는데 2시간 걸렸습니다...)
좌표계의 좌측은 중앙에서 얼마만큼 이동했는지에 대한 상대적 거리입니다.
좌표계의 우측은 좌측에서 얼마만큼 이동했는지에 대한 전체 길이입니다.
이러한 방식은 좌표계의 일관성을 유지하고, 물체의 위치를 명확히 정의하기 위한 것이라고 합니다.
쉽게 이해하기 위해서 다음과 같이 고민했습니다.
유니티에서 좌측은 0, 우측은 screen.width라고 합니다. 즉, 좌측은 0이지만 우측은 스크린 자체의 길이라는 것이죠.
그렇기 때문에 우측을 계산할 땐 절반 사이즈의 * 2를 해줘서 전체 화면 width를 구하고, 좌측을 계산할 땐 절반 사이즈만큼 왼쪽으로 이동(음수 부호를 붙임)해서 좌표를 구한다고 이해했습니다..
안된다면 외우는 것도 좋겠어요.
좌표계에서 좌측은? 중앙 사이즈의 음수값
좌표계에서 우측은? 중앙 사이즈의 2배
그럼 여기서 또 궁금한 점. rightPosX에 왜 스프라이트 개수 - 1 만큼을 곱해주냐?
아까 저희가 레일을 여러개 설치했죠? 총 4개의 레일이 왼쪽으로 이동합니다. 그러다 제일 앞단에 있던 레일이 경계에 걸리면 제일 마지막 레일의 뒤로 이동해야겠죠? 그래서 연결된 레일 스프라이트의 제일 뒤로 이동하기 위해서 추가로 스프라이트 개수를 곱해줍니다. 여기서 -1은요? 레일은 계속 이동하는데 개수 만큼 뒤로 가버리면 가운데 텅 빈 자리가 생기게 됩니다. 그래서 -1을 해줍니다. 기존 레일이 계속 왼쪽으로 이동하니까요. 이해가 어렵다면 -1을 빼고 실행시켜보세요! 그럼 제 말이 이해될겁니다!
왼쪽에서 오른쪽으로 가는 로직에선 왜 left position에선 scrollingSprites.Length + 1 해주는가에 대해서는.. 마이너스 좌표값으로 물체를 이동하기 때문에 Length를 그대로 곱해준 것입니다. 그리고 아래에 *2, *1.5도 달라서 각 레일에 맞는 수를 찾아 적용한 것입니다.
private void Update()
{
// 스프라이트 이동
for (int i = 0; i < scrollingSprites.Length; i++)
{
if(isLeft)
{
// 왼쪽 끝을 넘어가면 오른쪽 끝으로 이동
if (scrollingSprites[i].position.x < leftPosX * 2)
{
Vector3 nextPos = scrollingSprites[i].position;
nextPos.x += rightPosX; // 오른쪽 끝으로 이동
scrollingSprites[i].position = nextPos;
}
}
else
{
// 오른쪽 끝을 넘어가면 왼쪽 끝으로 이동
if (scrollingSprites[i].position.x > rightPosX * 1.5)
{
Vector3 nextPos = scrollingSprites[i].position;
nextPos.x += leftPosX; // 왼쪽 끝으로 이동
scrollingSprites[i].position = nextPos;
}
}
}
}
if문의 조건은 leftPosX * 2 범위 만큼을 넘어간 sprite가 있으면 위치를 이동합니다. *2는 본인 프로젝트에 맞게 조절하면 됩니다. 테스트를 해본 결과 제 프로젝트에선 *2로 해야 예쁘게 뒤로 가지더라고요!
결과
위는 작업 화면 아래는 시뮬레이터로 아이패드에 적용한 모습입니다. 어때요!
'Project > 빵빵빵 타이쿤' 카테고리의 다른 글
[빵빵빵 타이쿤 개발일지] 유니티 Transform과 RectTransform 차이점 (0) | 2024.10.18 |
---|---|
[빵빵빵 타이쿤 개발일지] 유니티 게임 일시정지 구현하기(Time.scaleTime) (4) | 2024.10.16 |
[빵빵빵 타이쿤 개발일지] OnTriggerEnter가 인식이 안돼요;; (1) | 2024.10.07 |
[빵빵빵 타이쿤 개발일지] 2D 게임에서 UI와 배경 오브젝트의 차이와 유니티 2D 해상도 맞추기 (2) | 2024.10.02 |