Sunday, December 12, 2010

Chỉ dẫn lập trình game 3D trên Android (P5)

Đang chờ deploy cái web viết tiếp loạt bài về OpenGL vậy.
Bài hôm nay tôi sẽ giới thiệu cho các bạn cách vẽ một hình đa giác cách xoay chúng như thế nào. Bài trước các bạn đã được học về GLSurfaceView và hãy chắc chắn rằng bạn đã đọc nó vì nó rất quan trọng cho bài hôm nay.
Loạt bài trước tôi cũng đã giới thiệu với các bạn một số khái niệm về đỉnh, tam giác, đa giác. Hôm nay trước khi vào vẽ đa giác tôi sẽ giới thiệu cho các bạn thêm một số khái niệm khác.
1, Cạnh:
Cạnh là một đường thẳng nối 2 đỉnh với nhau. Chúng là đường viền của mặt và đa giác. Trong không gian 3D một cạnh có thể là một đường giao nhau của 2 mặt, do đó khi cạnh này chuyển đổi sẽ dẫn đến sự thay đổi theo của các đỉnh, các mặt kết nối với chúng.
Trong OpenGL ES bạn không định nghĩa các cạnh, thay vào đó bạn định nghĩa các mặt bởi các đỉnh khi đó ta sẽ có các cạnh.
Nếu bạn muốn sửa, thay đổi mộ cạnh bạn có thể thay đổi 2 đỉnh tạo nên cạnh đó.
2, Mặt:
Một cách tổng quát, mặt trong toán học là đa tạp n-1 chiều trong không gian n chiều. Trong tô pô, một mặt hai chiều được gọi là mặt đơn giản nếu nó đồng phôi với một hình vuông trên mặt phẳng hai chiều.
Ví dụ: mặt bán cầu là một mặt đơn giản, còn toàn bộ mặt cầu lại không phải là một mặt đơn giản.
Trong không gian ba chiều, mặt được mặc định là đa tạp hai chiều, là tập hợp những điểm trong hệ tọa độ Đề các ba chiều Oxyz thỏa phương trình: z = f(x,y).
Trong OpenGL ES ta hiểu rằng có thể chia mặt tới mức nhỏ nhất khi đó một mặt chỉ là một tam giác, chúng được tạo lên bởi 3 đỉnh, một chuyển đổi của mặt sẽ ảnh hưởng tới các đỉnh, cạnh liên kết với nó.
Khi uốn khúc trên bề mặt của bạn điều này rất quan trọng để thực hiện các điều khiển đúng hướng của nó. Khi đó bạn phải điều khiển những gì sẽ sảy ra với mặt phía trước và cả mặt phía sau nữa. Tại sao điều này lại rất quan trọng bởi vì hiệu năng của ứng dụng sẽ tăng lên khi bạn không phải vẽ cả 2 mặt mà chỉ thực hiện vẽ mặt phía trước. Đó là ý tưởng tốt sử dụng sự uốn khúc cho tất cả các dự án của bạn. Bạn có thể định nghĩa phía trên của bề mặt bằng cách.
gl.glFrontFace(GL10.GL_CCW); // OpenGL docs
gl.glEnable(GL10.GL_CULL_FACE); // OpenGL docs
gl.glCullFace(GL10.GL_BACK); // OpenGL docs

3, Render:
Thời gian để bạn đưa một cái j đó ra ngoài màn hình, có 2 phương thức để bạn làm điều này, 2 phương thức đó là:
public abstract void glDrawArrays(int mode, int first, int count); // OpenGL docs

public abstract void glDrawElements(int mode, int count, int type, Buffer indices); // OpenGL docs

Một số render cơ bản nhất:
GL_POINTS: Render một điểm ra màn hình.
GL_LINE_STRIP: Render một dãy các phân đoạn đường thẳng nối liền nhau, nhưng không nối điểm đầu và điểm cuối.
GL_LINE_LOOP: Giống như GL_LINE_STRIP nhưng không nối điểm đầu và điểm cuối.
GL_LINES: Render một đường thẳng.
GL_TRIANGLES: Render một tam giác.
GL_TRIANGLE_STRIP: Render một loạt các tam giác theo thứ tự VD: Ta có các đỉnh v0, v1, v2, v3, v4, v5 khi đó các tam giác được render là (v0, v1, v2) sau đó là (v2, v1, v3) (lưu ý thứ tự), tiếp theo là (v2, v3, v4) ...
Gl_triangle_strip
GL_TRIANGLE_FAN: Render một loạt các tam giác giống như GL_TRIANGLE_STRIP nhưng các tam giác được vẽ giống như một hình quạt dựa vào một gốc.
Gl_triangle_strip

Giờ chúng ta sẽ vẽ thử một tam giác:
Bạn vẫn còn project hôm trước chứ, ta sẽ thay đổi một chút để có thể render ra được một tam giác.
Ta chỉ cần sửa lại lớp VortexRenderer lại như sau:

package vn.vndev.android.opengl;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.opengl.GLSurfaceView;

/**
 * 
 * @author TanNM
 * 
 */
public class VortexRenderer implements GLSurfaceView.Renderer {
 private static final String LOG_TAG = VortexRenderer.class.getSimpleName();

 private float red = 0f;
 private float green = 0f;
 private float blue = 0f;

 // a raw buffer to hold indices allowing a reuse of points.
 private ShortBuffer indexBuffer;

 // a raw buffer to hold the vertices
 private FloatBuffer vertexBuffer;

 private short[] indicesArray = { 0, 1, 2 };
 private int nrOfVertices = 3;

 private float angle;

 @Override
 public void onSurfaceCreated(GL10 gl, EGLConfig config) {
  // preparation
  gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
  initTriangle();
 }

 @Override
 public void onSurfaceChanged(GL10 gl, int w, int h) {
  gl.glViewport(0, 0, w, h);
 }

 public void setAngle(float angle) {
  this.angle = angle;
 }

 @Override
 public void onDrawFrame(GL10 gl) {
  // define the color we want to be displayed as the "clipping wall"
  gl.glClearColor(red, green, blue, 1.0f);

  // clear the color buffer to show the ClearColor we called above...
  gl.glClear(GL10.GL_COLOR_BUFFER_BIT);

  // set rotation
  gl.glRotatef(angle, 0f, 1f, 0f);

  gl.glColor4f(0.2f, 0.5f, 0.2f, 0.5f);
  gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
  gl.glDrawElements(GL10.GL_TRIANGLES, nrOfVertices,
    GL10.GL_UNSIGNED_SHORT, indexBuffer);
 }

 private void initTriangle() {
  // float has 4 bytes
  ByteBuffer vbb = ByteBuffer.allocateDirect(nrOfVertices * 3 * 4);
  vbb.order(ByteOrder.nativeOrder());
  vertexBuffer = vbb.asFloatBuffer();

  // short has 4 bytes
  ByteBuffer ibb = ByteBuffer.allocateDirect(nrOfVertices * 2);
  ibb.order(ByteOrder.nativeOrder());
  indexBuffer = ibb.asShortBuffer();

  float[] coords = { -0.5f, -0.5f, 0f, // (x1, y1, z1)
    0.5f, -0.5f, 0f, // (x2, y2, z2)
    0f, 0.5f, 0f // (x3, y3, z3)
  };
  vertexBuffer.put(coords);
  indexBuffer.put(indicesArray);
  vertexBuffer.position(0);
  indexBuffer.position(0);
 }

 public void setColor(float r, float g, float b) {
  red = r;
  green = g;
  blue = b;
 }
}

Để hình tam giác của ta quay với tốc độ tùy vào vị chí mà ta click ta set thêm góc giống như
renderer.setAngle((event.getX() + event.getY()) / 20);
trong phương thức
public boolean onTouchEvent(final MotionEvent event)
của lớp VortexView

Bạn có thể download mã nguồn của ứng dụng về chạy thử.

Friday, December 3, 2010

Chỉ dẫn lập trình game 3D trên Android (P4)

Chúc các bạn một ngày tốt lành, hôm qua đi đá bóng về đau chân quá ko làm việc được nên ngồi viết bài tiếp vậy!
Hôm trước ứng bài demo chạy tốt chứ? Hôm nay tôi sẽ giải thích sơ qua một chút về ứng dụng đó.
1, Trước hết là lớp GLSurfaceView:
Bắt đầu được hỗ trợ trên Android từ phiên bản 1.5.
Lớp này hỗ trợ bạn kết nối vào OpenGL từ view bằng cách quản lý một bề mặt và ghép chúng vào hệ thống view của Android. Nó quản lý một EGL display, cho phép OpenGL thực hiện render vào một bề mặt.
Tạo khả năng giúp OpenGL ES làm việc với vòng đời của Activity.
Tạo khả năng lựa chọn định dạng frame buffer pixel một cách thích hợp.
Quản lý các thread rendering riêng biệt cho phép tạo các chuyển động mượt mà :D.
Cung cấp tools debugging một cách đơn giản cho tracing các lời gọi API OpenGL ES và kiểm tra lỗi.

Bạn muốn tiến xa hơn trong OpenGL thì đây là nơi mà bạn cần phải bắt đầu.
Để sử dụng GLSurfaceView bạn chỉ cần gọi phương thức:
 public void  setRenderer(GLSurfaceView.Renderer renderer);
 
có trong GLSurfaceView. Để tùy biến các thuộc tính của GLSurfaceView thì trước khi gọi phương thức setRenderer bạn có thể gọi một số các phương thức khác như:
 setDebugFlags(int);
 setEGLConfigChooser(boolean);
 setEGLConfigChooser(EGLConfigChooser);
 setEGLConfigChooser(int, int, int, int, int, int);
 setGLWrapper(GLWrapper);
 
Mặc định GLSurfaceView sẽ tạo một bề mặt với định dạng mặc định là PixelFormat.RGB_565. Nếu bạn cần một bề mặt trong suốt bạn có thể gọi phương thức getHolder().setFormat(PixelFormat.TRANSLUCENT).
Một GLSurfaceView phải được thông báo khi Activity là paused và resumed. GLSurfaceView clients cần phải gọi phương thức onPause() khi activity pauses và gọi onResume() khi activity resumes. Lời gọi cho phép GLSurfaceView thực hiện pause hay resume các thread rendering, và nó cũng cho phép GLSurfaceView release hay khởi tạo lại các đối tượng OpenGL display.

2, GLSurfaceView.Renderer:
Là một render interface.
Render sẽ được gọi trên một thread riêng biệt vì thế hiệu năng rendering sẽ tách rời UI thread. Nhưng các render cần giao tiếp với các UI thread bởi vì UI thread là nơi nhận được các sự kiện input. Các render có thể giao tiếp bằng bất kỳ kỹ thuật java chuẩn nào cho giao tiếp cross-thread, hoặc đơn giản hơn là sử dụng phương thức queueEvent(Runnable).
Khi bạn implementation render này bạn cần khai báo các phương thức sau:
 // Gọi khi một bề mặt được khởi tạo hay khởi tạo lại
 public void onSurfaceCreated(GL10 gl, EGLConfig config) 

 // Gọi để vẽ frame hiện tại.
 // Phương thức này sẽ chịu trách nhiệm vẽ frame hiện tại.
 public void onDrawFrame(GL10 gl)

 // Gọi khi bề mặt thay đổi kích thước
 public void onSurfaceChanged(GL10 gl, int width, int height)
 

onSurfaceCreated: Đây là nơi tốt để bạn cài đặt một điều gì đó mà bạn không thường xuyên thay đổi trong vòng đời của rendering.
onDrawFrame: Đây là nơi sự kiện vẽ thực sự diễn ra.
onSurfaceChanged: Nếu thiết bị của bạn cho phép chuyển giữa màn hình nằm ngang hay nằm dọc, bạn sẽ có lời gọi tới phương thức này khi sự chuyển đổi đó diễn ra. Bạn có thể thiết lập lại các tỷ lệ mới ở đây

Bạn có thể download mã nguồn của bài trước và bài này tại đây

Thursday, December 2, 2010

Chỉ dẫn lập trình game 3D trên Android (P3)

Hôm nay tôi sẽ chỉ các bạn lập trình OpenGL trong Android, cách sử dụng OpenGL trong cả 2 ngôn ngữ Java và C. Điều này rất quan trọng trong việc tái sử dụng mã nguồn trong Java và C cũng như sử dụng được các tính năng tốt nhất mà mỗi ngôn ngữ cung cấp.
Bất kỳ một nhà phát triển game nào cũng cần phải biết OpenGL là kim chỉ nam cho nhưng nhà phát triển game chuyên nghiệp. Bạn khó có thể tìm thấy một game mạnh mẽ nào mà không sử dụng API của OpenGl, bởi vì nó có khả năng tận dụng và tăng tốc phần cứng hơn hầu hết tất cả các phần mềm renderer khác.
OpenGL có thể là một môn học đáng sợ cho người mới bắt đầu (that's true for me :D). Nhưng bạn cũng không thể thành thạo OpenGL tới mức biết được làm thế nào để nó có thể vẽ các phần tử đó với OpenGL API. Bạn chỉ cần sự ham học hỏi, mong muốn tìm hiểu một công cụ mạnh mẽ để xây dựng các ứng dụng đồ họa như game.
Trong giới hạn của bài này tôi không thể chỉ bạn tất cả về OpenGL mà tôi chỉ đưa ra ví dụ sử dụng chúng trong ứng dụng Android, dựa vào đó và các API của OpenGL bạn có thể tùy biến theo ý của bạn.
Tham khảo thêm về OpenGL tại:
http://www.opengl.org/sdk/docs/man/
http://www.falloutsoftware.com/tutorials/gl/gl0.htm
http://mathworld.wolfram.com/OrthographicProjection.html
http://nehe.gamedev.net/

Về thiết bị thì khỏi bàn, hiện nay Android ngày càng trở nên mạnh mẽ cho việc phát triển các ứng dụng đồ họa.
Để tận dụng tối đa hiệu năng của CPU, Google đã đưa OpenGL Embedded System (OpenGL-ES) vào trong hệ điều hành Android.
OpenGL-ES cung cấp một loạt các API làm cho game có hiệu năng sử lý cao, tăng tốc phần cứng. Đây là các Java API, để xây dựng lại chúng từ C là một công việc rất phức tạp. Tôi sẽ chỉ các bạn cách thức làm việc trên cả Java và C.
Bắt đầu bằng một số khái niệm cơ bản về OpenGL

1, Đỉnh: là một điểm trong không gian 3D trong OpenGl có thể chỉ là 2 tọa độ (x, y) hoặc nhiều tọa độ như (x, y, z, w) ở đó w là tùy chọn và mặc định nó có giá trị là 1.0, tương tự trục z cũng là tùy chọn và giá trị mặc định của nó là 0. Tất các các đối tượng được vẽ bởi các đỉnh hay chính là các điểm, do đó kho nói tới điểm cũng chính là 1 đỉnh.
2, Tam giác: được tạo nên bởi 3 điểm, trong OpenGL chúng ta có thể dùng 3 đỉnh để tạo nên 1 tam giác.
3, Đa giác: được tạo nên bởi nhiều hơn 2 điểm, tam giác cũng là 1 đa giác.

Nào trước hết chúng ta bắt đầu chúng với Java:
Tạo một Android project mới, với activity là Vortex và một số các lớp sau:
package vn.vndev.android.opengl;

import android.app.Activity;
import android.os.Bundle;

/**
 * 
 * @author TanNM
 *
 */
public class Vortex extends Activity {
 private static final String LOG_TAG = Vortex.class.getSimpleName();
 private VortexView vortexView;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  // Hien thi toan man hinh
  this.requestWindowFeature(Window.FEATURE_NO_TITLE); 
  getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
    WindowManager.LayoutParams.FLAG_FULLSCREEN);
  vortexView = new VortexView(this);
  setContentView(vortexView);
 }
}
package vn.vndev.android.opengl;

import android.content.Context;
import android.opengl.GLSurfaceView;
import android.view.MotionEvent;

/**
 * 
 * @author TanNM
 *
 */
public class VortexView extends GLSurfaceView {
 private static final String LOG_TAG = VortexView.class.getSimpleName();
 private VortexRenderer renderer;

 /**
  * 
  * @param context
  */
 public VortexView(Context context) {
  super(context);
  renderer = new VortexRenderer();
  setRenderer(renderer);
 }

 public boolean onTouchEvent(final MotionEvent event) {
  queueEvent(new Runnable() {
   public void run() {
    renderer.setColor(event.getX() / getWidth(), event.getY() / getHeight(), 1.0f);
   }
  });
  return true;
 }
}
package vn.vndev.android.opengl;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.opengl.GLSurfaceView;

/**
 * 
 * @author TanNM
 *
 */
public class VortexRenderer implements GLSurfaceView.Renderer {
 private static final String LOG_TAG = VortexRenderer.class.getSimpleName();

 private float red = 0.7f;
 private float green = 0.5f;
 private float blue = 0.8f;

 @Override
 public void onSurfaceCreated(GL10 gl, EGLConfig config) {
  gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
 }

 @Override
 public void onSurfaceChanged(GL10 gl, int w, int h) {
  gl.glViewport(0, 0, w, h);
  float ratio = (float) w / h;
  gl.glMatrixMode(GL10.GL_PROJECTION);
  gl.glLoadIdentity();
  gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);
 }

 @Override
 public void onDrawFrame(GL10 gl) {
  gl.glClearColor(red, green, blue, 1.0f);
  gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
 }

 public void setColor(float r, float g, float b) {
  red = r;
  green = g;
  blue = b;
 }
}
Ok giờ bạn hãy chạy thử ứng dụng và click lên các vị trí khác nhau của màn hình. Thấy j nhỉ?

Friday, November 26, 2010

Tối ưu hóa ứng dụng J2ME

Ứng dụng trên J2ME thường bị chậm bởi hạn chế về bộ nhớ, vậy làm sao để chúng ta có thể tối ưu hóa ứng dụng J2ME của mình. Đây là một số chỉ dẫn có ích cho bạn:
1, Khởi tạo và hủy bỏ đối tượng: Khi tạo một đối tượng bằng từ khóa new chúng sẽ chiếm một bộ nhớ của thiết bị do đó chỉ nên tạo đối tượng khi cần thiết, nên sử dụng lại các đối tượng đã có. Không nên tạo đối tượng trong các vòng lặp

for (int i = 0; i < length; i++) {
ClassName p = new ClassName ();
results[i] = p.calculateResult();
}


Chú ý: Khi sử dụng toán tử "+" với các chuỗi String nhỏ khi đó nó sẽ tạo ra các đối tượng String không cần thiết vì thế nếu sử dụng thao tác với chuỗi tôi khuyến cáo các bạn nên dùng StringBuffers hoặc mảng char

2, Trong vòng lặp bạn không nên sử dụng các thuật toán phức tạp, các tính toán trong vòng lặp. Một số cách khai báo vòng lặp tối ưu:


//Một vòng lặp tồi (Vòng lặp a)
for (int i = 0; i < v.size(); i++) {
// Do something
}
//Tốt hơn vòng lặp a (Vòng lặp b)
int size = v.size();
for (int i = 0; i < size; i++) {
// Do something
}
//Tốt hơn vòng lặp b (Vòng lặp c)
for (int i = 0,n = v.size(); i < n; i++) {
// Do something
}
/* Nếu thứ tự trong đối tượng bạn duyệt không quan trọng, bạn hãy duyệt ngược lại như bên dưới để tranh các biến local trong stack. So sánh với 0 luôn hiệu quả nhất trong các ngôn ngữ */
//Tốt hơn vòng lặp c
for( int i = v.size() - 1; i >= 0; i-- ) {
// Do something
}


3, Phân chia ứng dụng của bạn ra: Một MIDP trong thời gian thực thi sẽ load các lớp mà chúng cần, khi đó nếu một lớp lớn sẽ làm tốn bộ nhớ hơn. Hãy chia ra các lớp nhỏ nếu có thể.
Trong câu lệnh import, chỉ rõ lớp mà bạn sử dụng, không nên để như vn.vndev.mzone.util.* mà nên để như vn.vndev.mzone.util.StringUtil
Khai báo biến, khai báo là public nếu có thể bởi vì khi bạn khai báo private bạn sẽ phải truy xuất chúng thông qua phương thức getter và setter khi đó sẽ tốn hiệu năng hơn.

4, Tránh sử dụng thread, khi sử dụng một vài synchronization, hiệu năng của hệ thống sẽ giảm xuống 2/3 lần

5, Sử dụng lại các thành phần giao diện giống như Forms,TextBox... thay vì khởi tạo chúng nếu có thể, điều này làm giảm bộ nhớ sử dụng của ứng dụng.

6, Tránh thường xuyên mở Recordstores

7, Sử dụng loại phù hợp cho biến trong J2ME, như vậy sẽ tránh lãng phí bộ nhớ RAM

8, Sử dụng lại biến: Cố gắng sử dụng lại biến cang nhiều càng tốt, bởi vì tạo nhiều biến làm giảm hiệu năng và tốn dung lượng bộ nhớ. Bằng cách khai báo các biến global và nhớ ko làm ảnh hưởng tới design của lớp.

9, Chia các mảng đa chiều thành các mảng 1 chiều, truy xuất mảng đa chiều luôn làm giảm hiệu năng hệ thống.

10, Tính toán: Nên sử dụng các toán tử dịc bit thay vì dùng các toán tử bình thường khác ví dụ: sử dụng int a = 11<< 1 thay vì dùng int a = 11* 2.
Thay vì nhân chia ta nên sử dụng cộng và trừ càng nhiều càng tốt.

11, Sử dụng lời gọi Native Methods: giống như String.indexOf(), String.lastIndexOf()

12, Sử dụng obfuscater trong ứng dụng của bạn.
Đừng gọi garbage collector trong chương trình của bạn:
System.gc();

Tránh sử dụng synchronization.

13, Cố gắng giữ tính đa hình của đối tượng bằng các interface.

14, Sử dụng Singleton Design Pattern.

Thursday, November 18, 2010

Chỉ dẫn lập trình game 3D trên Android (P2)

Bài hôm nay tôi sẽ hướng dẫn các bạn biên dịch native code trong ứng dụng Android.
JNI là viết tắt của Java Native Interface. Sử dụng JNI chúng ta có thể gọi các hàm được viết trong những ngôn ngữ khác từ Java.
Trước hết bạn tạo một Android project tạo một activity MainActivity:

package com.vndev.jni.activities;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import jni.Natives;

import android.app.Activity;
import android.os.Bundle;

public class MainActivity extends Activity {
    private static final String LIB = "libch02.so";
    private static final String LIB_PATH = "/data/data/com.vndev.jni.activities/files/" + LIB;

    /** Called when the activity is first created. */

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

        try {

            // Install lib

            System.out.println("Installing LIB: " + LIB);

            // Copy lib from assests folder to files folder:

            // /data/data/PKG_NAME/files

            writeToStream(getAssets().open(LIB), openFileOutput(LIB, 0));

            // Load Lib

            System.load(LIB_PATH);

            // Run it

            String[] argv = { "MyLib", "arg1", "arg2" };

            Natives.LibMain(argv);

        } catch (Exception e) {

            e.printStackTrace();

        }

    }



    /**

     * Write to a stream

     * 

     * @param in

     * @param out

     * @throws IOException

     */

    public static void writeToStream(InputStream in, OutputStream out)

            throws IOException {

        byte[] bytes = new byte[2048];

        for (int c = in.read(bytes); c != -1; c = in.read(bytes)) {

            out.write(bytes, 0, c);

        }

        in.close();

        out.close();

    }

}

Trong activity này ta sẽ load thư viện từ C vào bằng cách gọi:

System.load(LIB_PATH);


Activity này gọi một phương thức trong lớp Natives:
Natives.LibMain(argv);


Phương thức này được khai báo:
public static native int LibMain(String[] argv);


Phương thức này có từ khóa native, nó sẽ gọi phương thức LibMain trong thư viên được load ở trên.
Toàn bộ nội dung class Natives sẽ như sau:
package jni;

public class Natives {
    /**
     * Native Main Doom Loop
     * @param argv
     * @return
     */
    public static native int LibMain(String[] argv);
    
    /**
     * This fires on messages from the C layer
     * @param text
     */
    @SuppressWarnings("unused")
    private static void OnMessage(String text, int level) {
        System.out.println("OnMessage text:" + text + " level=" + level);
    }
}

Để tạo file header cho lớp này ta sử dụng javah trong java như sau
Javah -jni Natives


Khi đó ta có file header như sau
/* DO NOT EDIT THIS FILE - it is machine generated */

#include 

/* Header for class jni_Natives */



#ifndef _Included_jni_Natives

#define _Included_jni_Natives

#ifdef __cplusplus

extern "C" {

#endif

/*

 * Class:     jni_Natives

 * Method:    LibMain

 * Signature: ([Ljava/lang/String;)I

 */

JNIEXPORT jint JNICALL Java_jni_Natives_LibMain

  (JNIEnv *, jclass, jobjectArray);



//implements method call by java native



#ifdef __cplusplus

}

#endif

#endif



Giờ bạn cần tạo một file C khác dựa vào khai báo trên cài đặt phương thức này trong C và biên dịch chúng, chạy để thấy kết quả.

Download source

Thursday, November 11, 2010

Chỉ dẫn lập trình game 3D trên Android (P1)

Trước khi bạn bắt đầu, hãy chuẩn bị cho mình một số kỹ năng cần thiết để bắt đầu:
Về ngôn ngữ lập trình, không chỉ Java mà bạn cần biết cả ngôn ngữ lập trình C.
Bởi vì Java cho bạn cách thức lập trình hướng đối tượng và nó chạy trên Android, nhưng chỉ có C mới có sức mạnh mà một lập trình viên games cần tới.
Một số kỹ năng cứng bạn cần biết trong Android là:
    Activities, view, layout....
    Services.
    Content providers.
    Broadcast receivers.
Một số kỹ năng khác là: Hiểu biết cơ bản về Linux và shell scripting:
    Bạn cần biết một số câu lệnh cơ bản như: liệt kê các file, cài đặt một thành phần, một ứng dụng...

Yêu cầu về phần mềm:
    Hệ điều hành Ubuntu.
    Eclipse.
    Android SDK.
    Java JDK.
(Còn tiếp)