[안드로이드] moon lander 게임 프로그램 완성하기

Updated:

Intro

이번 과제에서는 스레드를 이용하여 moon lanber 게임 프로그램을 완성하여 보았습니다. 주요 기능은 우주선 움직이기, 우주선 속도 조절, 백그라운드로 타이머 재기, 백그라운드로 배경음악 실행, 메뉴 버튼을 누르면 STOP 기능과 HOME으로 돌아가기 기능을 선택할 수 있도록 하였습니다. STOP 버튼을 누르면 배경음악과 게임이 정지하는 기능, Bar 움직이기, Bar에 닿으면 부서진 우주선 이미지로 변경, up, left, right 키를 누르면 연료를 내뿜는 이미지로 변경하기 등등의 기능을 구현하였습니다.

하나의 애플리케이션이 동시에 여러 가지 작업을 하는 것을 다중 스레딩이라고 하는데 이때 작업을 스레드(Thread)라고 부릅니다. 안드로이드에서의 프로세스는 애플리케이션이 시작될 때 안드로이드 시스템이 새로운 리눅스 프로세스를 생성합니다. 기본적으로 애플리케이션 안의 모든 컴포넌트들은 동일한 프로세스의 동일한 스레드로 실행됩니다. 이때 기본적인 스레드를 메인 스레드라고 부릅니다. 메인 스레드는 사용자 인터페이스 위젯에게 이벤트를 전달하거나 화면을 그리는 작업을 담당하며 UI 스레드 라고도 불립니다. 단일 스레드 모델의 원칙이 있는데, 첫번째는 “UI 스레드는 블록시키면 안됩니다.”, 두번쨰는 “UI 스레드 외부에서 안드롱디 UI 툴킷을 조작하면 안된다.” 입니다. 작업 스레드는 별도로 생성되는 스레드입니다. 이번 과제에서는 Thread 클래스를 상속받아 Lunar스레드를 작성하였습니다.

설명

먼저 MainActivitiy와 activity_main.xml을 만들어 메인 화면을 만들어 주었습니다. START 버튼에 클릭 리스너를 등록하여 버튼을 누를시 이벤트가 발생하도록 하였습니다. 메인화면에서 START 버튼을 누르면 LunarLander 액티비티가 실행되면서 게임이 시작 됩니다.

1

스레드에서 직접적으로 사용자 인터페이스 위젯을 변경하면 안되기 때문에 인터페이스를 변경해주는 코드는View에서 해주지 않고, LunarLander에서 작성을 해주었습니다. MediaPlayer를 사용하여 배경음악을 삽입 해 주었습니다. onCreate() 메소드에 정의하여 게임 시작과 동시에 재생 될 수 있도록 하였습니다.

2

게임실행중에도 게임을 멈추거나 HOME 화면으로 갈 수 있도록 Menu 버튼을 만들고 그 안에 STOP과 HOME을 선택할 수 있도록 PopupMenu 객체를 정의하고 이벤트 처리를 해주었습니다. STOP 버튼을 누르면 배경음악과 게임이 멈춥니다. 이때 pause()메소드를 호출하여 멈출수 있도록 하였습니다.

3

checkGame() 메소드는 백그라운드에서 계속 호출되어 게임의 상태를 검사합니다. 만약 시간안에 이겼을 경우 TextView를 You Win!으로 변경해주고 시간안에 졌을 경우 Time Over로 변경해줍니다. 스레드에서 직접적으로 사용자 인터페이스 위젯을 변경하면 안되기 때문에 해당 코드를 작성하여 인터페이스를 변경하였습니다.

4

onKeyDown 메소드를 사용하여 키가 눌렸을 때 이벤트가 발생하는 것을 처리해 주었습니다. Up 키와 Left, Right 키를 누르면 기존의 로켓 이미지가 연료를 내뿜는 이미지로 변경되고 각 방향으로 움직입니다. Left와 Right키는 x축 좌표를 더하고 빼면서 움직임을 제어하였고, Up키와 Down키는 y축의 값을 조절하여 움직임을 제어하였습니다.

5

AsyncTask를 사용하여서 Progress Bar를 작업스레드로 변경시켜주어 타이머 기능을 구현하였습니다. Execute(0)을 하면 CounterTask가 실행 됩니다. Counter Task는 AsyncTask를 상속받은 클래스 입니다. 백그라운드에서 하는 작업은 count를 증가시키면서 리턴을 해줍니다. onProgressUpdate()는 프로그래스 바를 업데이트 하고 checkGame()메소드를 호출하여 게임이 종료 되었는지 계속 실행 중인지를 체크합니다. onPostExecute()는 끝났을 때 카운트가 어떤 값 이상이면 시간 초과로 게임이 종료 될 수 있도록 정의 해주었습니다.

6

Thread 객체를 상속 받은 LunarThread 클래스는 SurfaceView를 상속받고 Callback 메소드를 구현하는 LunarView에 정의 하였습니다. 게임과 같이 복잡하고 빠른 그래픽이 요구되는 애플리케이션에서는 캔버스에 직접 이미지를 그리는 것은 무리가 있기 때문에 전용 화면을 제공하는 SurfaceViewd를 사용하여야 합니다.

SurfaceHodler.Callback을 구현하여 Surface가 생성되고 소멸되는 시점을 알려줍니다. SurfaceView 객체는 직접 처리할 수 없고 반드시 SurfaceHolder를 통하여 처리해야 합니다.

LunarThread 클래스에서는 surfaceHolder를 얻어서 초기화 해주고 사용할 이미지들을 정의하고 필드 값들을 초기화 해주었습니다.

doDraw 메소드로 화면에 그림을 그려주는데 해당 메소드에서 로켓 이미지를 그려주고 움직이는 line(bar)를 그려주었습니다. barFlag를 정의하여 만약 bar의 x2의 좌표가 캔버스의 폭과 같아지면 false로 정의하여 왼쪽으로 움직이고 x1의 값이 0이되면 true로 변경하여 오른쪽으로 움직일 수 있도록 하였습니다.

7

bar에 우주선이 닿았을 경우는 조건문으로 구분을 하여주었습니다. 만약 우전의 y좌표가 bar의 y이 좌표보다 크고, x좌표가 bar의 x1 좌표보다는 크고 x2 좌표보다는 작을 경우가 bar에 우주선이 제대로 착륙한 것입니다. 이때 winFlag를 1로 변경하여 승리하였음을 구분하고 게임이 끝났으므로 isStart 값을 false로 줍니다. 이미지도 plain 이미지로 변경하여줍니다. Bar가 아닌 다른 곳에 닿으면 제대로 착륙을 하지 못한 경우이므로 winFlag를 2로 주어 승리했을 때와의 경우를 구분하여줍니다. 이 경우에도 게임이 끝났으므로 isStart 값을 false로 정의하여줍니다. 착륙에 실패했으므로 우주선 이미지를 crash이미지로 변경해줍니다.

8

음악과 폰트를 사용하기 위해 res > font 폴더를 만들고 ttf 파일들을 넣어주었습니다. 또한 raw 폴더를 만들어 mp3 파일을 넣어주었습니다.

9

Main 화면에서 보이는 버튼은 custom 버튼입니다. Res > drawable 폴더에 circle.xml을 정의해주고 android:background=”@drawable/circle”으로 button background의 속성으로 해당 파일을 지정해주었습니다.

10

결과

  • 시작 화면

11


  • 게임 화면 (timer progress bar, menu 버튼, 움직이는 bar)

12


  • 메뉴 버튼 누를 경우

13


  • 방향 키를 누르면 불꽃이 나오는 우주선 이미지로 변경

14


  • 우주선이 bar에 착륙 성공할 경우

15


  • 우주선이 bar에 착륙 성공할 경우

16


  • 타이머가 끝났을 경우

17

결과 영상

![결과]https://www.youtube.com/watch?v=iN-SapSLi0o&ab_channel=_najiwon

▲ 클릭

참고

전체 코드는 AndroidProject_MyLunarLander에서 확인할 수 있습니다.

Leave a comment