3D에선 Skybox만 설정해주면 끝나는 배경이 2D에선 은근히 까다롭다.
2D는 기본적으로 3D와는 내부 구현이 다르다보니 Skybox를 쓸 수가 없다.
따라서 Sprite Renderer로 배경을 포현하는게 대부분이다.
쿠기런 같은 횡스크롤 게임은 배경을 복사하거나, 풀링하여 재배치하는 방식으로 쉽게 배경을 구현할 수 있다.
아니면 타일맵으로 배경을 그려넣는 방법도 있다. (물론 중노동이라 배제했다.)
하지만 나는 내 게임에 어울리도록 카메라를 따라다니는 정적인 배경을 구현하기로 했다.
우선 단순하게 의식의 흐름대로 코드를 짰다.
Camera _camera;
private void Start()
{
_camera = Camera.main;
}
private void LateUpdate()
{
transform.position = new Vector3(_camera.transform.position.x, _camera.transform.position.y, 0);
}
메인 카메라의 글로벌 좌표계의 x, y값으로 위치를 조절해준다.
메인 카메라의 z값이 -10이라 z값은 0을 줬다.
또 카메라 스크립트는 LateUpdate에서 호출되기 때문에 LateUpdate에서 위치를 조절해준다.
위 코드는 이론상 전혀 문제가 없어보인다.
하지만 결과물은 아래와 같았다.
배경의 이동 시점이 카메라의 이동보다 빨라서 지터와 비슷한 현상이 발생했다.
이 상태로 앱을 출시한다면 플레이어는 상당히 불쾌한 경험을 할 것이다.
그래서 나는 이 문제를 해결하기 위한 방안을 생각했다.
첫번째로 선형보간(Lerp)를 적용시켜 봤다.
배경의 크기를 더 키워 스크린에 배경의 테두리가 노출되지 않게 하고 이동을 자연스럽게 적용시켜봤다.
물론 내가 원하는 완전한 정적 배경은 아니지만 보정값을 잘 조절하면 적어도 배경이 깨지듯이 보이지는 않을 것 같았다.
실제로 배경이 자연스럽게 움직여서 눈은 덜 피로했으나, 보정값이 작으면 배경의 이동도 느려서 전혀 배경같지 않고 보정값이 높으면 여전히 깨지듯이 보였다.
그래서 이 방법은 폐기했다.
두번째 방법은 프로젝트 설정에서 스크립트 실행 순서를 직접 지정해주는 방법이다.
배경의 이동, 카메라의 이동이 전부 LateUpdate에서 이루어지고, 배경이 카메라보다 먼저 이동해서 생기는 현상이니 그 순서를 바꿔주면 그만이다.
적용해보니 생각했던대로 잘 동작했다.
스크립트간에 의존성이 생기기 때문에 개인적으로 좋아하지 않는 방식이지만 우선 임시방편으로 적용했다.
이후에 더 좋은 방법이 떠오르면 수정해야겠다.
여러 해상도에 대응하려면 배경의 사이즈는 반드시 조절해줘야 한다.
하지만 Sprite Renderer는 UGUI Image처럼 스크린 사이즈에 맞춰 크기를 조절할 수 없다.
즉 배경이 스크린에 꽉 차도록 하려면 스크립트로 제어해줘야 한다.
사이즈 조절에 앞서 OrthographicSize에 대해 알아야 했다.
카메라의 Projection Type을 Orthograph(직교 투영)으로 할 경우 size를 조절할 수 있다.
이 size값은 카메라의 중심으로부터 위쪽 끝까지의 높이를 뜻하며, 1 size당 1 unit에 해당한다.
즉 OrthographSize가 6이면 스크린의 높이는 12 unit에 해당한다.
그럼 이제 계산 과정을 정리해보자.
우선은 배경을 스크린의 가로에 맞출지, 세로에 맞출지 판단해야 된다.
배경이 가로로 길 경우 스크린의 세로에 맞춰야 한다.
그렇지 않을 경우 위아래 배경의 길이가 짧아서 Skybox가 보일 것이다.
반대로 배경이 세로로 긴 경우는 스크린의 가로에 맞춘다.
세로로 맞추는 경우를 먼저 생각해보자.
단순히 y unit인 sprite.y를 OrthographSize * 2 unit으로 만들어주면 된다.
sprite.y * scale = OrthographSize * 2
scale = OrthographSize * 2 / sprite.y
이를 코드로 포현하면 다음과 같다.
float screenRatio = (float)Screen.width / Screen.height;
float backgroundRatio = sprite.bounds.size.x / sprite.bounds.size.y;
if // 세로에 맞추기
{
float scale = _camera.orthographicSize * 2 / sprite.bounds.size.y;
transform.localScale = new Vector2(scale, scale);
}
가로는 계산이 한단계 추가된다.
OrthographSize가 높이이기 때문에 가로의 unit값을 추가적으로 구해줘야 한다.
sprite.x * scale = OrthographSize * 2 * (Screen.width / Screen.height)
scale = (OrthographSize * 2 / sprite.x) * (Screen.width / Screen.height)
이를 코드로 표현하면 다음과 같다.
else (screenRatio > backgroundRatio) // 가로에 맞추기
{
float scale = _camera.orthographicSize * 2 * screenRatio / sprite.bounds.size.x;
transform.localScale = new Vector2(scale, scale);
}
적용해보면 배경이 해상도에 구애받지 않고 잘 조절되는 것을 확인할 수 있다.