libgdx 3 D Bullet衝突検出3
42414 ワード
原文の住所:http://blog.xoppa.com/using-the-libgdx-3d-physics-bullet-wrapper-part2/
原文を見ることを勧めます。直接コードを入れます。完全コードの原文にはgithubがあります。
原文を見ることを勧めます。直接コードを入れます。完全コードの原文にはgithubがあります。
1 package org.forus.game.test;
2
3 import com.badlogic.gdx.ApplicationListener;
4 import com.badlogic.gdx.Gdx;
5 import com.badlogic.gdx.graphics.Color;
6 import com.badlogic.gdx.graphics.GL20;
7 import com.badlogic.gdx.graphics.PerspectiveCamera;
8 import com.badlogic.gdx.graphics.VertexAttributes.Usage;
9 import com.badlogic.gdx.graphics.g3d.*;
10 import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute;
11 import com.badlogic.gdx.graphics.g3d.environment.DirectionalLight;
12 import com.badlogic.gdx.graphics.g3d.utils.CameraInputController;
13 import com.badlogic.gdx.graphics.g3d.utils.ModelBuilder;
14 import com.badlogic.gdx.math.MathUtils;
15 import com.badlogic.gdx.math.Matrix4;
16 import com.badlogic.gdx.math.Vector3;
17 import com.badlogic.gdx.physics.bullet.Bullet;
18 import com.badlogic.gdx.physics.bullet.collision.*;
19 import com.badlogic.gdx.physics.bullet.dynamics.*;
20 import com.badlogic.gdx.physics.bullet.linearmath.btMotionState;
21 import com.badlogic.gdx.utils.Array;
22 import com.badlogic.gdx.utils.ArrayMap;
23 import com.badlogic.gdx.utils.Disposable;
24
25 public class CollisionWorldTest2 implements ApplicationListener {
26 final static short GROUND_FLAG = 1<<8;
27 final static short OBJECT_FLAG = 1<<9;
28 final static short ALL_FLAG = -1;
29
30 class MyContactListener extends ContactListener {
31 /**
32 @Override
33 public boolean onContactAdded (int userValue0, int partId0, int index0, int userValue1, int partId1, int index1) {
34 // instances.get(userValue0).moving = false;
35 // instances.get(userValue1).moving = false;
36 // if (userValue0 != 0)
37 // ((ColorAttribute)instances.get(userValue0).materials.get(0).get(ColorAttribute.Diffuse)).color.set(Color.WHITE);
38 // if (userValue1 != 0)
39 // ((ColorAttribute)instances.get(userValue1).materials.get(0).get(ColorAttribute.Diffuse)).color.set(Color.WHITE);
40 if (userValue1 == 0)
41 ((ColorAttribute)instances.get(userValue0).materials.get(0).get(ColorAttribute.Diffuse)).color.set(Color.WHITE);
42 if (userValue0 == 0)
43 ((ColorAttribute)instances.get(userValue1).materials.get(0).get(ColorAttribute.Diffuse)).color.set(Color.WHITE);
44 return true;
45 }*/
46
47
48 //Note that by default the contact callback filter will be set to zero, so overriding this method without setting the contact callback flag and filter values, will cause the callback never to be triggered.
49 @Override
50 public boolean onContactAdded (int userValue0, int partId0, int index0, boolean match0,
51 int userValue1, int partId1, int index1, boolean match1) {
52 if (match0)
53 ((ColorAttribute)instances.get(userValue0).materials.get(0).get(ColorAttribute.Diffuse)).color.set(Color.WHITE);
54 if (match1)
55 ((ColorAttribute)instances.get(userValue1).materials.get(0).get(ColorAttribute.Diffuse)).color.set(Color.WHITE);
56 return true;
57 }
58 }
59
60 static class MyMotionState extends btMotionState {
61 Matrix4 transform;
62 @Override
63 public void getWorldTransform (Matrix4 worldTrans) {
64 worldTrans.set(transform);//TODO
65 }
66 @Override
67 public void setWorldTransform (Matrix4 worldTrans) {
68 transform.set(worldTrans);//TODO
69 }
70 }
71
72 static class GameObject extends ModelInstance implements Disposable {
73 public final btRigidBody body;
74 public final MyMotionState motionState;
75
76 public GameObject(Model model, String node, btRigidBody.btRigidBodyConstructionInfo constructionInfo) {
77 super(model, node);
78 motionState = new MyMotionState();
79 motionState.transform = transform;
80 body = new btRigidBody(constructionInfo);
81 body.setMotionState(motionState);
82 }
83
84 @Override
85 public void dispose() {
86 body.dispose();
87 motionState.dispose();
88 }
89
90 static class Constructor implements Disposable {
91 public final Model model;
92 public final String node;
93 public final btCollisionShape shape;
94 public final btRigidBody.btRigidBodyConstructionInfo constructionInfo;
95 private static Vector3 localInertia = new Vector3();
96
97 public Constructor(Model model, String node, btCollisionShape shape, float mass) {//mass--the weight of the object, , : ,
98 this.model = model;
99 this.node = node;
100 this.shape = shape;
101 //If the mass is equal or less than zero, we simply set the local inertia also to zero. Otherwise we need to calculate the local intertia
102 if (mass > 0f)
103 shape.calculateLocalInertia(mass, localInertia);
104 else
105 localInertia.set(0, 0, 0);
106 this.constructionInfo = new btRigidBody.btRigidBodyConstructionInfo(mass, null, shape, localInertia);
107 }
108
109 public GameObject construct() {
110 return new GameObject(model, node, constructionInfo);
111 }
112
113 @Override
114 public void dispose() {
115 shape.dispose();
116 constructionInfo.dispose();
117 }
118 }
119 }
120
121 PerspectiveCamera cam;
122 CameraInputController camController;
123 ModelBatch modelBatch;
124 Environment environment;
125 Model model;
126 Array<GameObject> instances;
127 ArrayMap<String, GameObject.Constructor> constructors;
128 float spawnTimer;
129
130 btCollisionConfiguration collisionConfig;
131 btDispatcher dispatcher;
132 MyContactListener contactListener;
133 btBroadphaseInterface broadphase;
134
135 btDynamicsWorld dynamicsWorld;
136 btConstraintSolver constraintSolver;
137
138 float angle, speed = 90f;//ground
139
140 @Override
141 public void create () {
142 Bullet.init();
143
144 modelBatch = new ModelBatch();
145 environment = new Environment();
146 environment.set(new ColorAttribute(ColorAttribute.AmbientLight, 0.4f, 0.4f, 0.4f, 1f));
147 environment.add(new DirectionalLight().set(0.8f, 0.8f, 0.8f, -1f, -0.8f, -0.2f));
148
149 cam = new PerspectiveCamera(67, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
150 cam.position.set(3f, 7f, 10f);
151 cam.lookAt(0, 4f, 0);
152 cam.near = 1f;
153 cam.far = 300f;
154 cam.update();
155
156 camController = new CameraInputController(cam);
157 Gdx.input.setInputProcessor(camController);
158
159 ModelBuilder mb = new ModelBuilder();
160 mb.begin();
161 mb.node().id = "ground";
162 mb.part("ground", GL20.GL_TRIANGLES, Usage.Position | Usage.Normal, new Material(ColorAttribute.createDiffuse(Color.RED)))
163 .box(5f, 1f, 5f);
164 mb.node().id = "sphere";
165 mb.part("sphere", GL20.GL_TRIANGLES, Usage.Position | Usage.Normal, new Material(ColorAttribute.createDiffuse(Color.GREEN)))
166 .sphere(1f, 1f, 1f, 10, 10);
167 mb.node().id = "box";
168 mb.part("box", GL20.GL_TRIANGLES, Usage.Position | Usage.Normal, new Material(ColorAttribute.createDiffuse(Color.BLUE)))
169 .box(1f, 1f, 1f);
170 mb.node().id = "cone";
171 mb.part("cone", GL20.GL_TRIANGLES, Usage.Position | Usage.Normal, new Material(ColorAttribute.createDiffuse(Color.YELLOW)))
172 .cone(1f, 2f, 1f, 10);
173 mb.node().id = "capsule";
174 mb.part("capsule", GL20.GL_TRIANGLES, Usage.Position | Usage.Normal, new Material(ColorAttribute.createDiffuse(Color.CYAN)))
175 .capsule(0.5f, 2f, 10);
176 mb.node().id = "cylinder";
177 mb.part("cylinder", GL20.GL_TRIANGLES, Usage.Position | Usage.Normal,
178 new Material(ColorAttribute.createDiffuse(Color.MAGENTA))).cylinder(1f, 2f, 1f, 10);
179 model = mb.end();
180
181 constructors = new ArrayMap<String, GameObject.Constructor>(String.class, GameObject.Constructor.class);
182 constructors.put("ground", new GameObject.Constructor(model, "ground", new btBoxShape(new Vector3(2.5f, 0.5f, 2.5f)), 0f));
183 constructors.put("sphere", new GameObject.Constructor(model, "sphere", new btSphereShape(0.5f), 1f));
184 constructors.put("box", new GameObject.Constructor(model, "box", new btBoxShape(new Vector3(0.5f, 0.5f, 0.5f)), 1f));
185 constructors.put("cone", new GameObject.Constructor(model, "cone", new btConeShape(0.5f, 2f), 1f));
186 constructors.put("capsule", new GameObject.Constructor(model, "capsule", new btCapsuleShape(.5f, 1f), 1f));
187 constructors.put("cylinder", new GameObject.Constructor(model, "cylinder", new btCylinderShape(new Vector3(.5f, 1f, .5f)), 1f));
188
189 collisionConfig = new btDefaultCollisionConfiguration();
190 dispatcher = new btCollisionDispatcher(collisionConfig);
191 broadphase = new btDbvtBroadphase();
192 constraintSolver = new btSequentialImpulseConstraintSolver();
193 dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher, broadphase, constraintSolver, collisionConfig);//Discrete
194 dynamicsWorld.setGravity(new Vector3(0, -10f, 0));
195 contactListener = new MyContactListener();
196
197 instances = new Array<GameObject>();
198 GameObject object = constructors.get("ground").construct();
199 object.body.setCollisionFlags(object.body.getCollisionFlags()
200 | btCollisionObject.CollisionFlags.CF_KINEMATIC_OBJECT);
201 instances.add(object);
202 //dynamicsWorld.addRigidBody(object.body, GROUND_FLAG, ALL_FLAG);
203 dynamicsWorld.addRigidBody(object.body);
204 object.body.setContactCallbackFlag(GROUND_FLAG);
205 object.body.setContactCallbackFilter(0);// 。 , 。
206 object.body.setActivationState(Collision.DISABLE_DEACTIVATION);
207 }
208
209 public void spawn () {
210 GameObject obj = constructors.values[1 + MathUtils.random(constructors.size - 2)].construct();
211 obj.transform.setFromEulerAngles(MathUtils.random(360f), MathUtils.random(360f), MathUtils.random(360f));
212 obj.transform.trn(MathUtils.random(-2.5f, 2.5f), 9f, MathUtils.random(-2.5f, 2.5f));
213 //obj.body.setWorldTransform(obj.transform);
214 obj.body.proceedToTransform(obj.transform);// motionState
215 obj.body.setUserValue(instances.size);
216 obj.body.setCollisionFlags(obj.body.getCollisionFlags() | btCollisionObject.CollisionFlags.CF_CUSTOM_MATERIAL_CALLBACK);
217 instances.add(obj);
218 //dynamicsWorld.addRigidBody(obj.body, OBJECT_FLAG, GROUND_FLAG);// addCollisionObject, makes sure that for example gravity is correctly applied to each object
219 dynamicsWorld.addRigidBody(obj.body);
220 obj.body.setContactCallbackFlag(OBJECT_FLAG);
221 // !!! , ,
222 obj.body.setContactCallbackFilter(GROUND_FLAG);// Ground
223 }
224
225 @Override
226 public void render () {
227 final float delta = Math.min(1f / 30f, Gdx.graphics.getDeltaTime());
228
229 angle = (angle + delta * speed) % 360f;
230 instances.get(0).transform.setTranslation(0, MathUtils.sinDeg(angle) * 2.5f, 0f);
231 //instances.get(0).body.setWorldTransform(instances.get(0).transform);// motionstate
232 //instances.get(0).body.activate();// object.body.setActivationState(Collision.DISABLE_DEACTIVATION);
233
234
235 // The discrete dynamics world uses a fixed time step.
236 // This basically means that it will always use the same delta value to perform calculations.
237 // This fixed delta value is supplied as the third argument of stepSimulation.
238 // If the actual delta value (the first argument) is greater than the desired fixed delta value, then the calculation will be done multiple times.
239 // The maximum number of times that this will be done (the maximum number of sub-steps) is specified by the second argument.
240 dynamicsWorld.stepSimulation(delta, 5, 1f/60f);
241 /* motionState ,
242 for (GameObject obj : instances)
243 obj.body.getWorldTransform(obj.transform);// body obj
244
245 dynamicsWorld.performDiscreteCollisionDetection();
246 */
247
248 if ((spawnTimer -= delta) < 0) {
249 spawn();
250 spawnTimer = 1.5f;
251 }
252
253 camController.update();
254
255 Gdx.gl.glClearColor(0.3f, 0.3f, 0.3f, 1.f);
256 Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
257
258 modelBatch.begin(cam);
259 modelBatch.render(instances, environment);
260 modelBatch.end();
261 }
262
263 @Override
264 public void dispose () {
265 for (GameObject obj : instances)
266 obj.dispose();
267 instances.clear();
268
269 for (GameObject.Constructor ctor : constructors.values())
270 ctor.dispose();
271 constructors.clear();
272
273 dynamicsWorld.dispose();
274 constraintSolver.dispose();
275 broadphase.dispose();
276 dispatcher.dispose();
277 collisionConfig.dispose();
278
279 contactListener.dispose();
280
281 modelBatch.dispose();
282 model.dispose();
283 }
284
285 @Override
286 public void pause () {
287 }
288
289 @Override
290 public void resume () {
291 }
292
293 @Override
294 public void resize (int width, int height) {
295 }
296 }