Saturday, February 22, 2014

게임 엔진(AndEngine)을 이용한 안드로이드 앱 개발 (5)

Contents
앱을 위한 액티비티는 하나면 됩니다.
AndEngine을 이용해 만드는 첫번째 액티비티
Genymotion을 이용해서 테스트 해 보자.
다시 코드로 돌아가서 : 배경색 변경
이제 뭘 고민해야 할까요?




이제 본격적으로 AndEngine을 이용해서 코드를 작성할 때가 된 것 같네요? 하지만, 지금 우린 그냥 '설치'만 했을 뿐 AndEngine에 대해선 아무것도 모르고 있는 상태입니다. 이제부터 하나씩, 그리고 조금씩 AndEngine에 대해서도 알아가면서 코드를 작성해 나가도록 할께요.



앱을 위한 액티비티는 하나면 됩니다

뭐라구요? 액티비티가 하나만 있으면 된다구요? 네, 그렇습니다.
우리가 현재 계획하고 있는 안드로이드 앱은 서두에서 그려본 데로 (아직은) 10개 정도의 화면으로 구성이 됩니다. 기존에 여러분이 만들어보셨던 안드로이드 앱의 경우엔 각각의 화면을 별도의 액티비티로 작성하고 각각의 액티비티를 연결해서 이동하며 원하는 동작을 하게 했을 거예요. 하지만, 지금은 '게임처럼' 만들려고 하잖아요? 10개의 우리가 미리 그린 화면들은 모두 각각의 씬(scene)으로 만들어지게 되고, scene에서 scene으로 이동하게 작성이 될 겁니다.

우리가 지금 만들 액티비티는 사용자의 이벤트에 따라 어느 한 씬에서 다른 씬으로의 이동을 관리하게 되죠. 씬에서 또 다른 씬으로의 변경과 관련된 모든 처리는 이 단 하나의 액티비티를 중심으로 이루어지게 된다는 뜻입니다.



> 액티비티를 만들어 보자

우선은 액티비티를 만들어 놓고 더 자세히 볼까요?
아래 그림처럼 우리가 만들 첫 번째, 그리고 (아직은) 오직 하나의 액티비티는 BaseActivity라는 이름을 갖고 org.andengine.ui.activity.BaseGameActivity를 상속하는 액티비티입니다.


[ BaseActivity 클래스 생성 ]

생성된 BaseActivity 클래스의 코드를 볼까요? 아래처럼 네 개의 메소드를 오버라이드 하도록 제시됩니다.

[ 우리가 구현해 줘야할 4개의 메소드 ]

물론, BaseActivity의 상위 클래스인 BaseGameActivity는 더 많은 메소드들을 가지고 있고 때에 따라 저 네 개가 아닌 다른 메소드들도 오버라이드해서 작성해 줄 수도 있어요. 하지만, 여기서는 '중요한, 그리고 오버라이드 해줘야만 하는' 네 개의 메소드를 우선적으로 설명하려 합니다.


> AndEngine 액티비티의 Lifecycle

안드로이드 앱 개발을 다루는 책의 서두에 꼭 나오는 부분이 있죠? 'Activity Lifecycle'
마찬가지로 AndEngine의 액티비티도 Lifecycle이 있어요. 위에 보이는 저 메소드들이 바로 그 Lifecycle과 관련된 메소드들입니다.

  • 우리가 사용하려는 엔진의 옵션을 설정하고(onCreateEngineOptions),
  • 리소스들도 준비하고(onCreateResources),
  • 씬을 생성한 다음에(onCreateScene),
  • 화면에 뿌리도록 하는 것이죠(onPopulateScene).


+ onCreateEngineOptions() 메소드

@Override
public EngineOptions onCreateEngineOptions(){

   //Camera 객체를 생성합니다
   mCamera = new Camera(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);

   //Engine 객체에 적용할 EngineOptions를 우리가 원하는 스타일에 맞게 선언합니다.
   EngineOptions engineOptions = new EngineOptions(true, ScreenOrientation.POTRAIT_FIXED, new FillResolutionPolicy(), mCamera);

   //Wakelock도 설정해 줄 수 있습니다.
   engineOptions.setWakeLockOptions(WakeLockOptions.SCREEN_ON);

   return engineOptions;

}

이 메소드에서 가장 신경써 줘야 하는 부분은 'Camera 객체의 인스턴스를 생성해 주는 것, 그리고 EngineOptions 객체를 우리의 앱에 맞게 설정해서 생성해 주는 것' 입니다. 두 객체의 생성을 위해 전달되는 인자들이 모두 우리 앱이 어떻게 보여질 것인가에 대한 설정 값들입니다.


+ onCreateResources() 메소드

@Override
public void onCreateResources(OnCreateResourcesCallback pOnCreateResourcesCallback){
   
   // 필요한 리소스들이 모두 로딩이 되면 pOnCreateResourcesCallback 객체의
   // onCreateResourcesFinished() 메소드를 호출해서 완료되었다는 것을 알려
   // 주어야 합니다. 
   
   //리소스 로딩에 대한 작업을 처리해 주고...
   
   pOnCreateResourcesCallback.onCreateResourcesFinished();
} 

게임 내에서 사용할 리소스들을 생성하고 세팅할 수 있도록 해주는 메소드입니다. 텍스쳐, 효과음이나 배경음악, 앱에서 사용될 폰트 등을 이 메소드 내에서 미리 준비할 수 있습니다. 액티비티의 Lifecycle과 관련된 콜백 메소드들이 이후로도 제대로 호출되어 연결될 수 있게 마지막에 onCreateResourcesFinished()를 '반드시' 호출해 줘야 한다는 것 잊지 마세요.


+ onCreateScene() 메소드

@Override
public void onCreateScene(OnCreateSceneCallback pOnCreateSceneCallback){

   //Scene객체를 생성합니다.
   mScene = new Scene();

   // Scene의 생성이 끝났음을 pOnCreateSceneCallback객체에 알리면서, 
   // Scene객체의 레퍼런스도 넘깁니다
   
   pOnCreateSceneCallback.onCreateSceneFinished(mScene);
}

이 메소드 내에서는 아주 단순한 Scene 객체를 생성해주고 있습니다만 일반적으로 이렇지는 않죠. 이것보다 조금은 더 복잡해 질 것입니다.터치 이벤트에 관한 리스너(listener)나 업데이트 핸들러와 관련된 것들이 이 안에서 처리되기도 하거든요. 앞의 메소드와 마찬가지로 씬을 설정하는 작업이 모두 끝나면 마지막에 onCreateSceneFinished() 메소드를 호출해 주는 걸 잊으면 안됩니다.

+ onPopulateScene() 메소드

@Override
public void onPopulateScene(Scene pScene, OnPopulateSceneCallback pOnPopulateSceneCallback){

   //앞의 두 메소드와 마찬가지로 scene을 화면에 올린 후엔 OnPopulateSceneCallback
   //객체의 onPopulateSceneFinished()메소드를 호출해 줘야 합니다.

   //추가적으로 해줘야 할 일이 있으면 처리해주고...
   pOnPopulateSceneCallback.onPopulateSceneFinished();
}

씬에 추가적으로 엔티티(entity, 씬에 부착이 가능한 다른 객체들이라고 생각하고 넘어 가게요)를 붙이고 싶다면 여기서 하시면 됩니다. 이 메소드도 앞의 두 메소드와 마찬가지로 마지막에 꼭 호출해 줘야하는 메소드가 있네요. 코드와 주석을 읽어보세요.


+ 현재까지 작성된 액티비티의 코드 전체 보기

import java.io.IOException;

import org.andengine.engine.camera.Camera;
import org.andengine.engine.options.EngineOptions;
import org.andengine.engine.options.ScreenOrientation;
import org.andengine.engine.options.resolutionpolicy.RatioResolutionPolicy;
import org.andengine.entity.scene.Scene;
import org.andengine.ui.activity.BaseGameActivity;

public class BaseActivity extends BaseGameActivity {
   private static final int CAMERA_WIDTH = 800;
   private static final int CAMERA_HEIGHT = 1280;

   private Camera mCamera;
   private EngineOptions mEngineOptions;

   @Override
   public EngineOptions onCreateEngineOptions() {
      mCamera = new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
      mEngineOptions = new EngineOptions(true, 
                                         ScreenOrientation.PORTRAIT_FIXED,
                                         new RatioResolutionPolicy(CAMERA_WIDTH, CAMERA_HEIGHT),
                                         mCamera);
      return mEngineOptions;
   }

   @Override
   public void onCreateResources(OnCreateResourcesCallback pOnCreateResourcesCallback) 
   throws IOException {
      // TODO 앱에 필요한 리소스를 로드해 주는 코드가 여기 작성될 것입니다.
      pOnCreateResourcesCallback.onCreateResourcesFinished();
   }

   @Override
   public void onCreateScene(OnCreateSceneCallback pOnCreateSceneCallback) 
   throws IOException {
       Scene splashScene = new Scene();
       pOnCreateSceneCallback.onCreateSceneFinished(splashScene);
   }

   @Override
   public void onPopulateScene(Scene pScene,OnPopulateSceneCallback pOnPopulateSceneCallback)
   throws IOException {
       // TODO 추가적으로 scene에 엔티티들을 추가하는 작업이 들어갈 수 있습니다.
       pOnPopulateSceneCallback.onPopulateSceneFinished();
   }

}


아! 그러고 보니 우리가 처음 프로젝트를 생성할 때의 액티비티 이름과 다르군요. AndroidManifest.xml 파일을 수정해 줘야 방금 우리가 작성한 액티비티가 시작 액티비티가 되어 화면에 보이겠네요.



   

   
      
      
            
            
         
      
   





Genymotion을 이용해서 어플리케이션을 실행시켜 보자

안드로이드의 가상 디바이스(AVD)에서도 테스트 해 볼 수도 있지만, 여기서는 Genymotion이라는 안드로이드 에뮬레이터를 이용해서 테스트 해 보려 합니다.(Genymotion site)

앱을 올려서 테스트 해 볼 디바이스를 다양하게 소유하고 있다면야 아무 걱정없겠지만, 개인이 그러기가 어렵잖아요? 다행스럽게도 안드로이드 앱을 개발하는 PC나 노트북이 시간에 뒤떨어지지 않는 제품이기만 하다면 '수많은 디바이스를 소유'한 것처럼 테스트 할 수 있게 해주니 얼마나 고마운 제품입니까? 거기다 'free for personal use' 잖아요.

그나저나, 구글이 주는 가상 디바이스들은 왜 그리 느린지 모르겠습니다. 두어해 전만 해도 OS X에서 구동 시킬 땐 그나마 속도가 나와서 봐줄 만(그렇다고 그걸 켜고 일하지는 않았지만) 했는데 요새는 도저히 참고 기다릴 수 없을 정도더라구요.


무턱대고 설치하기 보단 Genymotion의 시스템 요구 사항부터 보기로 하죠.(설치 방법은 Genymotion의 공식 홈페이지가 훨씬 친절하니 그것을 참고하시고, 여기에선 사용자 입장에서의 조언만 덧붙이겠습니다)






Genymotion의 설치와 관련된 이야기들

자주색으로 박스 친 부분만 보세요. 아래 박스에 보면 Oracle의 VitualBox가 설치되어 있어야 한다고 써있네요. 윈도우즈의 경우엔 다운로드한 패키지에 이미 포함되어 있다고 하니, OSX를 쓰시는 분만 별도로 다운로드 해서 설치하시면 될 듯해요.

그리고, 언듯 듣기론 메인보드에 붙여진 내장 그래픽카드로는 힘들다고 하니 그래픽 카드가 요구 사항에 맞는지도 확인해야 할테고, CPU도 가상화가 가능한 것들인지를 확인해봐야 합니다.  BIOS에서 가상화가 가능한지, 혹시 비활성화 되어있는지도 확인해 봐야 하고요.

인스톨할 때의 여유 공간이 100정도라고 하는데, 이것은 실제 이 프로그램의 설치 공간일 뿐 여러분이 다양한 가상 디바이스를 많이 설치할 수록 공간도 많이 필요합니다. 가상 디바이스 하나당 250M 정도가 필요하더라구요.



Genymotion Download & Install( for Mac OS X user )

1. VirtualBox를 https://www.virtualbox.org/wiki/Downloads 에 가서 다운로드 한 후 먼저 설치합니다.( torrent로도 제공되더라구요.googling~)

2. Genymotion의 공식 홈페이지에 가서, 아주 간단한 정보(이메일, 패스워드, 개인 용도로 쓸건지, 인디 기업인지, 사람 많은 기업인지 등등의 정보)를 기입하면, 기입한 이메일로 confirm 메일이 날아오고, 그 안에서 클릭해서 confirm 하면 바로 처리된 다음 다운로드 할 수 있도록 해줍니다. 다운로드가 완료되면 늘 하던데로 설치해주면 끝.

  • Genymotion이 설치되면, 가상 디바이스도 설치해 주세요. 테스트가 필요한 타겟을 잘 따져서 해주세요. 2.3.7에서 4.4.2 까지 지원되며, 기기의 종류도 다양합니다. 다른 에뮬레이터에 비해 Genymotion이 갖는 강점이죠.
  • 나머지는 사용자 메뉴얼(https://cloud.genymotion.com/page/doc/)을 꼭 읽어 보세요. 가상 디바이스 설정과 관련된 것이며, ADB설정,  추가 기능들에 대한 설명이 그림과 함께 알기 쉽게 설명되어 있습니다. 설치하면 메뉴얼이 포함되어 오니 그것을 보셔도 되고요


3. 이클립스에서 작업을 할테니 이클립스에서 쉽게 사용할 수 있도록 Genymotion 플러그인도 설치해 줍니다. (Plugin update site : http://plugins.genymotion.com/eclipse )



 다시 코드로 돌아가서

모두 설치하셨나요? 그럼 이클립스로 다시 돌아가죠. 플러그인을 설치하고 이클립스를 다시 켜면 툴바에 버튼이 생겼을 겁니다. 이 버튼을 클릭하면 아래 처럼 사용가능한 Genymotion의 가상 디바이스들이 보입니다. 이 중 하나를 선택해서 start...  해주시면 됩니다.




그리고, 우리가 작성한 앱을 그 가상 디바이스에 올려 테스트 하면 되죠. 아래는 위 리스트 중 Nexus 5-4.4.2-API 19 - 1080x1920에 올려서 테스트한 화면 입니다. 하단에 화살표 부분을 잘 보시면 화면 전체가 검은데도 불구하고 회색으로 다른 영역이 나타나죠?  우리가 처음 카메라의 WIDTH, HEIGHT를 어떻게 설정했는지 기억하시나요? 800, 1280으로 했거든요. 우리가 선택한 화면 비율은 10:16인데 비해, 실제 디바이스는 9:16 이라서 그 차이가 생기는 것입니다.

그렇다면 회색 비율이 더 커야하지 않나요? 네, 맞아요. 더 커야 하죠. 하지만, 그 부분을 맨 하단의 소프트 버튼이 차지 하고 있잖아요. 그래서 얇은 선으로 나타난 것입니다. 앞으로도 많은 앱을 만들다보면 디바이스의 해상도와 앱이 나타나야 하는 크기 사이의 차이 때문에 고민하는 일이 많을 겁니다.  이걸 티나지 않게 처리하는 방법은 차차 알아보도록 하죠.



우리가 만든 앱의 배경색을 바꿔 보자

약간의 변화를 줘 볼까요? 배경 색만 바꿔 보겠습니다.

지금 우리가 보는 것은 BaseActivity의 onCreateScene()메소드에서 생성된 Scene객체 입니다. 그럼 Scene객체에 배경색을 바꿀 수 있는 메소드가 있는지를 먼저 알아봐야 겠네요? 그래서 알아봤더니 setBackground() 메소드가 있네요.



그리고, 이 메소드의 인자는 IBackground 타입이네요. IBackground는 이름에서 알 수 있듯 인터페이스 입니다. 그리고, 이 인터페이스를 구현한 것이 Background클래스 입니다.



쪽에 파랗게 표시된 메소드가 우리가 사용할 생성자 메소드 입니다. RGB 각각의 색상 값을 float 타입으로 전달해서 우리가 원하는 색상을 만들어 내고 그것을 배경색으로 사용하려는 것이죠. 바로 아래 있는  float 값 네 개를 받는 생성자는 마지막 float 값이 alpha 값이 됩니다.

각각 0.09f, 0.68f, 0.89f 이렇게 사용해서 색깔을 만들어 내고,, 그 색깔을 배경색으로 적용해 보겠습니다.

@Override
public void onCreateScene(OnCreateSceneCallback pOnCreateSceneCallback){

   //Scene객체를 생성합니다.
   Scene splashScene = new Scene();
   splashScene.setBackground(new Background(0.09f, 0.68f, 0.89f));
   
   pOnCreateSceneCallback.onCreateSceneFinished(mScene);
}


변경 후 같은 디바이스에 올려 테스트 해 보면 아래 처럼 Scene의 배경색이 바뀐걸 확인할 수 있습니다.



자, 여기까지 해서 AndEngine에서 제공하는 액티비티 클래스를 상속하여 우리만의 액티비티도 만들어 봤고, 몇 가지 Lifecycle과 관련된 메소드도 오버라이딩 해서 우리가 원하는 '아주 간단한' 동작을 하도록 작성해 봤습니다.



이제 뭘 고민해야 할까요?

앞으로 어떤 것들이 이 앱에 추가가 될 지 생각해 볼까요?
우선 '게임 처럼' 만들자고 했으니 굉장히 많은 이미지 파일들이 사용될 듯 합니다. 가끔은 효과음도 써야 할거 같고, 멋들어진 폰트도 사용해야 하겠죠?

아~ onCreateResources() 메소드 안에서 리소스 생성 등의 일을 처리한다고 했었죠? 거기서 해주면 되겠네요~ (아... 오글오글...)
그런데, 그것만으론 부족해요. 생성하고 관리해야하는 리소스들 전부를 거기에 몰아 넣게 되면 아주 복잡해져서 나중엔 감당 못할 정도가 될테고, 쓸데 없이 로딩해서 메모리만 잡아먹게 하는 것들도 생길 수 있을 테구요. 좀 더 효율적으로 관리할 방법을 찾아야 겠네요


그리고, 화면이 적어도 10개 이상은 쓰일 것입니다.

아~ 화면이 곧 scene 이라고 했으니, 그건 onCreateScene()메소드 내에서 하면 되겠네요.
맞아요. 하지만, 바로 위에 말한 것처럼 '상황에 따라 적절한 Scene이 준비되면서도 성능에 나쁜 영향을 주지 않는 방법을 찾아야 하겠네요. Scene객체 뿐만 아니라 그 이외에도 수 많은 객체들도 관리해야 할텐데 어떤 방법이 있을까요?


그래서, 다음 이야기에서는 그러한 방법을 찾아보도록 하겠습니다.(끝)






혹시 가상 디바이스를 여러 개 설치하고 각각 테스트 해보다가 특정 디바이스에서 아래와 같은 에러가 발생한다면...

[이런 에러가 발생하며 앱이 종료되어 버리나요?]


그렇다면, AndroidManifest.xml 파일에   application 태크의 속성에 아래와 같이 추가 작성해 보세요.(line 5) 좌우로 스크롤 하면서 보세요. 문장이 길어요.


   

   
      
      
            
            
         
      
   



혹은 아래처럼 android:largeHeap="true" 만 추가시켜줘도 문제는 발생하지 않는데, 두 방법 모두 좀 더 알아보고 살펴보고 해야 할 듯 합니다.


   

   
      
      
            
            
         
      
   




No comments:

Post a Comment