我已经实施并添加了一个PhysicsCollisionListener
来注册一个弹丸击中一个玩家。但是当一个射弹击中一名玩家时。触发多个事件。
我在我的simpleInitApp()方法中添加了bulletAppState.getPhysicsSpace().addCollisionListener(collisionListener)
的监听器。我在碰撞后移除了抛射物。
我需要做些什么来为每个射弹只获得一个事件?
这是我的代码:
public void collision(PhysicsCollisionEvent event) {
//nodeA is a projectile
if(event.getNodeA().getName().startsWith("Projectile")) {
//projectile hits player
if(event.getNodeB().getName().startsWith("Player")) {
onHit(event.getNodeA(), event.getNodeB().getParent().getUserData("player");
}
//projectile hits projectile
else if(event.getNodeB().getName().startsWith("Projectile")) {
return;
}
//in any case, remove projectile
projectileNode.detachChild(event.getNodeA());
bulletAppState.getPhysicsSpace().remove(event.getNodeA());
}
//nodeB is a projectile
if(event.getNodeB().getName().startsWith("Projectile")) {
//projectile hits player
if(event.getNodeA().getName().startsWith("Player")) {
onHit(event.getNodeB(), event.getNodeA().getParent().getUserData("player");
}
//in any case, remove projectile
projectileNode.detachChild(event.getNodeB());
bulletAppState.getPhysicsSpace().remove(event.getNodeB());
}
}
答案 0 :(得分:3)
问题是底层的jBullet引擎以固定的帧速率在不同的线程中运行。如果PhysicsSpace
的状态从外部更改,则不会立即识别更改。
引用jME Wiki:
http://hub.jmonkeyengine.org/wiki/doku.php/jme3:advanced:physics_listeners#physics_tick_listener
施加力或检查重叠仅在物理更新周期产生效果,而不是每一帧。如果你在simpleUpdate()循环中的任意位置进行物理交互,调用将以不规则的间隔被删除,因为它们发生在循环之外。
解决方案是从PhysicsTickListener
中删除物理对象,该对象将调用与jBullet的帧速率同步。它也在wiki中有所描述。此实现只会产生一个碰撞事件:
private class ProjectileCollisionControl extends GhostControl implements PhysicsTickListener {
public ProjectileCollisionControl(CollisionShape shape) {
super(shape);
}
public void prePhysicsTick(PhysicsSpace space, float tpf) {}
// Invoked after calculations and after events have been queued
public void physicsTick(PhysicsSpace space, float tpf) {
for(PhysicsCollisionObject o : getOverlappingObjects()) {
Spatial other = (Spatial) o.getUserObject();
// I just hit a player, remove myself
if(other.getName().startsWith("Player"))
{
space.remove(this);
space.removeTickListener(this);
}
}
}
}
射弹现在需要ProjectileCollisionControl
。设置如下:
public void simpleInitApp() {
BulletAppState state = new BulletAppState();
getStateManager().attach(state);
PhysicsSpace space = state.getPhysicsSpace();
space.addCollisionListener(new PhysicsCollisionListener()
{
public void collision(PhysicsCollisionEvent event) {
// Same code but without bulletAppState.getPhysicsSpace().remove()
}
});
Material mat = new Material(getAssetManager(), "Common/MatDefs/Misc/ShowNormals.j3md");
CollisionShape collisionShape = new BoxCollisionShape(new Vector3f(5, 5, 5));
ProjectileCollisionControl ctrlA = new ProjectileCollisionControl(collisionShape);
Box a = new Box(new Vector3f(0.4f, 0, 0), 1, 1, 1);
Geometry boxGeomA = new Geometry("Box A", a);
boxGeomA.setMaterial(mat);
boxGeomA.addControl(ctrlA);
ProjectileCollisionControl ctrlB = new ProjectileCollisionControl(collisionShape);
Box b = new Box(new Vector3f(-0.4f, 0, 0), 1, 1, 1);
Geometry boxGeomB = new Geometry("Box B", b);
boxGeomB.setMaterial(mat);
boxGeomB.addControl(ctrlB);
getRootNode().attachChild(boxGeomA);
getRootNode().attachChild(boxGeomB);
space.add(ctrlA);
space.add(ctrlB);
space.addTickListener(ctrlA);
space.addTickListener(ctrlB);
}