Bullet Player Controller gravity is sideways

Viewed 365

I am making a 3D game using LibGDX and bullet by following the directions in the book Building a 3D Game with LibGDX by Sebastian Di Giuseppe. I've gotten to the part where you add a controllable character and for some reason instead of being thrown down, hes thrown sideways. My code is almost word for word the same as in the book.


import com.badlogic.ashley.core.Entity;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.VertexAttributes;
import com.badlogic.gdx.graphics.g3d.Material;
import com.badlogic.gdx.graphics.g3d.Model;
import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute;
import com.badlogic.gdx.graphics.g3d.attributes.FloatAttribute;
import com.badlogic.gdx.graphics.g3d.attributes.TextureAttribute;
import com.badlogic.gdx.graphics.g3d.utils.ModelBuilder;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.math.collision.BoundingBox;
import com.badlogic.gdx.physics.bullet.collision.btBoxShape;
import com.badlogic.gdx.physics.bullet.collision.btBroadphaseProxy;
import com.badlogic.gdx.physics.bullet.collision.btCapsuleShape;
import com.badlogic.gdx.physics.bullet.collision.btCollisionObject;
import com.badlogic.gdx.physics.bullet.collision.btCollisionShape;
import com.badlogic.gdx.physics.bullet.collision.btPairCachingGhostObject;
import com.badlogic.gdx.physics.bullet.dynamics.btKinematicCharacterController;
import com.badlogic.gdx.physics.bullet.dynamics.btRigidBody;

import Components.BulletComponent;
import Components.CharacterComponent;
import Components.ModelComponent;
import Components.PlayerComponent;
import States.MotionState;
import Systems.BulletSystem;

public class EntityFactory
{
    static ModelBuilder modelBuilder = new ModelBuilder();
    static Texture playerTexture = new Texture("data/badlogic.jpg");
    static Material material = new Material(TextureAttribute.createDiffuse(playerTexture), ColorAttribute.createSpecular(1, 1, 1, 1), FloatAttribute.createShininess(8f));
    static Model playerModel = modelBuilder.createCapsule(2f, 6f, 16, material, VertexAttributes.Usage.Position | VertexAttributes.Usage.Normal | VertexAttributes.Usage.TextureCoordinates);

    public static Entity createStaticEntity(Model model, float x, float y, float z)
    {
        final BoundingBox boundingBox = new BoundingBox();
        model.calculateBoundingBox(boundingBox);
        Vector3 tmpV = new Vector3();
        btCollisionShape col = new btBoxShape(tmpV.set(boundingBox.getWidth() * 0.5f, boundingBox.getHeight() * 0.5f, boundingBox.getDepth() * 0.5f));
        Entity entity = new Entity();
        ModelComponent modelComponent = new ModelComponent (model, x, y, z);
        entity.add(modelComponent);
        BulletComponent bulletComponent = new BulletComponent();
        bulletComponent.bodyInfo = new btRigidBody.btRigidBodyConstructionInfo(0, null, col, Vector3.Zero);
        bulletComponent.body = new btRigidBody(bulletComponent.bodyInfo);
        bulletComponent.body.userData = entity;
        bulletComponent.motionState = new MotionState(modelComponent.modelInstance.transform);
        ((btRigidBody)bulletComponent.body).setMotionState(bulletComponent.motionState);
        entity.add(bulletComponent);
        return entity;

    }

    public static Entity createCharacter(BulletSystem bulletSystem, float x, float y, float z)
    {
        Entity entity = new Entity();
        ModelComponent modelComponent = new ModelComponent(playerModel, x, y, z);
        entity.add(modelComponent);
        CharacterComponent characterComponent = new CharacterComponent();
        characterComponent.ghostObject = new btPairCachingGhostObject();
        characterComponent.ghostObject.setWorldTransform(modelComponent.modelInstance.transform);
        characterComponent.ghostShape = new btCapsuleShape(2f, 2f);
        characterComponent.ghostObject.setCollisionShape(characterComponent.ghostShape);
        characterComponent.ghostObject.setCollisionFlags(btCollisionObject.CollisionFlags.CF_CHARACTER_OBJECT);
        characterComponent.characterController = new btKinematicCharacterController(characterComponent.ghostObject, characterComponent.ghostShape, .35f);
        characterComponent.ghostObject.userData = entity;
        entity.add(characterComponent);
        bulletSystem.collisionWorld.addCollisionObject(entity.getComponent(CharacterComponent.class).ghostObject,
                (short) btBroadphaseProxy.CollisionFilterGroups.CharacterFilter,
                (short) (btBroadphaseProxy.CollisionFilterGroups.AllFilter));
        bulletSystem.collisionWorld.addAction(entity.getComponent(CharacterComponent.class).characterController);
        return entity;

    }

    public static Entity createPlayer(BulletSystem bulletSystem, float x, float y, float z)
    {
        Entity entity = createCharacter(bulletSystem, x, y ,z);
        entity.add(new PlayerComponent());
        return entity;
    }

}
package Systems;

import com.badlogic.ashley.core.Engine;
import com.badlogic.ashley.core.Entity;
import com.badlogic.ashley.core.EntityListener;
import com.badlogic.ashley.core.EntitySystem;
import com.badlogic.ashley.core.Family;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.graphics.Camera;
import com.badlogic.gdx.graphics.PerspectiveCamera;
import com.badlogic.gdx.math.Matrix4;
import com.badlogic.gdx.math.Vector3;
import com.laterdated.hotbox.GameWorld;

import Components.CharacterComponent;
import Components.ModelComponent;
import Components.PlayerComponent;

public class PlayerSystem extends EntitySystem implements EntityListener
{
    private Entity player;
    private PlayerComponent playerComponent;
    private CharacterComponent characterComponent;
    private ModelComponent modelComponent;
    private GameWorld gameWorld;
    private final Vector3 tmp = new Vector3();
    private final Camera camera;

    public PlayerSystem(GameWorld gameWorld, Camera camera)
    {
        this.camera = camera;
        this.gameWorld = gameWorld;
    }

    @Override
    public void addedToEngine(Engine engine)
    {
        engine.addEntityListener(Family.all(PlayerComponent.class).get(), this);
    }

    @Override
    public void entityAdded(Entity entity) 
    {
        player = entity;
        playerComponent = entity.getComponent(PlayerComponent.class);
        characterComponent = entity.getComponent(CharacterComponent.class);
        modelComponent = entity.getComponent(ModelComponent.class);
    }

    @Override
    public void update(float delta)
    {
        if(player == null)
            return;
        updateMovement(delta);
    }

        private void updateMovement(float delta) {
             float deltaX = -Gdx.input.getDeltaX() * 0.5f;
             float deltaY = -Gdx.input.getDeltaY() * 0.5f;
             tmp.set(0, 0, 0);
             camera.rotate(camera.up, deltaX);
             tmp.set(camera.direction).crs(camera.up).nor();
             camera.direction.rotate(tmp, deltaY);
             tmp.set(0, 0, 0);
             characterComponent.characterDirection.set(-1, 0,
             0).rot(modelComponent.modelInstance.transform).nor();
             characterComponent.walkDirection.set(0, 0, 0);
             if (Gdx.input.isKeyPressed(Input.Keys.W))
             characterComponent.walkDirection.add(camera.direction);
             if (Gdx.input.isKeyPressed(Input.Keys.S))
             characterComponent.walkDirection.sub(camera.direction);
             if (Gdx.input.isKeyPressed(Input.Keys.A))
             tmp.set(camera.direction).crs(camera.up).scl(-1);
             if (Gdx.input.isKeyPressed(Input.Keys.D))
             tmp.set(camera.direction).crs(camera.up);
             characterComponent.walkDirection.add(tmp);
             characterComponent.walkDirection.scl(10f * delta);
             characterComponent.characterController.setWalkDirection(characterComponent.
            walkDirection);
             Matrix4 ghost = new Matrix4();
             Vector3 translation = new Vector3();
             characterComponent.ghostObject.getWorldTransform(ghost); //TODO export this
             ghost.getTranslation(translation);
             modelComponent.modelInstance.transform.set(translation.x,
                     translation.y,
translation.z, camera.direction.x, camera.direction.y,
             camera.direction.z,
             0);
             camera.position.set(translation.x, translation.y, translation.z);
             camera.update(true);
    }

    @Override
    public void entityRemoved(Entity entity)
    {
    }
}

package Systems;

import com.badlogic.ashley.core.Engine;
import com.badlogic.ashley.core.Entity;
import com.badlogic.ashley.core.EntityListener;
import com.badlogic.ashley.core.EntitySystem;
import com.badlogic.ashley.core.Family;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.physics.bullet.collision.btAxisSweep3;
import com.badlogic.gdx.physics.bullet.collision.btBroadphaseInterface;
import com.badlogic.gdx.physics.bullet.collision.btCollisionConfiguration;
import com.badlogic.gdx.physics.bullet.collision.btCollisionDispatcher;
import com.badlogic.gdx.physics.bullet.collision.btDefaultCollisionConfiguration;
import com.badlogic.gdx.physics.bullet.collision.btGhostPairCallback;
import com.badlogic.gdx.physics.bullet.dynamics.btConstraintSolver;
import com.badlogic.gdx.physics.bullet.dynamics.btDiscreteDynamicsWorld;
import com.badlogic.gdx.physics.bullet.dynamics.btRigidBody;
import com.badlogic.gdx.physics.bullet.dynamics.btSequentialImpulseConstraintSolver;

import Components.BulletComponent;
import Components.CharacterComponent;

public class BulletSystem extends EntitySystem implements EntityListener {
    public final btCollisionConfiguration collisionConfiguration;
    public final btCollisionDispatcher dispatcher;
    public final btBroadphaseInterface broadphase;
    public final btConstraintSolver solver;
    public final btDiscreteDynamicsWorld collisionWorld;
    private btGhostPairCallback ghostPairCallback;
    public int maxSubSteps = 5;
    public float fixedTimeStep = 1f / 60f;

    @Override
    public void addedToEngine(Engine engine) {
        engine.addEntityListener(Family.all(BulletComponent.class).get(), this);
    }

    public BulletSystem() {
        collisionConfiguration = new btDefaultCollisionConfiguration();
        dispatcher = new btCollisionDispatcher(collisionConfiguration);
        broadphase = new btAxisSweep3(new Vector3(-1000, -1000, -1000), new Vector3(1000, 1000, 1000));
        solver = new btSequentialImpulseConstraintSolver();
        collisionWorld = new btDiscreteDynamicsWorld(dispatcher, broadphase, solver, collisionConfiguration);
        ghostPairCallback = new btGhostPairCallback();
        broadphase.getOverlappingPairCache().setInternalGhostPairCallback(ghostPairCallback);
        this.collisionWorld.setGravity(new Vector3(0, -0.5f, 0));
    }

    @Override
    public void update(float delta) {
        collisionWorld.stepSimulation(delta);
    }

    public void dispose() {
        collisionWorld.dispose();
        if (solver != null) solver.dispose();
        if (broadphase != null) broadphase.dispose();
        if (dispatcher != null) dispatcher.dispose();
        if (collisionConfiguration != null) collisionConfiguration.dispose();
        ghostPairCallback.dispose();
    }

    @Override
    public void entityAdded(Entity entity) {
        BulletComponent bulletComponent = entity.getComponent(BulletComponent.class);
        if (bulletComponent.body != null) {
            collisionWorld.addRigidBody((btRigidBody) bulletComponent.body);
        }
    }

    public void removeBody(Entity entity) {
        BulletComponent comp = entity.getComponent(BulletComponent.class);
        if (comp != null)
            collisionWorld.removeCollisionObject(comp.body);
        CharacterComponent character = entity.getComponent(CharacterComponent.class);
        if (character != null) {
            collisionWorld.removeAction(character.characterController);
            collisionWorld.removeCollisionObject(character.ghostObject);
        }
    }

    @Override
    public void entityRemoved(Entity entity) {
    }
}
package com.laterdated.hotbox;

import com.badlogic.ashley.core.Engine;
import com.badlogic.ashley.core.Entity;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.PerspectiveCamera;
import com.badlogic.gdx.graphics.VertexAttributes;
import com.badlogic.gdx.graphics.g3d.Environment;
import com.badlogic.gdx.graphics.g3d.Material;
import com.badlogic.gdx.graphics.g3d.Model;
import com.badlogic.gdx.graphics.g3d.ModelBatch;
import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute;
import com.badlogic.gdx.graphics.g3d.attributes.FloatAttribute;
import com.badlogic.gdx.graphics.g3d.utils.ModelBuilder;
import com.badlogic.gdx.physics.bullet.Bullet;
import com.badlogic.gdx.physics.bullet.dynamics.btKinematicCharacterController;

import Components.CharacterComponent;
import Components.ModelComponent;
import Managers.EntityFactory;
import Systems.BulletSystem;
import Systems.PlayerSystem;
import Systems.RenderSystem;

public class GameWorld
{
    private static final float FOV = 90f;
    private ModelBatch modelBatch;
    private Environment environment;
    private PerspectiveCamera camera;
    private Engine engine;
    private Entity character;
    public BulletSystem bulletSystem;
    public ModelBuilder modelBuilder = new ModelBuilder();

    Model wallHorizontal = modelBuilder.createBox(40, 20, 1,
    new Material(ColorAttribute.createDiffuse(Color.WHITE),
    ColorAttribute.createSpecular(Color.RED), FloatAttribute
    .createShininess(16f)), VertexAttributes.Usage.Position
    | VertexAttributes.Usage.Normal);
    Model wallVertical = modelBuilder.createBox(1, 20, 40,
    new Material(ColorAttribute.createDiffuse(Color.GREEN),
    ColorAttribute.createSpecular(Color.WHITE),
    FloatAttribute.createShininess(16f)),
    VertexAttributes.Usage.Position |
    VertexAttributes.Usage.Normal);
    Model groundModel = modelBuilder.createBox(40, 1, 40,
    new Material(ColorAttribute.createDiffuse(Color.YELLOW),
    ColorAttribute.createSpecular(Color.BLUE),
    FloatAttribute.createShininess(16f)),
    VertexAttributes.Usage.Position
    | VertexAttributes.Usage.Normal);

    public GameWorld()
    {
        Bullet.init();
        initiatePerspectiveCamera();
        initiateEnvironment();
        initiateModelBatch();
        addSystems();
        addEntities();

    }

     private void addEntities()
     {
         createGround();
         createPlayer(5, 3, 5);
     }

     private void createGround()
     {
         engine.addEntity(EntityFactory.createStaticEntity(groundModel, 0, 0, 0));
         engine.addEntity(EntityFactory.createStaticEntity(wallHorizontal, 0, 10, -20));
         engine.addEntity(EntityFactory.createStaticEntity(wallHorizontal, 0, 10, 20));
         engine.addEntity(EntityFactory.createStaticEntity(wallVertical, 20, 10, 0));
         engine.addEntity(EntityFactory.createStaticEntity(wallVertical, -20, 10, 0));
     }

     private void createPlayer(float x, float y, float z)
     {
         character = EntityFactory.createPlayer(bulletSystem, x, y, z);
         engine.addEntity(character);
     }

    public void render(float delta)
    {
        renderWorld(delta);
    }

     protected void renderWorld(float delta) 
     {
         modelBatch.begin(camera);
         engine.update(delta);
         modelBatch.end();
     }

    private void initiatePerspectiveCamera()
    {
        camera = new PerspectiveCamera(FOV, Core.VIRTUAL_WIDTH, Core.VIRTUAL_HEIGHT);
    }

    private void initiateEnvironment()
    {
        environment = new Environment();
        environment.set(new ColorAttribute(ColorAttribute.AmbientLight, 0.3f, 0.3f, 0.3f, 1f));
    }

    private void initiateModelBatch()
    {
        modelBatch = new ModelBatch();
    }

     private void addSystems()
     {
         engine = new Engine();
         engine.addSystem(new RenderSystem(modelBatch, environment));
         engine.addSystem(bulletSystem = new BulletSystem());
         engine.addSystem(new PlayerSystem(this, camera));
     }

    public void dispose()
    {
        bulletSystem.collisionWorld.removeAction(character.getComponent(CharacterComponent.class).characterController);
        bulletSystem.collisionWorld.removeCollisionObject(character.getComponent(CharacterComponent.class).ghostObject);
        character.getComponent(CharacterComponent.class).characterController.dispose();
        character.getComponent(CharacterComponent.class).ghostObject.dispose();
        character.getComponent(CharacterComponent.class).ghostShape.dispose();
        bulletSystem.dispose();
        bulletSystem = null;
        wallHorizontal.dispose();
        wallVertical.dispose();
        groundModel.dispose();
        modelBatch.dispose();
        modelBatch = null;
    }

    public void resize(int width, int height)
    {
        camera.viewportHeight = height;
        camera.viewportWidth = width;
    }
}

1 Answers

I found the solution if anyone else has the same problem. You have to add a new vector3 or your walk direction at the end of your characterController.

 characterComponent.characterController = new btKinematicCharacterController(characterComponent.ghostObject, characterComponent.ghostShape, .35f);

 characterComponent.characterController = new btKinematicCharacterController(characterComponent.ghostObject, characterComponent.ghostShape, .35f, characterComponent.walkDirection);
Related