• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*******************************************************************************
2  * Copyright 2011 See AUTHORS file.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  ******************************************************************************/
16 
17 package com.badlogic.gdx.tests.bullet;
18 
19 import com.badlogic.gdx.Gdx;
20 import com.badlogic.gdx.Input.Keys;
21 import com.badlogic.gdx.graphics.Color;
22 import com.badlogic.gdx.graphics.Texture;
23 import com.badlogic.gdx.graphics.VertexAttributes.Usage;
24 import com.badlogic.gdx.graphics.g3d.Material;
25 import com.badlogic.gdx.graphics.g3d.Model;
26 import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute;
27 import com.badlogic.gdx.graphics.g3d.attributes.FloatAttribute;
28 import com.badlogic.gdx.graphics.g3d.attributes.TextureAttribute;
29 import com.badlogic.gdx.math.MathUtils;
30 import com.badlogic.gdx.math.Vector3;
31 import com.badlogic.gdx.math.collision.BoundingBox;
32 import com.badlogic.gdx.physics.bullet.collision.Collision;
33 import com.badlogic.gdx.physics.bullet.collision.btBoxShape;
34 import com.badlogic.gdx.physics.bullet.dynamics.btDefaultVehicleRaycaster;
35 import com.badlogic.gdx.physics.bullet.dynamics.btDiscreteDynamicsWorld;
36 import com.badlogic.gdx.physics.bullet.dynamics.btDynamicsWorld;
37 import com.badlogic.gdx.physics.bullet.dynamics.btRaycastVehicle;
38 import com.badlogic.gdx.physics.bullet.dynamics.btRigidBody;
39 import com.badlogic.gdx.physics.bullet.dynamics.btVehicleRaycaster;
40 import com.badlogic.gdx.physics.bullet.dynamics.btRaycastVehicle.btVehicleTuning;
41 import com.badlogic.gdx.physics.bullet.dynamics.btWheelInfo;
42 
43 /** @author Xoppa */
44 public class VehicleTest extends BaseBulletTest {
45 	public btVehicleRaycaster raycaster;
46 	public btRaycastVehicle vehicle;
47 	public btVehicleTuning tuning;
48 	BulletEntity chassis;
49 	BulletEntity wheels[] = new BulletEntity[4];
50 
51 	boolean downPressed;
52 	boolean upPressed;
53 	boolean leftPressed;
54 	boolean rightPressed;
55 	Vector3 tmpV = new Vector3();
56 
57 	@Override
create()58 	public void create () {
59 		super.create();
60 		instructions = "Tap to shoot\nArrow keys to drive\nR to reset\nLong press to toggle debug mode\nSwipe for next test";
61 
62 		final Model chassisModel = objLoader.loadModel(Gdx.files.internal("data/car.obj"));
63 		disposables.add(chassisModel);
64 		chassisModel.materials.get(0).clear();
65 		chassisModel.materials.get(0).set(ColorAttribute.createDiffuse(Color.RED), ColorAttribute.createSpecular(Color.WHITE));
66 		final Model wheelModel = objLoader.loadModel(Gdx.files.internal("data/wheel.obj"));
67 		disposables.add(wheelModel);
68 		wheelModel.materials.get(0).clear();
69 		wheelModel.materials.get(0).set(ColorAttribute.createDiffuse(Color.BLACK), ColorAttribute.createSpecular(Color.WHITE),
70 			FloatAttribute.createShininess(128));
71 		Texture checkboard = new Texture(Gdx.files.internal("data/g3d/checkboard.png"));
72 		final Model largeGroundModel = modelBuilder.createBox(
73 			1000f,
74 			2f,
75 			1000f,
76 			new Material(TextureAttribute.createDiffuse(checkboard), ColorAttribute.createSpecular(Color.WHITE), FloatAttribute
77 				.createShininess(16f)), Usage.Position | Usage.Normal | Usage.TextureCoordinates);
78 		largeGroundModel.manageDisposable(checkboard);
79 		disposables.add(largeGroundModel);
80 		world.addConstructor("largeground", new BulletConstructor(largeGroundModel, 0f));
81 
82 		BoundingBox bounds = new BoundingBox();
83 		Vector3 chassisHalfExtents = chassisModel.calculateBoundingBox(bounds).getDimensions(new Vector3()).scl(0.5f);
84 		Vector3 wheelHalfExtents = wheelModel.calculateBoundingBox(bounds).getDimensions(new Vector3()).scl(0.5f);
85 
86 		world.addConstructor("chassis", new BulletConstructor(chassisModel, 5f, new btBoxShape(chassisHalfExtents)));
87 		world.addConstructor("wheel", new BulletConstructor(wheelModel, 0, null));
88 
89 		world.add("largeground", 0, -1f, 0f);
90 
91 		chassis = world.add("chassis", 0, 3f, 0);
92 		wheels[0] = world.add("wheel", 0, 0, 0);
93 		wheels[1] = world.add("wheel", 0, 0, 0);
94 		wheels[2] = world.add("wheel", 0, 0, 0);
95 		wheels[3] = world.add("wheel", 0, 0, 0);
96 
97 		// Create the vehicle
98 		raycaster = new btDefaultVehicleRaycaster((btDynamicsWorld)world.collisionWorld);
99 		tuning = new btVehicleTuning();
100 		vehicle = new btRaycastVehicle(tuning, (btRigidBody)chassis.body, raycaster);
101 		chassis.body.setActivationState(Collision.DISABLE_DEACTIVATION);
102 		((btDynamicsWorld)world.collisionWorld).addVehicle(vehicle);
103 
104 		vehicle.setCoordinateSystem(0, 1, 2);
105 
106 		btWheelInfo wheelInfo;
107 		Vector3 point = new Vector3();
108 		Vector3 direction = new Vector3(0, -1, 0);
109 		Vector3 axis = new Vector3(-1, 0, 0);
110 		wheelInfo = vehicle.addWheel(point.set(chassisHalfExtents).scl(0.9f, -0.8f, 0.7f), direction, axis,
111 			wheelHalfExtents.z * 0.3f, wheelHalfExtents.z, tuning, true);
112 		wheelInfo = vehicle.addWheel(point.set(chassisHalfExtents).scl(-0.9f, -0.8f, 0.7f), direction, axis,
113 			wheelHalfExtents.z * 0.3f, wheelHalfExtents.z, tuning, true);
114 		wheelInfo = vehicle.addWheel(point.set(chassisHalfExtents).scl(0.9f, -0.8f, -0.5f), direction, axis,
115 			wheelHalfExtents.z * 0.3f, wheelHalfExtents.z, tuning, false);
116 		wheelInfo = vehicle.addWheel(point.set(chassisHalfExtents).scl(-0.9f, -0.8f, -0.5f), direction, axis,
117 			wheelHalfExtents.z * 0.3f, wheelHalfExtents.z, tuning, false);
118 	}
119 
120 	float maxForce = 100f;
121 	float currentForce = 0f;
122 	float acceleration = 50f; // force/second
123 	float maxAngle = 60f;
124 	float currentAngle = 0f;
125 	float steerSpeed = 45f; // angle/second
126 
127 	@Override
update()128 	public void update () {
129 		final float delta = Gdx.graphics.getDeltaTime();
130 		float angle = currentAngle;
131 		if (rightPressed) {
132 			if (angle > 0f) angle = 0f;
133 			angle = MathUtils.clamp(angle - steerSpeed * delta, -maxAngle, 0f);
134 		} else if (leftPressed) {
135 			if (angle < 0f) angle = 0f;
136 			angle = MathUtils.clamp(angle + steerSpeed * delta, 0f, maxAngle);
137 		} else
138 			angle = 0f;
139 		if (angle != currentAngle) {
140 			currentAngle = angle;
141 			vehicle.setSteeringValue(angle * MathUtils.degreesToRadians, 0);
142 			vehicle.setSteeringValue(angle * MathUtils.degreesToRadians, 1);
143 		}
144 
145 		float force = currentForce;
146 		if (upPressed) {
147 			if (force < 0f) force = 0f;
148 			force = MathUtils.clamp(force + acceleration * delta, 0f, maxForce);
149 		} else if (downPressed) {
150 			if (force > 0f) force = 0f;
151 			force = MathUtils.clamp(force - acceleration * delta, -maxForce, 0f);
152 		} else
153 			force = 0f;
154 		if (force != currentForce) {
155 			currentForce = force;
156 			vehicle.applyEngineForce(force, 0);
157 			vehicle.applyEngineForce(force, 1);
158 		}
159 
160 		super.update();
161 
162 		for (int i = 0; i < wheels.length; i++) {
163 			vehicle.updateWheelTransform(i, true);
164 			vehicle.getWheelInfo(i).getWorldTransform().getOpenGLMatrix(wheels[i].transform.val);
165 		}
166 
167 		chassis.transform.getTranslation(camera.position);
168 		tmpV.set(camera.position).sub(5, 0, 5).y = 0f;
169 		camera.position.add(tmpV.nor().scl(-6f)).y = 4.f;
170 		chassis.transform.getTranslation(tmpV);
171 		camera.lookAt(tmpV);
172 		camera.up.set(Vector3.Y);
173 		camera.update();
174 	}
175 
176 	@Override
tap(float x, float y, int count, int button)177 	public boolean tap (float x, float y, int count, int button) {
178 		shoot(x, y);
179 		return true;
180 	}
181 
182 	@Override
dispose()183 	public void dispose () {
184 		super.dispose();
185 		vehicle.dispose();
186 		vehicle = null;
187 		raycaster.dispose();
188 		raycaster = null;
189 		tuning.dispose();
190 		tuning = null;
191 	}
192 
193 	@Override
keyDown(int keycode)194 	public boolean keyDown (int keycode) {
195 		switch (keycode) {
196 		case Keys.DOWN:
197 			downPressed = true;
198 			break;
199 		case Keys.UP:
200 			upPressed = true;
201 			break;
202 		case Keys.LEFT:
203 			leftPressed = true;
204 			break;
205 		case Keys.RIGHT:
206 			rightPressed = true;
207 			break;
208 		}
209 		return super.keyDown(keycode);
210 	}
211 
212 	@Override
keyUp(int keycode)213 	public boolean keyUp (int keycode) {
214 		switch (keycode) {
215 		case Keys.DOWN:
216 			downPressed = false;
217 			break;
218 		case Keys.UP:
219 			upPressed = false;
220 			break;
221 		case Keys.LEFT:
222 			leftPressed = false;
223 			break;
224 		case Keys.RIGHT:
225 			rightPressed = false;
226 			break;
227 		case Keys.R:
228 			chassis.body.setWorldTransform(chassis.transform.setToTranslation(0, 5, 0));
229 			chassis.body.setInterpolationWorldTransform(chassis.transform);
230 			((btRigidBody)(chassis.body)).setLinearVelocity(Vector3.Zero);
231 			((btRigidBody)(chassis.body)).setAngularVelocity(Vector3.Zero);
232 			chassis.body.activate();
233 			break;
234 		}
235 		return super.keyUp(keycode);
236 	}
237 }
238