jMonkeyEngine单次碰撞的多个碰撞事件

时间:2014-10-28 17:40:04

标签: java jmonkeyengine

我已经实施并添加了一个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());
        }
    }

1 个答案:

答案 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);
}