2014-10-28 2 views
1

발사체가 플레이어를 때릴 때 등록하기 위해 PhysicsCollisionListener을 구현하고 추가했습니다. 그러나 발사체가 플레이어를 때릴 때. 여러 이벤트가 트리거됩니다. 내 SimpleInitApp() 메소드에 bulletAppState.getPhysicsSpace().addCollisionListener(collisionListener)과 함께 리스너를 추가합니다. 충돌 후 발사체를 제거합니다.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 위키를 인용 :

http://hub.jmonkeyengine.org/wiki/doku.php/jme3:advanced:physics_listeners#physics_tick_listener
힘을 적용 또는 중복 검사는 바로 모든 프레임이 아닌 물리학 업데이트주기에 효과가있다. simpleUpdate() 루프의 임의의 지점에서 물리학적인 상호 작용을 수행하면주기가 다르기 때문에 불규칙한 간격으로 호출이 삭제됩니다.

해결책은 호출을 jBullet의 프레임 속도와 동기화하는 PhysicsTickListener 내에서 물리 객체를 제거하는 것입니다. 또한 위키에 다소 묘사되어 있습니다. 이 구현은 하나 개의 충돌 이벤트를 생성합니다 :

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