AndEngine 1강 - andengine.jar 생성하기 (by wono77)

 

AndEngine 라이브러리 전체 소스, export된 andengine.jar 는 펍의 용량제한으로 올리지 못하였습니다.

제 블로그에서 받을 수 있으세요 : http://blog.naver.com/wono77/140172582693 

 

AndEngine 은 오픈소스(LGPL) 기반의 안드로이드용 OpenGL 2D 게임 엔진으로 http://www.andengine.org/ 에서 관련 정보를 확인할 수 있습니다. 다음 사이트에서 소스를 다운로드해서 압축을 풀어 주세요. git 툴을 사용해서 다운로드 해도 되지만, 직접 압축 파일을 다운로드해서 압축을 푸세도 됩니다.(저는 이 방법을 사용했습니다.)

 
소스를 모두 받았다면 해당 라이브러리를 빌드하여 jar 파일을 생성하는 방법을 살펴 보겠습니다. AndEngine을 사용하는 방법은 여러가지가 있겠지만 우리는 jar 라이브러리를 생성한 다음 이 jar를 다른 프로젝트에서 import하여 라이브러리 형태로 사용하는 방식을 취할 것입니다.

1. jar 파일 생성
이클립스에서 File -> Import 를 실행한 후, General 항목의 Existing Projects into Workspace 를 선택합니다.(안드로이드 프로젝트 import가 아닌 그냥 import 프로젝트임에 주의합니다.)

?f=cfile29.uf%40161906464ED6E3C32F3F00.png&size=480


AndEngine 소스가 위치하는 디렉토리를 지정한 후, Finish 버튼을 클릭합니다.

import.png


다음과 같은 에러가 발생하면,

?f=cfile2.uf%4020185E474ED6E4BF1BBE64.png&size=480


프로젝트에서 마우스 우클릭하여 팝업 메뉴를 띄운 후 Properties 를 실행합니다. 그리고 대상 안드로이드를 지정 합니다. AndEngine는 안드로이드 sdk 버전 2.3인 진저브레드 이상에서 컴파일이 잘 됩니다.

 

4.0 아이스크림에서 해도 되지만 전 진저브레드에서 설치하였습니다. 단, 진저브레드까지만 이클립스에 sdk를 설치해두었다면, AndEngine에서 정의해둔 아이스크림에 대한 부분을 인식하지 못하기 때문에 다음처럼 관련 부분을 몇군데 주석을 달아주어야 정상적으로 jar가 에러 없이 생성됩니다. 

sdk2.3.3.png

 
만약, @Override 관련하여 에러 메시지가 뜬다면, 마찬가지로 Properties 를 실행하고 Java Compiler 에서 1.6 이상 버전을 선택하여 줍니다.

?f=cfile25.uf%40183BA54A4ED6E6F113B09D.png&size=480

 
우리는 진저브레드를 sdk로 선택했기 때문에 소스 중 2군데에 빨간 에러표시가 날 수도 있습니다. AndEngine은 내부적으로 안드로이드의 OS에 따라 처리를 다르게 하는 부분이 있는데, 사용자의 sdk에 아이스크림이 없다면 에러가 뜨게 됩니다. 이 소스 코드를 찾아서 주석 처리를 합니다.

 

에러발생.png

[org.andengine.util.system > SystemUtils.java ]

 

// public static final boolean SDK_VERSION_HONEYCOMB_OR_LATER = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB;
// public static final boolean SDK_VERSION_ICE_CREAM_SANDWICH_OR_LATER = Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH;

이렇게 처리하면 허니콤과 아이스크림에 대한 정의 자체가 없어지게 되므로 관련된 에러가 더 나타납니다.

org.andengine.opengl.util > BufferUtils.java

org.andengine.opengl.vbo > HighPerformanceVertexBufferObj.java

 

이 소스들의 허니콤과 아이스크림의 관련 코드를 찾아(빨간 에러가 표시된 부분) 주석처리 합니다. 

 

BufferUtils.java의 경우 다음처럼 처리합니다.

 

기존

if(BufferUtils.NATIVE_LIB_LOADED) {
   if(SystemUtils.isAndroidVersion(Build.VERSION_CODES.HONEYCOMB, Build.VERSION_CODES.HONEYCOMB_MR2)) {
    WORKAROUND_BYTEBUFFER_ALLOCATE_DIRECT = true;
   } else {
    WORKAROUND_BYTEBUFFER_ALLOCATE_DIRECT = false;
   }

   if(SystemUtils.isAndroidVersionOrLower(Build.VERSION_CODES.FROYO)) {
    WORKAROUND_BYTEBUFFER_PUT_FLOATARRAY = true;
   } else {
    WORKAROUND_BYTEBUFFER_PUT_FLOATARRAY = false;
   }
  } else {
   WORKAROUND_BYTEBUFFER_ALLOCATE_DIRECT = false;
   if(SystemUtils.isAndroidVersion(Build.VERSION_CODES.HONEYCOMB, Build.VERSION_CODES.HONEYCOMB_MR2)) {
    Debug.w("Creating a " + ByteBuffer.class.getSimpleName() + " will actually allocate 4x the memory than requested!");
   }

   WORKAROUND_BYTEBUFFER_PUT_FLOATARRAY = false;
  }

변경

  if(BufferUtils.NATIVE_LIB_LOADED) {
//   if(SystemUtils.isAndroidVersion(Build.VERSION_CODES.HONEYCOMB, Build.VERSION_CODES.HONEYCOMB_MR2)) {
//    WORKAROUND_BYTEBUFFER_ALLOCATE_DIRECT = true;
//   } else 
   {
    WORKAROUND_BYTEBUFFER_ALLOCATE_DIRECT = false;
   }

   if(SystemUtils.isAndroidVersionOrLower(Build.VERSION_CODES.FROYO)) {
    WORKAROUND_BYTEBUFFER_PUT_FLOATARRAY = true;
   } else {
    WORKAROUND_BYTEBUFFER_PUT_FLOATARRAY = false;
   }
  } else {
   WORKAROUND_BYTEBUFFER_ALLOCATE_DIRECT = false;
//   if(SystemUtils.isAndroidVersion(Build.VERSION_CODES.HONEYCOMB, Build.VERSION_CODES.HONEYCOMB_MR2)) {
//    Debug.w("Creating a " + ByteBuffer.class.getSimpleName() + " will actually allocate 4x the memory than requested!");
//   }

   WORKAROUND_BYTEBUFFER_PUT_FLOATARRAY = false;
  }

HightPerformanceVertexBufferObj.java도 마찬가지로 빨갛게 에러가 나타난 부분을 주석처리합니다.

기존

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

 public HighPerformanceVertexBufferObject(final VertexBufferObjectManager pVertexBufferObjectManager, final int pCapacity, final DrawType pDrawType, final boolean pAutoDispose, final VertexBufferObjectAttributes pVertexBufferObjectAttributes) {
  super(pVertexBufferObjectManager, pCapacity, pDrawType, pAutoDispose, pVertexBufferObjectAttributes);

  this.mBufferData = new float[pCapacity];
  if(SystemUtils.SDK_VERSION_HONEYCOMB_OR_LATER) {
   this.mFloatBuffer = this.mByteBuffer.asFloatBuffer();
  } else {
   this.mFloatBuffer = null;
  }
 }

 public HighPerformanceVertexBufferObject(final VertexBufferObjectManager pVertexBufferObjectManager, final float[] pBufferData, final DrawType pDrawType, final boolean pAutoDispose, final VertexBufferObjectAttributes pVertexBufferObjectAttributes) {
  super(pVertexBufferObjectManager, pBufferData.length, pDrawType, pAutoDispose, pVertexBufferObjectAttributes);
  this.mBufferData = pBufferData;
  
  if(SystemUtils.SDK_VERSION_HONEYCOMB_OR_LATER) {
   this.mFloatBuffer = this.mByteBuffer.asFloatBuffer();
  } else {
   this.mFloatBuffer = null;
  }
 }

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

 public float[] getBufferData() {
  return this.mBufferData;
 }

 @Override
 public int getHeapMemoryByteSize() {
  return this.getByteCapacity();
 }

 @Override
 public int getNativeHeapMemoryByteSize() {
  return this.getByteCapacity();
 }

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

 @Override
 protected void onBufferData() {
  // TODO Check if, and how mow this condition affects performance.
  if(SystemUtils.SDK_VERSION_HONEYCOMB_OR_LATER) {
   // TODO Check if this is similar fast or faster than the non Honeycomb codepath.
   this.mFloatBuffer.position(0);
   this.mFloatBuffer.put(this.mBufferData);

   GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, this.mByteBuffer.capacity(), this.mByteBuffer, this.mUsage);
  } else {
   BufferUtils.put(this.mByteBuffer, this.mBufferData, this.mBufferData.length, 0);
   GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, this.mByteBuffer.limit(), this.mByteBuffer, this.mUsage);
  }
 }

변경

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

 public HighPerformanceVertexBufferObject(final VertexBufferObjectManager pVertexBufferObjectManager, final int pCapacity, final DrawType pDrawType, final boolean pAutoDispose, final VertexBufferObjectAttributes pVertexBufferObjectAttributes) {
  super(pVertexBufferObjectManager, pCapacity, pDrawType, pAutoDispose, pVertexBufferObjectAttributes);

  this.mBufferData = new float[pCapacity];
//  if(SystemUtils.SDK_VERSION_HONEYCOMB_OR_LATER) {
//   this.mFloatBuffer = this.mByteBuffer.asFloatBuffer();
//  } else 
  {
   this.mFloatBuffer = null;
  }
 }

 public HighPerformanceVertexBufferObject(final VertexBufferObjectManager pVertexBufferObjectManager, final float[] pBufferData, final DrawType pDrawType, final boolean pAutoDispose, final VertexBufferObjectAttributes pVertexBufferObjectAttributes) {
  super(pVertexBufferObjectManager, pBufferData.length, pDrawType, pAutoDispose, pVertexBufferObjectAttributes);
  this.mBufferData = pBufferData;
  
//  if(SystemUtils.SDK_VERSION_HONEYCOMB_OR_LATER) {
//   this.mFloatBuffer = this.mByteBuffer.asFloatBuffer();
//  } 
//  else 
  {
   this.mFloatBuffer = null;
  }
 }

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

 public float[] getBufferData() {
  return this.mBufferData;
 }

 @Override
 public int getHeapMemoryByteSize() {
  return this.getByteCapacity();
 }

 @Override
 public int getNativeHeapMemoryByteSize() {
  return this.getByteCapacity();
 }

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

 @Override
 protected void onBufferData() {
  // TODO Check if, and how mow this condition affects performance.
//  if(SystemUtils.SDK_VERSION_HONEYCOMB_OR_LATER) {
//   // TODO Check if this is similar fast or faster than the non Honeycomb codepath.
//   this.mFloatBuffer.position(0);
//   this.mFloatBuffer.put(this.mBufferData);
//
//   GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, this.mByteBuffer.capacity(), this.mByteBuffer, this.mUsage);
//  } else 
  {
   BufferUtils.put(this.mByteBuffer, this.mBufferData, this.mBufferData.length, 0);
   GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, this.mByteBuffer.limit(), this.mByteBuffer, this.mUsage);
  }
 }

 

res 폴더를 추가합니다.

?f=cfile25.uf%4011583E4E4ED6E76104F881.png&size=480



자바 라이브러리인 jar를 생성할 것입니다. 메뉴에서 프로젝트를 선택한 후 File -> Export 를 실행합니다. 그리고 Java 항목에서 JAR file 을 선택하고 Next 버튼을 클릭합니다.

?f=cfile22.uf%4015157B364ED6E7E736040C.png&size=480


생성한 res 디렉토리에 andengine.jar 파일명으로 지정하고 우상단의 모든 파일을 언체크합니다.

이 때 주의할 것은 우상단의 AndroidManifest.xml 이 체크되면 안된다는 것입니다.

그리고, 좌상단의  AndEngine 폴더에서 libs의 파일들 역시 모두 제외해야 합니다. 왜냐면 이부분에 c와 관련된 so 파일들이 있는데, 그대로 포함해서 jar를 만들면, 차후 이 jar 라이브러리를 사용할때 에러가 발생하게 됩니다.
jar_export.png

 

 
Finish 버튼을 클릭하고 해당 경로에 jar 파일이 정상적으로 생성되었는지 확인합니다. 이제 생성된 andengine.jar를 계속해서 사용할 것입니다.

 

* [ 블랙독의 "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)로 놀러 오세요~~~!!

 

참고자료 : http://saksin.tistory.com/m/post/view/id/903 

 

블랙독의 "AndEngine 강좌"는

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

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

에서 연재되고 있습니다.











androidPub에서 퍼온건데..

실상 엔진을 만들고 jar로 만드는 건 동일 함,