现在的位置: 首页 > 综合 > 正文

Android 游戏引擎libgdx之Box2D 案例实践——打砖块(一)

2013年09月02日 ⁄ 综合 ⁄ 共 4420字 ⁄ 字号 评论关闭

参考子龙山人系列博客:http://www.cnblogs.com/zilongshanren/tag/cocos2d/

此作者都是基于IOS的cocos2D开发,本人参考并且转化为libgdx的cocos2d使用。

libgdx目前还主要用于Android开发,想学IOS的亲,请看上述作者的博客。

欢迎转载,但请加上来自www.cnblogs.com/dwinter或者dwintergame.com

 

一个永远反弹的球

这次我们以一个打砖块小游戏展开学习。首先,在上篇的基础上我们做出调整。

world = new World(new Vector2(0, 0f), true);

我们把重力设置为0,因为该游戏中并不需要重力。

        EdgeShape edge = new EdgeShape();
        FixtureDef boxShapeDef = new FixtureDef();
        boxShapeDef.shape = edge;
        edge.set(new Vector2(0f, 0f), new Vector2(48f, 0f));
        groundBody.createFixture(boxShapeDef);
        edge.set(new Vector2(0f, 0f), new Vector2(0f, 80f));
        groundBody.createFixture(boxShapeDef);
        edge.set(new Vector2(48f, 0f), new Vector2(48f, 80f));
        groundBody.createFixture(boxShapeDef);
        edge.set(new Vector2(48f, 80f), new Vector2(0f, 80f));
        groundBody.createFixture(boxShapeDef);

创建四面墙

        // Create ball body and shape
        BodyDef ballBodyDef = new BodyDef();
        ballBodyDef.type = BodyType.DynamicBody;
        ballBodyDef.position.set(24f, 60f);
        body = world.createBody(ballBodyDef);
        body.setUserData("ball");
        CircleShape circle = new CircleShape();
        circle.setRadius(2f);
        FixtureDef ballShapeDef = new FixtureDef();
        ballShapeDef.shape = circle;
        ballShapeDef.density = 1.0f;
        ballShapeDef.friction = 0f;
        ballShapeDef.restitution = 1.0f;
        body.createFixture(ballShapeDef);

调整球的摩擦力和恢复力。

把回复力restitution设置为1,这意味着,我们的球在碰撞的时候,将会是完全弹性碰撞。

把摩擦力friction设置为0,这防止球在碰撞的时候,由于摩擦损失能量,导致来回碰撞的过程中会有一点点偏差。

Vector2 force = new Vector2(500f, 500f);
body.applyLinearImpulse(force, ballBodyDef.position);

我们再给物体加上一个冲力,使它运动起来,力的大小可以自己调整。

 

加一块砖

        BodyDef paddleBodyDef = new BodyDef();
        paddleBodyDef.type = BodyType.DynamicBody;
        paddleBodyDef.position.set(STAGE_W / 2, 10f);
        paddle = world.createBody(paddleBodyDef);
        PolygonShape paddleShape = new PolygonShape();
        paddleShape.setAsBox(8f, 2f);
        FixtureDef paddleShapeDef = new FixtureDef();
        paddleShapeDef.shape = paddleShape;
        paddleShapeDef.density = 10f;
        paddleShapeDef.friction = 0.4f;
        paddleShapeDef.restitution = 0.1f;
        paddle.createFixture(paddleShapeDef);

砖块为长方形,所以这里我们使用了PolygonShape多边形图形。砖块比小球重,所以这里将其密度改为10。适当调整摩擦力和恢复力。

为了方便起见,我们还是使用测试渲染器Box2DDebugRenderer。

    @Override
    public void draw() {
        Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
        world.step(Gdx.app.getGraphics().getDeltaTime(), 8, 8);
        renderer.render(world, camera.combined);
        super.draw();
    }

来看看效果吧,球与砖块进行了猛烈的碰撞。

 

移动砖块

球有了,砖块有了,但是他们都不受我们控制。下面要做的是在砖块的身上加上一个力,这个力是通过“鼠标关节”实现的。

什么是鼠标关节? 

鼠标关节用于通过鼠标(对于手机来说,就是您的手指)来操控物体。它试图将物体拖向当前鼠标光标的位置。而在旋转方面就没有限制。

鼠标关节的定义需要一个目标点(target point),最大力(maximum force),频率(frequency),阻尼率(damping ratio)。目标点最开始与物体的锚点重合。最大力用于防止在多个动态物体相互作用时,会有激烈反应。你想将最大力设为多大就多大。频率和阻尼率用于创造一种弹性效果。

PS:可能有些难以理解,其实他们就是一些参数,为何不自己测试下,看看效果呢。

 

1.我们首先需要调整下上面砖块声明的代码。因为我们需要控制砖块,所以这里先赋值一个变量来方便今后的使用。

fixPaddle = paddle.createFixture(paddleShapeDef);

2.覆盖touchDown方法

    @Override
    public boolean touchDown(int x, int y, int pointer, int button) {
        //mouseJoint是个变量,只有它失效了才去重新生成
        if (mouseJoint == null) {
            //这里将真实世界的坐标转换为游戏内的坐标
            //注意libgdx的坐标系以屏幕左下角为(0,0)
            float yy = STAGE_H - (y / RATIO); 
            float xx = x / RATIO;
            //首先判断当前触点是否在砖块范围内
            if (fixPaddle.testPoint(xx, yy)) {
                //我们来定义一个鼠标关节的声明
                MouseJointDef mouseJointDef = new MouseJointDef();
                mouseJointDef.bodyA = groundBody;//设为物理世界的边界
                mouseJointDef.bodyB = paddle;//我们想要拖动的物体
                //是否检测2个物体间的碰撞,不检测会怎么样?砖块会飞离屏幕!
                mouseJointDef.collideConnected = true;
                //最大力设为砖块质量的1000倍
                //设小点会怎么样?砖块响应你的速度会很慢很慢
                mouseJointDef.maxForce = 1000.0f * paddle.getMass();
                //好了,让世界生成它吧
                mouseJoint = (MouseJoint) world.createJoint(mouseJointDef);
                //传入目的地坐标
                mouseJoint.setTarget(new Vector2(x, STAGE_H - y));
            }
        }
        return super.touchDown(x, y, pointer, button);
    }

3.覆盖touchDragged方法

    @Override
    public boolean touchDragged(int x, int y, int p) {
        if (mouseJoint != null) {
            //更新目的地坐标
            mouseJoint.setTarget(new Vector2(x, STAGE_H - y));
        }
        return super.touchDragged(x, y, p);
    }

4.覆盖touchUp方法

    @Override
    public boolean touchUp(int x, int y, int pointer, int button) {
        if (mouseJoint != null) {
            //当触角离开屏幕时,销毁关节
            world.destroyJoint(mouseJoint);
            mouseJoint = null;
        }
        return super.touchUp(x, y, pointer, button);
    }

 

限制砖块的移动

我们现在虽然可以移动砖块了,但是移动的过于随意了。打砖块游戏只是水平的移动。所以我们还需要在砖块上加一个束缚!

这就是移动关节(prismatic joint),它允许两个物体沿指定轴相对移动,它会阻止相对旋转。因此,移动关节只有 一个自由度。

        //声明移动关节的定义
        PrismaticJointDef prismaticJointDef = new PrismaticJointDef();
        //设置一个约束向量,只能沿着x轴移动
        Vector2 axis = new Vector2(1f, 0f);
        //碰撞监测
        prismaticJointDef.collideConnected = true;
        //初始化移动关节的定义
        prismaticJointDef.initialize(groundBody, paddle,
                paddle.getWorldCenter(), axis);
        //生成移动关节的定义
        world.createJoint(prismaticJointDef);

运行后我们会发现如果用力的拖动砖块去碰撞小球的话,小球的速度会变得非常快!所以,我们还需要进行一下调整。

    public void draw() {
        //获得小球的当前速度
        Vector2 velocity = ball.getLinearVelocity();
        float speed = velocity.len();
        //当大于某一个值时,我们设置它的阻尼,来起到减速的效果,具体数值自行调整
        if (speed > 100f) {
            ball.setLinearDamping(0.1f);
        } else if (speed < 100f) {
            ball.setLinearDamping(0f);
        }
        ......
    }

 

到这里,我们结束第一部分。

 

源码下载

https://github.com/dwintercode/Box2D.git

抱歉!评论已关闭.