本帖最后由 weidongno1 于 2011-10-25 14:30 编辑
JBox2d入门学习一
最近想在网上学习一款Android的开源游戏框架,方便游戏的开发,在学习的过程中我发现无论是Rokon,AndEngine,libgdx他们都使用了同一款非常强大的物理引擎Box2d,所以决定先从这个引擎入手学习一下,将学习的心得记录下来。
首先对这边文章当中要用到几个概念进行说明一下:
World 这是box2d当中抽象出来的存在引力,坐标范围的一个模拟的世界
Body 刚体,存在于World当中的刚体,我们可以通过BodyDef来设置他得属性。在JBOX2D当中我们基本上不需要去关心刚体碰撞所产生的效果, 因为该引擎会根据你刚体的属性来帮你做这些处理。比如说你创建的物体会根据当前世界的引力自动下坠,如果两个钢铁相撞会弹开等等。
BodyDef 用来设置刚体的属性,包括密度density,摩擦力friction,弹性restitution等。
Shape 用来描述Body的形状,像PolygonDef 多边体 CircleDef 球体
通过这些概念,我们就可以创建一个最基本的示例:
首先通过去Jbox2d的官方下载源码项目或者是jar包,导入,这里就不做说明。
下面是一个基于android的jbox2d小例子
public class MainActivity extends Activity {
private final static int RATE = 10;//屏幕到现实世界的比例 10px:1m;这里要注意,当我们根据android当中的坐标去定义刚体的位置时,我们需要将坐标除以这个比例获得世界当中的长度,用这个长度来进行 定义。
private AABB worldAABB; //创建一个坐标系统
private World world; //创建一个世界
private float timeStep; //模拟的的频率
private int iterations; //迭代越大,模拟约精确,但性能越低
private Body body,body1; //创建刚体
private MyView myView; //我们自己定义的view,用来绘制出这个世界
private Handler mHandler;
private float density;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.requestWindowFeature(Window.FEATURE_NO_TITLE); //去title
getWindow().setFlags(WindowManager.LayoutParams. FLAG_FULLSCREEN ,WindowManager.LayoutParams. FLAG_FULLSCREEN);//全屏
DisplayMetrics metric = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metric);
density = metric.density;
//创建这个世界的坐标范围,并且设定上下限,这里应该是按世界的长度来算的,也就是说这个范围是足够大的,我们只能在这个范围内创建刚体
worldAABB = new AABB();
worldAABB.lowerBound.set(-100.0f, -100.0f);
worldAABB.upperBound.set(100.0f, 100.0f);
//end
Vec2 gravity = new Vec2(0.0f, 10.0f); //向量,用来标示当前世界的重力方向,第一个参数为水平方向,负数为做,正数为右。第二个参数表示垂直方向
boolean doSleep = true; //标示 是否睡眠
world = new World(worldAABB, gravity, doSleep);//创建世界
createBorder(0,410*density,320*density,10*density);//创建一个边界
createBall(150,50,20,1); //创建两个球
createBall(155,100,20,2);
myView = new MyView(this) ;
timeStep = 1.0f/60.0f; //定义频率
iterations = 10; //定义迭代
setContentView(myView);
mHandler = new Handler();
mHandler.post(update); //android的知识,就不做标识了
}
private Runnable update = new Runnable() {
public void run() {
world.step(timeStep, iterations); //开始模拟
/*Vec2 gravity = new Vec2(1000.0f, 0f);
Vec2 gravity1 = new Vec2(100.0f, -100f);
body.applyForce(gravity,gravity1); */ //这段代码是尝试给刚体一个力
Vec2 position = body.getPosition();
myView.x1=position.x*RATE;
myView.y1=position.y*RATE;
position = body1.getPosition();
myView.x2=position.x*RATE;
myView.y2=position.y*RATE;
myView.invalidate();
mHandler.postDelayed(update, (long)timeStep*1000);
}
};
public void createBorder(float x, float y, float half_width,
float half_height) {
PolygonDef shape = new PolygonDef(); //标识刚体的形状
shape.density = 0; //设置刚体的密度,应为这个是底边界,所以密度设为0,相当于没有质量的物体不受力
shape.friction = 11f; //摩擦力,学过物理吧….恩,就是这个意思…
shape.restitution = 0.3f; //弹力
shape.setAsBox(half_width / RATE, half_height/RATE); //设置刚体刚体的宽和高,要根据android坐标转换成世界当中的单位
BodyDef bodyDef = new BodyDef();
bodyDef.position.set(x / RATE, y / RATE); //定义刚体的位置
Body body1 = world.createBody(bodyDef); //在世界中创建这个刚体
body1.createShape(shape); //刚体形状
body1.setMassFromShapes(); //计算质量
}
public void createBall(float x,float y,float radius,int i)
{
CircleDef shape = new CircleDef();
shape.density = 7f;
shape.friction = 11f;
shape.restitution = 0.3f;
shape.radius = radius/RATE;
BodyDef bodyDef = new BodyDef();
bodyDef.position.set(x / RATE, y / RATE);
if( i == 1)
{
body = world.createBody(bodyDef);
body.createShape(shape);
body.setMassFromShapes();
}
else
{
body1 = world.createBody(bodyDef);
body1.createShape(shape);
body1.setMassFromShapes();
}
}
class MyView extends View
{
Canvas canvas;
public float x1 = 150, y1 = 50;
public float x2 = 155, y2 = 100;
public MyView(Context context) {
super(context);
}
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
this.canvas = canvas;
drawBall(x1,y1);
drawBall(x2, y2);
drawBorder();
}
private void drawBall(float x,float y)
{
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.GREEN);
canvas.drawCircle(x, y, 20, paint);
}
private void drawBorder()
{
Paint paint = new Paint();
paint.setColor(Color.GREEN);
paint.setAntiAlias(true);
canvas.drawRect(0,400*density,320*density,410*density,paint);
}
}
}
这样跑起来就可以实现二个小球下坠碰撞的小例子
效果图
学会了创建世界和刚体,明白了怎么给物体一个力,下一步学习一下做类似于愤怒的小鸟那种例子,敬请期待吧,
想要学习更多请到weidong公司的labs原文章http://labs.ywlx.net/?p=1421
入门学习二 http://labs.ywlx.net/?p=1613
原文章出处提供源代码下载,要的同学可以去拿