Search code examples
javaarrayslibgdxbulletphysics

Why Array size in my ContactListener derived class in Libgdx Bullet is always zero?


I am trying make create a ContactListener derived class in Libgdx using Bullet wrapper for collision detection like in this tutorial but in separate classes. It separate classes for rendering and game world. In render() method of class Render I pass an Array of model instances to this derived class. But when I run it gives an because Array size is zero. Here is the derived class :

package com.anutrix.brickbreaker3d.Helpers;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.g3d.ModelInstance;
import com.badlogic.gdx.physics.bullet.collision.ContactListener;
import com.badlogic.gdx.utils.Array;

public class CollisionListener extends ContactListener {

    private Array<ModelInstance> instances;

    public CollisionListener() {
        this.instances = new Array<ModelInstance>();
    }

    public void setModelInstances(Array<ModelInstance> instances) {
        this.instances = instances;
    }

    @Override
    public boolean onContactAdded(int userValue0, int partId0, int index0, int userValue1, int partId1, int index1) {
//instances.get(colObj1Wrap.getCollisionObject().getUserValue()).collided = false;error
        Gdx.app.log("instances.size", Integer.toString(instances.size));//zero
        Gdx.app.log("ddhbdfhd", "fhfgjfgj");
        return true;
    }
}

Here is the Renderer class:

package com.anutrix.brickbreaker3d.gameWorld;

import com.anutrix.brickbreaker3d.gameObjects.Ball;
import com.anutrix.brickbreaker3d.gameObjects.Brick;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.PerspectiveCamera;
import com.badlogic.gdx.graphics.g3d.Environment;
import com.badlogic.gdx.graphics.g3d.ModelBatch;
import com.badlogic.gdx.graphics.g3d.ModelInstance;
import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute;
import com.badlogic.gdx.graphics.g3d.environment.DirectionalLight;
import com.badlogic.gdx.graphics.g3d.utils.CameraInputController;
import com.badlogic.gdx.graphics.g3d.utils.ModelBuilder;
import com.badlogic.gdx.physics.bullet.DebugDrawer;
import com.badlogic.gdx.physics.bullet.collision.btCollisionDispatcher;
import com.badlogic.gdx.physics.bullet.collision.btCollisionWorld;
import com.badlogic.gdx.physics.bullet.collision.btDbvtBroadphase;
import com.badlogic.gdx.physics.bullet.collision.btDefaultCollisionConfiguration;
import com.badlogic.gdx.physics.bullet.linearmath.btIDebugDraw;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Disposable;

public class GameRenderer implements Disposable {

    private GameWorld gameWorld;
    private PerspectiveCamera cam;
    public ModelBatch modelBatch;
    private CameraInputController camController;
    private Environment environment;
    public Array<ModelInstance> instances;
    ModelBuilder mb = new ModelBuilder();
    btCollisionDispatcher dispatcher;

    public GameRenderer(GameWorld world) {
        this.modelBatch = new ModelBatch();
        this.environment = new Environment();
        this.instances = new Array<ModelInstance>();

        gameWorld = world;
        cam = new PerspectiveCamera(67, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
        cam.position.set(10f, 10f, 0f);
        cam.lookAt(0, 0, 0);
        cam.near = 1f;
        cam.far = 300f;
        cam.update();

        camController = new CameraInputController(cam);
        Gdx.input.setInputProcessor(camController);
        environment.set(new ColorAttribute(ColorAttribute.AmbientLight, 0.4f, 0.4f, 0.4f, 1f));
        environment.add(new DirectionalLight().set(0.8f, 0.8f, 0.8f, -1f, -0.8f, -0.2f));


    }

    public void render() {
        //Gdx.app.log("GameRenderer", "render");
        Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
        Gdx.gl.glClearColor(0f, 0.2f, 0.2f, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);

        for (Brick b : gameWorld.bricks) {
            b.getObject().setUserValue(instances.size);
            instances.add(b.getModelInstance());
        }
        for (Ball b : gameWorld.balls) {
            b.getObject().setUserValue(instances.size);
            instances.add(b.getModelInstance());
        }

        gameWorld.collisionListener.setModelInstances(instances);

        modelBatch.begin(cam);
        modelBatch.render(instances, environment);
        modelBatch.end();

        instances.clear();

    }

    @Override
    public void dispose() {
        modelBatch.dispose();
    }

}

What am I doing wrong? Inside setModelInstances() the instances.size is correct. But after each call to it, the instances.size is equal to 0 . Also I wasn't sure of pass by reference(since Java uses pass by value). So is it better(if it works) if I call setInstances() just once?


Solution

  • Both your CollisionListener#instances and GameRenderer#instances point to the same reference after your call to gameWorld.collisionListener.setModelInstances(instances); inside your GameRenderer#render() method.

    Then, at the end of the method, you are invoking:

        instances.clear();
    

    This would be clearing out instances. So, the size would become 0 when you call render.


    Instead, inside your setModelInstances method, you could create a new Array instance like this:

    public void setModelInstances(Array<ModelInstance> instances) {
        this.instances = new Array<>(instances);
    }
    

    Hope this helps!