Problem with PhysicsCollisionListiner

Hi, I have problem. I’m making a moba genre game. So it’s 3x3 players per room.
each room has separated physics.

This class is making and collecting rooms:
[java]
public class GameCore extends AbstractAppState {
private ArrayList<GameWorld> worldList;
private int gwID=0;

public GameCore(Model model) {
worldList = new ArrayList<GameWorld>();
Globals.INSTANCE.getApp().getRootNode().attachChild(loader.getNode());
Globals.INSTANCE.getApp().getStateManager().attach(this);
}

public void CreateRoom(final CreateRoomM message, final HostedConnection conn) {
Globals.INSTANCE.getApp().enqueue(new Callable<Void>() {
public Void call() throws Exception {
GameWorld gw = new GameWorld( gwID++, model, loader);
worldList.add(gw);
Globals.INSTANCE.getApp().getStateManager().attach(gw);
return null;
}
});

}
public GameWorld getGameWorldById(int id) {
for (GameWorld gm : worldList) {
if (gm.getId() == id) {
return gm;
}
}
return null;
}
}
[/java]

here i have room class

[java]
private SimpleApplication app;
private BulletAppState bulletAppState;
private int id;
private ParticleController particles;

public GameWorld(int id, Model model, MapLoader loader) {
this.id = id;
bulletAppState = new BulletAppState();
}

public void initialize(AppStateManager stateManager, Application app) {
super.initialize(stateManager, app);
this.app = (SimpleApplication) app;
app.getStateManager().attach(bulletAppState);
particles = new ParticleController(bulletAppState, this);
}
[/java]

here i’m making particles:

[java]
public class ParticleController {

private RigidBodyControl shootPhy;
private BulletAppState bulletAppState;

private GameWorld gw;


public ParticleController(BulletAppState bulletAppState, GameWorld gw) {
    this.gw=gw;
    this.bulletAppState = bulletAppState;
}

public void addParticle(Vector3f coordinate, Quaternion pointTo, String name, float friction, float mass, float size, float acceleration, AssetManager manager, Player   player, int damage, int skillType, int damageType) {

 
    
    Node ballGeo = new Node("shoot");
    ballGeo.setLocalTranslation(coordinate);

    shootPhy = new Particle(manager, new SphereCollisionShape(size*0.1f), mass/100, gw, damage, skillType, damageType);

    ballGeo.addControl(shootPhy);
  
    shootPhy.setFriction(friction);
    shootPhy.setMass(mass/100);
    shootPhy.setCcdSweptSphereRadius(0.001f);
    shootPhy.setCcdMotionThreshold(0.001f);

    Vector3f modelFowardDir = pointTo.mult(Vector3f.UNIT_Y);
    
    shootPhy.setLinearVelocity(modelFowardDir.mult(-acceleration));

    gw.getRootNode().attachChild(ballGeo);
    bulletAppState.getPhysicsSpace().add(shootPhy);
 
}

}

[/java]

and last my particle

[java]

public class Particle extends RigidBodyControl implements PhysicsCollisionListener, PhysicsTickListener {

private float fxTime = 0.5f;
private float maxTime = 4f;
private float curTime = -1.0f;
private float timer;
private int damage;
private int skillType;
private int damageType;
private GameWorld gw;
private Vector3f vector = new Vector3f();
private Vector3f vector2 = new Vector3f();

public Particle(AssetManager manager, CollisionShape shape, float mass, GameWorld gw, int damage, int skillType, int damageType) {
    super(shape, mass);
    this.gw = gw;
    this.damage = damage;
    this.skillType = skillType;
    this.damageType = damageType;
}

@Override
public void setPhysicsSpace(PhysicsSpace space) {
    super.setPhysicsSpace(space);
    if (space != null) {
        space.addCollisionListener(this);
    }
}


@Override
public void collision(PhysicsCollisionEvent event) {
    System.out.println("firing event");     &lt;&lt;-- PROBLEM 
}

@Override
public void physicsTick(PhysicsSpace space, float tpf) {
    space.removeTickListener(this);
}

}
[/java]

when client start a first world, collision is working and event is firing, but when second word is created and added in worldList, first world collision stops working, just in second world it is working and event is firing.

can someone explain this PhysicsCollisionListener behavior and help me to find solution ?

P.S. I hope i have cleaned code enough and it will be easy to read.

no one could help, or need more code ?
I think this problem is because i’m attaching one more ( Globals.INSTANCE.getApp().getStateManager().attach(gw):wink: app state. Whats why collision listener stops listening, but can’t understand why,I need make to listen somehow.

You remove the tick listener on the first tick so obviously it won’t be called anymore from that point on.

in this system particles means a bullet so after it has collide i’m removing it from scene. after i’m adding second app state, in first one collideListener stops working, but it was working before i have added new app state.
I have tested this part what you are saying, I removed all space.removeCollisionListener(this) in class particle and it’s still not working.

I had used parts from JmeTests (TestBrickTower.java)

And it’s very strange because setPhysicsSpace(PhysicsSpace space) is called in first room after created second one, but listener still not listening.

in setPhysicsSpace(PhysicsSpace space):
space is not null, it has some object
and this.isEnabled() gives true

Well theres no code that randomly removes collision listeners from the physics space in the engine so it must be in your code.

1 Like

ok will try to find, what i’m doing wrong. if i’m not gonna succeed I will as for help again.
Thank you normen for replaying :wink:

Ok I made simple app, here is same proble with full code
[java]
package mygame;

import com.jme3.app.SimpleApplication;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.PhysicsSpace;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.renderer.RenderManager;

/**

  • test

  • @author normenhansen
    */
    public class Main extends SimpleApplication {

    private BulletAppState bulletAppState;

    Room room1;
    Room room2;

    public static void main(String[] args) {
    Main app = new Main();
    app.start();
    }

    @Override
    public void simpleInitApp() {
    bulletAppState = new BulletAppState();
    bulletAppState.setThreadingType(BulletAppState.ThreadingType.PARALLEL);
    stateManager.attach(bulletAppState);

     inputManager.addMapping("shoot in room 1", new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
     inputManager.addMapping("shoot in room 2", new MouseButtonTrigger(MouseInput.BUTTON_RIGHT));
     inputManager.addListener(actionListener, "shoot in room 1", "shoot in room 2");
     
     initRooms();
    

    }
    private ActionListener actionListener = new ActionListener() {
    public void onAction(String name, boolean keyPressed, float tpf) {
    if (name.equals(“shoot in room 1”) && !keyPressed) {
    room1.createBullet(“first bullet in room 1”);
    }

          if (name.equals("shoot in room 2") &amp;&amp; !keyPressed) {
             room2.createBullet("second bullet in room 2");
         }
     }
    

    };

    @Override
    public void simpleUpdate(float tpf) {
    //TODO: add update code
    }

    @Override
    public void simpleRender(RenderManager rm) {
    //TODO: add render code
    }

    private PhysicsSpace getPhysicsSpace() {
    return bulletAppState.getPhysicsSpace();
    }

    private void initRooms() {
    room1 = new Room(“first”);
    room2 = new Room(“second”);
    getStateManager().attach(room1);
    getStateManager().attach(room2);
    }

}
[/java]
[java]
package mygame;

import com.jme3.app.Application;
import com.jme3.app.SimpleApplication;
import com.jme3.app.state.AbstractAppState;
import com.jme3.app.state.AppStateManager;
import com.jme3.asset.TextureKey;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.collision.shapes.BoxCollisionShape;
import com.jme3.bullet.collision.shapes.SphereCollisionShape;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.material.Material;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.shape.Box;
import com.jme3.scene.shape.Sphere;
import com.jme3.texture.Texture;

/**
*

  • @author Setas
    */
    public class Room extends AbstractAppState {

    private BulletAppState bulletAppState;
    private String name;
    private SimpleApplication app;
    private Node rootNode;
    private Bullet bullet;
    Material mat;
    Material mat3;

    Room(String name) {
    this.name = name;
    bulletAppState = new BulletAppState();
    ;
    }

    @Override
    public void initialize(AppStateManager stateManager, Application app) {
    super.initialize(stateManager, app);
    this.app = (SimpleApplication) app;
    rootNode = new Node();
    app.getStateManager().attach(bulletAppState);
    this.app.getRootNode().attachChild(rootNode);
    mat = new Material(app.getAssetManager(), “Common/MatDefs/Misc/Unshaded.j3md”);

     initFloor();
    

    }

    public void createBullet(String name) {
    Sphere ballMesh = new Sphere(32, 32, 0.25f, true, false);
    Geometry ballGeo = new Geometry(“cannon ball”, ballMesh);
    bullet = new Bullet(name);
    ballGeo.setMaterial(mat);
    ballGeo.setLocalTranslation(new Vector3f(0, 5, 0));
    ballGeo.addControl(bullet);
    bullet.setFriction(0.1f);
    bullet.setMass(1f);
    bullet.setCcdSweptSphereRadius(0.001f);
    bullet.setCcdMotionThreshold(0.001f);
    rootNode.attachChild(ballGeo);
    bulletAppState.getPhysicsSpace().add(bullet);

    }

    @Override
    public String toString() {
    return “[ room name is - " + name + " ]”;
    }

    public void initFloor() {
    mat3 = new Material(app.getAssetManager(), “Common/MatDefs/Misc/Unshaded.j3md”);
    TextureKey key3 = new TextureKey(“Textures/Terrain/Pond/Pond.jpg”);
    key3.setGenerateMips(true);
    Texture tex3 = app.getAssetManager().loadTexture(key3);
    tex3.setWrap(Texture.WrapMode.Repeat);
    mat3.setTexture(“ColorMap”, tex3);
    Box floorBox = new Box(Vector3f.ZERO, 10f, 0.1f, 5f);
    floorBox.scaleTextureCoordinates(new Vector2f(3, 6));
    Geometry floor = new Geometry(“floor”, floorBox);
    floor.setMaterial(mat3);
    floor.setShadowMode(RenderQueue.ShadowMode.Receive);
    floor.setLocalTranslation(0, -0.1f, 0);
    floor.addControl(new RigidBodyControl(new BoxCollisionShape(new Vector3f(10f, 0.1f, 5f)), 0));
    rootNode.attachChild(floor);
    bulletAppState.getPhysicsSpace().add(floor);
    }
    }
    [/java]
    [java]

package mygame;

import com.jme3.bullet.PhysicsSpace;
import com.jme3.bullet.PhysicsTickListener;
import com.jme3.bullet.collision.PhysicsCollisionEvent;
import com.jme3.bullet.collision.PhysicsCollisionListener;
import com.jme3.bullet.control.RigidBodyControl;

/**
*

  • @author Setas
    */
    public class Bullet extends RigidBodyControl implements PhysicsCollisionListener, PhysicsTickListener {

    public String name;

    Bullet(String name){
    this.name=name;
    }

    @Override
    public void setPhysicsSpace(PhysicsSpace space) {
    super.setPhysicsSpace(space);
    if (space != null) {
    space.addCollisionListener(this);
    }
    System.out.println("---->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>add collisionListiner");
    }

    public void collision(PhysicsCollisionEvent event) {
    System.out.println("bullet colliding - "+name);
    }

    public void prePhysicsTick(PhysicsSpace space, float tpf) {

    }

    public void physicsTick(PhysicsSpace space, float tpf) {

    }

}

[/java]

and i’m removing nothing. event is printing just in second room, first room is printing nothing.
It’s full code. So maybe someone can explain what i’m doing wrong.

Well you create new physics spaces for each room in this example. If they don’t get updated anymore you won’t get any callbacks anymore.

how i can update them ?

P.S. this way I’m creating separated rooms, so each room is not interacting with each other, and it’s easy, you need just select correct world in arraylist (it’s in my game).
Is it good way implement rooms this way ? Of course my server is in headless mode and I don’t use geometries in it, just for physics i’m making shapes,for player entity checking position, rotation and sending to client.

The problem is the multiple physics spaces. If you register with one and the collision happens in the other then there will be no callback fired anyway, no matter if you keep ut attached or not.

damn, so for all rooms i must use same physics space ?

No you don’t have to but collisions only happen within one physics space, collisions in the other one need a separate listener, separate objects etc.

maybe i’m asking too much, but can you give small example with this simple app ?
because i’m not sure what you mean by separate listener and objects. In simple app I’m making separated rooms with their own objects.

Sure, heres how you register one listener for two physics spaces:
[java]BulletAppState appState1 = new BulletAppState();
BulletAppState appState2 = new BulletAppState();

//enable AppStates
getStateManager().attach(appState1);
getStateManager().attach(appState2);

//register listener for space 1
appState1.getPhysicsSpace().addCollisionListener(listener);
//register listener for space 2
appState2.getPhysicsSpace().addCollisionListener(listener);[/java]

thank you normen, it’s helps a lot. Now I need just find solution to identify in which room event has been fired

but if two bullets are fired at same time the same listener cant listen in different rooms or does it ?
I thought that for each bullet you need to use a different listener.
[java]
package mygame;

import com.jme3.app.SimpleApplication;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.renderer.RenderManager;

/**

  • test

  • @author normenhansen
    */
    public class Main extends SimpleApplication {

    Room room1;
    Room room2;
    Bullet lissn = new Bullet();

    public static void main(String[] args) {
    Main app = new Main();
    app.start();
    }

    @Override
    public void simpleInitApp() {
    inputManager.addMapping(“shoot in room 1”, new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
    inputManager.addMapping(“shoot in room 2”, new MouseButtonTrigger(MouseInput.BUTTON_RIGHT));
    inputManager.addListener(actionListener, “shoot in room 1”, “shoot in room 2”);
    initRooms();
    }
    private ActionListener actionListener = new ActionListener() {
    public void onAction(String name, boolean keyPressed, float tpf) {
    if (name.equals(“shoot in room 1”) && !keyPressed) {
    room1.createBullet(“first bullet in room 1”);
    }

         if (name.equals("shoot in room 2") &amp;&amp; !keyPressed) {                
             room2.createBullet("second bullet in room 2");
         }
     }
    

    };

    @Override
    public void simpleUpdate(float tpf) {
    }

    @Override
    public void simpleRender(RenderManager rm) {
    //TODO: add render code
    }

    private void initRooms() {

     room1 = new Room("first", lissn);
     room2 = new Room("second", lissn);
     getStateManager().attach(room1);
     getStateManager().attach(room2);
    

    }
    }
    [/java]
    [java]
    /*

  • To change this template, choose Tools | Templates

  • and open the template in the editor.
    */
    package mygame;

import com.jme3.app.Application;
import com.jme3.app.SimpleApplication;
import com.jme3.app.state.AbstractAppState;
import com.jme3.app.state.AppStateManager;
import com.jme3.asset.TextureKey;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.PhysicsSpace;
import com.jme3.bullet.collision.shapes.BoxCollisionShape;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.material.Material;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.shape.Box;
import com.jme3.scene.shape.Sphere;
import com.jme3.texture.Texture;

/**
*

  • @author Setas
    */
    public class Room extends AbstractAppState {

    private BulletAppState bulletAppState;
    private String name;
    private SimpleApplication app;
    private Node rootNode;
    Material mat;
    Material mat3;
    Bullet lisn;

    Room(String name, Bullet lisn) {
    this.name = name;
    bulletAppState = new BulletAppState();
    this.lisn = lisn;
    }
    Room(String name) {
    this.name = name;
    bulletAppState = new BulletAppState();
    }

    @Override
    public void initialize(AppStateManager stateManager, Application app) {
    super.initialize(stateManager, app);
    this.app = (SimpleApplication) app;
    rootNode = new Node();
    app.getStateManager().attach(bulletAppState);
    this.app.getRootNode().attachChild(rootNode);
    mat = new Material(app.getAssetManager(), “Common/MatDefs/Misc/Unshaded.j3md”);
    bulletAppState.getPhysicsSpace().addCollisionListener(lisn);

     initFloor();
    

    }

    public void createBullet(String name) {
    Sphere ballMesh = new Sphere(32, 32, 0.25f, true, false);
    Geometry ballGeo = new Geometry(name + “[created]”, ballMesh);
    ballGeo.setMaterial(mat);
    ballGeo.setLocalTranslation(new Vector3f(0, 5, 0));
    lisn.setRoom(this);
    ballGeo.addControl(lisn);
    rootNode.attachChild(ballGeo);
    bulletAppState.getPhysicsSpace().add(lisn);

    }

    @Override
    public String toString() {
    return “[ room name is - " + name + " ]”;
    }

    public void initFloor() {
    mat3 = new Material(app.getAssetManager(), “Common/MatDefs/Misc/Unshaded.j3md”);
    TextureKey key3 = new TextureKey(“Textures/Terrain/Pond/Pond.jpg”);
    key3.setGenerateMips(true);
    Texture tex3 = app.getAssetManager().loadTexture(key3);
    tex3.setWrap(Texture.WrapMode.Repeat);
    mat3.setTexture(“ColorMap”, tex3);
    Box floorBox = new Box(Vector3f.ZERO, 10f, 0.1f, 5f);
    floorBox.scaleTextureCoordinates(new Vector2f(3, 6));
    Geometry floor = new Geometry(“floor”, floorBox);
    floor.setMaterial(mat3);
    floor.setShadowMode(RenderQueue.ShadowMode.Receive);
    floor.setLocalTranslation(0, -0.1f, 0);
    floor.addControl(new RigidBodyControl(new BoxCollisionShape(new Vector3f(10f, 0.1f, 5f)), 0));
    rootNode.attachChild(floor);
    bulletAppState.getPhysicsSpace().add(floor);
    }

    public BulletAppState getBulletAppState() {
    return bulletAppState;
    }

    public PhysicsSpace getPhysicSpace() {
    return bulletAppState.getPhysicsSpace();
    }

    public String getName() {
    return name;
    }

}
[/java] [java]
/*

  • To change this template, choose Tools | Templates
  • and open the template in the editor.
    */
    package mygame;

import com.jme3.bullet.collision.PhysicsCollisionEvent;
import com.jme3.bullet.collision.PhysicsCollisionListener;
import com.jme3.bullet.collision.shapes.CollisionShape;
import com.jme3.bullet.control.RigidBodyControl;

/**
*

  • @author Setas
    */
    public class Bullet extends RigidBodyControl implements PhysicsCollisionListener{
    private Room room;

    public Bullet(CollisionShape shape, float mass) {
    super(shape, mass);
    }
    Bullet(){}

    public void collision(PhysicsCollisionEvent event) {
    System.out.println(room.getName()+" - bullet colliding - " + event.getNodeA().getName());
    System.out.println(room.getName()+" - bullet colliding - " + event.getNodeB().getName());
    space.remove(this);
    spatial.removeFromParent();
    }
    void setRoom(Room aThis) {
    room=aThis;
    }

}

[/java]

and if two bullets is fired on same time i’m getting
[java]
Mar 30, 2014 11:37:17 PM com.jme3.app.Application handleError
SEVERE: Uncaught exception thrown in Thread[LWJGL Renderer Thread,5,main]
java.lang.NullPointerException
at com.bulletphysics.collision.broadphase.Dbvt.removeleaf(Dbvt.java:675)
at com.bulletphysics.collision.broadphase.Dbvt.update(Dbvt.java:140)
at com.bulletphysics.collision.broadphase.Dbvt.update(Dbvt.java:163)
at com.bulletphysics.collision.broadphase.DbvtBroadphase.setAabb(DbvtBroadphase.java:217)
at com.bulletphysics.collision.dispatch.CollisionWorld.updateSingleAabb(CollisionWorld.java:222)
at com.bulletphysics.collision.dispatch.CollisionWorld.updateAabbs(CollisionWorld.java:247)
at com.bulletphysics.collision.dispatch.CollisionWorld.performDiscreteCollisionDetection(CollisionWorld.java:135)
at com.bulletphysics.dynamics.DiscreteDynamicsWorld.internalSingleStepSimulation(DiscreteDynamicsWorld.java:378)
at com.bulletphysics.dynamics.DiscreteDynamicsWorld.stepSimulation(DiscreteDynamicsWorld.java:339)
at com.jme3.bullet.PhysicsSpace.update(PhysicsSpace.java:330)
at com.jme3.bullet.PhysicsSpace.update(PhysicsSpace.java:317)
at com.jme3.bullet.BulletAppState.render(BulletAppState.java:257)
at com.jme3.app.state.AppStateManager.render(AppStateManager.java:300)
at com.jme3.app.SimpleApplication.update(SimpleApplication.java:251)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.runLoop(LwjglAbstractDisplay.java:151)
at com.jme3.system.lwjgl.LwjglDisplay.runLoop(LwjglDisplay.java:185)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:228)
at java.lang.Thread.run(Thread.java:744)

AL lib: (EE) alc_cleanup: 1 device not closed

Exception: java.lang.NullPointerException thrown from the UncaughtExceptionHandler in thread “LWJGL Renderer Thread”
[/java]

maybe i’m implementing your solution not good way ?

and if one bullet is fired and i fired one more before first one collided, it losses physics and listener is overwritten. so geometry stops falling and stuck in middle of air.

Maybe because you keep assigning that one control and don’t make new physics controls.

yes you right I figured out now.
to this control i can’t attach firing bullet room. somehow i need identify a room. One way it would be set in bullet control name a room name.
also i can get userData from Geometry.
But maybe it’s better way how i can identify room ?

and how i can remove bullet from room after colliding ? in listener space and spatial are null.
P. S. sorry for taking your time, but only you is helping me,I really appreciate it. Thank you Normen.