1 /*******************************************************************************
\r
2 * Copyright 2011 See AUTHORS file.
\r
4 * Licensed under the Apache License, Version 2.0 (the "License");
\r
5 * you may not use this file except in compliance with the License.
\r
6 * You may obtain a copy of the License at
\r
8 * http://www.apache.org/licenses/LICENSE-2.0
\r
10 * Unless required by applicable law or agreed to in writing, software
\r
11 * distributed under the License is distributed on an "AS IS" BASIS,
\r
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
13 * See the License for the specific language governing permissions and
\r
14 * limitations under the License.
\r
15 ******************************************************************************/
\r
17 package com.badlogic.gdx.physics.box2d;
\r
19 import java.util.ArrayList;
\r
20 import java.util.Iterator;
\r
21 import java.util.List;
\r
23 import com.badlogic.gdx.math.Vector2;
\r
24 import com.badlogic.gdx.physics.box2d.JointDef.JointType;
\r
25 import com.badlogic.gdx.physics.box2d.joints.DistanceJoint;
\r
26 import com.badlogic.gdx.physics.box2d.joints.DistanceJointDef;
\r
27 import com.badlogic.gdx.physics.box2d.joints.FrictionJoint;
\r
28 import com.badlogic.gdx.physics.box2d.joints.FrictionJointDef;
\r
29 import com.badlogic.gdx.physics.box2d.joints.GearJoint;
\r
30 import com.badlogic.gdx.physics.box2d.joints.GearJointDef;
\r
31 import com.badlogic.gdx.physics.box2d.joints.MouseJoint;
\r
32 import com.badlogic.gdx.physics.box2d.joints.MouseJointDef;
\r
33 import com.badlogic.gdx.physics.box2d.joints.PrismaticJoint;
\r
34 import com.badlogic.gdx.physics.box2d.joints.PrismaticJointDef;
\r
35 import com.badlogic.gdx.physics.box2d.joints.PulleyJoint;
\r
36 import com.badlogic.gdx.physics.box2d.joints.PulleyJointDef;
\r
37 import com.badlogic.gdx.physics.box2d.joints.RevoluteJoint;
\r
38 import com.badlogic.gdx.physics.box2d.joints.RevoluteJointDef;
\r
39 import com.badlogic.gdx.physics.box2d.joints.RopeJoint;
\r
40 import com.badlogic.gdx.physics.box2d.joints.RopeJointDef;
\r
41 import com.badlogic.gdx.physics.box2d.joints.WeldJoint;
\r
42 import com.badlogic.gdx.physics.box2d.joints.WeldJointDef;
\r
43 import com.badlogic.gdx.physics.box2d.joints.WheelJoint;
\r
44 import com.badlogic.gdx.physics.box2d.joints.WheelJointDef;
\r
45 import com.badlogic.gdx.utils.Array;
\r
46 import com.badlogic.gdx.utils.Disposable;
\r
47 import com.badlogic.gdx.utils.LongMap;
\r
48 import com.badlogic.gdx.utils.Pool;
\r
50 /** The world class manages all physics entities, dynamic simulation, and asynchronous queries. The world also contains efficient
\r
51 * memory management facilities.
\r
52 * @author mzechner */
\r
53 public final class World implements Disposable {
\r
56 #include <Box2D/Box2D.h>
\r
58 static jclass worldClass = 0;
\r
59 static jmethodID shouldCollideID = 0;
\r
60 static jmethodID beginContactID = 0;
\r
61 static jmethodID endContactID = 0;
\r
62 static jmethodID preSolveID = 0;
\r
63 static jmethodID postSolveID = 0;
\r
64 static jmethodID reportFixtureID = 0;
\r
65 static jmethodID reportRayFixtureID = 0;
\r
67 class CustomRayCastCallback: public b2RayCastCallback
\r
74 CustomRayCastCallback( JNIEnv *env, jobject obj )
\r
80 virtual float32 ReportFixture( b2Fixture* fixture, const b2Vec2& point, const b2Vec2& normal, float32 fraction)
\r
82 return env->CallFloatMethod(obj, reportRayFixtureID, (jlong)fixture, (jfloat)point.x, (jfloat)point.y,
\r
83 (jfloat)normal.x, (jfloat)normal.y, (jfloat)fraction );
\r
87 class CustomContactFilter: public b2ContactFilter
\r
94 CustomContactFilter( JNIEnv* env, jobject obj )
\r
100 virtual bool ShouldCollide(b2Fixture* fixtureA, b2Fixture* fixtureB)
\r
102 if( shouldCollideID != 0 )
\r
103 return env->CallBooleanMethod( obj, shouldCollideID, (jlong)fixtureA, (jlong)fixtureB );
\r
109 class CustomContactListener: public b2ContactListener
\r
116 CustomContactListener( JNIEnv* env, jobject obj )
\r
122 /// Called when two fixtures begin to touch.
\r
123 virtual void BeginContact(b2Contact* contact)
\r
125 if( beginContactID != 0 )
\r
126 env->CallVoidMethod(obj, beginContactID, (jlong)contact );
\r
129 /// Called when two fixtures cease to touch.
\r
130 virtual void EndContact(b2Contact* contact)
\r
132 if( endContactID != 0 )
\r
133 env->CallVoidMethod(obj, endContactID, (jlong)contact);
\r
136 /// This is called after a contact is updated.
\r
137 virtual void PreSolve(b2Contact* contact, const b2Manifold* oldManifold)
\r
139 if( preSolveID != 0 )
\r
140 env->CallVoidMethod(obj, preSolveID, (jlong)contact, (jlong)oldManifold);
\r
143 /// This lets you inspect a contact after the solver is finished.
\r
144 virtual void PostSolve(b2Contact* contact, const b2ContactImpulse* impulse)
\r
146 if( postSolveID != 0 )
\r
147 env->CallVoidMethod(obj, postSolveID, (jlong)contact, (jlong)impulse);
\r
151 class CustomQueryCallback: public b2QueryCallback
\r
158 CustomQueryCallback( JNIEnv* env, jobject obj )
\r
164 virtual bool ReportFixture( b2Fixture* fixture )
\r
166 return env->CallBooleanMethod(obj, reportFixtureID, (jlong)fixture );
\r
170 inline b2BodyType getBodyType( int type )
\r
174 case 0: return b2_staticBody;
\r
175 case 1: return b2_kinematicBody;
\r
176 case 2: return b2_dynamicBody;
\r
178 return b2_staticBody;
\r
182 b2ContactFilter defaultFilter;
\r
185 /** pool for bodies **/
\r
186 protected final Pool<Body> freeBodies = new Pool<Body>(100, 200) {
\r
188 protected Body newObject () {
\r
189 return new Body(World.this, 0);
\r
193 /** pool for fixtures **/
\r
194 protected final Pool<Fixture> freeFixtures = new Pool<Fixture>(100, 200) {
\r
196 protected Fixture newObject () {
\r
197 return new Fixture(null, 0);
\r
201 /** the address of the world instance **/
\r
202 private final long addr;
\r
204 /** all known bodies **/
\r
205 protected final LongMap<Body> bodies = new LongMap<Body>(100);
\r
207 /** all known fixtures **/
\r
208 protected final LongMap<Fixture> fixtures = new LongMap<Fixture>(100);
\r
210 /** all known joints **/
\r
211 protected final LongMap<Joint> joints = new LongMap<Joint>(100);
\r
213 /** Contact filter **/
\r
214 protected ContactFilter contactFilter = null;
\r
216 /** Contact listener **/
\r
217 protected ContactListener contactListener = null;
\r
219 /** Construct a world object.
\r
220 * @param gravity the world gravity vector.
\r
221 * @param doSleep improve performance by not simulating inactive bodies. */
\r
222 public World (Vector2 gravity, boolean doSleep) {
\r
223 addr = newWorld(gravity.x, gravity.y, doSleep);
\r
225 contacts.ensureCapacity(contactAddrs.length);
\r
226 freeContacts.ensureCapacity(contactAddrs.length);
\r
228 for (int i = 0; i < contactAddrs.length; i++)
\r
229 freeContacts.add(new Contact(this, 0));
\r
232 private native long newWorld (float gravityX, float gravityY, boolean doSleep); /*
\r
233 // we leak one global ref.
\r
235 worldClass = (jclass)env->NewGlobalRef(env->GetObjectClass(object));
\r
236 beginContactID = env->GetMethodID(worldClass, "beginContact", "(J)V" );
\r
237 endContactID = env->GetMethodID( worldClass, "endContact", "(J)V" );
\r
238 preSolveID = env->GetMethodID( worldClass, "preSolve", "(JJ)V" );
\r
239 postSolveID = env->GetMethodID( worldClass, "postSolve", "(JJ)V" );
\r
240 reportFixtureID = env->GetMethodID(worldClass, "reportFixture", "(J)Z" );
\r
241 reportRayFixtureID = env->GetMethodID(worldClass, "reportRayFixture", "(JFFFFF)F" );
\r
242 shouldCollideID = env->GetMethodID( worldClass, "contactFilter", "(JJ)Z");
\r
245 b2World* world = new b2World( b2Vec2( gravityX, gravityY ));
\r
246 world->SetAllowSleeping( doSleep );
\r
247 return (jlong)world;
\r
250 /** Register a destruction listener. The listener is owned by you and must remain in scope. */
\r
251 public void setDestructionListener (DestructionListener listener) {
\r
255 /** Register a contact filter to provide specific control over collision. Otherwise the default filter is used
\r
256 * (b2_defaultFilter). The listener is owned by you and must remain in scope. */
\r
257 public void setContactFilter (ContactFilter filter) {
\r
258 this.contactFilter = filter;
\r
259 setUseDefaultContactFilter(filter == null);
\r
262 /** tells the native code not to call the Java world class if use is false **/
\r
263 private native void setUseDefaultContactFilter(boolean use); /*
\r
267 /** Register a contact event listener. The listener is owned by you and must remain in scope. */
\r
268 public void setContactListener (ContactListener listener) {
\r
269 this.contactListener = listener;
\r
272 /** Create a rigid body given a definition. No reference to the definition is retained.
\r
273 * @warning This function is locked during callbacks. */
\r
274 public Body createBody (BodyDef def) {
\r
275 long bodyAddr = jniCreateBody(addr, def.type.getValue(), def.position.x, def.position.y, def.angle, def.linearVelocity.x,
\r
276 def.linearVelocity.y, def.angularVelocity, def.linearDamping, def.angularDamping, def.allowSleep, def.awake,
\r
277 def.fixedRotation, def.bullet, def.active, def.gravityScale);
\r
278 Body body = freeBodies.obtain();
\r
279 body.reset(bodyAddr);
\r
280 this.bodies.put(body.addr, body);
\r
284 private native long jniCreateBody (long addr, int type, float positionX, float positionY, float angle, float linearVelocityX,
\r
285 float linearVelocityY, float angularVelocity, float linearDamping, float angularDamping, boolean allowSleep, boolean awake,
\r
286 boolean fixedRotation, boolean bullet, boolean active, float inertiaScale); /*
\r
288 bodyDef.type = getBodyType(type);
\r
289 bodyDef.position.Set( positionX, positionY );
\r
290 bodyDef.angle = angle;
\r
291 bodyDef.linearVelocity.Set( linearVelocityX, linearVelocityY );
\r
292 bodyDef.angularVelocity = angularVelocity;
\r
293 bodyDef.linearDamping = linearDamping;
\r
294 bodyDef.angularDamping = angularDamping;
\r
295 bodyDef.allowSleep = allowSleep;
\r
296 bodyDef.awake = awake;
\r
297 bodyDef.fixedRotation = fixedRotation;
\r
298 bodyDef.bullet = bullet;
\r
299 bodyDef.active = active;
\r
300 bodyDef.gravityScale = inertiaScale;
\r
302 b2World* world = (b2World*)addr;
\r
303 b2Body* body = world->CreateBody( &bodyDef );
\r
304 return (jlong)body;
\r
307 /** Destroy a rigid body given a definition. No reference to the definition is retained. This function is locked during
\r
309 * @warning This automatically deletes all associated shapes and joints.
\r
310 * @warning This function is locked during callbacks. */
\r
311 public void destroyBody (Body body) {
\r
312 body.setUserData(null);
\r
313 this.bodies.remove(body.addr);
\r
314 List<Fixture> fixtureList = body.getFixtureList();
\r
315 while(!fixtureList.isEmpty()) {
\r
316 this.fixtures.remove(fixtureList.remove(0).addr).setUserData(null);
\r
318 List<JointEdge> jointList = body.getJointList();
\r
319 while (!jointList.isEmpty())
\r
320 destroyJoint(body.getJointList().get(0).joint);
\r
321 jniDestroyBody(addr, body.addr);
\r
322 freeBodies.free(body);
\r
325 private native void jniDestroyBody (long addr, long bodyAddr); /*
\r
326 b2World* world = (b2World*)addr;
\r
327 b2Body* body = (b2Body*)bodyAddr;
\r
328 CustomContactFilter contactFilter(env, object);
\r
329 CustomContactListener contactListener(env,object);
\r
330 world->SetContactFilter(&contactFilter);
\r
331 world->SetContactListener(&contactListener);
\r
332 world->DestroyBody(body);
\r
333 world->SetContactFilter(&defaultFilter);
\r
334 world->SetContactListener(0);
\r
337 /** Create a joint to constrain bodies together. No reference to the definition is retained. This may cause the connected bodies
\r
338 * to cease colliding.
\r
339 * @warning This function is locked during callbacks. */
\r
340 public Joint createJoint (JointDef def) {
\r
341 long jointAddr = createProperJoint(def);
\r
342 Joint joint = null;
\r
343 if (def.type == JointType.DistanceJoint) joint = new DistanceJoint(this, jointAddr);
\r
344 if (def.type == JointType.FrictionJoint) joint = new FrictionJoint(this, jointAddr);
\r
345 if (def.type == JointType.GearJoint) joint = new GearJoint(this, jointAddr);
\r
346 if (def.type == JointType.MouseJoint) joint = new MouseJoint(this, jointAddr);
\r
347 if (def.type == JointType.PrismaticJoint) joint = new PrismaticJoint(this, jointAddr);
\r
348 if (def.type == JointType.PulleyJoint) joint = new PulleyJoint(this, jointAddr);
\r
349 if (def.type == JointType.RevoluteJoint) joint = new RevoluteJoint(this, jointAddr);
\r
350 if (def.type == JointType.WeldJoint) joint = new WeldJoint(this, jointAddr);
\r
351 if (def.type == JointType.RopeJoint) joint = new RopeJoint(this, jointAddr);
\r
352 if (def.type == JointType.WheelJoint) joint = new WheelJoint(this, jointAddr);
\r
353 if (joint != null) joints.put(joint.addr, joint);
\r
354 JointEdge jointEdgeA = new JointEdge(def.bodyB, joint);
\r
355 JointEdge jointEdgeB = new JointEdge(def.bodyA, joint);
\r
356 joint.jointEdgeA = jointEdgeA;
\r
357 joint.jointEdgeB = jointEdgeB;
\r
358 def.bodyA.joints.add(jointEdgeA);
\r
359 def.bodyB.joints.add(jointEdgeB);
\r
363 private long createProperJoint (JointDef def) {
\r
364 if (def.type == JointType.DistanceJoint) {
\r
365 DistanceJointDef d = (DistanceJointDef)def;
\r
366 return jniCreateDistanceJoint(addr, d.bodyA.addr, d.bodyB.addr, d.collideConnected, d.localAnchorA.x, d.localAnchorA.y,
\r
367 d.localAnchorB.x, d.localAnchorB.y, d.length, d.frequencyHz, d.dampingRatio);
\r
369 if (def.type == JointType.FrictionJoint) {
\r
370 FrictionJointDef d = (FrictionJointDef)def;
\r
371 return jniCreateFrictionJoint(addr, d.bodyA.addr, d.bodyB.addr, d.collideConnected, d.localAnchorA.x, d.localAnchorA.y,
\r
372 d.localAnchorB.x, d.localAnchorB.y, d.maxForce, d.maxTorque);
\r
374 if (def.type == JointType.GearJoint) {
\r
375 GearJointDef d = (GearJointDef)def;
\r
376 return jniCreateGearJoint(addr, d.bodyA.addr, d.bodyB.addr, d.collideConnected, d.joint1.addr, d.joint2.addr, d.ratio);
\r
378 if (def.type == JointType.MouseJoint) {
\r
379 MouseJointDef d = (MouseJointDef)def;
\r
380 return jniCreateMouseJoint(addr, d.bodyA.addr, d.bodyB.addr, d.collideConnected, d.target.x, d.target.y, d.maxForce,
\r
381 d.frequencyHz, d.dampingRatio);
\r
383 if (def.type == JointType.PrismaticJoint) {
\r
384 PrismaticJointDef d = (PrismaticJointDef)def;
\r
385 return jniCreatePrismaticJoint(addr, d.bodyA.addr, d.bodyB.addr, d.collideConnected, d.localAnchorA.x, d.localAnchorA.y,
\r
386 d.localAnchorB.x, d.localAnchorB.y, d.localAxisA.x, d.localAxisA.y, d.referenceAngle, d.enableLimit,
\r
387 d.lowerTranslation, d.upperTranslation, d.enableMotor, d.maxMotorForce, d.motorSpeed);
\r
389 if (def.type == JointType.PulleyJoint) {
\r
390 PulleyJointDef d = (PulleyJointDef)def;
\r
391 return jniCreatePulleyJoint(addr, d.bodyA.addr, d.bodyB.addr, d.collideConnected, d.groundAnchorA.x, d.groundAnchorA.y,
\r
392 d.groundAnchorB.x, d.groundAnchorB.y, d.localAnchorA.x, d.localAnchorA.y, d.localAnchorB.x, d.localAnchorB.y,
\r
393 d.lengthA, d.lengthB, d.ratio);
\r
396 if (def.type == JointType.RevoluteJoint) {
\r
397 RevoluteJointDef d = (RevoluteJointDef)def;
\r
398 return jniCreateRevoluteJoint(addr, d.bodyA.addr, d.bodyB.addr, d.collideConnected, d.localAnchorA.x, d.localAnchorA.y,
\r
399 d.localAnchorB.x, d.localAnchorB.y, d.referenceAngle, d.enableLimit, d.lowerAngle, d.upperAngle, d.enableMotor,
\r
400 d.motorSpeed, d.maxMotorTorque);
\r
402 if (def.type == JointType.WeldJoint) {
\r
403 WeldJointDef d = (WeldJointDef)def;
\r
404 return jniCreateWeldJoint(addr, d.bodyA.addr, d.bodyB.addr, d.collideConnected, d.localAnchorA.x, d.localAnchorA.y,
\r
405 d.localAnchorB.x, d.localAnchorB.y, d.referenceAngle);
\r
407 if (def.type == JointType.RopeJoint) {
\r
408 RopeJointDef d = (RopeJointDef)def;
\r
409 return jniCreateRopeJoint(addr, d.bodyA.addr, d.bodyB.addr, d.collideConnected, d.localAnchorA.x, d.localAnchorA.y,
\r
410 d.localAnchorB.x, d.localAnchorB.y, d.maxLength);
\r
412 if (def.type == JointType.WheelJoint) {
\r
413 WheelJointDef d = (WheelJointDef)def;
\r
414 return jniCreateWheelJoint(addr, d.bodyA.addr, d.bodyB.addr, d.collideConnected, d.localAnchorA.x, d.localAnchorA.y,
\r
415 d.localAnchorB.x, d.localAnchorB.y, d.localAxisA.x, d.localAxisA.y, d.enableMotor, d.maxMotorTorque, d.motorSpeed,
\r
416 d.frequencyHz, d.dampingRatio);
\r
422 private native long jniCreateWheelJoint (long addr, long bodyA, long bodyB, boolean collideConnected, float localAnchorAX,
\r
423 float localAnchorAY, float localAnchorBX, float localAnchorBY, float localAxisAX, float localAxisAY, boolean enableMotor,
\r
424 float maxMotorTorque, float motorSpeed, float frequencyHz, float dampingRatio); /*
\r
425 b2World* world = (b2World*)addr;
\r
426 b2WheelJointDef def;
\r
427 def.bodyA = (b2Body*)bodyA;
\r
428 def.bodyB = (b2Body*)bodyB;
\r
429 def.collideConnected = collideConnected;
\r
430 def.localAnchorA = b2Vec2(localAnchorAX, localAnchorAY);
\r
431 def.localAnchorB = b2Vec2(localAnchorBX, localAnchorBY);
\r
432 def.localAxisA = b2Vec2(localAxisAX, localAxisAY);
\r
433 def.enableMotor = enableMotor;
\r
434 def.maxMotorTorque = maxMotorTorque;
\r
435 def.motorSpeed = motorSpeed;
\r
436 def.frequencyHz = frequencyHz;
\r
437 def.dampingRatio = dampingRatio;
\r
439 return (jlong)world->CreateJoint(&def);
\r
442 private native long jniCreateRopeJoint (long addr, long bodyA, long bodyB, boolean collideConnected, float localAnchorAX,
\r
443 float localAnchorAY, float localAnchorBX, float localAnchorBY, float maxLength); /*
\r
444 b2World* world = (b2World*)addr;
\r
445 b2RopeJointDef def;
\r
446 def.bodyA = (b2Body*)bodyA;
\r
447 def.bodyB = (b2Body*)bodyB;
\r
448 def.collideConnected = collideConnected;
\r
449 def.localAnchorA = b2Vec2(localAnchorAX, localAnchorAY);
\r
450 def.localAnchorB = b2Vec2(localAnchorBX, localAnchorBY);
\r
451 def.maxLength = maxLength;
\r
453 return (jlong)world->CreateJoint(&def);
\r
456 private native long jniCreateDistanceJoint (long addr, long bodyA, long bodyB, boolean collideConnected, float localAnchorAX,
\r
457 float localAnchorAY, float localAnchorBX, float localAnchorBY, float length, float frequencyHz, float dampingRatio); /*
\r
458 b2World* world = (b2World*)addr;
\r
459 b2DistanceJointDef def;
\r
460 def.bodyA = (b2Body*)bodyA;
\r
461 def.bodyB = (b2Body*)bodyB;
\r
462 def.collideConnected = collideConnected;
\r
463 def.localAnchorA = b2Vec2(localAnchorAX, localAnchorAY);
\r
464 def.localAnchorB = b2Vec2(localAnchorBX, localAnchorBY);
\r
465 def.length = length;
\r
466 def.frequencyHz = frequencyHz;
\r
467 def.dampingRatio = dampingRatio;
\r
469 return (jlong)world->CreateJoint(&def);
\r
472 private native long jniCreateFrictionJoint (long addr, long bodyA, long bodyB, boolean collideConnected, float localAnchorAX,
\r
473 float localAnchorAY, float localAnchorBX, float localAnchorBY, float maxForce, float maxTorque); /*
\r
474 b2World* world = (b2World*)addr;
\r
475 b2FrictionJointDef def;
\r
476 def.bodyA = (b2Body*)bodyA;
\r
477 def.bodyB = (b2Body*)bodyB;
\r
478 def.collideConnected = collideConnected;
\r
479 def.localAnchorA = b2Vec2(localAnchorAX, localAnchorAY);
\r
480 def.localAnchorB = b2Vec2(localAnchorBX, localAnchorBY);
\r
481 def.maxForce = maxForce;
\r
482 def.maxTorque = maxTorque;
\r
483 return (jlong)world->CreateJoint(&def);
\r
486 private native long jniCreateGearJoint (long addr, long bodyA, long bodyB, boolean collideConnected, long joint1, long joint2,
\r
488 b2World* world = (b2World*)addr;
\r
489 b2GearJointDef def;
\r
490 def.bodyA = (b2Body*)bodyA;
\r
491 def.bodyB = (b2Body*)bodyB;
\r
492 def.collideConnected = collideConnected;
\r
493 def.joint1 = (b2Joint*)joint1;
\r
494 def.joint2 = (b2Joint*)joint2;
\r
496 return (jlong)world->CreateJoint(&def);
\r
499 private native long jniCreateMouseJoint (long addr, long bodyA, long bodyB, boolean collideConnected, float targetX,
\r
500 float targetY, float maxForce, float frequencyHz, float dampingRatio); /*
\r
501 b2World* world = (b2World*)addr;
\r
502 b2MouseJointDef def;
\r
503 def.bodyA = (b2Body*)bodyA;
\r
504 def.bodyB = (b2Body*)bodyB;
\r
505 def.collideConnected = collideConnected;
\r
506 def.target = b2Vec2( targetX, targetY );
\r
507 def.maxForce = maxForce;
\r
508 def.frequencyHz = frequencyHz;
\r
509 def.dampingRatio = dampingRatio;
\r
510 return (jlong)world->CreateJoint(&def);
\r
513 private native long jniCreatePrismaticJoint (long addr, long bodyA, long bodyB, boolean collideConnected, float localAnchorAX,
\r
514 float localAnchorAY, float localAnchorBX, float localAnchorBY, float localAxisAX, float localAxisAY, float referenceAngle,
\r
515 boolean enableLimit, float lowerTranslation, float upperTranslation, boolean enableMotor, float maxMotorForce,
\r
516 float motorSpeed); /*
\r
517 b2World* world = (b2World*)addr;
\r
518 b2PrismaticJointDef def;
\r
519 def.bodyA = (b2Body*)bodyA;
\r
520 def.bodyB = (b2Body*)bodyB;
\r
521 def.collideConnected = collideConnected;
\r
522 def.localAnchorA = b2Vec2(localAnchorAX, localAnchorAY);
\r
523 def.localAnchorB = b2Vec2(localAnchorBX, localAnchorBY);
\r
524 def.localAxisA = b2Vec2( localAxisAX, localAxisAY );
\r
525 def.referenceAngle = referenceAngle;
\r
526 def.enableLimit = enableLimit;
\r
527 def.lowerTranslation = lowerTranslation;
\r
528 def.upperTranslation = upperTranslation;
\r
529 def.enableMotor = enableMotor;
\r
530 def.maxMotorForce = maxMotorForce;
\r
531 def.motorSpeed = motorSpeed;
\r
532 return (jlong)world->CreateJoint(&def);
\r
535 private native long jniCreatePulleyJoint (long addr, long bodyA, long bodyB, boolean collideConnected, float groundAnchorAX,
\r
536 float groundAnchorAY, float groundAnchorBX, float groundAnchorBY, float localAnchorAX, float localAnchorAY,
\r
537 float localAnchorBX, float localAnchorBY, float lengthA, float lengthB, float ratio); /*
\r
538 b2World* world = (b2World*)addr;
\r
539 b2PulleyJointDef def;
\r
540 def.bodyA = (b2Body*)bodyA;
\r
541 def.bodyB = (b2Body*)bodyB;
\r
542 def.collideConnected = collideConnected;
\r
543 def.groundAnchorA = b2Vec2( groundAnchorAX, groundAnchorAY );
\r
544 def.groundAnchorB = b2Vec2( groundAnchorBX, groundAnchorBY );
\r
545 def.localAnchorA = b2Vec2(localAnchorAX, localAnchorAY);
\r
546 def.localAnchorB = b2Vec2(localAnchorBX, localAnchorBY);
\r
547 def.lengthA = lengthA;
\r
548 def.lengthB = lengthB;
\r
551 return (jlong)world->CreateJoint(&def);
\r
554 private native long jniCreateRevoluteJoint (long addr, long bodyA, long bodyB, boolean collideConnected, float localAnchorAX,
\r
555 float localAnchorAY, float localAnchorBX, float localAnchorBY, float referenceAngle, boolean enableLimit, float lowerAngle,
\r
556 float upperAngle, boolean enableMotor, float motorSpeed, float maxMotorTorque); /*
\r
557 b2World* world = (b2World*)addr;
\r
558 b2RevoluteJointDef def;
\r
559 def.bodyA = (b2Body*)bodyA;
\r
560 def.bodyB = (b2Body*)bodyB;
\r
561 def.collideConnected = collideConnected;
\r
562 def.localAnchorA = b2Vec2(localAnchorAX, localAnchorAY);
\r
563 def.localAnchorB = b2Vec2(localAnchorBX, localAnchorBY);
\r
564 def.referenceAngle = referenceAngle;
\r
565 def.enableLimit = enableLimit;
\r
566 def.lowerAngle = lowerAngle;
\r
567 def.upperAngle = upperAngle;
\r
568 def.enableMotor = enableMotor;
\r
569 def.motorSpeed = motorSpeed;
\r
570 def.maxMotorTorque = maxMotorTorque;
\r
571 return (jlong)world->CreateJoint(&def);
\r
574 private native long jniCreateWeldJoint (long addr, long bodyA, long bodyB, boolean collideConnected, float localAnchorAX,
\r
575 float localAnchorAY, float localAnchorBX, float localAnchorBY, float referenceAngle); /*
\r
576 b2World* world = (b2World*)addr;
\r
577 b2WeldJointDef def;
\r
578 def.bodyA = (b2Body*)bodyA;
\r
579 def.bodyB = (b2Body*)bodyB;
\r
580 def.collideConnected = collideConnected;
\r
581 def.localAnchorA = b2Vec2(localAnchorAX, localAnchorAY);
\r
582 def.localAnchorB = b2Vec2(localAnchorBX, localAnchorBY);
\r
583 def.referenceAngle = referenceAngle;
\r
585 return (jlong)world->CreateJoint(&def);
\r
588 /** Destroy a joint. This may cause the connected bodies to begin colliding.
\r
589 * @warning This function is locked during callbacks. */
\r
590 public void destroyJoint (Joint joint) {
\r
591 joint.setUserData(null);
\r
592 joints.remove(joint.addr);
\r
593 joint.jointEdgeA.other.joints.remove(joint.jointEdgeB);
\r
594 joint.jointEdgeB.other.joints.remove(joint.jointEdgeA);
\r
595 jniDestroyJoint(addr, joint.addr);
\r
598 private native void jniDestroyJoint (long addr, long jointAddr); /*
\r
599 b2World* world = (b2World*)addr;
\r
600 b2Joint* joint = (b2Joint*)jointAddr;
\r
601 CustomContactFilter contactFilter(env, object);
\r
602 CustomContactListener contactListener(env,object);
\r
603 world->SetContactFilter(&contactFilter);
\r
604 world->SetContactListener(&contactListener);
\r
605 world->DestroyJoint( joint );
\r
606 world->SetContactFilter(&defaultFilter);
\r
607 world->SetContactListener(0);
\r
610 /** Take a time step. This performs collision detection, integration, and constraint solution.
\r
611 * @param timeStep the amount of time to simulate, this should not vary.
\r
612 * @param velocityIterations for the velocity constraint solver.
\r
613 * @param positionIterations for the position constraint solver. */
\r
614 public void step (float timeStep, int velocityIterations, int positionIterations) {
\r
615 jniStep(addr, timeStep, velocityIterations, positionIterations);
\r
618 private native void jniStep (long addr, float timeStep, int velocityIterations, int positionIterations); /*
\r
619 b2World* world = (b2World*)addr;
\r
620 CustomContactFilter contactFilter(env, object);
\r
621 CustomContactListener contactListener(env,object);
\r
622 world->SetContactFilter(&contactFilter);
\r
623 world->SetContactListener(&contactListener);
\r
624 world->Step( timeStep, velocityIterations, positionIterations );
\r
625 world->SetContactFilter(&defaultFilter);
\r
626 world->SetContactListener(0);
\r
629 /** Manually clear the force buffer on all bodies. By default, forces are cleared automatically after each call to Step. The
\r
630 * default behavior is modified by calling SetAutoClearForces. The purpose of this function is to support sub-stepping.
\r
631 * Sub-stepping is often used to maintain a fixed sized time step under a variable frame-rate. When you perform sub-stepping
\r
632 * you will disable auto clearing of forces and instead call ClearForces after all sub-steps are complete in one pass of your
\r
633 * game loop. {@link #setAutoClearForces(boolean)} */
\r
634 public void clearForces () {
\r
635 jniClearForces(addr);
\r
638 private native void jniClearForces (long addr); /*
\r
639 b2World* world = (b2World*)addr;
\r
640 world->ClearForces();
\r
643 /** Enable/disable warm starting. For testing. */
\r
644 public void setWarmStarting (boolean flag) {
\r
645 jniSetWarmStarting(addr, flag);
\r
648 private native void jniSetWarmStarting (long addr, boolean flag); /*
\r
649 b2World* world = (b2World*)addr;
\r
650 world->SetWarmStarting(flag);
\r
653 /** Enable/disable continuous physics. For testing. */
\r
654 public void setContinuousPhysics (boolean flag) {
\r
655 jniSetContiousPhysics(addr, flag);
\r
658 private native void jniSetContiousPhysics (long addr, boolean flag); /*
\r
659 b2World* world = (b2World*)addr;
\r
660 world->SetContinuousPhysics(flag);
\r
663 /** Get the number of broad-phase proxies. */
\r
664 public int getProxyCount () {
\r
665 return jniGetProxyCount(addr);
\r
668 private native int jniGetProxyCount (long addr); /*
\r
669 b2World* world = (b2World*)addr;
\r
670 return world->GetProxyCount();
\r
673 /** Get the number of bodies. */
\r
674 public int getBodyCount () {
\r
675 return jniGetBodyCount(addr);
\r
678 private native int jniGetBodyCount (long addr); /*
\r
679 b2World* world = (b2World*)addr;
\r
680 return world->GetBodyCount();
\r
683 /** Get the number of joints. */
\r
684 public int getJointCount () {
\r
685 return jniGetJointcount(addr);
\r
688 private native int jniGetJointcount (long addr); /*
\r
689 b2World* world = (b2World*)addr;
\r
690 return world->GetJointCount();
\r
693 /** Get the number of contacts (each may have 0 or more contact points). */
\r
694 public int getContactCount () {
\r
695 return jniGetContactCount(addr);
\r
698 private native int jniGetContactCount (long addr); /*
\r
699 b2World* world = (b2World*)addr;
\r
700 return world->GetContactCount();
\r
703 /** Change the global gravity vector. */
\r
704 public void setGravity (Vector2 gravity) {
\r
705 jniSetGravity(addr, gravity.x, gravity.y);
\r
708 private native void jniSetGravity (long addr, float gravityX, float gravityY); /*
\r
709 b2World* world = (b2World*)addr;
\r
710 world->SetGravity( b2Vec2( gravityX, gravityY ) );
\r
713 /** Get the global gravity vector. */
\r
714 final float[] tmpGravity = new float[2];
\r
715 final Vector2 gravity = new Vector2();
\r
717 public Vector2 getGravity () {
\r
718 jniGetGravity(addr, tmpGravity);
\r
719 gravity.x = tmpGravity[0];
\r
720 gravity.y = tmpGravity[1];
\r
724 private native void jniGetGravity (long addr, float[] gravity); /*
\r
725 b2World* world = (b2World*)addr;
\r
726 b2Vec2 g = world->GetGravity();
\r
731 /** Is the world locked (in the middle of a time step). */
\r
732 public boolean isLocked () {
\r
733 return jniIsLocked(addr);
\r
736 private native boolean jniIsLocked (long addr); /*
\r
737 b2World* world = (b2World*)addr;
\r
738 return world->IsLocked();
\r
741 /** Set flag to control automatic clearing of forces after each time step. */
\r
742 public void setAutoClearForces (boolean flag) {
\r
743 jniSetAutoClearForces(addr, flag);
\r
746 private native void jniSetAutoClearForces (long addr, boolean flag); /*
\r
747 b2World* world = (b2World*)addr;
\r
748 world->SetAutoClearForces(flag);
\r
751 /** Get the flag that controls automatic clearing of forces after each time step. */
\r
752 public boolean getAutoClearForces () {
\r
753 return jniGetAutoClearForces(addr);
\r
756 private native boolean jniGetAutoClearForces (long addr); /*
\r
757 b2World* world = (b2World*)addr;
\r
758 return world->GetAutoClearForces();
\r
761 /** Query the world for all fixtures that potentially overlap the provided AABB.
\r
762 * @param callback a user implemented callback class.
\r
763 * @param lowerX the x coordinate of the lower left corner
\r
764 * @param lowerY the y coordinate of the lower left corner
\r
765 * @param upperX the x coordinate of the upper right corner
\r
766 * @param upperY the y coordinate of the upper right corner */
\r
767 public void QueryAABB (QueryCallback callback, float lowerX, float lowerY, float upperX, float upperY) {
\r
768 queryCallback = callback;
\r
769 jniQueryAABB(addr, lowerX, lowerY, upperX, upperY);
\r
772 private QueryCallback queryCallback = null;;
\r
774 private native void jniQueryAABB (long addr, float lowX, float lowY, float upX, float upY); /*
\r
775 b2World* world = (b2World*)addr;
\r
777 aabb.lowerBound = b2Vec2( lowX, lowY );
\r
778 aabb.upperBound = b2Vec2( upX, upY );
\r
780 CustomQueryCallback callback( env, object );
\r
781 world->QueryAABB( &callback, aabb );
\r
785 // /// Ray-cast the world for all fixtures in the path of the ray. Your callback
\r
786 // /// controls whether you get the closest point, any point, or n-points.
\r
787 // /// The ray-cast ignores shapes that contain the starting point.
\r
788 // /// @param callback a user implemented callback class.
\r
789 // /// @param point1 the ray starting point
\r
790 // /// @param point2 the ray ending point
\r
791 // void RayCast(b2RayCastCallback* callback, const b2Vec2& point1, const b2Vec2& point2) const;
\r
793 // /// Get the world contact list. With the returned contact, use b2Contact::GetNext to get
\r
794 // /// the next contact in the world list. A NULL contact indicates the end of the list.
\r
795 // /// @return the head of the world contact list.
\r
796 // /// @warning contacts are
\r
797 // b2Contact* GetContactList();
\r
799 private long[] contactAddrs = new long[200];
\r
800 private final ArrayList<Contact> contacts = new ArrayList<Contact>();
\r
801 private final ArrayList<Contact> freeContacts = new ArrayList<Contact>();
\r
803 /** Returns the list of {@link Contact} instances produced by the last call to {@link #step(float, int, int)}. Note that the
\r
804 * returned list will have O(1) access times when using indexing. contacts are created and destroyed in the middle of a time
\r
805 * step. Use {@link ContactListener} to avoid missing contacts
\r
806 * @return the contact list */
\r
807 public List<Contact> getContactList () {
\r
808 int numContacts = getContactCount();
\r
809 if (numContacts > contactAddrs.length) {
\r
810 int newSize = 2 * numContacts;
\r
811 contactAddrs = new long[newSize];
\r
812 contacts.ensureCapacity(newSize);
\r
813 freeContacts.ensureCapacity(newSize);
\r
815 if (numContacts > freeContacts.size()) {
\r
816 int freeConts = freeContacts.size();
\r
817 for (int i = 0; i < numContacts - freeConts; i++)
\r
818 freeContacts.add(new Contact(this, 0));
\r
820 jniGetContactList(addr, contactAddrs);
\r
823 for (int i = 0; i < numContacts; i++) {
\r
824 Contact contact = freeContacts.get(i);
\r
825 contact.addr = contactAddrs[i];
\r
826 contacts.add(contact);
\r
832 /** @param bodies an Array in which to place all bodies currently in the simulation */
\r
833 public void getBodies (Array<Body> bodies) {
\r
835 bodies.ensureCapacity(this.bodies.size);
\r
836 for (Iterator<Body> iter = this.bodies.values(); iter.hasNext();) {
\r
837 bodies.add(iter.next());
\r
841 /** @param joints an Array in which to place all joints currently in the simulation */
\r
842 public void getJoints (Array<Joint> joints) {
\r
844 joints.ensureCapacity(this.joints.size);
\r
845 for (Iterator<Joint> iter = this.joints.values(); iter.hasNext();) {
\r
846 joints.add(iter.next());
\r
850 private native void jniGetContactList (long addr, long[] contacts); /*
\r
851 b2World* world = (b2World*)addr;
\r
853 b2Contact* contact = world->GetContactList();
\r
855 while( contact != 0 )
\r
857 contacts[i++] = (long long)contact;
\r
858 contact = contact->GetNext();
\r
862 public void dispose () {
\r
866 private native void jniDispose (long addr); /*
\r
867 b2World* world = (b2World*)(addr);
\r
871 /** Internal method called from JNI in case a contact happens
\r
874 * @return whether the things collided */
\r
875 private boolean contactFilter (long fixtureA, long fixtureB) {
\r
876 if (contactFilter != null)
\r
877 return contactFilter.shouldCollide(fixtures.get(fixtureA), fixtures.get(fixtureB));
\r
879 Filter filterA = fixtures.get(fixtureA).getFilterData();
\r
880 Filter filterB = fixtures.get(fixtureB).getFilterData();
\r
882 if (filterA.groupIndex == filterB.groupIndex && filterA.groupIndex != 0) {
\r
883 return filterA.groupIndex > 0;
\r
886 boolean collide = (filterA.maskBits & filterB.categoryBits) != 0 && (filterA.categoryBits & filterB.maskBits) != 0;
\r
891 private final Contact contact = new Contact(this, 0);
\r
892 private final Manifold manifold = new Manifold(0);
\r
893 private final ContactImpulse impulse = new ContactImpulse(this, 0);
\r
895 private void beginContact (long contactAddr) {
\r
896 contact.addr = contactAddr;
\r
897 if (contactListener != null) contactListener.beginContact(contact);
\r
900 private void endContact (long contactAddr) {
\r
901 contact.addr = contactAddr;
\r
902 if (contactListener != null) contactListener.endContact(contact);
\r
905 private void preSolve (long contactAddr, long manifoldAddr) {
\r
906 contact.addr = contactAddr;
\r
907 manifold.addr = manifoldAddr;
\r
908 if (contactListener != null) contactListener.preSolve(contact, manifold);
\r
911 private void postSolve (long contactAddr, long impulseAddr) {
\r
912 contact.addr = contactAddr;
\r
913 impulse.addr = impulseAddr;
\r
914 if (contactListener != null) contactListener.postSolve(contact, impulse);
\r
917 private boolean reportFixture (long addr) {
\r
918 if (queryCallback != null)
\r
919 return queryCallback.reportFixture(fixtures.get(addr));
\r
924 /** Sets the box2d velocity threshold globally, for all World instances.
\r
925 * @param threshold the threshold, default 1.0f */
\r
926 public static native void setVelocityThreshold (float threshold); /*
\r
927 b2_velocityThreshold = threshold;
\r
930 /** @return the global box2d velocity threshold. */
\r
931 public static native float getVelocityThreshold (); /*
\r
932 return b2_velocityThreshold;
\r
935 /** Ray-cast the world for all fixtures in the path of the ray. The ray-cast ignores shapes that contain the starting point.
\r
936 * @param callback a user implemented callback class.
\r
937 * @param point1 the ray starting point
\r
938 * @param point2 the ray ending point */
\r
939 public void rayCast (RayCastCallback callback, Vector2 point1, Vector2 point2) {
\r
940 rayCastCallback = callback;
\r
941 jniRayCast(addr, point1.x, point1.y, point2.x, point2.y);
\r
944 private RayCastCallback rayCastCallback = null;
\r
946 private native void jniRayCast (long addr, float aX, float aY, float bX, float bY); /*
\r
947 b2World *world = (b2World*)addr;
\r
948 CustomRayCastCallback callback( env, object );
\r
949 world->RayCast( &callback, b2Vec2(aX,aY), b2Vec2(bX,bY) );
\r
952 private Vector2 rayPoint = new Vector2();
\r
953 private Vector2 rayNormal = new Vector2();
\r
955 private float reportRayFixture (long addr, float pX, float pY, float nX, float nY, float fraction) {
\r
956 if (rayCastCallback != null) {
\r
961 return rayCastCallback.reportRayFixture(fixtures.get(addr), rayPoint, rayNormal, fraction);
\r