分享

android box2d重力系统 创建游戏世界(一)

 幻魂1990 2013-07-29

 Box2D是一款用于2D游戏的物理引擎。在Box2D物理世界里,创建出的每个物体都更接近于真实世界中的物体,让游戏中的物体运动起来更加真实可信,让游戏世界看起来更具交互性。

Android平台常见的十几款游戏引擎中,例如:Rokon、AndEngine、libgdx等物理引擎都封装了Box2D物理引擎,可见Box2D在物理引擎中占据了多重要的位置。

Box2D在很多平台都有对应的版本:Flash版本、Iphone版本、Java版本(JBox2D)等等,由于Android语言采用的是Java,所以这里介绍的对应Box2D平台也是Java平台,称为JBox2D,对应的版本为JBox2d 2.1

要使用JBox2d首先对几个概念进行说明一下:
World    这是box2d当中抽象出来的存在引力,坐标范围的一个模拟的世界


Body     刚体,存在于World当中的刚体,我们可以通过BodyDef来设置他得属性。在JBOX2D当中我们基本上不需要去关心刚体碰撞所产生的效果,因为该引擎会根据你刚体的属性来帮你做这些处理。比如说你创建的物体会根据当前世界的引力自动下坠,如果两个钢铁相撞会弹开等等。


BodyDef  用来设置刚体的属性,包括密度density,摩擦力friction,弹性restitution等。


Shape    用来描述Body的形状,像PolygonDef 多边体 CircleDef 球体

 

现在我们进入正题 如何使用jbox2d创建一个的游戏世界

   创建一个android项目 并引入jbox2d jar 包  jar 包怎么引用 不用说了吧,哇哈哈   jbox2d下载地址 http://code.google.com/p/jbox2d/downloads/list?can=1&q=

 /**

 * 游戏世界

 * @author mahaile

 *

 */

public class WorldSurfaceView extends SurfaceView implements SurfaceHolder.Callback{

final static int FPS=30;       //设置帧数

MyThread myThread;  //ui线程

SurfaceHolder surfaceHolder;  

Canvas canvas;

Paint paint;

private final float RATE=10.0f; //物理世界与屏幕环境缩放比列

World world;   //游戏世界对象  

float timeStep = 1f / 60f;;  //模拟的频率

// 迭代值,迭代越大模拟越精确,但性能越低 

int velocityIterations = 10;

int positionIterations = 8;

public WorldSurfaceView(Context context) {

super(context);

surfaceHolder=this.getHolder();

surfaceHolder.addCallback(this);  //添加回调

Vec2 vect=new Vec2(0f,10.0f); //向量 用来标示当前世界的重力方向,第一个参数为水平方向,负数为左,正数为右。第二个参数表示垂直方向

world=new World(vect,true);  //初始化游戏世界  这里注意一点 jbox2d 2.1 以后没有 aabb游戏范围 对象了

}

public void onDraw(Canvas canvas){

Log.d("888","11111111111111111111");

canvas.drawColor(Color.WHITE);  //清屏

}

@Override

public void surfaceChanged(SurfaceHolder holder, int format, int width,

int height) {

// TODO Auto-generated method stub

}

 

@Override

public void surfaceCreated(SurfaceHolder holder) {

// TODO Auto-generated method stub

myThread=new MyThread();

myThread.flag=true;

myThread.start();

}

 

@Override

public void surfaceDestroyed(SurfaceHolder holder) {

// TODO Auto-generated method stub

myThread.flag=false;

}

public class MyThread extends Thread{

public boolean flag;

public void run(){

long lastTime=SystemClock.uptimeMillis();

Canvas canvas;

while(flag){

long firstTime=SystemClock.uptimeMillis()-lastTime;

if(firstTime>FPS){

canvas=surfaceHolder.lockCanvas();

try{

Logic();

onDraw(canvas);

}catch(Exception ex){

ex.printStackTrace();

}finally{

surfaceHolder.unlockCanvasAndPost(canvas);

}

}else{

try {

Thread.sleep(Math.max(2,FPS-firstTime));

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

}

}

public void Logic() {

// --开始模拟物理世界--->>

world.step(timeStep,velocityIterations, positionIterations);

}

 

上面的 代码 怎么这么简单呢?  呵呵,这只是最简单一个 游戏世界了,我们没有添加如何游戏组件,所以当我们运行游戏 屏幕上是什么都没有的,  那我们如果给游戏世界添加几个游戏组件呢 会怎么样, box2d 又是怎么工作的呢  我们看下面的代码

 

 

package yxqz.com;


import org.jbox2d.collision.shapes.CircleShape;

import org.jbox2d.collision.shapes.PolygonShape;

import org.jbox2d.common.Vec2;

import org.jbox2d.dynamics.Body;

import org.jbox2d.dynamics.BodyDef;

import org.jbox2d.dynamics.BodyType;

import org.jbox2d.dynamics.FixtureDef;

import org.jbox2d.dynamics.World;



import android.content.Context;

import android.graphics.Canvas;

import android.graphics.Color;

import android.graphics.Paint;

import android.graphics.Paint.Style;

import android.os.SystemClock;

import android.util.Log;

import android.view.SurfaceHolder;

import android.view.SurfaceView;


/**

 * 游戏世界 并且添加一个刚体

 * @author mahaile

 *

 */

public class WorldBodySurfaceView extends SurfaceView implements SurfaceHolder.Callback{

final static int FPS=30;       //设置帧数

MyThread myThread;  //ui线程

SurfaceHolder surfaceHolder;  

Canvas canvas;

Paint paint;

int screenW,screenH;

private final float RATE=10.0f; //物理世界与屏幕环境缩放比列

World world;   //游戏世界对象  

float timeStep = 1f / 60f;;  //模拟的频率

// 迭代值,迭代越大模拟越精确,但性能越低 

int velocityIterations = 10;

int positionIterations = 8;

public WorldBodySurfaceView(Context context) {

super(context);

surfaceHolder=this.getHolder();

surfaceHolder.addCallback(this);  //添加回调

Vec2 vect=new Vec2(0f,10.0f); //向量 用来标示当前世界的重力方向,第一个参数为水平方向,负数为左,正数为右。第二个参数表示垂直方向

world=new World(vect,true);  //初始化游戏世界  这里注意一点 jbox2d 2.1 以后没有 aabb游戏范围 对象了


//设置画笔

paint=new Paint();

paint.setAntiAlias(true);

paint.setStyle(Style.STROKE);

paint.setColor(Color.BLUE);

}


public void onDraw(Canvas canvas){

//Log.d("888","11111111111111111111");

canvas.drawColor(Color.WHITE);  //清屏

//Body body=world.getBodyList();

//canvas.drawRect(r, paint)

Body body=world.getBodyList();

for(int i=0;i<world.getBodyCount();i ){

BodyBox bodyBox=(BodyBox)body.m_userData;

bodyBox.onDraw(canvas, paint);

body=body.m_next;

}

}

@Override

public void surfaceChanged(SurfaceHolder holder, int format, int width,

int height) {

// TODO Auto-generated method stub

}


@Override

public void surfaceCreated(SurfaceHolder holder) {

screenW=this.getWidth();

screenH=this.getHeight();

createPolygon(5, this.getHeight() - 10, this.getWidth() - 10, 2,0.5f, true);

/**创建6个方形,isStatic设置为false,即在物理世界中是动态,收外力作用影响 */

for(int i=0;i<6;i )

{

createPolygon(screenW-150-30*i,50,20,20,Float.parseFloat("0." i),false);

}


myThread=new MyThread();

myThread.flag=true;

myThread.start();

}


@Override

public void surfaceDestroyed(SurfaceHolder holder) {

// TODO Auto-generated method stub

myThread.flag=false;

}

public class MyThread extends Thread{

public boolean flag;

public void run(){

long lastTime=SystemClock.uptimeMillis();

Canvas canvas;

while(flag){

long firstTime=SystemClock.uptimeMillis()-lastTime;

if(firstTime>FPS){

//Log.d("**", "-- " firstTime " firstTime is :" firstTime " lastTime is :" lastTime);

lastTime =FPS;

canvas=surfaceHolder.lockCanvas();

try{

Logic();

onDraw(canvas);

}catch(Exception ex){

ex.printStackTrace();

}finally{

surfaceHolder.unlockCanvasAndPost(canvas);

}

}else{

try {

//Log.d("88","FPS-firstTime is :" (FPS-firstTime) " firstTime is :" firstTime " lastTime is :" lastTime);

Thread.sleep(Math.max(2,FPS-firstTime));

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

}

}


public void Logic() {

// --开始模拟物理世界--->>

world.step(timeStep,velocityIterations, positionIterations);

/**遍历物理世界中的body,将物理世界仿真出的值反馈给屏幕,

* 改变bird和rect的参数

* */

Body body = world.getBodyList();

for (int i = 1; i < world.getBodyCount(); i ) {

if ((body.m_userData) instanceof BodyBox) {

BodyBox rect = (BodyBox) (body.m_userData);

rect.setX(body.getPosition().x * RATE - (rect.getW()/2));

rect.setY(body.getPosition().y * RATE - (rect.getH()/2));

//rect.setAngle((float)(body.getAngle()*180/Math.PI));

}else // body.m_userData==null时,将body销毁,表示被击毁

{

world.destroyBody(body);

}

body = body.m_next;

}

}

/**

*  创建圆型

* @param x

* @param y

* @param width

* @param height

* @param isStatic 是否为动态

* @return body

*/

public Body createCircle(float x,float y,float r,boolean isStatic){

CircleShape shape=new CircleShape();  //创建一个圆形对象

shape.m_radius=r/RATE;  //设置圆形的半径 设置半径需要把屏幕的大小参数转换成世界大小的参数

FixtureDef fDef=new FixtureDef();  //设置物体属性对象 游戏世界会根据此对象 创建刚体

if(isStatic){

fDef.density=0;  //设置物品的密度 当密度为0 时 物品不会受世界重力影响

}else{

fDef.density=1;  //设置物品的密度 当密度不为0 时 物品会受世界重力影响

}

fDef.friction=1.0f;  //设置物品的摩擦力  0~1

fDef.restitution=0.5f;  //设置物体的弹力  值越大 弹性就越强  值范围为 0~1

fDef.shape=shape;

BodyDef bodyDef=new BodyDef();//创建一个刚体的属性 对象 比如 动态,位置,旋转角度等

bodyDef.type=isStatic?BodyType.STATIC:BodyType.DYNAMIC;

bodyDef.position.set(x/RATE, y/RATE);

//创建刚体

Body body=world.createBody(bodyDef);   //根据刚体属性对象在游戏世界中添加刚体

body.createFixture(fDef);          //设置刚体的物理属性

return body;

}

/**

*  创建正方形

* @param x

* @param y

* @param width

* @param height

* @param isStatic 是否为动态

* @return body

*/

public Body createPolygon(float x,float y,float width,float height,float restitution,boolean isStatic){

PolygonShape shape=new PolygonShape();  //创建一个圆形对象

shape.setAsBox(width/2/RATE, height/2/RATE);  //设置圆形的半径 设置半径需要把屏幕的大小参数转换成世界大小的参数

FixtureDef fDef=new FixtureDef();  //设置物体属性对象 游戏世界会根据此对象 创建刚体

if(isStatic){

fDef.density=0;  //设置物品的密度 当密度为0 时 物品不会受世界重力影响

}else{

fDef.density=1;  //设置物品的密度 当密度不为0 时 物品会受世界重力影响

}

fDef.friction=0.0f;  //设置物品的摩擦力  0~1

fDef.restitution=restitution;  //设置物体的弹力  值越大 弹性就越强  值范围为 0~1

fDef.shape=shape;

BodyDef bodyDef=new BodyDef();//创建一个刚体的属性 对象 比如 动态,位置,旋转角度等

bodyDef.type=isStatic?BodyType.STATIC:BodyType.DYNAMIC;

bodyDef.position.set((x width/2)/RATE,(y height/2)/RATE);

//创建刚体

Body body=world.createBody(bodyDef);   //根据刚体属性对象在游戏世界中添加刚体

body.createFixture(fDef);          //设置刚体的物理属性

body.m_userData=new BodyBox(x,y,width,height);

return body;

}

}


箱子实体类

 

import android.graphics.Canvas;

import android.graphics.Paint;

import android.graphics.RectF;


public class BodyBox {

public float x,y,w,h;

public void setType(int type) {

this.type = type;

}


public int type=0;  //0 为地板

public BodyBox(float x,float y,float w,float h){

this.x=x;

this.y=y;

this.w=w;

this.h=h;

}

public void onDraw(Canvas canvas,Paint paint){

canvas.drawRect(new RectF(x,y,x w,y h), paint);

}

public float getX() {

return x;

}


public void setX(float x) {

this.x = x;

}


public float getY() {

return y;

}


public void setY(float y) {

this.y = y;

}


public float getW() {

return w;

}


public void setW(float w) {

this.w = w;

}


public float getH() {

return h;

}


public void setH(float h) {

this.h = h;

}


public int getType() {

return type;

}


}

 


效果图 如下  


运行游戏 我们会看到 有 6个箱子 自行掉落  碰到下方的 箱子的时候 就会反弹, 在代码中我们 并没有看到我们移动箱子的代码 , 这就是box2d的 功劳啦, 咔咔 ,   这章我们先学到这里,我们继续挖掘box2d 的魅力 , 欢迎各位童鞋同我一起学习,进步,一起讨论 

 

项目代码: http://download.csdn.net/detail/ma_haile/4067733 

 下一章我们学习 jbox2d如何检查碰撞的 

本文出自 “android,unity3d” 博客,请务必保留此出处http://mahaile.blog.51cto.com/2891586/776483

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多