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;
}
}