Search code examples
androidlibgdxgame-physicsbulletphysics

Bouncing ball in libgdx using bullet3d physics


I am trying to create program of bouncing balls uisng libgdx in 3d.I am complete beginner just started getting hands on libgdx. I am able to detect the collision between the bat and ball but unable to get it bounced back

Here is my  complete code

    public class Main implements ApplicationListener {
        final static short GROUND_FLAG = 1 << 8;
        final static short OBJECT_FLAG = 1 << 9;
        final static short ALL_FLAG = -1;

        class MyContactListener extends ContactListener {
            @Override
            public boolean onContactAdded(int userValue0, int partId0, int index0,
                    int userValue1, int partId1, int index1) {
                //instances.get(userValue0).moving = false;
                //instances.get(userValue1).moving = false;
                return true;
            }
        }

        static class MyMotionState extends btMotionState {
            Matrix4 transform;

            @Override
            public void getWorldTransform(Matrix4 worldTrans) {
                worldTrans.set(transform);
            }

            @Override
            public void setWorldTransform(Matrix4 worldTrans) {
                transform.set(worldTrans);
            }
        }

        static class GameObject extends ModelInstance implements Disposable {

            public final btRigidBody body;
            public boolean moving;
            public final MyMotionState motionState;

            public GameObject(Model model, String node,
                    btRigidBody.btRigidBodyConstructionInfo constructionInfo) {
                super(model, node);
                motionState = new MyMotionState();
                motionState.transform = transform;
                body = new btRigidBody(constructionInfo);
                body.setMotionState(motionState);
            }

            @Override
            public void dispose() {
                // TODO Auto-generated method stub
                body.dispose();
                motionState.dispose();
            }

            static class Constructor implements Disposable {
                public final Model model;
                public final String node;
                public final btCollisionShape shape;
                public final btRigidBody.btRigidBodyConstructionInfo constructionInfo;
                public static Vector3 inertia = new Vector3();

                public Constructor(Model model, String node,
                        btCollisionShape shape, float mass) {
                    this.model = model;
                    this.node = node;
                    this.shape = shape;
                    if (mass > 0f) {
                        shape.calculateLocalInertia(mass, inertia);
                    } else {
                        inertia.set(0, 0, 0);
                    }
                    this.constructionInfo = new btRigidBody.btRigidBodyConstructionInfo(
                            mass, null, shape, inertia);
                }

                public GameObject construct() {
                    return new GameObject(model, node, constructionInfo);
                }

                @Override
                public void dispose() {
                    shape.dispose();
                    constructionInfo.dispose();
                }
            }
        }

        PerspectiveCamera camera;
        Environment environment;
        ModelBatch modelBatch;
        Model model;
        Array<GameObject> instances;
        ArrayMap<String, GameObject.Constructor> constructors;
        btCollisionConfiguration configuration;
        btDispatcher dispatcher;
        btBroadphaseInterface broadphaseInterface;
        btDynamicsWorld dynamicWorld;
        btConstraintSolver solver;
        MyContactListener contactListener;
        float spawTimer;

        @Override
        public void create() {
            // TODO Auto-generated method stub
            Bullet.init();

            modelBatch = new ModelBatch();
            environment = new Environment();
            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));

            camera = new PerspectiveCamera(67, Gdx.graphics.getWidth(),
                    Gdx.graphics.getHeight());
            camera.position.set(3f, 7f, 10f);
            camera.lookAt(0, 4f, 0);
            camera.near = 1f;
            camera.far = 300f;
            camera.update();

            ModelBuilder builder = new ModelBuilder();

            builder.begin();
            builder.node().id = "ground";
            builder.part("ground", GL20.GL_TRIANGLES,
                    Usage.Position | Usage.Normal,
                    new Material(ColorAttribute.createDiffuse(Color.RED))).box(5f,
                    1f, 5f);
            builder.node().id = "sphere";
            builder.part("sphere", GL20.GL_TRIANGLES,
                    Usage.Position | Usage.Normal,
                    new Material(ColorAttribute.createDiffuse(Color.GREEN)))
                    .sphere(1f, 1f, 1f, 10, 10);
            model = builder.end();
            constructors = new ArrayMap<String, Main.GameObject.Constructor>(
                    String.class, GameObject.Constructor.class);

            constructors.put("ground", new GameObject.Constructor(model, "ground",
                    new btBoxShape(new Vector3(2.5f, .5f, 2.5f)), 0f));
            constructors.put("ball", new GameObject.Constructor(model, "sphere",
                    new btSphereShape(0.5f), 3f));

            configuration = new btDefaultCollisionConfiguration();
            dispatcher = new btCollisionDispatcher(configuration);
            solver = new btSequentialImpulseConstraintSolver();
            broadphaseInterface = new btDbvtBroadphase();
            dynamicWorld = new btDiscreteDynamicsWorld(dispatcher,
                    broadphaseInterface, solver, configuration);
            dynamicWorld.setGravity(new Vector3(0, -10, 0));
            contactListener = new MyContactListener();

            instances = new Array<Main.GameObject>();
            GameObject object = constructors.get("ground").construct();
            object.body.setCollisionFlags(object.body.getCollisionFlags()
                    | btCollisionObject.CollisionFlags.CF_KINEMATIC_OBJECT);
            instances.add(object);
            dynamicWorld.addRigidBody(object.body);
            object.body.setActivationState(Collision.DISABLE_DEACTIVATION);
            createBall();

        }

        public void createBall() {
            GameObject obj = constructors.get("ball").construct();
            //obj.moving = true;
            obj.transform.setFromEulerAngles(MathUtils.random(360f),
                    MathUtils.random(360f), MathUtils.random(360f));
            obj.transform.trn(0f, 9f, 0f);
            //obj.body.proceedToTransform(obj.transform);
            obj.body.setRestitution(1.0f);
            obj.body.setFriction(1.0f);
            obj.body.setWorldTransform(obj.transform);
            obj.body.setUserValue(instances.size);
            obj.body.setCollisionFlags(obj.body.getCollisionFlags()
                    | btCollisionObject.CollisionFlags.CF_CUSTOM_MATERIAL_CALLBACK);
            instances.add(obj);
            // dynamicWorld.addCollisionObject(obj.body, OBJECT_FLAG, GROUND_FLAG);
            dynamicWorld.addRigidBody(obj.body);
        }

        @Override
        public void resize(int width, int height) {

        }

        float angle, speed = 10f;

        @Override
        public void render() {
            // TODO Auto-generated method stub
            final float delta = Gdx.graphics.getDeltaTime();

            angle = (angle + delta+speed) % 360;
            instances.get(0).transform.setTranslation(0f,MathUtils.sinDeg(angle),0f);
            //instances.get(0).body.setWorldTransform(instances.get(0).transform);
            dynamicWorld.stepSimulation(delta, 5, 1 / 60f);


            Gdx.gl.glClearColor(0.3f, 0.3f, 0.3f, 1.f);
            Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);

            modelBatch.begin(camera);
            modelBatch.render(instances, environment);
            modelBatch.end();
        }

        @Override
        public void pause() {

        }

        @Override
        public void resume() {

        }

        @Override
        public void dispose() {
            // TODO Auto-generated method stub
            for (GameObject obj : instances)
                obj.dispose();
            instances.clear();

            for (GameObject.Constructor ctor : constructors.values())
                ctor.dispose();
            constructors.clear();

            dynamicWorld.dispose();
            solver.dispose();
            broadphaseInterface.dispose();
            dispatcher.dispose();
            configuration.dispose();

            contactListener.dispose();

            modelBatch.dispose();
            model.dispose();
        }

    }
}

Here is my updated code right now I am able to bounce the ground which is not my objective but my objective is to bounce the ball when it hits the code applied for moving of the ground is unable to get appied to ball. Please help.


Solution

  • Here is the code.Finally the ball bounce

    public class Main implements ApplicationListener {
        final static short GROUND_FLAG = 1 << 8;
        final static short OBJECT_FLAG = 1 << 9;
        final static short ALL_FLAG = -1;
        public float delta;
    
        class MyContactListener extends ContactListener {
            @Override
            public boolean onContactAdded(int userValue0, int partId0, int index0,
                    int userValue1, int partId1, int index1) {
                // Gdx.app.log("onContact", "onContact Added");
                instances.get(1).body.setLinearVelocity(new Vector3(0, 10f, 0f));
                return true;
            }
        }
    
        static class MyMotionState extends btMotionState {
            Matrix4 transform;
    
            @Override
            public void getWorldTransform(Matrix4 worldTrans) {
                worldTrans.set(transform);
            }
    
            @Override
            public void setWorldTransform(Matrix4 worldTrans) {
                transform.set(worldTrans);
            }
        }
    
        static class GameObject extends ModelInstance implements Disposable {
    
            public final btRigidBody body;
            public boolean moving;
            public final MyMotionState motionState;
    
            public GameObject(Model model, String node,
                    btRigidBody.btRigidBodyConstructionInfo constructionInfo) {
                super(model, node);
                motionState = new MyMotionState();
                motionState.transform = transform;
                body = new btRigidBody(constructionInfo);
                body.setMotionState(motionState);
            }
    
            @Override
            public void dispose() {
                // TODO Auto-generated method stub
                body.dispose();
                motionState.dispose();
            }
    
            static class Constructor implements Disposable {
                public final Model model;
                public final String node;
                public final btCollisionShape shape;
                public final btRigidBody.btRigidBodyConstructionInfo constructionInfo;
                public static Vector3 inertia = new Vector3();
    
    
                public Constructor(Model model, String node,
                        btCollisionShape shape, float mass) {
                    this.model = model;
                    this.node = node;
                    this.shape = shape;
                    if (mass > 0f) {
                        shape.calculateLocalInertia(mass, inertia);
    
                    } else {
                        inertia.set(0, 0, 0);
                    }
                    this.constructionInfo = new btRigidBody.btRigidBodyConstructionInfo(
                            mass, null, shape, inertia);
                }
    
                public GameObject construct() {
                    return new GameObject(model, node, constructionInfo);
                }
    
                @Override
                public void dispose() {
                    shape.dispose();
                    constructionInfo.dispose();
                }
            }
        }
    
        PerspectiveCamera camera;
        Environment environment;
        ModelBatch modelBatch;
        Model model;
        Array<GameObject> instances;
        ArrayMap<String, GameObject.Constructor> constructors;
        btCollisionConfiguration configuration;
        btDispatcher dispatcher;
        btBroadphaseInterface broadphaseInterface;
        btDynamicsWorld dynamicWorld;
        btConstraintSolver solver;
        MyContactListener contactListener;
        float spawTimer;
        GameObject obj;
    
        @Override
        public void create() {
            // TODO Auto-generated method stub
            Bullet.init();
    
            modelBatch = new ModelBatch();
            environment = new Environment();
            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));
    
            camera = new PerspectiveCamera(67, Gdx.graphics.getWidth(),
                    Gdx.graphics.getHeight());
            camera.position.set(3f, 7f, 10f);
            camera.lookAt(0, 4f, 0);
            camera.near = 1f;
            camera.far = 300f;
            camera.update();
    
            ModelBuilder builder = new ModelBuilder();
    
            builder.begin();
            builder.node().id = "ground";
            builder.part("ground", GL20.GL_TRIANGLES,
                    Usage.Position | Usage.Normal,
                    new Material(ColorAttribute.createDiffuse(Color.RED))).box(5f,
                    1f, 5f);
            builder.node().id = "sphere";
            builder.part("sphere", GL20.GL_TRIANGLES,
                    Usage.Position | Usage.Normal,
                    new Material(ColorAttribute.createDiffuse(Color.GREEN)))
                    .sphere(1f, 1f, 1f, 10, 10);
            model = builder.end();
            constructors = new ArrayMap<String, Main.GameObject.Constructor>(
                    String.class, GameObject.Constructor.class);
    
            constructors.put("ground", new GameObject.Constructor(model, "ground",
                    new btBoxShape(new Vector3(2.5f, .5f, 2.5f)), 0f));
            constructors.put("ball", new GameObject.Constructor(model, "sphere",
                    new btSphereShape(0.5f), 0.5f));
    
            configuration = new btDefaultCollisionConfiguration();
            dispatcher = new btCollisionDispatcher(configuration);
            solver = new btSequentialImpulseConstraintSolver();
            broadphaseInterface = new btDbvtBroadphase();
            dynamicWorld = new btDiscreteDynamicsWorld(dispatcher,
                    broadphaseInterface, solver, configuration);
            dynamicWorld.setGravity(new Vector3(0, -8f, 0));
            contactListener = new MyContactListener();
    
            instances = new Array<Main.GameObject>();
            GameObject object = constructors.get("ground").construct();
            object.body.setCollisionFlags(object.body.getCollisionFlags()
                    | btCollisionObject.CollisionFlags.CF_KINEMATIC_OBJECT);
            instances.add(object);
            dynamicWorld.addRigidBody(object.body);
            object.body.setActivationState(Collision.DISABLE_DEACTIVATION);
            createBall();
    
        }
    
        public void createBall() {
            obj = constructors.get("ball").construct();
    
            obj.transform.trn(0f, 11f, 0f);
            obj.body.setWorldTransform(obj.transform);
            obj.body.setUserValue(instances.size);
            obj.body.setCollisionFlags(obj.body.getCollisionFlags()
                    | btCollisionObject.CollisionFlags.CF_CUSTOM_MATERIAL_CALLBACK);
            obj.body.setFriction(1.0f);
            obj.body.setRestitution(3.0f);
            instances.add(obj);
    
            dynamicWorld.addRigidBody(obj.body);
        }
    
        @Override
        public void resize(int width, int height) {
    
        }
    
        float angle, speed = 10f, yTranslate = 0f, zAngle = 0f;
    
        @Override
        public void render() {
            // TODO Auto-generated method stub
            delta = Gdx.graphics.getDeltaTime();
            angle = (angle + delta + speed) % 360;
    
            if (Gdx.input.isTouched()) {
    
                if (yTranslate > -60f) {
                    zAngle -= 0.2f;
                } else {
                    // yTranslate = 30f;
                }
                instances.get(0).transform.setToRotation(0f, 0f, 2f, zAngle);
    
    
            } else {
                instances.get(0).transform.setToRotation(0f, 0f, 1f, 30f);
                instances.get(0).transform.setTranslation(0f, 0f, 0f);
            }
    
            //instances.get(0).transform.setTranslation(0f,0f,0f);
            dynamicWorld.stepSimulation(delta, 5, 1 / 60f);
    
            Gdx.gl.glClearColor(0.3f, 0.3f, 0.3f, 1.f);
            Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
            modelBatch.begin(camera);
            modelBatch.render(instances, environment);
            modelBatch.end();
        }
    
        @Override
        public void pause() {
    
        }
    
        @Override
        public void resume() {
    
        }
    
        @Override
        public void dispose() {
            // TODO Auto-generated method stub
            for (GameObject obj : instances)
                obj.dispose();
            instances.clear();
    
            for (GameObject.Constructor ctor : constructors.values())
                ctor.dispose();
            constructors.clear();
    
            dynamicWorld.dispose();
            solver.dispose();
            broadphaseInterface.dispose();
            dispatcher.dispose();
            configuration.dispose();
    
            contactListener.dispose();
    
            modelBatch.dispose();
            model.dispose();
        }
    
    }