I found some differences between jbullet and Minie.
When Jamie falls onto the floor, PhysicSpace will generate a PhysicsCollisionEvent between the floor and Jamie at
- jbullet: each tick
- Minie: the start tick
This is the difference in com.jme3.bullet.PhysicSpace
.
in jme3-jbullet, the collisionEvents
will be repopulated by all intersecting entities.
/**
* queue of collision events not yet distributed to listeners
*/
private ArrayDeque<PhysicsCollisionEvent> collisionEvents = new ArrayDeque<>();
public void distributeEvents() {
int cListSize = this.collisionListeners.size();
while(!this.collisionEvents.isEmpty()) {
PhysicsCollisionEvent physicsCollisionEvent = (PhysicsCollisionEvent)this.collisionEvents.pop();
for(int i = 0; i < cListSize; ++i) {
((PhysicsCollisionListener)this.collisionListeners.get(i)).collision(physicsCollisionEvent);
}
this.eventFactory.recycle(physicsCollisionEvent);
}
}
in Minie, contactStartedEvents only have PhysicsCollisionEvent at the first time.
/**
* contact-processed events not yet distributed to listeners
*/
final private Deque<PhysicsCollisionEvent> contactProcessedEvents
= new ArrayDeque<>(20);
/**
* contact-started events not yet distributed to listeners
*/
final private Deque<PhysicsCollisionEvent> contactStartedEvents
= new ArrayDeque<>(20);
public void distributeEvents() {
while (!contactStartedEvents.isEmpty()) {
PhysicsCollisionEvent event = contactStartedEvents.pop();
for (PhysicsCollisionListener listener : contactStartedListeners) {
listener.collision(event);
}
}
while (!contactProcessedEvents.isEmpty()) {
PhysicsCollisionEvent event = contactProcessedEvents.pop();
for (PhysicsCollisionListener listener
: contactProcessedListeners) {
listener.collision(event);
}
}
}
So this is not a Mac OS issue, but rather a difference in the behavior of the same interface (PhysicSpace#addCollisionListener) between Minie and jbullet.
The com.simsilica.demo.bullet.CharInputDriver
class calculate groundContactCount
at every frame.
private EntityRigidBody body;
private int groundContactCount = 0;
// listen to PhysicsCollisionEvent, only triggers at the start event
public void addCollision( EntityPhysicsObject otherBody, PhysicsCollisionEvent event ) {
// ....
if (event.getObjectA() == body || event.getObjectB() == body) {
groundContactCount++;
}
// ....
}
protected void invalidateCollisionData() {
groundContactCount = 0; // <------- this line makes Jamie floating in air.
}
public void update( SimTime time, EntityRigidBody body ) {
// ....
if (groundContactCount > 0) {
// let Jamie walking
} else {
// let Jamie floating
}
// ...
invalidateCollisionData();
}
To fix this issue, I modified BulletSystem a little, use addOngoingCollisionListener()
instead of addCollisionListener()
protected void initialize() {
if( ed == null ) {
ed = getSystem(EntityData.class, true);
}
if( shapes == null ) {
shapes = getSystem(CollisionShapes.class, true);
}
baseThread = Thread.currentThread();
pSpace = new PhysicsSpace(worldMin, worldMax, broadphaseType);
//pSpace.addCollisionListener(collisionDispatcher); // <----- Changed this line
pSpace.addOngoingCollisionListener(collisionDispatcher); // <------ to this line
bodies = new BodyContainer(ed);
ghosts = new GhostContainer(ed);
}
this change add collisionDispatcher
to contactProcessedListeners
in Minie’s contactProcessedListeners
, so CharInputDriver can receive PhysicsCollisionEvent at every tick.
That is how I fixed this issue in the demo.