AndEngine 3강 -  Examples(예제) 실행하기 (by wono77)

 

이제 처음 보고 군침을 흘렸던 AndEngine의 샘플들을 살펴보면서 공부할 차례입니다. 솔직히 우리는 이 멋있어 보이는 예제들 때문에 AndEngine을 시작하게 되었지요. 정말 멋진 샘플들인지 하나하나 음미해 볼 것입니다.

 

예제: https://github.com/nicolasgramlich/AndEngineExamples 

 

Screenshot_2012-11-13-18-49-23.png

[ 예제의 실행 화면 ]

 

위 예제는 처음 살펴본 AndEngine의 QRCode로 마켓에서 다운받아 설치가 가능합니다. 하나하나 실행을 해보면 그 매력에 놀라실 겁니다. 아직 해보지 않으셨다면 지금 바로 폰에 설치하셔서 하나하나 실행해 보시길 적극 추천드립니다. 우리는 이 중에서 백그라운드 이미지가 횡으로 스크롤되고, 스프라이트 이미지 2개가 즐겁게 걸어다니는 "BackGrounds > Using an AutoParallaxBackground" 를 실행해보고 입맛에 맞게 스프라이트 이미지와 배경 이미지를 변경해보도록 하겠습니다.

 

example을 직접 실행하기 위해서는 extention들을 다 다운 받아서 셋팅해야 합니다. 하지만, 앞서 우리가 만든 AESample 프로젝트에서 원하는 샘플을 가져다가 실행해 보는 것만으로도 extention을 추가하지 않고 몇가지 샘플의 실행은 가능합니다. 우리는 필요한 샘플을 하나하나 실행해보고, 샘플 실행에 필요한 elxtention이 있다면, 추가하는 방법으로 진행해보겠습니다.


Screenshot_2012-11-13-18-49-29.png

[ BackGrounds > Using an AutoParallaxBackground ]

 

다운 받은 샘플을 import 하셨을 겁니다. 이중 어떤게 저 예제인지 찾는것도 일입니다. 정리된 리스트가 있는 것도 아니니 말이죠. 다음 빨간 소스가 해당되는 소스입니다.

sample_list.png

 

소스를 한번 쭉~ 살펴봅니다.

자, 여기서 과제가 한번 나가야겠지요?

첫번째 과제입니다.

 

예제에 있는 AutoParallaxBackgroudExample.java를 앞서 작성한 샘플에 붙여서 작동되도록 만들어보세요. 필요한 이미지는 5개입니다. 예제 폴더의 asset에서 가져오셔야 합니다. 

 

package org.andengine.examples;

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.entity.scene.background.AutoParallaxBackground;
import org.andengine.entity.scene.background.ParallaxBackground.ParallaxEntity;
import org.andengine.entity.sprite.AnimatedSprite;
import org.andengine.entity.sprite.Sprite;
import org.andengine.entity.util.FPSLogger;
import org.andengine.opengl.texture.TextureOptions;
import org.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlas;
import org.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlasTextureRegionFactory;
import org.andengine.opengl.texture.region.ITextureRegion;
import org.andengine.opengl.texture.region.TiledTextureRegion;
import org.andengine.opengl.vbo.VertexBufferObjectManager;
import org.andengine.ui.activity.SimpleBaseGameActivity;

/**
 * (c) 2010 Nicolas Gramlich
 * (c) 2011 Zynga
 *
 * @author Nicolas Gramlich
 * @since 19:58:39 - 19.07.2010
 */
public class AutoParallaxBackgroundExample extends SimpleBaseGameActivity {
 // ===========================================================
 // Constants
 // ===========================================================

 private static final int CAMERA_WIDTH = 720;
 private static final int CAMERA_HEIGHT = 480;

 // ===========================================================
 // Fields
 // ===========================================================

 private BitmapTextureAtlas mBitmapTextureAtlas;
 private TiledTextureRegion mPlayerTextureRegion;
 private TiledTextureRegion mEnemyTextureRegion;

 private BitmapTextureAtlas mAutoParallaxBackgroundTexture;

 private ITextureRegion mParallaxLayerBack;
 private ITextureRegion mParallaxLayerMid;
 private ITextureRegion mParallaxLayerFront;

 // ===========================================================
 // Constructors
 // ===========================================================

 // ===========================================================
 // Getter & Setter
 // ===========================================================

 // ===========================================================
 // Methods for/from SuperClass/Interfaces
 // ===========================================================

 @Override
 public EngineOptions onCreateEngineOptions() {
  final Camera camera = new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);

  return new EngineOptions(true, ScreenOrientation.LANDSCAPE_FIXED, new RatioResolutionPolicy(CAMERA_WIDTH, CAMERA_HEIGHT), camera);
 }

 @Override
 public void onCreateResources() {
  BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("gfx/");
  
  this.mBitmapTextureAtlas = new BitmapTextureAtlas(this.getTextureManager(), 256, 128, TextureOptions.BILINEAR);
  this.mPlayerTextureRegion = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(this.mBitmapTextureAtlas, this, "player.png", 0, 0, 3, 4);
  this.mEnemyTextureRegion = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(this.mBitmapTextureAtlas, this, "enemy.png", 73, 0, 3, 4);
  this.mBitmapTextureAtlas.load();

  this.mAutoParallaxBackgroundTexture = new BitmapTextureAtlas(this.getTextureManager(), 1024, 1024);
  this.mParallaxLayerFront = BitmapTextureAtlasTextureRegionFactory.createFromAsset(this.mAutoParallaxBackgroundTexture, this, "parallax_background_layer_front.png", 0, 0);
  this.mParallaxLayerBack = BitmapTextureAtlasTextureRegionFactory.createFromAsset(this.mAutoParallaxBackgroundTexture, this, "parallax_background_layer_back.png", 0, 188);
  this.mParallaxLayerMid = BitmapTextureAtlasTextureRegionFactory.createFromAsset(this.mAutoParallaxBackgroundTexture, this, "parallax_background_layer_mid.png", 0, 669);
  this.mAutoParallaxBackgroundTexture.load();
 }

 @Override
 public Scene onCreateScene() {
  this.mEngine.registerUpdateHandler(new FPSLogger());

  final Scene scene = new Scene();
  final AutoParallaxBackground autoParallaxBackground = new AutoParallaxBackground(0, 0, 0, 5);
  final VertexBufferObjectManager vertexBufferObjectManager = this.getVertexBufferObjectManager();
  autoParallaxBackground.attachParallaxEntity(new ParallaxEntity(0.0f, new Sprite(0, CAMERA_HEIGHT - this.mParallaxLayerBack.getHeight(), this.mParallaxLayerBack, vertexBufferObjectManager)));
  autoParallaxBackground.attachParallaxEntity(new ParallaxEntity(-5.0f, new Sprite(0, 80, this.mParallaxLayerMid, vertexBufferObjectManager)));
  autoParallaxBackground.attachParallaxEntity(new ParallaxEntity(-10.0f, new Sprite(0, CAMERA_HEIGHT - this.mParallaxLayerFront.getHeight(), this.mParallaxLayerFront, vertexBufferObjectManager)));
  scene.setBackground(autoParallaxBackground);

  /* Calculate the coordinates for the face, so its centered on the camera. */
  final float playerX = (CAMERA_WIDTH - this.mPlayerTextureRegion.getWidth()) / 2;
  final float playerY = CAMERA_HEIGHT - this.mPlayerTextureRegion.getHeight() - 5;

  /* Create two sprits and add it to the scene. */
  final AnimatedSprite player = new AnimatedSprite(playerX, playerY, this.mPlayerTextureRegion, vertexBufferObjectManager);
  player.setScaleCenterY(this.mPlayerTextureRegion.getHeight());
  player.setScale(2);
  player.animate(new long[]{200, 200, 200}, 3, 5, true);

  final AnimatedSprite enemy = new AnimatedSprite(playerX - 80, playerY, this.mEnemyTextureRegion, vertexBufferObjectManager);
  enemy.setScaleCenterY(this.mEnemyTextureRegion.getHeight());
  enemy.setScale(2);
  enemy.animate(new long[]{200, 200, 200}, 3, 5, true);

  scene.attachChild(player);
  scene.attachChild(enemy);

  return scene;
 }

 // ===========================================================
 // Methods
 // ===========================================================

 // ===========================================================
 // Inner and Anonymous Classes
 // ===========================================================
}

어떻게 잘 작동되셨나요?
그대로 소스를 넣고 이미지 파일 찾아서 그대로 넣으면 되는것이라서 무리는 없었을 겁니다.
 
이제 소스를 이해 하기 위해서 스프라이트 이미지를 한번 바꾸어 볼께요.
스프라이트란 게임에 사용되는 플레어어 혹은 적의 이미지를 의미합니다.
 
player.png
해당 예제에서 사용된 player.png 입니다. 일정 크기의 이미지가 가로로 3개, 세로로 4개가 모여있습니다.
실제 소스에서는 다음과 같이 선언하고 사용하고 있습니다.
 

 

this.mBitmapTextureAtlas = new BitmapTextureAtlas(this.getTextureManager(), 256, 128, TextureOptions.BILINEAR);
this.mPlayerTextureRegion = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(this.mBitmapTextureAtlas, this, "player.png", 0, 0, 3, 4);
  this.mBitmapTextureAtlas.load();

mBitmapTextureAtlas라는 256,128 크기의 판을 선언하고, 그 안에 player.png를 넣는데 스프라이트를 읽어들일 시작좌표는 0,0이고 가로 3개, 세로 4개가 존재한다는 의미입니다.
 
네, AndEngine의 스프라이트는 읽어들일 크기를 지정하지 않고 "몇 by 몇" 이냐에 따로 자동 분할을 하는 것 같습니다. 그러므로 한장짜리 player.png 같은 스프라이트가 모여있는 이미지를 만들때, 잘 계산해서 만들어야 합니다.
 
실제로 화면에 뿌리는 부분은 다음과 같이 하고 있습니다.

  enemy.animate(new long[]{200, 200, 200}, 3, 5, true);

 

3장의 스프라이트 이미지를 각각 200프레임으로 총 갯수중 3~5번 이미지까지 뿌리라고 되어 있습니다.(배열의 첫 시작은 0입니다. player.png는 3x4 총 12장의 이미지이므로 3~5번 이미지이면, 위에서 2번째 줄의 3개 이미지가 되겠습니다.)

 

자, 이제 2번째 과제 나갑니다.

위 소스를 응용해서, 다음 이미지를 2개의 이미지가 반복되도록 출력해보세요~

 

runner.png  

[runner.png]

 

어렵지 않으니 직접 한번 고민해보신 다음 정답을 봐주세요.^^

 

[정답]

기존 소스는 파란색, 추가된 소스는 녹색으로 표시하였습니다.

  this.mBitmapTextureAtlas = new BitmapTextureAtlas(
    this.getTextureManager(), 256, 128, TextureOptions.BILINEAR);
  this.mBitmapTextureAtlas2 = new BitmapTextureAtlas(
    this.getTextureManager(), 111, 90, TextureOptions.BILINEAR);
  this.mPlayerTextureRegion = BitmapTextureAtlasTextureRegionFactory
    .createTiledFromAsset(this.mBitmapTextureAtlas, this,
      "player.png", 0, 0, 3, 4);
//  this.mEnemyTextureRegion = BitmapTextureAtlasTextureRegionFactory
//    .createTiledFromAsset(this.mBitmapTextureAtlas, this,
//      "enemy.png", 73, 0, 3, 4);
  this.mEnemyTextureRegion = BitmapTextureAtlasTextureRegionFactory
    .createTiledFromAsset(this.mBitmapTextureAtlas2, this,
      "runner.png", 0, 0, 2, 1);
  this.mBitmapTextureAtlas.load();
  this.mBitmapTextureAtlas2.load();

[이미지 선언부]

 

this.mBitmapTextureAtlas = new BitmapTextureAtlas(
this.getTextureManager(), 256, 128, TextureOptions.BILINEAR);

 

runner.png는 가로 111, 세로 90 픽셀의 이미지입니다. 이미지가 뿌려질 판을 선언하기 위해서는 TextureAtlas2를 선언합니다.

 

this.mEnemyTextureRegion = BitmapTextureAtlasTextureRegionFactory
.createTiledFromAsset(this.mBitmapTextureAtlas2, this,
"runner.png", 0, 0, 2, 1); 

 

runner.png의 이미지는 가로 2개, 세로 1줄의 스프라이트 이미지입니다. 

 

// final AnimatedSprite enemy = new AnimatedSprite(playerX - 80, playerY,
// this.mEnemyTextureRegion, vertexBufferObjectManager);
final float playerY2 = CAMERA_HEIGHT
- this.mEnemyTextureRegion.getHeight() - 5;

  final AnimatedSprite enemy = new AnimatedSprite(playerX - 80, playerY2,
    this.mEnemyTextureRegion, vertexBufferObjectManager);
  
  
  final AnimatedSprite enemy = new AnimatedSprite(playerX - 80, playerY2,
this.mEnemyTextureRegion, vertexBufferObjectManager);
enemy.setScaleCenterY(this.mEnemyTextureRegion.getHeight());
enemy.setScale(2);
//enemy.animate(new long[] { 200, 200, 200 }, 3, 5, true);
enemy.animate(new long[] { 200, 200 }, 0, 1, true);

[이미지 출력부]

final float playerY2

player 객체의 높이를 추가된 이미지인 palyerY2로 따로 선언했어요.

     

 emy.animate(new long[] { 200, 200 }, 0, 1, true);

반복되는 이미지가 2개 이므로, 프로엠도 2개만 선언했고, 0~1번 이미지가 반복됩니다.

 

결과는 다음과 같은 화면이 보여지게 됩니다.

Screenshot_2012-11-14-14-37-14.png

[결과]

 

이제 배경 이미지를 변경해 볼까요?

예제 소스에는 다음배경, 구름, 검은 땅 이미지의  3가지 이미지로 구성되어 있습니다.

parallax_background_layer_back.png

[1. parallax_background_layer_back]

parallax_background_layer_front.png 
[2. parallax_background_layer_front]

parallax_background_layer_mid.png

[3. parallax_background_layer_middle]

 

 

즉, 1번 배경은 가만히 있고, 2번, 3번 이미지만 움직여서 배경이 이동하는 효과를 내고 있습니다. 자세히 보시면 2번, 3번 이미지에서 끝나는 부분은 시작과 끝이 교묘하게 계산되어 어색하지 않도록 되어 있습니다. front, middle만 움직입니다. 다음 코드가 front, middle 이미지의 스크롤 속도를 조절하고 있습니다.

  autoParallaxBackground.attachParallaxEntity(new ParallaxEntity(0.0f,
    new Sprite(0, CAMERA_HEIGHT
      - this.mParallaxLayerBack.getHeight(),
      this.mParallaxLayerBack, vertexBufferObjectManager)));
 

 

//middle 이미지는 위에서 80 만큼 내려와서 출력합니다.

//-5 만큼 이동합니다.


  autoParallaxBackground.attachParallaxEntity(new ParallaxEntity( -5.0f,
    new Sprite(0, 80, this.mParallaxLayerMid,
      vertexBufferObjectManager)));
 

 


//front 선인장 이미지는 전체 화면 높이에서 front 높이를 뺀 만큼 위에서 내려온 위치에 출력됩니다.  
 

autoParallaxBackground.attachParallaxEntity(new ParallaxEntity( -10.0f,
    new Sprite(0, CAMERA_HEIGHT
      - this.mParallaxLayerFront.getHeight(),
      this.mParallaxLayerFront, vertexBufferObjectManager)));
 

[배경 이미지 횡스크롤 속도 조절]

 

과제 3.

이제 배경 이미지를 변경해 보겠습니다. 마음에 드는 이미지로 배경 이미지를 변경해보세요.

 

쉬우셨나요?

기존 이미지는 640 *480을 사용하는데 저는 800*480으로 변경하고 관련 소스를 조금 변경해보았습니다. 

 

  private static final int CAMERA_WIDTH = 720;
 private static final int CAMERA_HEIGHT = 480;

[기존]

 private static final int CAMERA_WIDTH = 800;
 private static final int CAMERA_HEIGHT = 480;

[변경]

 

  this.mAutoParallaxBackgroundTexture = new BitmapTextureAtlas(
    this.getTextureManager(), 1024, 1024);
  this.mParallaxLayerBack = BitmapTextureAtlasTextureRegionFactory
    .createFromAsset(this.mAutoParallaxBackgroundTexture, this,
      "parallax_background_layer_back.png", 0, 188);

[기존]

 

  this.mAutoParallaxBackgroundTexture = new BitmapTextureAtlas(
    this.getTextureManager(), 1280, 800);
  // 480 * 800 경주 안압지
  this.mParallaxLayerBack = BitmapTextureAtlasTextureRegionFactory
    .createFromAsset(this.mAutoParallaxBackgroundTexture, this,
      "ky_an.png", 0, 188);

[변경]

 

그리고 일단 달리는 캐릭터를 차후에 화면 터치시 달리기 위해, 움직이지 않도록 다음 소스를 주석 달아보았습니다.

   enemy.animate(new long[] { 200, 200 }, 0, 1, true);

 

Screenshot_2012-11-17-02-45-34.png

 

* [ 블랙독의 "AndEngine으로 배우는 안드로이드 게임 프로그래밍"

- 나도 이제 안드로이드 게임개발자!! 강좌 리스트 ]

AndEngine 6강 - 충돌 구현 : http://blog.naver.com/wono77/140176342020

AndEngine 5강 - 점프 구현 : http://blog.naver.com/wono77/140174350342

AndEngine 4강 - 터치, 이미지 출력/해제, 폰트 변경 : http://blog.naver.com/wono77/140173160582

AndEngine 3강 - Examples(예제) 실행하기 : http://blog.naver.com/wono77/140172587747
AndEngine 2강 - 샘플 프로젝트 생성 : http://blog.naver.com/wono77/140172586342
AndEngine 1강 - andengine.jar 생성하기: http://blog.naver.com/wono77/140172582693
안드로이드 게임 sdk 소개 : http://blog.naver.com/wono77/140172218034

 

* 안드엔진 까페( http://andengine.co.kr)로 놀러 오세요~~~!!

 

참고 : saksin님의 예제 실행을 위해 extention을 셋팅하는 강좌:

http://saksin.tistory.com/m/post/view/id/905

 

블랙독의 "AndEngine 강좌"는

데브안드로이 까페(http://cafe.naver.com/devandroi)

AndEngine 까페(http://cafe.naver.com/andenginekorea)

에서 연재되고 있습니다.

 

 

blackdog.png

 

안녕하세요, 블랙독입니다.

일주일간 준비한 강좌는 여기까지입니다. 반응 좋으면 다음 강좌까지 힘내어 계속 전진합니다.~

댓글로 아무글이나 많은 응원 부탁드립니다.

"이게 뭐냐~!" "똑바로해라!" "그걸 강좌라고!!!" "잘했다" "힘내요 오빠~"

등 다양한 댓글 대환영입니다!! 뉴.뉴

 

안드엔진 한국 사용자 모임을 개설해보았습니다. 아직은 회원이 저 혼자입니다.=ㅂ=a;'

회원이 많이 모이면, 오프 모임이나 AndEngine 개발자 니콜라스님의 축전등도 받아보고, ...

혹시 알아요~ 개발자 니콜라스님을 한국에 모셔서 세미나를 열수 있을지도;;

안드엔진의 고수, 혹은 저같은 초보 모두 오셔서 많은 정보 공유하고 같이 공부해보았으면 합니다.

http://andengine.co.kr/

 

 

안녕하세요. 블랙독입니다. ^-^
제가 운영하는 데브모바일(http://devmobile.co.kr), 데브게임즈(http://devgames.co.kr)에도 놀러오세요~