【问题标题】:jMonkeyEngine multiple collision events for single collisionjMonkeyEngine 单个碰撞的多个碰撞事件
【发布时间】:2014-10-28 17:40:04
【问题描述】:

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

【问题讨论】:

    标签: java jmonkeyengine


    【解决方案1】:

    问题在于底层的 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);
    }
    

    【讨论】:

    • 我已将删除例程移至刻度列表器,现在它可以工作了。您使用 GhostControl 的解决方案不起作用,它让我与 Terrain 发生了很多碰撞。不过非常感谢您的详细回答。
    猜你喜欢
    • 2013-10-28
    • 1970-01-01
    • 1970-01-01
    • 2018-07-07
    • 1970-01-01
    • 1970-01-01
    • 2015-05-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多