쾌락없는 책임 (공부)/Unity

[Unity] 유니티 배경 스크롤링을 고민하면서 겪은 일들

허스크 2022. 6. 3. 20:13
반응형

개요

아트분의 요청이 있었죠. '배경 원경 후경 효과가 있으면 어떨까요?'. 이 제안을 듣고 나서 한번 생각을 해 봤다. 확실히 원경 후경 효과가 들어갈 수 있다면 게임이 더 살아날 것 같았고 이를 승낙하기로 했습니다. '쿠키런' 같은 횡스크롤 게임에서 주로 사용하는 방식인 배경 스크롤링을 조금 개량하면 우리 게임에 넣을 수 있지 않을까 했고 이와 관련한 기능을 준비해 봤습니다.

 

 

 

일단 기능은 만들었다

기능 자체를 만드는 건 어렵지 않았습니다. 이미 시네머신을 활용하고 있어서 카메라는 플레이어를 따라가고 있었고 이를 활용해서 카메라에 아래 스크립트를 달아 뒀습니다.

public event Action<float, float> playerMoveEvent;
Vector2 prevPos;
private void Start()
{
    prevPos = transform.position;
}

private void Update()
{
    float xChangeAmount = prevPos.x - transform.position.x;
    float yChangeAmount = prevPos.y - transform.position.y;

    if(xChangeAmount != 0 || yChangeAmount != 0)
    {
        playerMoveEvent?.Invoke(xChangeAmount, yChangeAmount);
        prevPos = transform.position;
    }
}

 Update 함수를 사용해 프레임별 이전 위치와의 차이를 알아냈고 이후 이를 event에 달아둬 Invoke 했습니다. 그러면 위 playerMoveEvent에는 어떤 함수들이 담기게 되는가?

private void OnEnable()
{
    FindObjectOfType<BackGroundScroller>().playerMoveEvent += MoveLayer;
    transform.position = savePos;
}

private void OnDisable()
{
    FindObjectOfType<BackGroundScroller>().playerMoveEvent -= MoveLayer;

    savePos = transform.position;
    canMove = false;
}

void MoveLayer(float x, float y)
{
    if (!canMove) return;

    newPosition = transform.localPosition;
    if(!lockHorizontal)   newPosition.x -= x * moveAmount;
    if(!lockVertical)     newPosition.y -= y * moveAmount;

    transform.localPosition = newPosition;
}

 위 스크립트는 각 배경에 붙여지는 스크립트로 여기 MoveLayer 함수가 불리면 x, y 좌표를 받아서 이만큼 움직이는 역할을 합니다. 필드는 아트분들을 위해서 넣은 ToolTip들이 많아 따로 첨부하지는 않았습니다. 여기서 핵심은 배경이 Active(true)가 되면 OnEnable 함수를 통해 위에 만든 playerMoveEvent에 넣어뒀고 OnDisable에는 구독 취소를 해 델리게이트 호출 시 오류가 나지 않게 했습니다.

 

 보면 플레이어가 올라갈 때, 좌우로 움직일 때 배경들이 찬찬히 따라오게 됩니다. GIF 녹화를 해서 톡톡 끊겨 보이지만 실제 게임 플레이에서는 부드럽게 배경이 따라오는 모습을 볼 수 있습니다.

 

 

 

델리게이트를 함수 그릇으로 잘 활용했다고 생각했다... 그러나!

기본기에 충실하게 델리게이트를 잘 활용했다고 생각을 했습니다. 배경도 어느 정도 잘 따라오고 있었고요. 그런데 문제가 하나 터졌습니다!

 스테이지 최적화를 위해 + 배경 원경 작업 시 플레이어 움직임을 알기 쉽게 하는 데 있어 플레이어의 스테이지에 맞는 배경만 활성화하는 방식을 채택했습니다. 그런데 이 과정에서 스테이지를 계속 왔다 갔다 하면 오차가 누적되어 처음 진입 시 배경 위치와 이후의 배경 위치가 달라지게 됩니다. 플레이어는 이전이랑 같은 위치인데! 

 

 일단 실제 게임 내에서 저렇게 격렬한 움직임은 일어나지 않아 저 오차를 알아내기 힘들지만 그래도 영 탐탁지 않은 문제였습니다. 그래서 이를 해결하기 위해서 여러 오류들을 살펴봤습니다.

 

 

 

오류 1 : 시네머신 카메라 전환 중 일어나는 딜레이

위 사진에는 카메라가 1개지만 이전에는 스테이지 이동을 위해 카메라를 2개 사용한 적이 있습니다. 때문에 카메라 전환이 있는 동안 이전 스테이지 배경이 카메라 전환과 함께 이동하는 시간이 있었고 이로 인해서 지금보다 오차가 더 커진 것입니다.

 

 이 문제는 스테이지 이동에 있어 아트웍을 자연스럽게 가져가기로 했기에 카메라를 다시 1개로 통합해 해결할 수 있었습니다.

 

 

 

오류 2 : 현재의 문제

이전의 오류를 해결했음에도 아직 오류가 있게 되었습니다. 그게 바로 위 움짤 사진이었죠. 일단은 전환 뒤 delay를 넣어 1 프레임 뒤 이동을 하게 만들었는데 조금은 격차가 줄어들 수 있었습니다. 하지만 여전히 이전과의 오차가 누적되고 있습니다.

 

 

 

 

현재 생각나는 해결 방안들

1. 플레이어의 첫 시작 지점을 기반으로 카메라 전환을 하기

- 지금은 카메라의 움직임에 따라 이를 한 것인데 이후에는 각 배경에 첫 플레이어의 위치를 기억하게 한 뒤 MoveLayer에서 이를 이용해 계산하는 것입니다.

 

2. 어떻게든 delay 간격을 없애기

- 지금까지는 이 딜레이를 줄일 방법이 생각나지는 않습니다.

 

3. 배경에 저장 위치를 2가지 넣기

- 현재는 배경 스크립트 필드에 Vector3는 1개로 단순히 비활성화될 때의 위치를 저장해 이후 활성화 시 그 위치를 불러오는 역할을 합니다. 다만 이게 이후 스테이지로 가는지 이전 스테이지로 가는지 알 수 있는 방법은 없습니다.

- 이를 readonly가 달린 클래스를 새로 만들어서 첫 진입에 입력을 받은 뒤 다음 진입 시에는 그걸 계속 활용하는 방향으로 제작해볼 계획입니다.

 

 생각나는 방안은 1, 3번이 제일 유력해 보이지 않을까 하는데 두개 다 시도해보면서 어떤 점이 좋을지 알아봐야겠습니다.

반응형