wezrule
December 24, 2011, 12:22pm
1
I think there are 2 bugs which i have found:
Only the PhysicsCollisionListeners are called of the last BulletAppState attached to the AppStateManager
collisions detected across all the BulletAppStates are detected in the last BulletAppState’s PhysicsCollisionListeners
Heres a testcase of it, each BulletAppState has a square with a sphere collision shape inside. The order of the attached BulletAppStates dictates which PhysicsCollisionListener is called (always the last one)
TestMultipleBulletPhysicsCollisions.java
[java]package test;
import com.jme3.app.SimpleApplication;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.collision.shapes.BoxCollisionShape;
import com.jme3.bullet.collision.shapes.SphereCollisionShape;
import com.jme3.bullet.control.GhostControl;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
public class TestMultipleBulletPhysicsCollisions extends SimpleApplication {
private BulletAppState bulletAppState1;
private BulletAppState bulletAppState2;
private BulletAppState bulletAppState3;
private static TestMultipleBulletPhysicsCollisions thisApp;
public static void main(String args[]) {
new TestMultipleBulletPhysicsCollisions().start();
}
@Override
public void simpleInitApp() {
thisApp = this;
bulletAppState1 = new BulletAppState();
bulletAppState2 = new BulletAppState();
bulletAppState3 = new BulletAppState();
stateManager.attach(bulletAppState1);
stateManager.attach(bulletAppState2);
stateManager.attach(bulletAppState3);
bulletAppState1.getPhysicsSpace().enableDebug(assetManager);
bulletAppState2.getPhysicsSpace().enableDebug(assetManager);
bulletAppState3.getPhysicsSpace().enableDebug(assetManager);
Node box1 = new Node(“box1”);
box1.setLocalTranslation(new Vector3f (-2.5f,0,0));
BoxCollisionShape boxCollisionShape1 = new BoxCollisionShape(new Vector3f(1, 1, 1));
box1.addControl(new GhostControl(boxCollisionShape1));
bulletAppState1.getPhysicsSpace().add(box1);
Node sphere1 = new Node(“sphere1”);
sphere1.setLocalTranslation(new Vector3f (-2.5f,0,0));
SphereCollisionShape sphereCollisionShape1 = new SphereCollisionShape(0.5f);
sphere1.addControl(new GhostControl(sphereCollisionShape1));
bulletAppState1.getPhysicsSpace().add(sphere1);
rootNode.attachChild(box1);
rootNode.attachChild(sphere1);
rootNode.addControl(new PhysicsCollisionControl(“one”));
Node box2 = new Node(“box2”);
BoxCollisionShape boxCollisionShape2 = new BoxCollisionShape(new Vector3f(1, 1, 1));
box2.addControl(new GhostControl(boxCollisionShape2));
bulletAppState2.getPhysicsSpace().add(box2);
Node sphere2 = new Node(“sphere2”);
SphereCollisionShape sphereCollisionShape2 = new SphereCollisionShape(0.5f);
sphere2.addControl(new GhostControl(sphereCollisionShape2));
bulletAppState2.getPhysicsSpace().add(sphere2);
rootNode.attachChild(box2);
rootNode.attachChild(sphere2);
rootNode.addControl(new PhysicsCollisionControl(“two”));
Node box3 = new Node(“box3”);
box3.move(new Vector3f(2.5f, 0, 0));
BoxCollisionShape boxCollisionShape3 = new BoxCollisionShape(new Vector3f(1, 1, 1));
box3.addControl(new GhostControl(boxCollisionShape3));
bulletAppState3.getPhysicsSpace().add(box3);
Node sphere3 = new Node(“sphere3”);
sphere3.move(new Vector3f(2.5f, 0, 0));
SphereCollisionShape sphereCollisionShape3 = new SphereCollisionShape(0.5f);
sphere3.addControl(new GhostControl(sphereCollisionShape3));
bulletAppState3.getPhysicsSpace().add(sphere3);
rootNode.attachChild(box3);
rootNode.attachChild(sphere3);
rootNode.addControl(new PhysicsCollisionControl(“three”));
}
public static TestMultipleBulletPhysicsCollisions getApp() {
return thisApp;
}
@Override
public void simpleUpdate(float tpf) {
}
public BulletAppState getBulletAppState1() {
return bulletAppState1;
}
public BulletAppState getBulletAppState2() {
return bulletAppState2;
}
public BulletAppState getBulletAppState3() {
return bulletAppState3;
}
}
[/java]
PhysicsCollisionControl.java
[java]
package test;
import com.jme3.bullet.collision.PhysicsCollisionEvent;
import com.jme3.bullet.collision.PhysicsCollisionListener;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.AbstractControl;
import com.jme3.scene.control.Control;
class PhysicsCollisionControl extends AbstractControl implements PhysicsCollisionListener {
private String number;
private TestMultipleBulletPhysicsCollisions myApp = TestMultipleBulletPhysicsCollisions.getApp();
public PhysicsCollisionControl(String number) {
this.number = number;
if(number.equals(“one”)) {
myApp.getBulletAppState1().getPhysicsSpace().addCollisionListener(this);
} else if (number.equals(“two”)) {
myApp.getBulletAppState2().getPhysicsSpace().addCollisionListener(this);
} else {
myApp.getBulletAppState3().getPhysicsSpace().addCollisionListener(this);
}
}
@Override
protected void controlUpdate(float tpf) {
}
@Override
protected void controlRender(RenderManager rm, ViewPort vp) {
}
public Control cloneForSpatial(Spatial spatial) {
throw new UnsupportedOperationException(“Not supported yet.”);
}
public void collision(PhysicsCollisionEvent event) {
System.out.println(number);
System.out.println(event.getNodeA() + " " + event.getNodeB());
}
}
[/java]
http://i.imgur.com/8YZUG.png
This image shows that all collision events detected are called in the last PhysicsCollisionListener, as shown by “three”
http://i.imgur.com/Ubws4.png
1 Like
normen
December 24, 2011, 2:29pm
2
Thanks. This is due to bullet doing the callbacks to a threadlocal listener… Can you try adding the listeners using he enqueue method of physicsspace and a callable?
1 Like
wezrule
December 24, 2011, 2:34pm
3
i will try but knowing me i will screw it up
wezrule
December 24, 2011, 2:40pm
4
i tried this (no idea if its right), but nothing gets called now
[java]
package test;
import com.jme3.bullet.collision.PhysicsCollisionEvent;
import com.jme3.bullet.collision.PhysicsCollisionListener;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.AbstractControl;
import com.jme3.scene.control.Control;
import java.util.concurrent.Callable;
class PhysicsCollisionControl extends AbstractControl implements PhysicsCollisionListener {
private String number;
private TestMultipleBulletPhysicsCollisions myApp = TestMultipleBulletPhysicsCollisions.getApp();
private PhysicsCollisionListener listener = this;
public PhysicsCollisionControl(String number) {
this.number = number;
if (number.equals("one")) {
myApp.getBulletAppState1().getPhysicsSpace().enqueue(new Callable<Void>() {
public Void call() throws Exception {
myApp.getBulletAppState1().getPhysicsSpace().addCollisionListener(listener);
return null;
}
});
} else if (number.equals("two")) {
myApp.getBulletAppState2().getPhysicsSpace().enqueue(new Callable<Void>() {
public Void call() throws Exception {
myApp.getBulletAppState2().getPhysicsSpace().addCollisionListener(listener);
return null;
}
});
} else {
myApp.getBulletAppState3().getPhysicsSpace().enqueue(new Callable<Void>() {
public Void call() throws Exception {
myApp.getBulletAppState3().getPhysicsSpace().addCollisionListener(listener);
return null;
}
});
}
}
@Override
protected void controlUpdate(float tpf) {
}
@Override
protected void controlRender(RenderManager rm, ViewPort vp) {
}
public Control cloneForSpatial(Spatial spatial) {
throw new UnsupportedOperationException("Not supported yet.");
}
public void collision(PhysicsCollisionEvent event) {
System.out.println(number);
System.out.println(event.getNodeA() + " " + event.getNodeB());
}
}
[/java]
normen
December 24, 2011, 2:44pm
5
Okay, thanks. I’ll look into this. Basically you have to register each listener on the thread its supposed to listen on… And they all have to listen on separate threads… Does it work when you enable parallel multithreading?
1 Like
wezrule
December 24, 2011, 2:47pm
6
i removed the callable, and added the bulletAppState.setThreadingType(BulletAppState.ThreadingType.PARALLEL); to all the bulletAppStates and, yeh that fixed it :), thanks!
normen
December 24, 2011, 2:50pm
7
Okay good, basically I guess this will be the only way it can work anyway… But it also only makes sense having multiple physics spaces in a parallel setup.
1 Like
wezrule
December 24, 2011, 2:56pm
8
ah ok sorry, thanks for the help! :), for completeness heres the working classes.
[java]
package test;
import com.jme3.app.SimpleApplication;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.collision.shapes.BoxCollisionShape;
import com.jme3.bullet.collision.shapes.SphereCollisionShape;
import com.jme3.bullet.control.GhostControl;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
public class TestMultipleBulletPhysicsCollisions extends SimpleApplication {
private BulletAppState bulletAppState1;
private BulletAppState bulletAppState2;
private BulletAppState bulletAppState3;
private static TestMultipleBulletPhysicsCollisions thisApp;
public static void main(String args[]) {
new TestMultipleBulletPhysicsCollisions().start();
}
@Override
public void simpleInitApp() {
thisApp = this;
bulletAppState1 = new BulletAppState();
bulletAppState1.setThreadingType(BulletAppState.ThreadingType.PARALLEL);
bulletAppState2 = new BulletAppState();
bulletAppState2.setThreadingType(BulletAppState.ThreadingType.PARALLEL);
bulletAppState3 = new BulletAppState();
bulletAppState3.setThreadingType(BulletAppState.ThreadingType.PARALLEL);
stateManager.attach(bulletAppState1);
stateManager.attach(bulletAppState2);
stateManager.attach(bulletAppState3);
bulletAppState1.getPhysicsSpace().enableDebug(assetManager);
bulletAppState2.getPhysicsSpace().enableDebug(assetManager);
bulletAppState3.getPhysicsSpace().enableDebug(assetManager);
Node box1 = new Node(“box1”);
box1.setLocalTranslation(new Vector3f (-2.5f,0,0));
BoxCollisionShape boxCollisionShape1 = new BoxCollisionShape(new Vector3f(1, 1, 1));
box1.addControl(new GhostControl(boxCollisionShape1));
bulletAppState1.getPhysicsSpace().add(box1);
Node sphere1 = new Node(“sphere1”);
sphere1.setLocalTranslation(new Vector3f (-2.5f,0,0));
SphereCollisionShape sphereCollisionShape1 = new SphereCollisionShape(0.5f);
sphere1.addControl(new GhostControl(sphereCollisionShape1));
bulletAppState1.getPhysicsSpace().add(sphere1);
rootNode.attachChild(box1);
rootNode.attachChild(sphere1);
rootNode.addControl(new PhysicsCollisionControl(“one”));
Node box2 = new Node(“box2”);
BoxCollisionShape boxCollisionShape2 = new BoxCollisionShape(new Vector3f(1, 1, 1));
box2.addControl(new GhostControl(boxCollisionShape2));
bulletAppState2.getPhysicsSpace().add(box2);
Node sphere2 = new Node(“sphere2”);
SphereCollisionShape sphereCollisionShape2 = new SphereCollisionShape(0.5f);
sphere2.addControl(new GhostControl(sphereCollisionShape2));
bulletAppState2.getPhysicsSpace().add(sphere2);
rootNode.attachChild(box2);
rootNode.attachChild(sphere2);
rootNode.addControl(new PhysicsCollisionControl(“two”));
Node box3 = new Node(“box3”);
box3.move(new Vector3f(2.5f, 0, 0));
BoxCollisionShape boxCollisionShape3 = new BoxCollisionShape(new Vector3f(1, 1, 1));
box3.addControl(new GhostControl(boxCollisionShape3));
bulletAppState3.getPhysicsSpace().add(box3);
Node sphere3 = new Node(“sphere3”);
sphere3.move(new Vector3f(2.5f, 0, 0));
SphereCollisionShape sphereCollisionShape3 = new SphereCollisionShape(0.5f);
sphere3.addControl(new GhostControl(sphereCollisionShape3));
bulletAppState3.getPhysicsSpace().add(sphere3);
rootNode.attachChild(box3);
rootNode.attachChild(sphere3);
rootNode.addControl(new PhysicsCollisionControl(“three”));
}
public static TestMultipleBulletPhysicsCollisions getApp() {
return thisApp;
}
@Override
public void simpleUpdate(float tpf) {
}
public BulletAppState getBulletAppState1() {
return bulletAppState1;
}
public BulletAppState getBulletAppState2() {
return bulletAppState2;
}
public BulletAppState getBulletAppState3() {
return bulletAppState3;
}
} [/java]
[java]
package test;
import com.jme3.bullet.collision.PhysicsCollisionEvent;
import com.jme3.bullet.collision.PhysicsCollisionListener;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.AbstractControl;
import com.jme3.scene.control.Control;
class PhysicsCollisionControl extends AbstractControl implements PhysicsCollisionListener {
private String number;
private TestMultipleBulletPhysicsCollisions myApp = TestMultipleBulletPhysicsCollisions.getApp();
private PhysicsCollisionListener listener = this;
public PhysicsCollisionControl(String number) {
this.number = number;
if (number.equals(“one”)) {
myApp.getBulletAppState1().getPhysicsSpace().addCollisionListener(listener);
} else if (number.equals(“two”)) {
myApp.getBulletAppState2().getPhysicsSpace().addCollisionListener(listener);
} else {
myApp.getBulletAppState3().getPhysicsSpace().addCollisionListener(listener);
}
}
@Override
protected void controlUpdate(float tpf) {
}
@Override
protected void controlRender(RenderManager rm, ViewPort vp) {
}
public Control cloneForSpatial(Spatial spatial) {
throw new UnsupportedOperationException(“Not supported yet.”);
}
public void collision(PhysicsCollisionEvent event) {
System.out.println(number);
System.out.println(event.getNodeA() + " " + event.getNodeB());
}
}
[/java]
http://i.imgur.com/xdcd3.png