post list

2013년 2월 10일

[Android] Surface View 에 움직이는 그림 그리기


Surface View 에서 터치에 의해 움직이는 물체 표현

 이번 포스트는 Surface View를 여러 Tile 로 쪼갠 다음에 도형들을 움직여보는 프로그램을 만들어 볼 것이다. 특히 다음의 주제를 중점으로 다룬다.  
  1. Tile 
  2. Map
  3. Rendering 
 이 부분은 Tiled based game이라고 하는 주제로 Google 검색을 통해 더욱 자세히 알 수 있다. 만약 모르는 부분이 생긴다면 검색을 하거나 댓글을 달아주시길 바란다. 코드는 포스트 제일 하단에 첨부해 두었으니 다운로드 받아서 분석해 보셔도 좋다.
 이 주제는 Tiled based game을 만드는 기초중에 기초를 설명하고 있다. 그런데 이 정보를 찾기가 조금 힘들었다. 이 내용이 많은 한국 분들에게 도움이 되길 바란다. 


 Tile

 먼저 Tile에 대하여 알아보자.
 여기서 Tile이란 Map을 이루는 한 단위이다. 즉, Tile 들이 모여서 Map을 완성시킨다. 본 프로그램에서는 하나의 Tile을 80 x  80 pixel로 정의했으며 2종류가 있다. 


 첫번째는 Black Tile이고 아무것도 없는 상태(Nothing)를 의미한다. 다음의 그림을 보자.



 두번째는 White Tile이고 물체로 존재(Is)를 의미한다.



 간단히 말해서 하얀색 Tile은 우리가 터치를 해서 움직일 수 있는 물체다. 검은색 Tile은 마치 배경처럼 보이게 된다. 
 이 Tile들은 코드를 보면 알겠지만 하나의 클래스(MAP_Tile)로 정의가 되어 있다. 이 클래스는 Member 변수로 흰색인지 검은색인지, 크기는 얼마인지, 자신의 현재 위치가 어디인지에 대한 정보들을 저장하고 있다.
 이 Tile들이 다음 목차에서 알아볼 Map의 기본 단위이다. 이것들이 모여서 Map을 이루게 되며 Map에서 다룰 내용이지만 이것들이 존재하는 곳 그렇지 않은 곳은 배열로서 미리 저장되어 있다. 


Map

 Map은 Tile들이 모여서 구성된다. Map 역시 코드를 보면 하나의 클래스(Map_Street_1)로 정의되어 있다. 여기서 Tile의 이미지를 메모리에 저장시킨다. 만약 화면에 Map을 뿌릴때마다 이미지를 불러오게 되면 아주 급격한 느림을 경험하게 된다. 이래서 미리 이미지를 불러오는 것이 중요하다. 

 Map은 초기에 화면이 구성되어 있어야 한다. 이 정보를 MAP_DATA라는 배열에 구현했다. 이 배열에는 오직 0 아니면 1인 값만 존재한다. 0인 값은 흑색타일이 자리 잡을 것이며, 1인 값은 흰색타일이 자리하게 될 것이다. MAP_DATA는 오직 초기 타일들의 구성에만 관심이 있을 뿐이다.
 실제 코드로는 다음과 같이 정의되어 있다.

        public int[][] MAP_DATA = { 
{ 1, 1, 1, 1, 1, 1 }, 
{ 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0 }, 
{ 0, 0, 0, 0, 0, 0 }, 
{ 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0 }, 
{ 0, 0, 0, 0, 0, 0 }, 
{ 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0 }, 
{ 1, 1, 1, 1, 1, 1 }, 
{ 0, 0, 0, 0, 0, 0 }, };


 다음의 그림은 이러한 초기 상태를 나타낸다. 아래 위로 흰색 타일을 배치했다. MAP_DATA의 첫번째 row의 값은 모두 1이라는 의미다. 맨 아래도 마찬가지다.




 실질적인 Map의 정보는 map 이라는 배열에 구현되어 있다. 이 배열은 타일의 개수만큼으로 2차원으로 구성되어 있다. 각 배열에는 TILE 객체가 들어간다. 그리고 Activity로부터 명령을 받아 Tile의 색상을 구분해서 boolean값을 돌려주거나, Tile의 색상을 변화시키는 등의 일을 수행하기도 한다.
 만약에 흰색을 터치하게 되면 그 자리의 타일은 검은색으로 변하게 된다. 그리고 드래그를 하는 위치를 따라서 흰색 타일이 그려지게 되며 손을 떼는 순간 그 자리에 흰색 타일이 다시 그려지게 된다. 물론 흰색 타일이 이미 존재할 때에는 본래 있었던 자리에 흰색 타일을 그려넣는다. 
 여기서 그린다 라는 의미는 map에서 그 좌표의 타일 색깔을 0(BLACK) 또는 1(WHITE)로 바꾼다는 의미다.


Rendering
 이 부분은 Surface View 및 그에 대응되는 Thread에 관한 내용이다. 이것에 대한 기초 내용은 이미 포스팅을 한 바 있으므로 자세한 설명은 생략한다. 물론 구글링을 통해서 쉽게 정보를 얻을 수도 있다.

 다음의 그림을 보자. 위에서 타일이 초기화 된 모습에서 실제로 몇몇 타일을 움직였을 때의 화면이다.



 보다 시피 일정한 흰색 타일의 개수를 유지하고 있으며 그 자리가 변경된 것을 알 수 있다. 여기서는 SurfaceView를 이용해서 Rendering을 하고 있다. 또한 Rendering을 하는 Thread를 새롭게 만들어서 지속적으로 화면을 update해준다. 본 프로그램에서는 MyThread라는 클래스로 정의되어 있다.
 많은 시행착오를 겪었는데 이 시행착오를 나열해 보면 다음과 같다.

1. 하나의 Surface View 에서 여러개의 Thread를 돌리는 것.
 배경화면을 그대로 계속 그려주는 Thread와 드래그를 할때 타일을 표현해주는 Thread를 따로 두려고 한 경우다. 그러나 Surface View에는 오직 하나의 Canvas가 있고 그것을 여러개의 Thread가 그려내는 것은 Canvas를 Thread 간에 공유를 해야하기 때문에 비효율적이라고 판단했다. 그래서 Surface View 하나에 Thread 하나를 접목시켰다.

2. 여러개의 Surface View 에서 각각 하나의 Thread를 돌리는 것.

 1번의 시행착오를 겪고 나서 생각했던 것은 Surface View를 2개를 만들어서 하나는 이미 존재하는 타일들을 그려주고 두번째 Surface View에서는 드래그 중인 타일을 그려주는 것을 생각해 보았다. 아마도 앞으로 Game 프로그래밍을 하다보면 이 방법을 자주 쓰게 될 것으로 보인다. 그러나 현재는 단지 드래그만 쓸 뿐이어서 이 방법은 나중에 필요할 때 구현할 것이다.

 그렇게 해서 현재 하나의 Surface View와 하나의 Thread가 본 프로그램을 구현하고 있다. 아주 단순한 방법이기 때문에 그다지 어렵지 않았다. 소스코드는 아래에 첨부해 놨다. 또한 코드 안에도 설명이 되어 있기 때문에 곰곰히 분석해 본다면 이해하는데 많은 시간이 소요되지 않을 것이다.




댓글 없음:

댓글 쓰기