本帖最后由 weidongno1 于 2011-10-25 14:30 编辑

demo 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


原文章出处提供源代码下载,要的同学可以去拿