2016-04-11 33 views
2

so habe ich ein Problem, das ich wirklich nicht verstehe. Nachdem ich versucht habe herauszufinden, was los ist, habe ich beschlossen, eine video aufzunehmen und hier zu fragen.Box2D Kollisionserkennung schlägt fehl

Behalten Sie im Video den True/False-Booleschen Wert in der linken Ecke im Auge. Das ist meine Variable canJumps Wert. Am Anfang geht der Wert zwischen wahr und falsch, nur indem man den "Player" links und rechts bewegt. Dies tritt auch auf, wenn der Spieler Steigungen und Gefälle ansteigt.

Die Karte/Kollisionsschicht wird mit Tiled erstellt.

Meine TiledObject Klasse:

public class TiledObjectUtil { 

public static float PPM = 32; 

public static void parseTiledObjectLayer(World world, MapObjects objects) { 
    for(MapObject object : objects) { 
     Shape shape; 

     if(object instanceof PolylineMapObject) { 
      shape = createPolyLine((PolylineMapObject) object); 

     } else { 
      continue; 
     } 

     Body body; 
     BodyDef bdef = new BodyDef(); 
     bdef.type = BodyDef.BodyType.StaticBody; 
     body = world.createBody(bdef); 
     body.createFixture(shape, 1.0f); 

     shape.dispose(); 
    } 
} 

private static ChainShape createPolyLine(PolylineMapObject polyline) { 
    float[] vertices = polyline.getPolyline().getTransformedVertices(); 
    Vector2[] worldVertices = new Vector2[vertices.length/2]; 

    for(int i = 0; i<worldVertices.length; i++) { 
     worldVertices[i] = new Vector2(vertices[i * 2]/PPM, vertices[i*2+1]/PPM); 
    } 
    ChainShape cs = new ChainShape(); 
    cs.createChain(worldVertices); 
    return cs; 
}} 

Und meine Spielerklasse:

public class Player { 

private BodyDef def = new BodyDef(); 
public Body playerBody; 


private float speed = 10; 

public Player() { 

} 

public void update() { 

    if (InputUtil.moveLeft) { 
     playerBody.setLinearVelocity(-speed, playerBody.getLinearVelocity().y); 
    } 
    if (InputUtil.moveRight) { 
     playerBody.setLinearVelocity(speed, playerBody.getLinearVelocity().y); 
    } 

    if (!InputUtil.moveLeft && !InputUtil.moveRight) { 

     playerBody.setLinearVelocity(0, playerBody.getLinearVelocity().y); 
    } 
} 

public void jump() { 
    if (ContactUtil.canJump) { 
     playerBody.applyLinearImpulse(0, 80, 0, 0, true); 

    } 

} 


public Body createPlayer(World world) { 
    def.type = BodyDef.BodyType.DynamicBody; 
    def.position.set(20, 20); 
    def.fixedRotation = true; 

    playerBody = world.createBody(def); 

    PolygonShape shape = new PolygonShape(); 
    shape.setAsBox(2f/2, 2f/2); 

    FixtureDef playerFixture = new FixtureDef(); 
    playerFixture.density = 1f; 
    playerFixture.shape = shape; 
    playerFixture.restitution = 0f; 
    playerFixture.friction = 1f; 
    playerBody.createFixture(playerFixture); 

    shape.setAsBox(2f/2, 1f/2, new Vector2(0, 0 - 1), 0); 
    playerFixture.shape = shape; 
    playerFixture.isSensor = true; 
    playerBody.createFixture(playerFixture).setUserData("player"); 

    shape.dispose(); 

    return playerBody; 
} } 

Und schließlich meine ContactListener:

public class ContactUtil implements ContactListener { 

public static boolean canJump; 


public ContactUtil() { 

} 

@Override 
public void beginContact(Contact contact) { 

    Fixture fixtureA = contact.getFixtureA(); 
    Fixture fixtureB = contact.getFixtureB(); 

    System.out.println(fixtureA.getUserData() + ", " + fixtureB.getUserData()); 

    if (fixtureA.getUserData() == "player" && fixtureB.getUserData() == null) { 
     canJump = true; 
    } 
    if (fixtureA.getUserData() == null && fixtureB.getUserData() == "player") { 
     canJump = true; 
    } 

} 

@Override 
public void endContact(Contact contact) { 

    Fixture fixtureA = contact.getFixtureA(); 
    Fixture fixtureB = contact.getFixtureB(); 

    System.out.println(fixtureA.getUserData() + ", " + fixtureB.getUserData()); 

    if (fixtureA.getUserData() == "player" && fixtureB.getUserData() == null) { 
     canJump = false; 
    } 
    if (fixtureA.getUserData() == null && fixtureB.getUserData() == "player") { 
     canJump = false; 
    } 

} 

Auch meine Spieler springt ein wenig jedes Mal stoppt in einer Steigung. Ich weiß, dass es wegen dieser Linie ist: playerBody.setLinearVelocity(0, playerBody.getLinearVelocity().y);

Wenn jemand einen besseren Weg kennt, um die Bewegung zu behandeln, würde es sehr geschätzt werden.

Antwort

1

Ich erinnere mich, dieses genaue Problem in der Vergangenheit zu haben! Ich denke, das Problem ist mit Ihrer Logik in beginContact und endContact.

Ich werde meine rohen MS Paint Fähigkeiten ausbrechen, um das Problem zu erklären. Stellen Sie sich die folgende Situation vor: Ihr Spieler ist in der Luft und fällt auf eine Plattform darunter. Wie zu erwarten, ist canJump false: enter image description here

Der Spieler fällt und landet, und beginContact mit Plattform einer aufgerufen. Dies setzt canJump auf true. Auch dies ist wie erwartet: enter image description here

Jetzt bewegt sich der Spieler nach rechts, bis sie mit Plattform zwei in Kontakt kommen. beginContact mit Plattform zwei heißt. Nochmals, canJump ist auf wahr gesetzt. enter image description here

Und hier ist das Problem. Im letzten Schritt war der Spieler immer noch in Kontakt mit der ersten Plattform. Aber jetzt sind sie nicht, also endContact mit Plattform wird genannt. canJump ist jetzt auf false eingestellt. Dies erklärt das unerwartete Verhalten, das Sie bekommen. enter image description here

Die Lösung ist ziemlich einfach. Sie müssen eine Kontaktliste pflegen, die der Spieler unten berührt. Es gibt eine Anleitung genau das in diesem iforce2d Artikel zu tun: http://www.iforce2d.net/b2dtut/jumpability

Viel Glück!