3.Libgdx扩展学习之Box2D_夹具

Posted zqiang_55

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了3.Libgdx扩展学习之Box2D_夹具相关的知识,希望对你有一定的参考价值。

文章中涉及的很多概念,都是来自《Box2D中文手册》。有统一的解释方便理解


夹具

概念介绍

形状不知道物体的存在,并可独立于物理模拟而被使用。因此 Box2D 提供 Fixture 类,用于将形状附加到物体上。一个物体可以有零个或多个 fixture。拥有多个 fixture 的物体有时被叫做组合物体。
fixture具有下列属性:

  • 关联的形状
  • broad-phase 代理
  • 密度(density)、摩擦(friction)、恢复(restitution)
  • 碰撞筛选标记(collision filtering flags)
  • 指向父物体的指针
  • 传感器标记(sensor flag)

创建夹具

创建夹具,必须先初始化和夹具定义FixtureDef,并将定义传到父物体中,
先看夹具定义:

/** A fixture definition is used to create a fixture. This class defines an abstract fixture definition. You can reuse fixture
 * definitions safely.
 * @author mzechner */
public class FixtureDef 
    /** The shape, this must be set. The shape will be cloned, so you can create the shape on the stack. */
    public Shape shape;

    /** The friction coefficient, usually in the range [0,1]. **/
    public float friction = 0.2f;

    /** The restitution (elasticity) usually in the range [0,1]. **/
    public float restitution = 0;

    /** The density, usually in kg/m^2. **/
    public float density = 0;

    /** A sensor shape collects contact information but never generates a collision response. */
    public boolean isSensor = false;

    /** Contact filtering data. **/
    public final Filter filter = new Filter();

上面列出的FixtureDef属性,其实就是上面文字描述的代码形式,在实际操作中我们是这样创建的:
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = circleShape;
fixtureDef.density = 1.0f;
fixtureDef.restitution = 0.6f;
body.createFixture(fixtureDef);
这会创建 fixture,并将它附加到物体之上。不需要保存 fixture 的指针,因为当它的父物体被摧毁时, fixture 也会自动被摧毁。 可以在单个物体上创建多个 fixture。
可以摧毁父物体上的 fixture,来模拟一个可分裂开的物体。

FixtureDef属性介绍

密度(density)

fixture 的密度用来计算父物体的质量属性。密度值可以为零或者是正数。所有的 fixture 都应该使用相似的密度,这样做可以改善堆叠稳定性。
当设置密度的时候,物体的质量不会立即改变。你必须调用 resetMassData ,使之生效。
fixture.setDensity (float density)
body.resetMassData ()

摩擦(friction)

摩擦可以使对象逼真地沿其它对象滑动。摩擦参数通常会设置在 0 到 1 之间,但也可是任意的非负数, 0 意味着没有摩擦, 1 会产生强摩擦。

恢复系数(restitution)

恢复可以使对象弹起。恢复的值通常设置在 0 到 1 之间。想象一个小球掉落到桌子上,值为 0 表示着小球不会弹起, 这称为非弹性碰撞。值为 1 表示小球的速度跟原来一样,只是方向相反,这称为完全弹性碰撞。

筛选(filter)

碰撞筛选是为了防止某些 fixture 之间发生碰撞。比如,创造了一个骑自行车的角色。希望自行车与地形之间有碰撞,角色与地形有碰撞,但你不希望角色和自行车之间发生碰撞 (因为它们必须重叠)。 Box2D 通过种群和分组来支持这样的碰撞筛选。
Box2D 支持 16 个种群。任意 fixture 你都可以指定它属于哪个种群。你还可以指定这个 fixture 可以和其它哪些种群发生碰撞。例如,你可以在一个多人游戏中指定玩家之间不会碰撞,怪物之间也不会碰撞,但是玩家和怪物会发生碰撞。这是通过掩码来完成的,例如:
playerFixtureDef.filter.categoryBits = 0x0002
monsterFixtureDef.filter.categoryBits = 0x0004
playerFixtureDef.filter.maskBits = 0x0004
monsterFixtureDef.filter.maskBits = 0x0002
下面是产生碰撞的规则:

short catA = fixtureA.filter.categoryBits ;
short maskA = fixtureA.filter.maskBits;
short catB = fixtureB.filter.categoryBits
short maskB = fixtureB.filter.maskBits;

if((catA & catB) != 0 && (catB & maskA) != 0) 
    // fixtures can collide

碰撞分组让你指定一个整数的组索引。你可以融同一个组的所有fixture总是相互碰撞(正索引)或者永远不碰撞(负索引)。组索引通常用于一些以某种方式关联的事物,就像自行车的那些不见。在下面例子中,fixture1和fixture2总是碰撞,而fixture3和fixture4永远不会碰撞

fixture1Def.filter.groupIndex = 2;
fixture2Def.filter.groupIndex = 2;
fixture3Def.filter.groupIndex = -8;
fixture4Def.filter.groupIndex = -8;

如果组索引不同,碰撞筛选会按照种群和掩码来进行。换句话说,分组筛选和种群筛选相比,具有更高的优选级。
注意在Box2D中还有其它的碰撞筛选,这里有一个列表:

  • static上的fixture只会与dynamic物体上的fixture发生碰撞
  • kinematic物体只会和dynamic物体发生碰撞
  • 同一个物体上的fixture永远不会相互碰撞
  • 如果两个物体用关节连接起来,物体上面的fixture可以选择启用或者禁止它们之间的相互碰撞
传感器

有时候游戏逻辑需要判断两个 fixture 是否相交,而不想有碰撞反应。这可以通过传感器(sensor)来完成。传感器也是个 fixture,但它只会侦测碰撞,而不产生其它反应。
可以将任意 fixture 标记为传感器。传感器可以是 static、 kinematic 或 dynamic 的。记住,每个物体上可以有多个 fixture,传感器和实体 fixture 是可以混合存在的。而且,只有至少一个物体是dynamic 的,传感器才会产生接触事件,而 kinematic 与 kinematic 、 kinematic 与 static ,或者static 与 static 之间都不会产生接触事件。

public class BodyShapeA extends ApplicationAdapter 

    World world;
    Box2DDebugRenderer box2DDebugRenderer;

    OrthographicCamera camera;

    float scene_width = 12.8f;
    float scene_height = 7.2f;

    @Override
    public void create() 
        world = new World(new Vector2(0.0f, -9.8f), true);
        box2DDebugRenderer = new Box2DDebugRenderer();


        camera = new OrthographicCamera(scene_width, scene_height);
        camera.position.set(scene_width / 2, scene_height / 2, 0);
        camera.update();

        createStaticBox();

        Gdx.input.setInputProcessor(new InputHandA());
    

    @Override
    public void render() 
        world.step( 1/ 60f, 6, 2);

        Gdx.gl.glClearColor(0.39f, 0.58f, 0.92f, 1.0f);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

        box2DDebugRenderer.render(world, camera.combined);
    

    @Override
    public void dispose() 
        world.dispose();
        box2DDebugRenderer.dispose();
    

    private void createStaticBox() 
        //  创建地面
        createBorderBox(scene_width * 0.5f, 0.2f, scene_width * 0.5f, 0.2f, 0);
        // 创建倾斜矩形,这里创建矩形,然后用angle来控制
        createBorderBox(3.0f, 5.0f, 0.1f, 1.3f, MathUtils.PI / 3);
        // 创建池子
        createBorderBox(5.0f, 2.5f, 0.1f, 1.0f, 0);
        createBorderBox(9.0f, 2.5f, 0.1f, 1.0f, 0);
        createBorderBox(7.0f, 1.6f, 2.1f, 0.1f, 0);
    

    private void createBorderBox(float px, float py, float w, float h, float angle) 
        BodyDef bodyDef = new BodyDef();
        bodyDef.position.set(px, py);
        bodyDef.angle = angle;
        Body body = world.createBody(bodyDef);

        PolygonShape polygonShape = new PolygonShape();
        polygonShape.setAsBox(w, h);
        body.createFixture(polygonShape, 0);
        polygonShape.dispose();
    

    private void createCircle(float x, float y) 
        BodyDef bodyDef = new BodyDef();
        bodyDef.type = BodyDef.BodyType.DynamicBody;
        bodyDef.position.set(x, y);
        Body body = world.createBody(bodyDef);

        CircleShape circleShape = new CircleShape();
        circleShape.setRadius(0.2f);

        FixtureDef fixtureDef = new FixtureDef();
        fixtureDef.shape = circleShape;
        fixtureDef.density = 1.0f;
        fixtureDef.restitution = 0.6f;
        body.createFixture(fixtureDef);
        circleShape.dispose();
    

    private  class InputHandA extends InputAdapter 
        @Override
        public boolean touchDown(int screenX, int screenY, int pointer, int button) 
            // 在屏幕点击出创建响应的圆形Body
            Vector3 vector3 = new Vector3(screenX, screenY, 0);
            camera.unproject(vector3);
            createCircle(vector3.x, vector3.y);
            return true;
        
    

以上是关于3.Libgdx扩展学习之Box2D_夹具的主要内容,如果未能解决你的问题,请参考以下文章

3.Libgdx扩展学习之Box2D_夹具

2.Libgdx扩展学习之Box2D_刚体和形状

2.Libgdx扩展学习之Box2D_刚体和形状

2.Libgdx扩展学习之Box2D_刚体和形状

7.Libgdx扩展学习之Box2D_距离关节 旋转关节

7.Libgdx扩展学习之Box2D_距离关节 旋转关节