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 프로젝트임에 주의합니다.)
AndEngine 소스가 위치하는 디렉토리를 지정한 후, Finish 버튼을 클릭합니다.
다음과 같은 에러가 발생하면,
프로젝트에서 마우스 우클릭하여 팝업 메뉴를 띄운 후 Properties 를 실행합니다. 그리고 대상 안드로이드를 지정 합니다. AndEngine는 안드로이드 sdk 버전 2.3인 진저브레드 이상에서 컴파일이 잘 됩니다.
4.0 아이스크림에서 해도 되지만 전 진저브레드에서 설치하였습니다. 단, 진저브레드까지만 이클립스에 sdk를 설치해두었다면, AndEngine에서 정의해둔 아이스크림에 대한 부분을 인식하지 못하기 때문에 다음처럼 관련 부분을 몇군데 주석을 달아주어야 정상적으로 jar가 에러 없이 생성됩니다.
만약, @Override 관련하여 에러 메시지가 뜬다면, 마찬가지로 Properties 를 실행하고 Java Compiler 에서 1.6 이상 버전을 선택하여 줍니다.
우리는 진저브레드를 sdk로 선택했기 때문에 소스 중 2군데에 빨간 에러표시가 날 수도 있습니다. AndEngine은 내부적으로 안드로이드의 OS에 따라 처리를 다르게 하는 부분이 있는데, 사용자의 sdk에 아이스크림이 없다면 에러가 뜨게 됩니다. 이 소스 코드를 찾아서 주석 처리를 합니다.
[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 폴더를 추가합니다.
자바 라이브러리인 jar를 생성할 것입니다. 메뉴에서 프로젝트를 선택한 후 File -> Export 를 실행합니다. 그리고 Java 항목에서 JAR file 을 선택하고 Next 버튼을 클릭합니다.
생성한 res 디렉토리에 andengine.jar 파일명으로 지정하고 우상단의 모든 파일을 언체크합니다.
이 때 주의할 것은 우상단의 AndroidManifest.xml 이 체크되면 안된다는 것입니다.
그리고, 좌상단의 AndEngine 폴더에서 libs의 파일들 역시 모두 제외해야 합니다. 왜냐면 이부분에 c와 관련된 so 파일들이 있는데, 그대로 포함해서 jar를 만들면, 차후 이 jar 라이브러리를 사용할때 에러가 발생하게 됩니다.
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로 만드는 건 동일 함,
본 블로그는 페이스북 댓글을 지원합니다.