GameLogic : 2D 화면 스크롤 (Scroll) Game Logic


게임을 한다고 생각해봅시다.
스타크래프트나, 리그 오브 레전드 등등 여러 게임들 말입니다.





화면에는 타일과, 여러 유닛들 그리고 UI가 있습니다.
여기서 마우스를 오른쪽 가장자리로 가지고 가면,
화면 스크롤이 변경되어, 맵 오른쪽으로 이동하게 될 것입니다.

이때 모든 유닛들은 화면이 오른쪽으로 이동하는것처럼 보이게 만들기 위해서
모두 왼쪽으로 이동하고, 이윽고 화면 밖으로 나가서 보이지 않는 상태가 되겠지요.
이러한 처리는 유저가 화면상에 보이는 장면보다 더 큰 규모의 세계를 조작하고 있다는
듯한 느낌을 줄 수 있는 처리입니다.

이러한 처리를 게임을 만드는 입장에서 생각해봅시다.
그냥 자동으로 지원되는 기능일까요? 
당연하지만 직접 만들어야 하는 기능입니다.




다음 슬라이드들은 애니매이션 영화 슈렉 3 의 도입부를 활용해 만든 슬라이드입니다.
초기에 개념을 조금 쉽게 잡기 위해서 준비해 보았습니다.

이 영화는 악역 챠밍 왕자의 연극 공연 장면으로 시작합니다.
여기서 공연을 할때, 배경 화면을 두루마리를 통해서 돌려주는 모습을 보여주고 있습니다.

관객들이 공연을 보는 공간은 정해져 있지만 두루마리를 통해서 보다 많은 배경을
보여주고 있지요, 저 배경을 모두 펼쳐놓을 필요 없이 관객들에게 보여줄 공간에
조금씩 분할해서 보여주고 있는 것입니다.


윈도우 화면과 게임 좌표계의 관계도 이와 마찬가지입니다.
스크롤 값은 객체들의 좌표를 수정하게 되며, 이것은 두루마리를 감는 것과 같습니다.

그러면 여기서부터는 구체적인 윈도우 좌표계에 대해서 작성하겠습니다.
우선 기준을 몇가지 잡겠습니다.

1. 화면좌표계는 어디까지나 일정한 좌표개념이 적용됩니다. 
    윈도우 내부에서 화면 스크롤과 같은 개념을 제공하지 않습니다.

2. 화면의 객체들은 윈도우 화면 영역에 포함된 좌표에 있을때만 출력될 것입니다.
    음수 좌표가 되거나, 윈도우 사이즈를 넘어가는 좌표를 가지게 되면 출력되지 않습니다.
   (조금 더 정확히는 출력처리는 하는데 영역 바깥으로 나가서 보이지 않게 되는 것이지요)

3. 화면이 움직이는게 아니라, 객체들의 좌표가 수정되어 마치 화면이 움직이는 것처럼
    보이도록 속여야 합니다.


중요한건, 화면은 언제나 일정한 좌표를 유지하는 것이고, 스크롤 개념에 따라서
객체의 좌표를 모두 변경해서 마치 화면이 이동되는 것 같은 효과를 만들어야 한다는 점입니다.




간단하게 예시를 준비했습니다. 게임 세계에서의 자신의 좌표를 가지고 있습니다.
하지만 이 좌표는 화면 출력과는 상관없는 게임 세계라는 가상의 정보로써,
출력 시에는 화면에 보이도록 출력해야 합니다.

다음 객체는 게임 좌표상으로 (50,60) 의 좌표를 가지고 있지만
윈도우 좌표계로 출력될 때는 (20,30) 의 좌표로 출력되어야 합니다.

게임 좌표계라는 것은 어디까지나 실존하지 않는 가상의 정보입니다.
결국 화면에 출력되는 것은 윈도우에 출력될 좌표만 존재합니다.

그렇기에 출력시에는 윈도우에 출력할 좌표로 변환해야 합니다.

이렇게 변환을 한다... 라는 식의 관점으로 접근하자면,
위 예시에서는

(50,60) 의 좌표가
(20,30) 으로 수정되었습니다.

X좌표에서 30의 감소가, Y 좌표에서도 30의 감소로 변환이 이루어졌습니다.
주목할 것은 스크롤이 가르킬 영역에 따라 감소가 일어났다는 점입니다.





만일 스크롤이 가르키는 게임 영역이 저런 식으로 0,0 과 동일한 기준의 상태라면
어떻습니까? 이 상황에서는 게임 세계의 좌표와, 윈도우 영역의 좌표값이 동일해지지 않습니까?





여기서 화면이 이동하면 어떻습니까?
화면의 시작 위치는 게임좌표로 (50,0)이 되었습니다.

하지만 화면 출력 좌표계는 (50,0) 이 0,0 이 됩니다. 50부터가 시작이란 뜻이죠.

여기서 객체의 좌표를 보정하지 않으면 객체가 이전과 동일한 위치에 출력될 것입니다.
화면을 가르키는 위치가 변했는데, 객체의 위치가 그대로 출력되면, 화면이 이동된다는 
개념이 적용된 것이 아니게 됩니다.

따라서 이 경우 50,0이 화면의 스크롤값이며, 이만큼 이동된 화면을 보고 있다고 
생각하여, 이 좌표만큼을 객체에서 빼 버립니다.

가상의 스크롤이 존재하여 게임 영역을 이동하는 것처럼 보이게 속이기 위해서 
가상 스크롤값만큼 객체의 좌표를 뒤로 밀어버리는 것입니다.



화면 스크롤값이라는 것은 가상의 개념입니다.
이 스크롤 값만큼 객체의 좌표를 빼거나 더하거나 하여
화면 영역에서 이동시켜 버리는 것이지요. 이는 하나가 아니라 모든 객체에 적용됩니다.

결국 화면 스크롤이라는 것은 가상의 게임 세계를 표현하기 위하여,
객체들 전체의 좌표를 이리 저리 이동시켜서 마치 화면이 움직이는 것처럼
속이는 개념이라는 겁니다.

실제로는 객체들의 좌표만 변경되고 있지만, 스크롤값에 따라
전체가 이동하는 것으로써, 사용자의 눈에는 마치 큰 게임 세계가 있으며,
플레이 화면이 이 속을 이동하며 보고 싶은 영역을 표현해주는 것 처럼 보이게 됩니다.




코드를 간단히 작성했습니다. 이 코드는 제가 이전에 작업한 프로젝트에 적용된
스크롤 클래스입니다. 때문에 당장 스크롤 개념만을 보는 것 이상의 기능이 적용되어 있습니다.

참고로 저 스크롤 클래스는 단순히 X,Y 의 좌표만 들어가 있을 뿐,
별다른 기능이 없습니다.

POINT 구조체로 대체해도 무방합니다.

싱글톤 클래스로 스크롤 매니저를 준비했고, 이 내부에 게임 전체의 스크롤을 관장하기 위한
포인트값을 적어둔 것입니다.
이 값은 내부에서 마우스 조작에 의해 수정되고 객체에서 받아서 참조하게 됩니다.

나머지 변수들은 중요하지 않습니다. 중요한건 스크롤 좌표가 존재하고,
이 좌표가 관리되고 있으며, Get 함수로 이 좌표를 받아서 객체가 사용할 수 있는 루틴이
마련되어 있다는 점이 중요합니다. 이게 핵심이기도 하구요.




이 매니저의 프로세스는 이런 식입니다.

1. 현재 마우스 포인터의 좌표를 얻는다.
2. 마우스 좌표에 따라서, 스크롤 좌표를 변경한다.
3. 스크롤 범위를 체크한다. 범위를 넘어가는 경우 스크롤값 변경에 제한을 걸어준다.

이 코드에서는 스크롤 좌표를 드래그에 따라 변경했지만,
마우스가 윈도우 창 가장자리에 있을때 스크롤값을 증가시킨다던지 하는 식으로
처리할 수도 있습니다. 처리는 원하는 기능 나름이며, 중요한건 스크롤값을 수정한다는 겁니다.

이 처리를 통해서 스크롤값은 항상 조작에 따라서 변경되고 있는 상태가 됩니다.




이러한 스크롤값은 객체의 출력처리를 할때, 좌표를 수정하는 역할을 하게 됩니다.
각각의 객체는 스크롤 클래스에서 현재의 스크롤값을 받도록 되어있습니다.

객체는 자신의 좌표에서 스크롤 값만큼 밀리거나 당겨지게 됩니다.

이 처리로 스크롤값이 커지면, 그만큼 빼는 값도 커져서, 최초의 화면에서 멀리 있는 객체의
좌표가 점점 작아지다가 화면에 도달하게 됩니다. 이러한 과정을 화면으로 직접 보면
화면이 이동하는것처럼 보이게 되는 것이지요.







위 스크린샷은 파랜드 택틱스 리소스 데이터를 사용해 작업했던 디펜스 게임 프로젝트입니다.
배경 이미지를 보시면 아시겠지만, 저 게임의 월드 좌표는 이미지의 시작 부분부터, 끝 부분까지입니다.

또한 유닛 객체들의 좌표 역시 위의 스크린샷과 아래의 스크린샷은 많은 차이가 있습니다.
하지만 정작 출력된 화면에서는 비슷한 좌표상에서 표현되고 있지요.

두번째 스크린샷의 객체들은 첫번째 스크린샷의 객체에 비해서 저 멀리 떨어져 있었지만
스크롤 값이 증가하면서, 그만큼 값을 좌표에서 빼 낸 결과, 앞으로 당겨져 화면에 출력될 
수 있는 좌표범위까지 온 것입니다. 이런 연유로, 스크롤의 개념은 객체들의 좌표를 수정하여 
마치 화면이 이동하는 것처럼 보이도록 속이는 과정이라고 하는 것입니다.

사실 3D 역시 이러한 개념은 크게 다르지 않습니다. 좌표계가 3차원이 되었고, 이에 따라 복잡한
연산이 들어가게 된다는 것이 다를뿐, 3D 카메라를 구현할때 역시 타 객체들의 회전값 이동값 등으로
마치 카메라가 존재하는 것 처럼 속이게 만듭니다.

결국 다룰 수 있는건 윈도우 스크린이고, 윈도우 스크린 좌표계는 한계가 있으니, 
객체들의 좌표를 수정하여 넓은 공간에 있는 것처럼 느껴지도록 만드는 것이라 할 수 있겠습니다.


다음 글에서는 타일 관리에 대한 글을 이어갈 것입니다.
타일에도 스크롤 개념이 적용될 수 있으며,
이에 따른 컬링(Culling) 작업을 하게 되는데, 이 작업에 대해서 작성하겠습니다.




덧글

  • 2019/05/15 15:43 # 삭제 답글 비공개

    비공개 덧글입니다.
  • 에이레네 2019/05/15 22:51 #

    http://eirenehue.egloos.com/971626 요 포스팅을 참고해 주시면 될것같습니다.
  • 에이레네 2019/05/15 22:53 #

    http://eirenehue.egloos.com/967113 이외에 마우스 좌표 얻는부분은 해당 코드에서는 공개되어있지 않은데 요 포스트를 참고해주시면 될것같네요. 마우스 매니저에서 좌표 얻는부분자체를 이 포스트 내용으로 대체하시면 됩니다
  • tkfkdalfh9 2019/05/16 09:28 # 삭제

    ScrollMgr.h에 SCROLL이라는 타입은 다른 헤더에서 따로 선언을 해주신건가요?
  • 에이레네 2019/05/16 11:14 #

    네 본문에도 언급해 두었지만 별도로 구조체로 만들었어요. 그런데 안에 든것은 X,Y 좌표 변수만 들어있어서, X,Y 에 대응하는 좌표용 변수만 따로 만드시면 될것같아요. 참고 되셨으면 좋겠습니다.
댓글 입력 영역


라운드 시계