0
votes

I'm working in a game in which I spawn an object every 1-3 seconds. This game object contains some assets for renderization purposes and a Box2D body. The thing is that I don't want to create thousands of objects. Instead, I would like to reuse them, resetting its properties (position, friction, etc.) and not creating a brand new object. I think that the best way to do this is implementing a pool of this objects but I'm concerned about it because after search for some info I've found several developers reporting memory leaks because all the objects created by Box2D internally.

What do you think is the best way to do this?

This is the class that I use to represent each game object:

public class GameObject extends Box2dGameObject {

    private static final float WIDTH = 0.85f;
    private static final float HEIGHT = 1;

    private Animation animationDying;
    private Animation animationFalling;
    private Animation animationIdle;
    private Animation animationJumping;
    private Animation animationRunning;

    private Body body;

    public GameObject(Vector2 position, World world) {
        super(position, world);

        init();
    }

    private void init() {
        super.init();

        dimensions.set(WIDTH, HEIGHT);

        /* Get assets */
        animationDying = Assets.instance.pirate.animationDying;
        animationFalling = Assets.instance.pirate.animationFalling;
        animationIdle = Assets.instance.pirate.animationIdle;
        animationJumping = Assets.instance.pirate.animationJumping;
        animationRunning = Assets.instance.pirate.animationRunning;

        /* Set default animation */
        setAnimation(animationIdle);

        body = createBox2dBody();  
    }

    private Body createBox2dBody() {
        BodyDef bodyDef = new BodyDef();
        bodyDef.fixedRotation = true;
        bodyDef.position.set(position);
        bodyDef.type = BodyType.DynamicBody;

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

        FixtureDef fixtureDef = new FixtureDef();
        fixtureDef.density = 1;
        fixtureDef.friction = 1;
        fixtureDef.shape = shape;

        Body body = world.createBody(bodyDef);
        fixture = body.createFixture(fixtureDef);

        shape.dispose();

        return body;
    }

    /* More code omitted */
}
1
Reposting the same question is not nice... However, I believe that you can reuse BodyDef, Shape, FixtureDef to create new bodies. Bodies cannot be pooled, because they are actually created and maintained by an external native (C++) module. Furthermore, I think that those "several developers reporting memory leaks" are all wrong, because a memory leak in this case makes no sense at all. You would probably get very weird behaviour, but no memory leaks...noone

1 Answers

2
votes

This seems like a case of early optimization and may not yield the results you are looking for.

Consider:

  1. All those objects sitting your "pool" are still registered internally in Box2D as objects. Will collision checking be performed on them? Will collision response? Will their usertag be pointing to an object in the "pool" (user tags are often used to reference the "owner" of the body)?
  2. There are life cycle issues associated with all the values in an object...you will have to be careful to manage the values (position is easy, but collision flags etc. gets deeper) for each object you take into and pull out of the pool. That sounds error prone.

If you are really only creating/destroying a single object every second, that does not seem like much of a performance/memory hit. If you are creating hundreds, that is a different story. I wrote a game where I had bullets being generated at a rate of 10-20 per second...each was derived from an "Entity" base class which is a composite (I called the class "Slug" I think). The "Slug" class held the body, the sprite, the collision handling logic, etc. When it collided or after a few seconds, it "died" and went into the pool. Pulling it from the pool caused it to re-create the body and I did not see this as a performance or memory bottleneck.

It did not recreate the parts that may cause larger allocation or were not necessary (e.g. the sprite). These don't need to be reclaimed until it is actually deleted from the pool because it is really just a reference to a sprite sheet that is shared. A specific "Init(...)" method was associated with the class so that the memory allocation could be separate from the initialization.

Your mileage may vary, of course. But I think you should look to see if it is really a problem (i.e. prototype it) before you build infrastructure to fix it.