Home | History | Annotate | Download | only in bullet
      1 package com.badlogic.gdx.tests.bullet;
      2 
      3 import com.badlogic.gdx.Gdx;
      4 import com.badlogic.gdx.Input.Keys;
      5 import com.badlogic.gdx.graphics.Texture;
      6 import com.badlogic.gdx.graphics.VertexAttributes.Usage;
      7 import com.badlogic.gdx.graphics.g3d.Material;
      8 import com.badlogic.gdx.graphics.g3d.Model;
      9 import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute;
     10 import com.badlogic.gdx.graphics.g3d.attributes.FloatAttribute;
     11 import com.badlogic.gdx.graphics.g3d.attributes.TextureAttribute;
     12 import com.badlogic.gdx.math.Matrix4;
     13 import com.badlogic.gdx.math.Vector3;
     14 import com.badlogic.gdx.physics.bullet.collision.btAxisSweep3;
     15 import com.badlogic.gdx.physics.bullet.collision.btBroadphaseProxy;
     16 import com.badlogic.gdx.physics.bullet.collision.btCapsuleShape;
     17 import com.badlogic.gdx.physics.bullet.collision.btCollisionDispatcher;
     18 import com.badlogic.gdx.physics.bullet.collision.btCollisionObject;
     19 import com.badlogic.gdx.physics.bullet.collision.btConvexShape;
     20 import com.badlogic.gdx.physics.bullet.collision.btDbvtBroadphase;
     21 import com.badlogic.gdx.physics.bullet.collision.btDefaultCollisionConfiguration;
     22 import com.badlogic.gdx.physics.bullet.collision.btGhostPairCallback;
     23 import com.badlogic.gdx.physics.bullet.collision.btPairCachingGhostObject;
     24 import com.badlogic.gdx.physics.bullet.dynamics.btDiscreteDynamicsWorld;
     25 import com.badlogic.gdx.physics.bullet.dynamics.btDynamicsWorld;
     26 import com.badlogic.gdx.physics.bullet.dynamics.btKinematicCharacterController;
     27 import com.badlogic.gdx.physics.bullet.dynamics.btSequentialImpulseConstraintSolver;
     28 
     29 public class CharacterTest extends BaseBulletTest {
     30 	final int BOXCOUNT_X = 5;
     31 	final int BOXCOUNT_Y = 5;
     32 	final int BOXCOUNT_Z = 1;
     33 
     34 	final float BOXOFFSET_X = -2.5f;
     35 	final float BOXOFFSET_Y = 0.5f;
     36 	final float BOXOFFSET_Z = 0f;
     37 
     38 	BulletEntity ground;
     39 	BulletEntity character;
     40 
     41 	btGhostPairCallback ghostPairCallback;
     42 	btPairCachingGhostObject ghostObject;
     43 	btConvexShape ghostShape;
     44 	btKinematicCharacterController characterController;
     45 	Matrix4 characterTransform;
     46 	Vector3 characterDirection = new Vector3();
     47 	Vector3 walkDirection = new Vector3();
     48 
     49 	@Override
     50 	public BulletWorld createWorld () {
     51 		// We create the world using an axis sweep broadphase for this test
     52 		btDefaultCollisionConfiguration collisionConfiguration = new btDefaultCollisionConfiguration();
     53 		btCollisionDispatcher dispatcher = new btCollisionDispatcher(collisionConfiguration);
     54 		btAxisSweep3 sweep = new btAxisSweep3(new Vector3(-1000, -1000, -1000), new Vector3(1000, 1000, 1000));
     55 		btSequentialImpulseConstraintSolver solver = new btSequentialImpulseConstraintSolver();
     56 		btDiscreteDynamicsWorld collisionWorld = new btDiscreteDynamicsWorld(dispatcher, sweep, solver, collisionConfiguration);
     57 		ghostPairCallback = new btGhostPairCallback();
     58 		sweep.getOverlappingPairCache().setInternalGhostPairCallback(ghostPairCallback);
     59 		return new BulletWorld(collisionConfiguration, dispatcher, sweep, solver, collisionWorld);
     60 	}
     61 
     62 	@Override
     63 	public void create () {
     64 		super.create();
     65 		instructions = "Tap to shoot\nArrow keys to move\nR to reset\nLong press to toggle debug mode\nSwipe for next test";
     66 
     67 		// Create a visual representation of the character (note that we don't use the physics part of BulletEntity, we'll do that manually)
     68 		final Texture texture = new Texture(Gdx.files.internal("data/badlogic.jpg"));
     69 		disposables.add(texture);
     70 		final Material material = new Material(TextureAttribute.createDiffuse(texture), ColorAttribute.createSpecular(1,1,1,1), FloatAttribute.createShininess(8f));
     71 		final long attributes = Usage.Position | Usage.Normal | Usage.TextureCoordinates;
     72 		final Model capsule = modelBuilder.createCapsule(2f, 6f, 16, material, attributes);
     73 		disposables.add(capsule);
     74 		world.addConstructor("capsule", new BulletConstructor(capsule, null));
     75 		character = world.add("capsule", 5f, 3f, 5f);
     76 		characterTransform = character.transform; // Set by reference
     77 
     78 		// Create the physics representation of the character
     79 		ghostObject = new btPairCachingGhostObject();
     80 		ghostObject.setWorldTransform(characterTransform);
     81 		ghostShape = new btCapsuleShape(2f, 2f);
     82 		ghostObject.setCollisionShape(ghostShape);
     83 		ghostObject.setCollisionFlags(btCollisionObject.CollisionFlags.CF_CHARACTER_OBJECT);
     84 		characterController = new btKinematicCharacterController(ghostObject, ghostShape, .35f);
     85 
     86 		// And add it to the physics world
     87 		world.collisionWorld.addCollisionObject(ghostObject,
     88 			(short)btBroadphaseProxy.CollisionFilterGroups.CharacterFilter,
     89 			(short)(btBroadphaseProxy.CollisionFilterGroups.StaticFilter | btBroadphaseProxy.CollisionFilterGroups.DefaultFilter));
     90 		((btDiscreteDynamicsWorld)(world.collisionWorld)).addAction(characterController);
     91 
     92 		// Add the ground
     93 		(ground = world.add("ground", 0f, 0f, 0f))
     94 			.setColor(0.25f + 0.5f * (float)Math.random(), 0.25f + 0.5f * (float)Math.random(), 0.25f + 0.5f * (float)Math.random(), 1f);
     95 		// Create some boxes to play with
     96 		for (int x = 0; x < BOXCOUNT_X; x++) {
     97 			for (int y = 0; y < BOXCOUNT_Y; y++) {
     98 				for (int z = 0; z < BOXCOUNT_Z; z++) {
     99 					world.add("box", BOXOFFSET_X + x, BOXOFFSET_Y + y, BOXOFFSET_Z + z)
    100 						.setColor(0.5f + 0.5f * (float)Math.random(), 0.5f + 0.5f * (float)Math.random(), 0.5f + 0.5f * (float)Math.random(), 1f);
    101 				}
    102 			}
    103 		}
    104 	}
    105 
    106 	@Override
    107 	public void update () {
    108 		// If the left or right key is pressed, rotate the character and update its physics update accordingly.
    109 		if (Gdx.input.isKeyPressed(Keys.LEFT)) {
    110 			characterTransform.rotate(0, 1, 0, 5f);
    111 			ghostObject.setWorldTransform(characterTransform);
    112 		}
    113 		if (Gdx.input.isKeyPressed(Keys.RIGHT)) {
    114 			characterTransform.rotate(0, 1, 0, -5f);
    115 			ghostObject.setWorldTransform(characterTransform);
    116 		}
    117 		// Fetch which direction the character is facing now
    118 		characterDirection.set(-1,0,0).rot(characterTransform).nor();
    119 		// Set the walking direction accordingly (either forward or backward)
    120 		walkDirection.set(0,0,0);
    121 		if (Gdx.input.isKeyPressed(Keys.UP))
    122 			walkDirection.add(characterDirection);
    123 		if (Gdx.input.isKeyPressed(Keys.DOWN))
    124 			walkDirection.add(-characterDirection.x, -characterDirection.y, -characterDirection.z);
    125 		walkDirection.scl(4f * Gdx.graphics.getDeltaTime());
    126 		// And update the character controller
    127 		characterController.setWalkDirection(walkDirection);
    128 		// Now we can update the world as normally
    129 		super.update();
    130 		// And fetch the new transformation of the character (this will make the model be rendered correctly)
    131 		ghostObject.getWorldTransform(characterTransform);
    132 	}
    133 
    134 	@Override
    135 	protected void renderWorld () {
    136 		// TODO Auto-generated method stub
    137 		super.renderWorld();
    138 	}
    139 
    140 	@Override
    141 	public boolean tap (float x, float y, int count, int button) {
    142 		shoot(x, y);
    143 		return true;
    144 	}
    145 
    146 	@Override
    147 	public void dispose () {
    148 		((btDiscreteDynamicsWorld)(world.collisionWorld)).removeAction(characterController);
    149 		world.collisionWorld.removeCollisionObject(ghostObject);
    150 		super.dispose();
    151 		characterController.dispose();
    152 		ghostObject.dispose();
    153 		ghostShape.dispose();
    154 		ghostPairCallback.dispose();
    155 		ground = null;
    156 	}
    157 }
    158