Box2D перемещает тело в другое положение при столкновении - PullRequest
0 голосов
/ 02 июня 2019

У меня есть два тела, динамическое и кинематическое тело.Когда они столкнулись друг с другом, я хочу изменить положение кинематического тела.Я добавил контактный прослушиватель и смог обнаружить столкновение.Но когда я хочу изменить трансформацию кинематического тела, моя игра вылетает.Я действительно оценил бы вашу помощь.

Ошибка: AL lib: (EE) alc_cleanup: 1 устройство не закрыто Утверждение не удалось!

Программа: D: \ Program Files \ Android \ Android Studio \ jre\ bin \ java.exe Файл: /var/jenkins/.jenkins/workspace/libgdx/extensions/gdx-box2d/gdx-box2d/jni/Box2D/Dynamics/b2Body.cpp, строка 419

Выражение:m_world-> IsLocked () == false

public class Player extends Sprite {
public static final float scale = 12;
public static final float moveSpeed = 110;
public Body b2body;

public Player(World world) {
    super(new Texture("playercut.jpg"));
    setBounds(0,0,getWidth() / (FishAdventureMain.PPM * Player.scale), getHeight() / (FishAdventureMain.PPM * Player.scale));
    BodyDef bdef = new BodyDef();
    PolygonShape shape = new PolygonShape();
    FixtureDef fdef = new FixtureDef();
    bdef.type = BodyDef.BodyType.DynamicBody;
    bdef.position.set(650/FishAdventureMain.PPM, 200 / FishAdventureMain.PPM);
    b2body = world.createBody(bdef);
    shape.setAsBox(getWidth() / 3, getHeight() / 5);
    fdef.shape = shape;
    b2body.createFixture(fdef).setUserData("head");
}

public void update() {
    super.setPosition(b2body.getPosition().x - getWidth()/2, (b2body.getPosition().y - getHeight()/2) + (float)Math.sin(System.currentTimeMillis() * 0.009) * 0.04f);
}

}

public class AbstractGameObj {
protected final float moveSpeed = 90;
private Sprite sprite;
protected World world;
protected Body body;
protected Fixture fixture;
protected Vector2 position;

public AbstractGameObj(World world, Sprite sprite, Vector2 position, float scaleFactor1, float scaleFactor2) {
    this.world = world;
    this.sprite = sprite;
    this.position = position;

    BodyDef bdef = new BodyDef();
    PolygonShape shape = new PolygonShape();
    FixtureDef fdef = new FixtureDef();
    bdef.position.set(position);
    bdef.type = BodyDef.BodyType.KinematicBody;
    body = world.createBody(bdef);
    shape.setAsBox(sprite.getWidth() / scaleFactor1, sprite.getHeight() / scaleFactor2);
    fdef.shape = shape;
    fixture = body.createFixture(fdef);
}
public void update(float dt) {
    sprite.setPosition(body.getPosition().x - sprite.getWidth()/2, body.getPosition().y - sprite.getWidth() / 2);
    body.setLinearVelocity(moveSpeed *dt, 0);
}
public void onCollision() {

}
public Sprite getSprite() { return this.sprite; }

}

public class Coconut extends AbstractGameObj{

public Coconut(World world, Sprite sprite, Vector2 position, float scaleFactor1, float scaleFactor2) {
    super(world, sprite, position, scaleFactor1, scaleFactor2);
    fixture.setUserData(this);
}

@Override
public void onCollision() {
    body.setTransform(100, 100, body.getAngle());
}

}

public class B2WorldCreator {

private Sprite cocoSprite1;
private Sprite cocoSprite2;

private Array<Coconut> cocoNuts;

public B2WorldCreator(World world) {
    //Border bottom
    BodyDef bdef = new BodyDef();
    PolygonShape shape = new PolygonShape();
    FixtureDef fdef = new FixtureDef();

    bdef.type = BodyDef.BodyType.StaticBody;
    bdef.position.set(0, 0);
    shape.setAsBox(FishAdventureMain.V_WIDTH / FishAdventureMain.PPM, 1 / FishAdventureMain.PPM);
    fdef.shape = shape;
    world.createBody(bdef).createFixture(fdef);

    //Border Top
    bdef.type = BodyDef.BodyType.StaticBody;
    bdef.position.set(0, FishAdventureMain.V_HEIGHT / FishAdventureMain.PPM);
    shape.setAsBox(FishAdventureMain.V_WIDTH / FishAdventureMain.PPM, 1 / FishAdventureMain.PPM);
    fdef.shape = shape;
    world.createBody(bdef).createFixture(fdef);

    //Border left
    bdef.type = BodyDef.BodyType.StaticBody;
    bdef.position.set(FishAdventureMain.V_WIDTH / FishAdventureMain.PPM, FishAdventureMain.V_HEIGHT / FishAdventureMain.PPM);
    shape.setAsBox(1 / FishAdventureMain.PPM, FishAdventureMain.V_HEIGHT / FishAdventureMain.PPM);
    fdef.shape = shape;
    world.createBody(bdef).createFixture(fdef);

    //Border kind of middle
    bdef.type = BodyDef.BodyType.StaticBody;
    bdef.position.set(200 / FishAdventureMain.PPM, 0);
    shape.setAsBox(1 / FishAdventureMain.PPM, FishAdventureMain.V_HEIGHT / FishAdventureMain.PPM);
    fdef.shape = shape;
    world.createBody(bdef).createFixture(fdef);

    //Coconuts
    cocoNuts = new Array<Coconut>();
    cocoSprite1 = new Sprite(new Texture("coconut.jpg"));
    cocoSprite1.setBounds(0,0, cocoSprite1.getWidth() / FishAdventureMain.PPM/10, cocoSprite1.getHeight() / FishAdventureMain.PPM/10);
    cocoSprite2 = new Sprite(new Texture("coconut.jpg"));
    cocoSprite2.setBounds(0,0, cocoSprite2.getWidth() / FishAdventureMain.PPM/10, cocoSprite2.getHeight() / FishAdventureMain.PPM/10);
    cocoNuts.add(new Coconut(world, cocoSprite1, new Vector2(-300 / FishAdventureMain.PPM, 2), 1.8f, 1.8f));
    cocoNuts.add(new Coconut(world, cocoSprite2, new Vector2(-1800 / FishAdventureMain.PPM, 2), 1.8f, 1.8f));

}
public void updateCocoNuts(float dt) {
    for (Coconut nut : cocoNuts) {
        nut.update(dt);
    }
}
public void showCocoNuts(SpriteBatch sb) {
    for (Coconut nut : cocoNuts) {
        nut.getSprite().draw(sb);
    }
}

}

public class PlayScreen extends InputAdapter implements Screen {
private FishAdventureMain main;
private OrthographicCamera gameCam;
private Viewport gamePort;
private Hud hud;
private ButtonController bcont;
private Texture background;
private World world;
private Box2DDebugRenderer renderer;
private Player player;
private B2WorldCreator creator;

public PlayScreen(FishAdventureMain main) {
    this.main = main;
    gameCam = new OrthographicCamera();
    gamePort = new StretchViewport(FishAdventureMain.V_WIDTH / FishAdventureMain.PPM, FishAdventureMain.V_HEIGHT / FishAdventureMain.PPM, gameCam);
    hud = new Hud(main.batch);
    bcont = new ButtonController(main.batch);
    background = new Texture("background.jpg");
    world = new World(new Vector2(0, 0), true);
    creator = new B2WorldCreator(world);
    renderer = new Box2DDebugRenderer();
    player = new Player(world);
    gameCam.position.set(gamePort.getWorldWidth()/2, gamePort.getWorldHeight()/2,0);
    world.setContactListener(new ContactListener() {
        @Override
        public void beginContact(Contact contact) {
            Fixture fixA = contact.getFixtureA();
            Fixture fixB = contact.getFixtureB();

            if (fixA.getUserData() == "head" || fixB.getUserData() == "head") {
                Fixture head = fixA.getUserData() == "head" ? fixA : fixB;
                Fixture object = head == fixA ? fixB : fixA;
                if (object.getUserData() != null && AbstractGameObj.class.isAssignableFrom(object.getUserData().getClass())) {
                    ((AbstractGameObj) object.getUserData()).onCollision();
                }
            }
        }

        @Override
        public void endContact(Contact contact) {

        }

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

        }

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

        }
    });
}

@Override
public void show() {
    Gdx.gl.glClearColor(0, 0,0,1);
    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

    main.batch.setProjectionMatrix(gamePort.getCamera().combined);
    main.batch.begin();
    main.batch.draw(background, 0, 0, FishAdventureMain.V_WIDTH / FishAdventureMain.PPM, FishAdventureMain.V_HEIGHT / FishAdventureMain.PPM);
    player.draw(main.batch);
    creator.showCocoNuts(main.batch);
    main.batch.end();
    renderer.render(world, gameCam.combined);

    main.batch.setProjectionMatrix(hud.stage.getCamera().combined);
    hud.stage.draw();
    bcont.stage.draw();
}

@Override
public void render(float delta) {
    update(delta);
    show();
}

public void update(float dt) {
    handleInput(dt);
    world.step(1/60f, 6, 2);
    gameCam.update();
    player.update();
    creator.updateCocoNuts(dt);
}

private void handleInput(float dt) {
    if (bcont.getUpPressed())
        player.b2body.setLinearVelocity(new Vector2(player.b2body.getLinearVelocity().x, Player.moveSpeed * dt));
    else if (bcont.getDownPressed())
        player.b2body.setLinearVelocity(new Vector2(player.b2body.getLinearVelocity().x, -Player.moveSpeed * dt));
    else
        player.b2body.setLinearVelocity(player.b2body.getLinearVelocity().x, 0);
    if(bcont.getLeftPressed())
        player.b2body.setLinearVelocity(new Vector2(-Player.moveSpeed * dt, player.b2body.getLinearVelocity().y));
    else if (bcont.getRightPressed())
        player.b2body.setLinearVelocity(new Vector2(Player.moveSpeed * dt, player.b2body.getLinearVelocity().y));
    else
        player.b2body.setLinearVelocity(new Vector2(0, player.b2body.getLinearVelocity().y));
}

@Override
public void resize(int width, int height) {
    gamePort.update(width, height);
}

@Override
public void pause() {

}

@Override
public void resume() {

}

@Override
public void hide() {

}

@Override
public void dispose() {
    background.dispose();
    hud.dispose();
}

} ​​

1 Ответ

1 голос
/ 03 июня 2019

Проблема в том, что вы пытаетесь переместить объект во время физической обработки.Box2D не любит, чтобы объект перемещался или изменялся во время физической обработки (например, во время столкновений)

Чтобы обойти эту проблему, вы должны установить флаг для столкнувшегося объекта, а затем переместить его, как только физиказавершено.

например,

// during physics processing
@Override
public void onCollision() {
    //add body to array of objects to move
}

, а затем добавить

 public void update(float dt) {
    handleInput(dt);
    world.step(1/60f, 6, 2);
    // world is done processing physics
    // loop through array and move objects
    gameCam.update();
    player.update();
    creator.updateCocoNuts(dt);
}
...