# JME3 - PhysicsCollisionListener



## Supernatural (19. Apr 2011)

hey leute,
ich hab mir ein kleines jme3 programm geschrieben in dem man mit ego-perspektive rumlaufen kann und kannonenkugeln abfeuern kann. ich weiß das ist nichts großes, es dient ja nur zur übung^^
jetzt hab ich vor die farbe der kannonenkugel zu ändern, wenn die die scene trifft, aber ich habe keinen plan wie ich das anstellen soll.

dies ist mein programm:

```
package mygame;

import com.jme3.app.SimpleApplication;
import com.jme3.asset.TextureKey;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
import com.jme3.bullet.collision.shapes.CollisionShape;
import com.jme3.bullet.control.CharacterControl;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.bullet.util.CollisionShapeFactory;
import com.jme3.collision.CollisionResult;
import com.jme3.collision.CollisionResults;
import com.jme3.font.BitmapText;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.light.AmbientLight;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Ray;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Box;
import com.jme3.scene.shape.Sphere;
import com.jme3.scene.shape.Sphere.TextureMode;
import com.jme3.system.AppSettings;
import com.jme3.texture.Texture;


public class Main extends SimpleApplication {
    
  BulletAppState bulletAppState;
  CharacterControl player;
  Vector3f walkDirection = new Vector3f();
  boolean left = false, right = false, up = false, down = false;
  Node shootables;
  Geometry mark;
  // materials vorbereiten
  Material wall_mat;
  Material stone_mat;
  // dimensionen für ziegel und mauer
  static final float brickLength = 0.48f;
  static final float brickWidth  = 0.24f;
  static final float brickHeight = 0.12f;
  
  public static void main(String[] args) {
      
      // eigenes dialogbild und titel einfügen
      AppSettings settings = new AppSettings(true);
      settings.setSettingsDialogImage("/Interface/Logo/bild.png");
      settings.setTitle("My Game");
      
      Main app = new Main();
      app.setSettings(settings);
      app.start();
  }

  @Override
  public void simpleInitApp() {

    // physik einrichten
    bulletAppState = new BulletAppState();
    stateManager.attach(bulletAppState);
    
    // flyby camera einrichten
    viewPort.setBackgroundColor(new ColorRGBA(0.7f,0.8f,1f,1f));
    flyCam.setMoveSpeed(100);
    
    // die scene laden
    Spatial sceneModel = assetManager.loadModel("Scenes/town/main.j3o");
    sceneModel.setLocalScale(2f);
    sceneModel.setName("Scene");
    // collision für die scene einrichten
    CollisionShape sceneShape =
      CollisionShapeFactory.createMeshShape((Node) sceneModel);
    RigidBodyControl landscape = new RigidBodyControl(sceneShape, 0);
    sceneModel.addControl(landscape);
    landscape.addCollideWithGroup(02);
    
    // collision für den spieler einrichten
    CapsuleCollisionShape capsuleShape = new CapsuleCollisionShape(1.5f, 6f, 1);
    player = new CharacterControl(capsuleShape, 0.05f);
    player.setJumpSpeed(20);
    player.setFallSpeed(30);
    player.setGravity(30);
    player.setPhysicsLocation(new Vector3f(0, 10, 15));
    
    // scene und spieler dem rootNode und physics space hinzufügen
    rootNode.attachChild(sceneModel);
    bulletAppState.getPhysicsSpace().add(landscape);
    bulletAppState.getPhysicsSpace().add(player);
    
    
    //vier boxen der scene hinzufügen
    shootables = new Node("Shootables");
    rootNode.attachChild(shootables);
    shootables.attachChild(makeCube("a Dragon",    -2f, 4f, -19f));
    shootables.attachChild(makeCube("a tin can",    1f, 6f, -20f));
    shootables.attachChild(makeCube("the Sheriff",  0f, 2f, -22f));
    shootables.attachChild(makeCube("the Deputy",   1f, 8f, -24f));
    shootables.attachChild(sceneModel);
    
    
    initCrossHairs(); // ein "+" in der bildschirmmitte
    initMark();       // roter punkt zum markieren der "auswahl"
    setUpKeys();      // tasten einrichten
    setUpLight();     // licht
    
    initMaterials();
    initWall();
  }

  private void setUpLight() {
        
        // licht einrichten
        AmbientLight al = new AmbientLight();
        al.setColor(ColorRGBA.White.mult(1.3f));
        rootNode.addLight(al);

        DirectionalLight dl = new DirectionalLight();
        dl.setColor(ColorRGBA.White); 
        dl.setDirection(new Vector3f(2.8f, -2.8f, -2.8f).normalizeLocal());
        rootNode.addLight(dl);
    }

  private void setUpKeys() {
      
    // tasten einrichten
    inputManager.addMapping("Lefts",  new KeyTrigger(KeyInput.KEY_A));
    inputManager.addMapping("Rights", new KeyTrigger(KeyInput.KEY_D));
    inputManager.addMapping("Ups",    new KeyTrigger(KeyInput.KEY_W));
    inputManager.addMapping("Downs",  new KeyTrigger(KeyInput.KEY_S));
    inputManager.addMapping("Jumps",  new KeyTrigger(KeyInput.KEY_SPACE));
    inputManager.addListener(actionListener, "Lefts");
    inputManager.addListener(actionListener, "Rights");
    inputManager.addListener(actionListener, "Ups");
    inputManager.addListener(actionListener, "Downs");
    inputManager.addListener(actionListener, "Jumps");
    
    //"Select" aktion einrichten
    inputManager.addMapping("Select",  new KeyTrigger(KeyInput.KEY_E));
    inputManager.addListener(actionListener, "Select");
    
    //"Shoot" aktion einrichten
    inputManager.addMapping("Shoot",  new MouseButtonTrigger(0)); // left-button click
    inputManager.addListener(actionListener, "Shoot");
  }
  
  private ActionListener actionListener = new ActionListener() {
      @Override
      public void onAction(String name, boolean keyPressed, float tpf) {
          //aktionen für die tasten einrichten
          if (name.equals("Lefts")) {
          left = keyPressed;
          } else if (name.equals("Rights")) {
          right = keyPressed;
          } else if (name.equals("Ups")) {
          up = keyPressed;
          } else if (name.equals("Downs")) {
          down = keyPressed;
          } else if (name.equals("Jumps")) {
          player.jump();
          }
          
          if (name.equals("Shoot") && !keyPressed) {
              makeCannonBall();
          }
          
          //"Select" aktion definieren
          if (name.equals("Select") && !keyPressed) {    
              CollisionResults results = new CollisionResults();
              Ray ray = new Ray(cam.getLocation(), cam.getDirection());
              shootables.collideWith(ray, results);
              System.out.println("----- Collisions? " + results.size() + "-----");
              for (int i = 0; i < results.size(); i++) {
              float dist = results.getCollision(i).getDistance();
              Vector3f pt = results.getCollision(i).getContactPoint();
              String hit = results.getCollision(i).getGeometry().getName();
              System.out.println("* Collision #" + i);
              System.out.println("  You shot " + hit + " at " + pt + ", " + dist + " wu away.");
              }
              if (results.size() > 0){
              CollisionResult closest = results.getClosestCollision();
              mark.setLocalTranslation(closest.getContactPoint());
              rootNode.attachChild(mark);           
              } else {
              rootNode.detachChild(mark);
              }
          }
      }
  };

  protected Geometry makeCube(String name, float x, float y, float z) {
    // eine box als ziel für "select aktion" einrichten
    Box box = new Box(new Vector3f(x, y, z), 1, 1, 1);
    Geometry cube = new Geometry(name, box);
    Material mat1 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
    mat1.setColor("Color", ColorRGBA.randomColor());
    cube.setMaterial(mat1);
    return cube;
  }
  
  public void initMaterials() {
    wall_mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
    TextureKey key = new TextureKey("Textures/Brick/Brick.jpg");
    key.setGenerateMips(true);
    Texture tex = assetManager.loadTexture(key);
    wall_mat.setTexture("ColorMap", tex);
 
    stone_mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
    TextureKey key2 = new TextureKey("Textures/Rock/Rock.jpg");
    key2.setGenerateMips(true);
    Texture tex2 = assetManager.loadTexture(key2);
    stone_mat.setTexture("ColorMap", tex2);
  }
  
  //einen physikalischen zigelstein erstellen
  public void makeBrick(Vector3f loc) {
    Box box = new Box(Vector3f.ZERO, brickLength, brickHeight, brickWidth);
    box.scaleTextureCoordinates(new Vector2f(1f, .5f));
    Geometry brick_geo = new Geometry("brick", box);
    brick_geo.setMaterial(wall_mat);
    rootNode.attachChild(brick_geo);
    brick_geo.setLocalTranslation(loc);
    RigidBodyControl brick_phy = new RigidBodyControl(2f);
    brick_phy.addCollideWithGroup(02);
    brick_geo.addControl(brick_phy);
    bulletAppState.getPhysicsSpace().add(brick_phy);
  }
  
  //wand aus ziegelsteinen erstellen
  public void initWall() {
    float startpt = brickLength / 4;
    float height = 0;
    for (int j = 0; j < 15; j++) {
      for (int i = 0; i < 4; i++) {
        Vector3f vt =
         new Vector3f(i * brickLength * 2 + startpt, brickHeight + height, 0);
        makeBrick(vt);
      }
      startpt = -startpt;
      height += 2 * brickHeight;
    }
  }
  
  // physikalische kannonenkugel erstellen
  public void makeCannonBall() {  
    Sphere sphere = new Sphere(32, 32, 0.4f, true, false);
    sphere.setTextureMode(TextureMode.Projected);
    Geometry ball_geo = new Geometry("cannon ball", sphere);
    ball_geo.setMaterial(stone_mat);
    rootNode.attachChild(ball_geo);
    ball_geo.setLocalTranslation(cam.getLocation());
    RigidBodyControl ball_phy = new RigidBodyControl(1f);   
    ball_phy.setCollisionGroup(02);
    ball_phy.addCollideWithGroup(02);
    ball_phy.removeCollideWithGroup(01);
    ball_geo.addControl(ball_phy);
    bulletAppState.getPhysicsSpace().add(ball_phy);
    ball_phy.setGravity(new Vector3f(0,0,0));
    ball_phy.setLinearVelocity(cam.getDirection().mult(50));
  }
  
  //roten punkt erstellen zum markieren der auswahl ("select" aktion)
  protected void initMark() {
    Sphere sphere = new Sphere(30, 30, 0.2f);
    mark = new Geometry("BOOM!", sphere);
    Material mark_mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
    mark_mat.setColor("Color", ColorRGBA.Red);
    mark.setMaterial(mark_mat);
  }
  
  //fadenkreuz
  protected void initCrossHairs() {
    guiNode.detachAllChildren();
    guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
    BitmapText ch = new BitmapText(guiFont, false);
    ch.setSize(guiFont.getCharSet().getRenderedSize() * 2);
    ch.setText("+"); // crosshairs
    ch.setLocalTranslation( // center
      settings.getWidth()/2 - guiFont.getCharSet().getRenderedSize()/3*2,
      settings.getHeight()/2 + ch.getLineHeight()/2, 0);
      guiNode.attachChild(ch);
  }
  
  @Override
  public void simpleUpdate(float tpf) {
   // laufen-aktion 
    Vector3f camDir = cam.getDirection().clone().multLocal(0.6f);
    Vector3f camLeft = cam.getLeft().clone().multLocal(0.4f);
    walkDirection.set(0, 0, 0);
    if (left)  { walkDirection.addLocal(camLeft); }
    if (right) { walkDirection.addLocal(camLeft.negate()); }
    if (up)    { walkDirection.addLocal(camDir); }
    if (down)  { walkDirection.addLocal(camDir.negate()); }
    player.setWalkDirection(walkDirection);
    cam.setLocation(player.getPhysicsLocation());
  }
}
```

ich hatte mich etwas schlau gemacht und es heißt ich muss PhysicsCollisionListener implementieren. was ich damit dann mache weiß ich aber nicht 

implementieren:

```
public class Main extends SimpleApplication implements PhysicsCollisionListener{...}
```
die methode:

```
public void collision(PhysicsCollisionEvent event) {
            if ("Scene".equals(event.getNodeA().getName()) || "Scene".equals(event.getNodeB().getName())) {
                if ("cannon ball".equals(event.getNodeA().getName()) || "cannon ball".equals(event.getNodeB().getName())) {
                   System.out.println("HIT!");
                }
            }
        }
```
so hab ich es dann gemacht. ich bekomme aber einfach keine nachricht wenn ich mit der kannonenkugel etwas treffe.
hat einer von euch vielleicht eine ahnung was ich in meinem code noch einfügen/ändern muss, damit ich festhalten kann wann die kannonenkugel kollidiert?
(hoffe das ist verständlich xD)


----------



## Empire Phoenix (21. Apr 2011)

Hm keine ahnung frag mal norman im jme forum der hat das physic system gebaut (kann auch Deutsch), aber haste den Listener auch irgetwie im bullet regestriert?


----------



## pinguinmann (6. Mai 2011)

Schau mal hier..vllt. hilfts.

GUI Programming


----------

