您的位置:首页 > 移动开发 > Android开发

android 3D 游戏实现之简单碰撞检测

2011-05-19 11:55 796 查看
先还是大体说一下这个程序的原理吧(正方体与球体之间)。

(1)建立相关对象:正方体,3个球体以及为它们铺上纹理

(2)分别为每个对象设定碰撞模式,方法为setCollisionMode(int mode),3个球体为COLLISION_CHECK_OTHERS,cube为COLLISION_CHECK_SELF

(3)将其添加到world对象中,及处理必要的Camera参数

(4)在onDrawFrame函数中进行碰撞处理工作,因为是球体与正方体之间的碰撞,所以采用了相近的椭圆碰撞检测checkForCollisionEllipsoid(如果要用球体检测checkForCollisionSpherical,也能很好工作,这在代码处有相应注释)

下面附上源代码

(1)Activity类

package sim.feel;

import android.app.Activity;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLSurfaceView;
import android.os.Bundle;

/**
* Activity类
*
* @author Administrator
*
*/
public class Basic_collision extends Activity {
private GLSurfaceView glView;
private MyRenderer mr = new MyRenderer();

// onCreate
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 传入Resources方法
LoadBitmap.loadb(getResources());
glView = new GLSurfaceView(this);
glView.setRenderer(mr);
setContentView(glView);
}
}

// 载入位图文件
class LoadBitmap {
public static Bitmap bitmap;

// 载入位图方法
public static void loadb(Resources res) {
bitmap = BitmapFactory.decodeResource(res, R.drawable.icon);
}
}

(2)MyRenderer类

package sim.feel;

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

import android.opengl.GLSurfaceView.Renderer;

import com.threed.jpct.Camera;
import com.threed.jpct.Config;
import com.threed.jpct.FrameBuffer;
import com.threed.jpct.Logger;
import com.threed.jpct.Object3D;
import com.threed.jpct.Primitives;
import com.threed.jpct.RGBColor;
import com.threed.jpct.SimpleVector;
import com.threed.jpct.Texture;
import com.threed.jpct.TextureManager;
import com.threed.jpct.World;
import com.threed.jpct.util.MemoryHelper;

/**
* MyRenderer类
*
* @author Administrator
*
*/
public class MyRenderer implements Renderer {
// FrameBuffer对象
private FrameBuffer fb;
// World对象
private World world;
// RGBColor
private RGBColor back = new RGBColor(50, 50, 100);
// Object3D对象
private Object3D sphere1 = null;
private Object3D sphere2 = null;
private Object3D sphere3 = null;
private Object3D cube = null;

// SimpleVector
// 通过设置组件的x,y,z向量来创建一个SimpleVector对象
private SimpleVector move = new SimpleVector(0, 0.3, 1);
// 被碰撞Object3D的x,y,z(此处该对象为球体)
private SimpleVector ellips = new SimpleVector(7, 7, 7);
private SimpleVector tmp = new SimpleVector();

// FPS
private int fps = 0;
private long time = System.currentTimeMillis();
private boolean stop = false;

// 默认构造
// 对该项目的一些优化
public MyRenderer() {
// 绘制的最多的Polygon数量,默认为4096,此处如果超过500,则不绘制
Config.maxPolysVisible = 500;
// 最远的合适的平面,默认为1000
Config.farPlane = 1500;
// Modifies the multiplicator for the transparency calculations in
// jPCT-AE. The actual formula is trans=offset+objTrans*mul, default for
// offset is 0.1f.
Config.glTransparencyMul = 0.1f;
// Modifies the offset for the transparency calculations in jPCT-AE. The
// actual formula is trans=offset+objTrans*mul, default for offset is
// 0.1f.
Config.glTransparencyOffset = 0.1f;
// 使JPCT-AE这个引擎使用顶点而不是顶点数组缓冲对象,因为它可能会使某些硬件更快
// 但在Samsung Galaxy,它并不能工作的很好,可能使之崩溃,这就是它默认为false的原因
Config.useVBO = true;

Texture.defaultToMipmapping(true);
Texture.defaultTo4bpp(true);
}

public void onDrawFrame(GL10 gl) {
try {
if (!stop) {
// Do collision detections(碰撞检测)

// 第1个参数为cube的移动(translation)
// 第2个参数为碰撞的区域大小(ellips)
// 此处的第3个参数为:递归深度的碰撞检测,较高的值将提高碰撞检测精度,而且降低性能。合理的值介于1和5。
// trsn包含当前的坐标信息
SimpleVector trsn = cube.checkForCollisionEllipsoid(move,
ellips, 5);
// 用下面的球体间碰撞也能很好的工作
// SimpleVector trsn = cube.checkForCollisionSpherical(move, 2);
// "移动这个对象通过改变其在JPCT-AE坐标系下的矩阵"
cube.translate(trsn);
// 如果cube当前z轴坐标大于
// 100,重置当前cube的旋转值到默认值,换言之,没有了旋转
if (cube.getTranslation(tmp).z > 50) {
// 清除旋转
cube.clearTranslation();
// 重置为初始值
cube.translate(10, -40, -30);
}

// 以定义好的RGBColor清屏
fb.clear(back);
// 变换和灯光所有的多边形
world.renderScene(fb);
// 绘制由renderScene产生的场景
world.draw(fb);
// 渲染显示图像
fb.display();
// fps加1
fps++;
// 打印输出fps
if (System.currentTimeMillis() - time > 1000) {
System.out.println(fps + "fps");
fps = 0;
time = System.currentTimeMillis();
}
} else {
if (fb != null) {
fb.dispose();
fb = null;
}
}
} catch (Exception e) {
e.printStackTrace();
// 打印异常信息
Logger.log("Drawing thread terminated!", Logger.MESSAGE);
}
}

public void onSurfaceChanged(GL10 gl, int width, int height) {
if (fb != null) {
fb = null;
}
// 新产生一个FrameBuffer对象
fb = new FrameBuffer(gl, width, height);
}

public void onSurfaceCreated(GL10 gl, EGLConfig config) {
Logger.log("onCreate");
// 混合渲染
gl.glEnable(GL10.GL_BLEND);
gl.glBlendFunc(GL10.GL_ONE, GL10.GL_ONE_MINUS_SRC_ALPHA);
// 新建world对象
world = new World();
// 纹理相关
TextureManager tm = TextureManager.getInstance();
Texture texture2 = new Texture(LoadBitmap.bitmap);
tm.addTexture("texture2", texture2);
// 初始化各3D元素

// 返回一个给定数量的面,第一个20表示面的数量,第二是球体的缩放
sphere1 = Primitives.getSphere(20, 20);
// 以纹理对象的方式给对象包装上纹理
sphere1.calcTextureWrapSpherical();
// 为sphere1设置纹理图片
sphere1.setTexture("texture2");

// 复制当前的Object3D对象
sphere2 = sphere1.cloneObject();
sphere3 = sphere1.cloneObject();
// 返回一个立方体,其中2为其缩放变量
cube = Primitives.getCube(2);
// 以Z轴20处来旋转球体(其实就是向里移动球体)
sphere2.translate(0, 0, 20);
// 以Z轴40处来旋转球体
sphere3.translate(0, 0, 40);

// 以(10, -40, -30)来旋转立方体
cube.translate(10, -40, -30);

cube.setAdditionalColor(RGBColor.GREEN);

// 将3D元素添加到world对象中
world.addObject(sphere1);
world.addObject(sphere2);
world.addObject(sphere3);
world.addObject(cube);

// 建立碰撞模式
sphere1.setCollisionMode(Object3D.COLLISION_CHECK_OTHERS);
world.addObject(sphere1);
sphere2.setCollisionMode(Object3D.COLLISION_CHECK_OTHERS);
world.addObject(sphere1);
sphere3.setCollisionMode(Object3D.COLLISION_CHECK_OTHERS);
world.addObject(sphere1);
// 建立碰撞模式
cube.setCollisionMode(Object3D.COLLISION_CHECK_SELF);

// 设置环境光
world.setAmbientLight(255, 255, 255);
// 编译所有对象
world.buildAllObjects();

// Camera相关
Camera cam = world.getCamera();
// 向里以50的速度移动
cam.moveCamera(Camera.CAMERA_MOVEOUT, 50);
// 向外以60的速度移动
cam.moveCamera(Camera.CAMERA_MOVEUP, 60);
// 以sphere2对象作为中心视角
cam.lookAt(sphere2.getTransformedCenter());

// 回收内存
MemoryHelper.compact();
}
}

运行效果如下图所示:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐