Libgdx box2d ContactListener非常小问题

时间:2017-07-08 04:50:48

标签: java libgdx box2d collision

我在使用libgdx开发我的2D小型滚动平台游戏时遇到了这种情况。主要问题是beginContact(Contact contact)在明确需要时不会被调用。以下是一些简化的代码片段,以便快速概述:

记录传感器与地面之间每次接触的

ContactListener类:

public class WorldContactListener implements ContactListener
{
Player player;

public WorldContactListener(Player player, World world)
{
    this.player = player;
    world.setContactListener(this);
}

@Override
public void beginContact(Contact contact)
{
    Object userDataA = contact.getFixtureA().getUserData();
    Object userDataB = contact.getFixtureB().getUserData();

    if((userDataA == Tomb.UserData.GROUND || userDataB == Tomb.UserData.GROUND) 
  && (userDataA == Tomb.UserData.PLAYER_FEET  || userDataB == Tomb.UserData.PLAYER_FEET))
    {   
        Gdx.app.log("collision", "start");
    } 
}

@Override
public void endContact(Contact contact) 
{
    Object userDataA = contact.getFixtureA().getUserData();
    Object userDataB = contact.getFixtureB().getUserData();

    if((userDataA == Tomb.UserData.GROUND || userDataB == Tomb.UserData.GROUND) 
  && (userDataA == Tomb.UserData.PLAYER_FEET  || userDataB == Tomb.UserData.PLAYER_FEET))
    {   
        Gdx.app.log("collision", "stop");
    } 
}

@Override
public void preSolve(Contact contact, Manifold oldManifold) 
{
}

@Override
public void postSolve(Contact contact, ContactImpulse impulse) 
{
}
}

玩家创建:

    //Main rectangle:
    BodyDef bodyDef = new BodyDef();
    bodyDef.position.set(spawnCoordinates);
    bodyDef.type = BodyType.DynamicBody;
    body = world.createBody(bodyDef);
    FixtureDef fixtureDef = new FixtureDef();
    PolygonShape shape = new PolygonShape();
    shape.setAsBox(5 / Tomb.PPM, 14 / Tomb.PPM);
    fixtureDef.shape = shape;
    fixtureDef.friction = FRICTION; //1
    fixtureDef.restitution = RESTITUTION; //0
    body.createFixture(fixtureDef).setUserData(Tomb.UserData.PLAYER);

    //Circle-shaped sensor:
    fixtureDef = new FixtureDef();
    CircleShape feet = new CircleShape();
    feet.setPosition(new Vector2(0, -16 / Tomb.PPM));
    feet.setRadius(10 / Tomb.PPM);
    fixtureDef.shape = feet;
    fixtureDef.isSensor = true; 
    body.createFixture(fixtureDef).setUserData(Tomb.UserData.PLAYER_FEET);

球员动作:

private void handleInput(float delta)
{
    if(Gdx.input.isKeyJustPressed(Input.Keys.UP))
    {
        body.applyLinearImpulse(new Vector2(0, JUMP_POWER), body.getWorldCenter(), true);
    }
    if(Gdx.input.isKeyPressed(Input.Keys.RIGHT) && body.getLinearVelocity().x <= MAX_HORIZONTAL_VELOCITY)
    {
        body.applyLinearImpulse(new Vector2(HORIZONTAL_SPEED, 0), body.getWorldCenter(), true);
    }
    if(Gdx.input.isKeyPressed(Input.Keys.LEFT) && body.getLinearVelocity().x >= -MAX_HORIZONTAL_VELOCITY)
    {
        body.applyLinearImpulse(new Vector2(-HORIZONTAL_SPEED, 0), body.getWorldCenter(), true);
    }
}

初始化.tmx地图,从Tiled Map Editor导入。值得注意的是,整个地形只有一个PolygonMapObject,所以特别是在这种情况下不需要for循环。

protected void defineGround(int layerIndex) 
{
    for(PolygonMapObject object : map.getLayers().get(layerIndex).getObjects().getByType(PolygonMapObject.class))
    {
        BodyDef bodyDef = new BodyDef();
        ChainShape chainShape = new ChainShape();
        FixtureDef fixtureDef = new FixtureDef();
        Body body;

        Polygon polygon = object.getPolygon();
        bodyDef.type = BodyType.StaticBody;
        bodyDef.position.set(polygon.getX() / Tomb.PPM, polygon.getY() / Tomb.PPM);
        body = world.createBody(bodyDef);   
        float[] scaledVertices = new float[polygon.getVertices().length];
        for(int i = 0; i < polygon.getVertices().length; i++)
        {
            scaledVertices[i] = polygon.getVertices()[i] / Tomb.PPM;
        }
        chainShape.createChain(scaledVertices);
        fixtureDef.shape = chainShape;
        body.createFixture(fixtureDef).setUserData(Tomb.UserData.GROUND);
    }
}

最后,自我解释的图片,用WorldContactListener日志显示游戏画面本身和eclipse控制台:

enter image description here enter image description here

enter image description here

当试图爬上斜坡(或绝对任何非平坦表面)时会发生同样的事情:

enter image description here enter image description here

我已经尝试了所有可能的传感器形状和大小变化,因此这种行为不是由CircleShape的大小引起的。可能是这样的?或者任何不涉及ContactListener的解决方法?

1 个答案:

答案 0 :(得分:0)

这笔交易是一次发生多次碰撞。在你的最后一张图片上你可以看到你的玩家和多边形之间仍然存在(2-1 + 2-1)= 2次碰撞。

这是我的示例解决方案: 使用函数incCollision()和decCollision()制作一些碰撞计数器类,也许会有一些bool isCollison()告诉你实际上是否有碰撞。

编辑ContactListener类:

public void beginContact(Contact contact)
{
...
   if((userDataA == Tomb.UserData.GROUND || userDataB == Tomb.UserData.GROUND) 
      && (userDataA == Tomb.UserData.PLAYER_FEET  || userDataB == Tomb.UserData.PLAYER_FEET))
        {   
            Gdx.app.log("collision", "start");
            counter.incCollision();
        } 
}

public void endContact(Contact contact)
{
...
if((userDataA == Tomb.UserData.GROUND || userDataB == Tomb.UserData.GROUND) 
  && (userDataA == Tomb.UserData.PLAYER_FEET  || userDataB == Tomb.UserData.PLAYER_FEET))
    {   
        Gdx.app.log("collision", "stop");
        counter.decCollision();
    } 
}