josephoneill
josephoneill

Reputation: 853

Box2D crashes when destroying body (Expression: m_bodyCount < m_bodyCapacity)

Expression: m_bodyCount < m_bodyCapacity

That is the error I'm getting. The entire game crashes when I get this error. Now, here's the thing: I only get the error on certain I try to destroy, more specifically, bodies that were made during the game. What I mean is at the beginning of the game, I load the level and create all the bodies for each piece of the level. But, there are items that are made as the game runs, such as bullets, cannons, and coins. I can destroy any of the bodies created when the level is loaded, but when I try to destroy bodies created afterwards, I get the above error.

Here's an example. I spawn a CannonBall with my Cannon: Cannon.class

if(reloadProgress >= RELOAD_TIME) {
            CannonBall cannonBall = new CannonBall();
            cannonBall.setXDirection(xDirection);
            cannonBall.setYDirection(yDirection);
            cannonBall.position.set(cannonBallPos);
            Box2DHelper.makeFixture(cannonBall, BodyType.KinematicBody, origin, WorldController.b2world,
                    true, false);
            Level.cannonBalls.add(cannonBall);
            reloadProgress -= RELOAD_TIME;
        } else {
            reloadProgress += deltaTime;
        }

Where Box2DHelper.makeFixture() is:

public static void makeFixture(GameObject object, BodyType type,
            Vector2 origin, World b2world, boolean addUserData, boolean isMonster) {
        BodyDef bodyDef = new BodyDef();
        bodyDef.type = type;
        bodyDef.position.set(object.position);
        Body body = b2world.createBody(bodyDef);
        if(addUserData)
            body.setUserData(object);
        object.body = body;
        PolygonShape polygonShape = new PolygonShape();
        origin.x = object.bounds.width / 2.0f;
        origin.y = object.bounds.height / 2.0f;
        polygonShape.setAsBox(object.bounds.width / 2.0f,
                object.bounds.height / 2.0f, origin, 0);
        FixtureDef fixtureDef = new FixtureDef();
        fixtureDef.shape = polygonShape;
        if(isMonster) fixtureDef.filter.groupIndex = Constants.GROUP_MONSTER;
        body.createFixture(fixtureDef);
        polygonShape.dispose();
    }

So now I've created my CannonBall and set its body. Now, after 10 seconds, if it hasn't hit anything, I destroy it:

CannonBall.class

if (existanceDuration >= CANNON_BALL_EXISTANCE_DURATION) {
            //Destroy cannon ball
            CollisionHandler.bodiesToRemoveList.add(this.body);
        }

Now that I have added the body into the list, I have to remove it: CollisionHandler.class:

public static void removeSpecifiedBodies() {
        Iterator<Body> i = bodiesToRemoveList.iterator();
        while (i.hasNext()) {
            Body desBod = i.next();
            removeObjectFromList(desBod); //This is just to remove the object as well

            WorldController.b2world.destroyBody(desBod);

            if (perCharHitAction == true) {
                performCharacterDeathAction(Level.character);
                perCharHitAction = false;
            }
            i.remove();
        }
        bodiesToRemoveList.clear();
    }

But now, I need to actually call this method. I do this in my main update method, right after b2world.step(): WorldController.class:

public void update(float deltaTime) {
        ...
        b2world.step(deltaTime, 8, 3);
        if (CollisionHandler.bodiesToRemoveList.size() > 0)
            CollisionHandler.removeSpecifiedBodies();

Now, like I stated before, this method works fine when I destroy objects made at the loading of the level, but on objects I later create, it doesn't.

Why does my game keep crashing after trying to destroy box2d bodies later created in my game?

Edit: I call this method right after the level has loaded for creating the object's bodies:

private void initPhysics() {
        if (b2world != null)
            b2world.dispose();
        b2world = new World(new Vector2(0, -9.81f), true);
        Vector2 origin = new Vector2();
        b2world.setContactListener(new CollisionHandler());

        // Create Box2D Fixtures
        for (Grass grass : Level.grasses)
            Box2DHelper.makeEdgeChain(grass, BodyType.StaticBody, origin,
                    b2world, true);

        // Bricks
        for (Brick brick : Level.bricks)
            // Box2DHelper.makeFixture(brick, BodyType.KinematicBody, origin,
            // b2world, true);
            Box2DHelper.makeEdgeChain(brick, BodyType.StaticBody, origin,
                    b2world, true);

        // Item Boxes
        for (ItemBox box : Level.itemBoxes)
            Box2DHelper.makeFixture(box, BodyType.KinematicBody, origin,
                    b2world, true, false);

        //Enemies
        for (Goomba goomba : Level.goombas)
            Box2DHelper.makeFixture(goomba, BodyType.DynamicBody, origin,
                    b2world, true, true);

        for (Koopa koopa : Level.koopas)
            Box2DHelper.makeFixture(koopa, BodyType.DynamicBody, origin,
                    b2world, true, true);

        // Cannons
        for (Cannon cannon : Level.cannons)
            Box2DHelper.makeFixture(cannon, BodyType.KinematicBody, origin,
                    b2world, true, true);


        // Character
        BodyDef bodyDef = new BodyDef();
        bodyDef.type = BodyType.DynamicBody;
        bodyDef.position.set(Level.character.position);
        Body body = b2world.createBody(bodyDef);
        body.setUserData(Level.character);
        Level.character.body = body;

        CircleShape polygonShapeHead = new CircleShape();
        origin.x = Level.character.circleBoundOrigin.x * 2.0f;
        origin.y = Level.character.circleBoundOrigin.y * 3.0f;
        // polygonShapeHead.setAsBox(level.character.circleBoundOrigin.x,
        // level.character.circleBoundOrigin.y, origin, 0);
        polygonShapeHead.setPosition(origin);
        polygonShapeHead.setRadius(Level.character.circleBoundOrigin.x);
        FixtureDef fixtureDefHead = new FixtureDef();
        fixtureDefHead.shape = polygonShapeHead;
        fixtureDefHead.friction = Level.character.friction.x;
        body.createFixture(fixtureDefHead);

        polygonShapeHead.dispose();

        PolygonShape polygonShapeBod = new PolygonShape();
        origin = Level.character.rectBoundOrigin;
        polygonShapeBod.setAsBox(Level.character.rectBoundOrigin.x,
                Level.character.rectBoundOrigin.y, origin, 0);
        FixtureDef fixtureDefBod = new FixtureDef();
        fixtureDefBod.shape = polygonShapeBod;
        fixtureDefBod.friction = Level.character.friction.x;
        body.createFixture(fixtureDefBod);

        polygonShapeBod.dispose();
    }

Maybe the issue when creating bodies later in the game is the b2world?

Upvotes: 1

Views: 2048

Answers (1)

JPS
JPS

Reputation: 426

I had the same Error - I figured out, that it happens if you destroy the same body multiple times.

In my case I put the body into a list in the contact listener.. but I didn't make sure it was in the list only once.

That also explains why your problem was fixed once you worked with a boolean flag, that also made sure the same body was only destroyed once.

In short: You get this error if you try to destroy the same body over and over again.

Upvotes: 3

Related Questions