Android游戏——引擎Box2D
Box2D是以手机屏幕左上方(0,0)为物理世界的中心坐标。在该物理世界中创建一个物体,一般默认左上角(0,0)作为质心(可以理解中心点)。
Box2D是以米(m)作为单位,而手机中是像素,因为在实际开发中需要转换一下。像素和米的换算单位 RATE=30。
jbox2d.dynamics.World类是引擎Box2D的物理世界,物体和关节都是在物理世界中创建的,如果不在物理世界,则不能进行模拟。
参数1:物理世界的范围 参数2:加速度 参数3:如果不动的物体是否进行休眠 World(AABB aabb,Vec2 gravity,boolean doSleep) //定义一个物理世界范围 AABB aabb=new AABB(); aabb.lowerBound.set(-100,-100); aabb.upperBound.set(100,100); Vec2 gravity=new Vec2(0,10f);//定义重力加速度 World world=new World(aabb,gravity,true);//创建一个物理世界 //开始物理世界的模拟 参数1:物理世界模拟的频率 参数2:迭代值,越大越精确,性能就越低 world.step(float timeStep,int iterations)
再启动物理世界模拟应注意:
第一:因为物理世界模拟具有持续性,所以应该将此放入一个单独的线程进行循环不断的模拟
第二:应该与游戏的刷新率一致,否则物理世界的模拟将不同步
第三:迭代值可以理解为单次时间步中进行遍历的模拟运算数据的次数
在物理世界中创建一个多边形(参考android游戏编程之从零开始)
/** * 创建一个多边形 * @param world 物理世界 * @param x x坐标 * @param y 有坐标 * @param width 宽 * @param height 高 * @param isStatic 是否是静态的 * @return */ public Body createPolygon(World world,float x, float y, float width, float height,boolean isStatic) { // ---创建多边形皮肤 PolygonDef pd = new PolygonDef(); // 实例一个多边形的皮肤 if (isStatic) { pd.density = 0; // 设置多边形为静态 } else { pd.density = 1; // 设置多边形的质量 } pd.friction = 0.8f; // 设置多边形的摩擦力 pd.restitution = 0.3f; // 设置多边形的恢复力 // 设置多边形快捷成盒子(矩形) // 两个参数为多边形宽高的一半 pd.setAsBox(width / 2 / RATE, height / 2 / RATE); // ---创建刚体 BodyDef bd = new BodyDef(); // 实例一个刚体对象 bd.position.set((x + width / 2) / RATE, (y + height / 2) / RATE);// 设置刚体的坐标 // ---创建Body(物体) Body body = world.createBody(bd); // 物理世界创建物体 body.createShape(pd); // 为Body添加皮肤 body.setMassFromShapes(); // 将整个物体计算打包 return body; }
下面代码将在物理世界中添加两个矩形并进行模拟
public class MySurfaceView extends SurfaceView implements Callback, Runnable { private Thread thread; private SurfaceHolder surfaceHolder; private Canvas canvas; private Paint paint; private boolean flag; //线程的运行状态 // ---添加物理世界----->> final float RATE = 30; //像素和米的转化 World world; AABB aabb; Vec2 gravity; float timeStep = 1f / 60f; final int iterations = 10; // ----在物理世界中添加一个多边形--->> Body body;// 声明物体对象 float polygonX = 5;// 声明矩形X坐标 float polygonY = 10;// 声明矩形Y坐标 float polygonWidth = 50;// 声明矩形宽度 float polygonHeight = 50;// 声明矩形高度 // ----在物理世界中添加一个多边形--->> Body body2;// 声明物体对象 float polygonX2 = 5;// 声明矩形X坐标 float polygonY2 = 160;// 声明矩形Y坐标 float polygonWidth2 = 50;// 声明矩形宽度 float polygonHeight2 = 50;// 声明矩形高度 public MySurfaceView(Context context) { super(context); this.setKeepScreenOn(true); surfaceHolder = this.getHolder(); surfaceHolder.addCallback(this); paint = new Paint(); paint.setAntiAlias(true); paint.setStyle(Style.STROKE); setFocusable(true); // ---添加物理世界-->> aabb = new AABB(); gravity = new Vec2(0f, 10f); aabb.lowerBound.set(-100f, -100f); aabb.upperBound.set(100f, 100f); world = new World(aabb, gravity, true); // ----在物理世界中添加一个多边形--->> body = createPolygon(world,polygonX, polygonY, polygonWidth, polygonHeight, false);// 创建一个多边形 // ----在物理世界中添加一个多边形--->> body2 = createPolygon(world,polygonX2, polygonY2, polygonWidth2, polygonHeight2, true);// 创建一个多边形 } public void surfaceCreated(SurfaceHolder holder) { flag = true; thread = new Thread(this); if(!thread.isAlive()){ thread.start(); } } public void myDraw() { try { canvas = surfaceHolder.lockCanvas(); if (canvas != null) { canvas.drawColor(Color.WHITE); canvas.drawRect(polygonX, polygonY, polygonX + polygonWidth, polygonY + polygonHeight, paint);// 绘画矩形 canvas.drawRect(polygonX2, polygonY2, polygonX2 + polygonWidth2, polygonY2 + polygonHeight2, paint);// 绘画矩形 } } catch (Exception e) { Log.e("Himi", "myDraw is Error!"); } finally { if (canvas != null) surfaceHolder.unlockCanvasAndPost(canvas); } } public void Logic() { // ----物理世界进行模拟 world.step(timeStep, iterations); //开始模拟 获取两个矩形的位置然后赋值重新绘制 Vec2 position = body.getPosition(); polygonX = position.x * RATE - polygonWidth / 2; polygonY = position.y * RATE - polygonHeight / 2; Vec2 position2 = body2.getPosition(); polygonX2 = position2.x * RATE - polygonWidth2 / 2; polygonY2 = position2.y * RATE - polygonHeight2 / 2; } public void run() { while (flag) { myDraw(); Logic(); try { Thread.sleep((long) timeStep * 1000); } catch (Exception ex) { Log.e("Himi", "Thread is Error!"); } } } public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } public void surfaceDestroyed(SurfaceHolder holder) { flag = false; } }