Java jMonkeyEngine针对单个碰撞的多个碰撞事件

Java jMonkeyEngine针对单个碰撞的多个碰撞事件,java,jmonkeyengine,Java,Jmonkeyengine,我已经实现并添加了一个physiccollisionlistener,以在投射物击中玩家时进行注册。但当一颗炮弹击中一名球员时。触发多个事件。 我使用simpleInitApp()方法中的bulletAppState.getPhysicsSpace().addCollisionListener(collisionListener)添加侦听器。我在碰撞后取出了弹丸 我需要做什么才能为每个射弹只获得一个事件 这是我的密码: public void collision(PhysicsCollision

我已经实现并添加了一个
physiccollisionlistener
,以在投射物击中玩家时进行注册。但当一颗炮弹击中一名球员时。触发多个事件。 我使用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());
        }
    }

问题是底层jBullet引擎以固定的帧速率在不同的线程中运行。如果
physicspace
的状态从外部更改,则不会立即识别更改

引用jME Wiki:


应用力或检查重叠仅在物理更新周期(不是每一帧)生效。如果在simpleUpdate()循环中的任意点进行物理交互,调用将以不规则的间隔被丢弃,因为它们发生在循环之外

解决方案是从
physicticklistener
中删除物理对象,该文件将调用与jBullet的帧速率同步。维基上也有一些描述。此实现将只产生一个冲突事件:

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);
            }
        }
    }
}
射弹现在需要一个
射弹CollisionControl
。设置如下:

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

我已经将删除例程移到了tick listner,现在它可以工作了。你的GhostControl解决方案不起作用,它会让我与地形发生大量碰撞。但是非常感谢你详细的回答。