2014-10-28 2 views
1

Я внедрил и добавил PhysicsCollisionListener для регистрации, когда снаряд попадает в игрока. Но когда снаряд попадает в игрока. запускается несколько событий. Я добавляю свой слушатель с bulletAppState.getPhysicsSpace().addCollisionListener(collisionListener) в свой метод simpleInitApp(). Я удаляю снаряд после столкновения.jMonkeyEngine несколько событий столкновения для одиночного столкновения

Что мне нужно сделать, чтобы получить только одно событие для каждого снаряда?

Вот мой код:

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

ответ

3

Проблема заключается в том, что лежащий в основе jBullet двигатель работает в другом потоке при фиксированной частоте кадров. Если состояние PhysicsSpace изменено снаружи, изменения не сразу распознаются.

Цитирую Jme Wiki:

http://hub.jmonkeyengine.org/wiki/doku.php/jme3:advanced:physics_listeners#physics_tick_listener
Применение силы или проверки наложений действует только право на цикл обновления физики, который не каждый кадр. Если вы выполняете физическое взаимодействие в произвольных точках в цикле simpleUpdate(), вызовы будут отбрасываться с нерегулярными интервалами, потому что они происходят из цикла.

Решение заключается в удалении объекта физики изнутри PhysicsTickListener, который синхронизирует вызов с частотой кадров 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); 
      } 
     } 
    } 
} 

Снаряды Теперь нужно 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); 
} 
+0

Я переместил процедуры удаления в список подписчиков и теперь это работает. Ваше решение с GhostControl не работает, оно дает мне много конфликтов с Terrain. Но большое спасибо за ваш подробный ответ. – kaetzacoatl

Смежные вопросы