• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
createWorld()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
create()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
update()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
renderWorld()135 	protected void renderWorld () {
136 		// TODO Auto-generated method stub
137 		super.renderWorld();
138 	}
139 
140 	@Override
tap(float x, float y, int count, int button)141 	public boolean tap (float x, float y, int count, int button) {
142 		shoot(x, y);
143 		return true;
144 	}
145 
146 	@Override
dispose()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