3D物體的碰撞和2D類似,都是根據座標來計算物體的距離,判斷是否碰撞。下面舉個簡單的列子吧,我這個列子比較局限,簡單,只是為了說明這個方法而已,大家可以參照方法進行改進,下面看看代碼吧。
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:id="@+id/main_liner" android:layout_width="fill_parent" android:layout_height="fill_parent"></LinearLayout>
package yy.cal;import android.app.Activity;import android.os.Bundle;import android.widget.LinearLayout;public class GLSurfaceViewActivity extends Activity {private MySurfaceView mSurfaceView;//聲明MySurfaceView對象 public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mSurfaceView=new MySurfaceView(this);//建立MySurfaceView對象 mSurfaceView.requestFocus();//擷取焦點 mSurfaceView.setFocusableInTouchMode(true);//設定為可觸控 LinearLayout ll=(LinearLayout)this.findViewById(R.id.main_liner);//獲得線性布局的引用 ll.addView(mSurfaceView); }@Overrideprotected void onPause() {// TODO Auto-generated method stubsuper.onPause();mSurfaceView.onPause();}@Overrideprotected void onResume() {// TODO Auto-generated method stubsuper.onResume();mSurfaceView.onResume();} }
package yy.cal;import javax.microedition.khronos.egl.EGLConfig;import javax.microedition.khronos.opengles.GL10;import android.content.Context;import android.opengl.GLSurfaceView;import android.opengl.GLU;import android.view.KeyEvent;import android.view.MotionEvent;public class MySurfaceView extends GLSurfaceView{private final float TOUCH_SCALE_FACTOR = 180.0f/320;//角度縮放比例 private SceneRenderer mRenderer;//情境渲染器 private float mPreviousX;//上次的觸控位置X座標public MySurfaceView(Context context) { super(context); mRenderer = new SceneRenderer();//建立情境渲染器 setRenderer(mRenderer);//設定渲染器 setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);//設定渲染模式為主動渲染 }//觸摸事件回調方法 @Override public boolean onTouchEvent(MotionEvent e) { float x = e.getX(); switch (e.getAction()) { case MotionEvent.ACTION_MOVE: float dx = x - mPreviousX;//計算觸控筆X位移 mRenderer.angle += dx * TOUCH_SCALE_FACTOR;//設定沿x軸旋轉角度 requestRender(); //重繪畫面 } mPreviousX = x;//記錄觸控筆位置 return true; }public boolean onKeyDown(int keyCode,KeyEvent event){if(keyCode==KeyEvent.KEYCODE_DPAD_UP){mRenderer.x +=0.5f;}if(keyCode==KeyEvent.KEYCODE_DPAD_DOWN){mRenderer.x -=0.5f;}if(keyCode==KeyEvent.KEYCODE_DPAD_LEFT){ mRenderer.angle+=90;}if(keyCode==KeyEvent.KEYCODE_DPAD_RIGHT){ mRenderer.angle+=90;}return super.onKeyDown(keyCode, event);}private class SceneRenderer implements GLSurfaceView.Renderer { Cube cube=new Cube();//立方體 float angle=45;//總旋轉角度 float x=0,y=0,z=0; public void onDrawFrame(GL10 gl) { //設定為開啟背面剪裁 gl.glEnable(GL10.GL_CULL_FACE); //設定著色模型為平滑著色 gl.glShadeModel(GL10.GL_SMOOTH); //清除顏色緩衝於深度緩衝 gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); //設定當前矩陣為模式矩陣 gl.glMatrixMode(GL10.GL_MODELVIEW); //設定當前矩陣為單位矩陣 gl.glLoadIdentity(); GLU.gluLookAt//不太可能變形的視角——小視角 ( gl, 0f, //人眼位置的X 10f, //人眼位置的Y 15.0f, //人眼位置的Z 0, //人眼球看的點X 0f, //人眼球看的點Y 0, //人眼球看的點Z 0, 1, 0 ); //旋轉總座標系 gl.glRotatef(angle, 0, 1, 0); //繪製右立方體 gl.glPushMatrix(); gl.glTranslatef(x, y, z); cube.drawSelf(gl); gl.glPopMatrix(); gl.glPushMatrix(); gl.glTranslatef(2, 0, 0); cube.drawSelf(gl); gl.glPopMatrix(); if(x>1.0f&&x<3.0f){ ColorRect.flag=false; }else{ ColorRect.flag=true; } } public void onSurfaceChanged(GL10 gl, int width, int height) { //設定視窗大小及位置 gl.glViewport(0, 0, width, height); //設定當前矩陣為投影矩陣 gl.glMatrixMode(GL10.GL_PROJECTION); //設定當前矩陣為單位矩陣 gl.glLoadIdentity(); //計算透視投影的比例 float ratio = (float) height/width ; //調用此方法計算產生透視投影矩陣 //gl.glFrustumf( -1, 1,-ratio, ratio, 1, 100); //可能變形的視角——大視角 gl.glFrustumf( -1, 1,-ratio, ratio, 8f, 100); //不太可能變形的視角——小視角 } public void onSurfaceCreated(GL10 gl, EGLConfig config) { //關閉抗抖動 gl.glDisable(GL10.GL_DITHER); //設定特定Hint項目的模式,這裡為設定為使用快速模式 gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT,GL10.GL_FASTEST); //設定螢幕背景色黑色RGBA gl.glClearColor(0,0,0,0); //啟用深度測試 gl.glEnable(GL10.GL_DEPTH_TEST); } }}
package yy.cal;import javax.microedition.khronos.opengles.GL10;import static yy.cal.Constant.*;public class Cube {//用於繪製各個面的顏色矩形ColorRect cr=new ColorRect(SCALE,SCALE);public void drawSelf(GL10 gl){//總繪製思想:通過把一個顏色矩形旋轉移位到立方體每個面的位置//繪製立方體的每個面gl.glPushMatrix();//繪製前小面gl.glPushMatrix();gl.glTranslatef(0, 0, UNIT_SIZE*SCALE);cr.drawSelf(gl);gl.glPopMatrix();//繪製後小面gl.glPushMatrix();gl.glTranslatef(0, 0, -UNIT_SIZE*SCALE);gl.glRotatef(180, 0, 1, 0);cr.drawSelf(gl);gl.glPopMatrix();//繪製上大面gl.glPushMatrix();gl.glTranslatef(0,UNIT_SIZE*SCALE,0);gl.glRotatef(-90, 1, 0, 0);cr.drawSelf(gl);gl.glPopMatrix();//繪製下大面gl.glPushMatrix();gl.glTranslatef(0,-UNIT_SIZE*SCALE,0);gl.glRotatef(90, 1, 0, 0);cr.drawSelf(gl);gl.glPopMatrix();//繪製左大面gl.glPushMatrix();gl.glTranslatef(UNIT_SIZE*SCALE,0,0);gl.glRotatef(-90, 1, 0, 0);gl.glRotatef(90, 0, 1, 0);cr.drawSelf(gl);gl.glPopMatrix();//繪製右大面gl.glPushMatrix();gl.glTranslatef(-UNIT_SIZE*SCALE,0,0);gl.glRotatef(90, 1, 0, 0);gl.glRotatef(-90, 0, 1, 0);cr.drawSelf(gl);gl.glPopMatrix();gl.glPopMatrix();}}
package yy.cal;import java.nio.ByteBuffer;import java.nio.ByteOrder;import java.nio.FloatBuffer;import java.nio.IntBuffer;import javax.microedition.khronos.opengles.GL10;public class ColorRect {private FloatBuffer mVertexBuffer;//頂點座標資料緩衝 private IntBuffer mColorBuffer,mColorBuffer1,mColor;//頂點著色資料緩衝 int vCount=0;//頂點數量 static boolean flag=true; public ColorRect(float width,float height) { //頂點座標資料的初始化================begin============================ vCount=6; final float UNIT_SIZE=1.0f; float vertices[]=new float[] { 0,0,0, width*UNIT_SIZE,height*UNIT_SIZE,0, -width*UNIT_SIZE,height*UNIT_SIZE,0, -width*UNIT_SIZE,-height*UNIT_SIZE,0, width*UNIT_SIZE,-height*UNIT_SIZE,0, width*UNIT_SIZE,height*UNIT_SIZE,0 }; //建立頂點座標資料緩衝 //vertices.length*4是因為一個整數四個位元組 ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length*4); vbb.order(ByteOrder.nativeOrder());//設定位元組順序 mVertexBuffer = vbb.asFloatBuffer();//轉換為Float型緩衝 mVertexBuffer.put(vertices);//向緩衝區中放入頂點座標資料 mVertexBuffer.position(0);//設定緩衝區起始位置 //特別提示:由於不同平台位元組順序不同資料單元不是位元組的一定要經過ByteBuffer //轉換,關鍵是要通過ByteOrder設定nativeOrder(),否則有可能會出問題 //頂點座標資料的初始化================end============================ //頂點著色資料的初始化================begin============================ final int one = 65535; int colors[]=new int[]//頂點顏色值數組,每個頂點4個色彩值RGBA { one,one,one,0, 0,0,one,0, 0,0,one,0, 0,0,one,0, 0,0,one,0, 0,0,one,0, }; //建立頂點著色資料緩衝 //vertices.length*4是因為一個int型整數四個位元組 ByteBuffer cbb = ByteBuffer.allocateDirect(colors.length*4); cbb.order(ByteOrder.nativeOrder());//設定位元組順序 mColorBuffer = cbb.asIntBuffer();//轉換為int型緩衝 mColorBuffer.put(colors);//向緩衝區中放入頂點著色資料 mColorBuffer.position(0);//設定緩衝區起始位置 int colors1[]=new int[] { 0,0,one,0, 0,0,one,0, 0,0,one,0, one,one,one,0, 0,0,one,0, 0,0,one,0, }; ByteBuffer cbb1 = ByteBuffer.allocateDirect(colors1.length*4); cbb1.order(ByteOrder.nativeOrder()); mColorBuffer1 = cbb1.asIntBuffer();//轉換為int型緩衝 mColorBuffer1.put(colors1);//向緩衝區中放入頂點著色資料 mColorBuffer1.position(0);//設定緩衝區起始位置 //特別提示:由於不同平台位元組順序不同資料單元不是位元組的一定要經過ByteBuffer //轉換,關鍵是要通過ByteOrder設定nativeOrder(),否則有可能會出問題 //頂點著色資料的初始化================end============================ } public void drawSelf(GL10 gl) { gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);//啟用頂點座標數組 gl.glEnableClientState(GL10.GL_COLOR_ARRAY);//啟用頂點顏色數組 //為畫筆指定頂點座標資料 gl.glVertexPointer ( 3,//每個頂點的座標數量為3 xyz GL10.GL_FLOAT,//頂點座標值的類型為 GL_FIXED 0, //連續頂點座標資料之間的間隔 mVertexBuffer//頂點座標資料 ); if(flag){ mColor=mColorBuffer; }else{ mColor=mColorBuffer1; } //為畫筆指定頂點著色資料 gl.glColorPointer ( 4, //設定顏色的組成成分,必須為4—RGBA GL10.GL_FIXED, //頂點顏色值的類型為 GL_FIXED 0, //連續頂點著色資料之間的間隔 mColor//頂點著色資料 ); //繪製圖形 gl.glDrawArrays ( GL10.GL_TRIANGLE_FAN, //以三角形方式填充 0, //開始點編號 vCount//頂點的數量 ); }}
package yy.cal;public class Constant { public static final float UNIT_SIZE=1.0f;//單位尺寸 public static final float SCALE=0.5f;//尺寸縮放比}