Collition is not cleared

Hi guys

i wrote a class for a projectile to shoot on a ball. i don’t want the ball moving if the projectile hits the ball(no applied forces).

This workes sometimes fine, but sometime the ball get an impulse from the projectile. It looks like the collition event is not cleared
after the collition-method. or maybe the collition-method(from rigidbody) of the ball is called first.

event.clean() doesn’t fix the problem.

do you got any idea whats wrong here?

the projectile class looks like this:
[java]
public class PistolBullet {

private final static int DAMAGE = 10;
private Spatial bullet;
private Vector3f direction;
private float BULLET_SPEED = 30f;
private float BULLET_LENGTH = 0.5f;
private Vector3f spaceBox = new Vector3f(0.1f, 0.1f, 0.1f);
private MyCustomControl phys;

public PistolBullet(Player player) {
    float possitionOffset = 10f;
    Vector3f camDirection = LevelManager.getInstance().getCamera().getDirection();
    camDirection.y = 0;
    camDirection = camDirection.normalize();
    direction = camDirection.mult(BULLET_SPEED);

    Box box = new Box(new Vector3f(spaceBox.x / 2, spaceBox.y / 2, spaceBox.z / 2), spaceBox.x, spaceBox.y, spaceBox.z);
    Vector3f position = new Vector3f(0f,0f,0f).add(camDirection.mult(possitionOffset));
    bullet = new Geometry("PistolBullet", box);
    bullet.move(position);
    Material mat1 = MaterialFactory.getInstance().getMaterial(EMaterial.PISTOL_BULLET);
    bullet.setMaterial(mat1);

    BoxCollisionShape boxShape = new BoxCollisionShape(spaceBox);
    phys = new MyCustomControl(boxShape, 1f);
    phys.setSpatial(bullet);
    phys.setCollisionShape(new BoxCollisionShape(spaceBox));
    phys.setCollisionGroup(GlobalConstants.COLLISION_GROUP_WEAPONS);
    phys.setCollideWithGroups(GlobalConstants.COLLISION_GROUP_WEAPONS);

    GameState.getInstance().getBulletAppState().getPhysicsSpace().add(phys);
    GameState.getInstance().getBulletAppState().getPhysicsSpace().addCollisionListener(phys);
    GameState.getInstance().getBulletAppState().getPhysicsSpace().addTickListener(phys);
    bullet.addControl(phys);
}
public class MyCustomControl extends RigidBodyControl implements PhysicsCollisionListener, PhysicsTickListener {

    MyCustomControl me;

    public MyCustomControl(BoxCollisionShape b, float mass) {
        super(b, mass);
        me = this;
    }

    public void collision(PhysicsCollisionEvent event) {
        Object other = null;
        if (event.getObjectA() == this) {
            other = event.getObjectB();
        } else if (event.getObjectB() == this) {
            other = event.getObjectA();
        }

        if(other instanceof RigidBodyControl && ((RigidBodyControl) other).getUserObject() instanceof Ball){                
            ((Ball) ((RigidBodyControl) other).getUserObject()).getPlayer().decHealth(DAMAGE);
        }
        // remove the projectile after hit something
        GameState.getInstance().getApp().enqueue(new Callable() {
            public Object call() throws Exception {
                GameState.getInstance().getBulletAppState().getPhysicsSpace().removeCollisionListener(me);
                GameState.getInstance().getBulletAppState().getPhysicsSpace().remove(me);
                GameState.getInstance().getStateNode().detachChild(bullet);
                return null;
            }
        });
    }

    public void prePhysicsTick(PhysicsSpace space, float tpf) {
        // this is to clear the gravity
        this.clearForces();
        final float finalTpf = tpf;
        GameState.getInstance().getApp().enqueue(new Callable() {
            public Object call() throws Exception {
                phys.setLinearVelocity(direction);
                return this;
            }
        });
    }
    public void physicsTick(PhysicsSpace space, float tpf) {
    }
}

}
[/java]

The Ball Class looks like this:
[java]
public class Ball {

private Spatial ballSpatial;
private RigidBodyControl ballPhysics;
private Player owner;

public Ball(Player p) {
    owner = p;
    Sphere sphere = new Sphere(21, 21, GlobalConstants.BALL_RADIUS, true, false);

    // init Graphics
    ballSpatial = new Geometry("ball", sphere);
    Material mat1 = MaterialFactory.getInstance().getBallMaterial(GameState.getInstance().getAssetManager(), p.getColor());
    ballSpatial.setMaterial(mat1);
    sphere.setTextureMode(Sphere.TextureMode.Projected);
    GameState.getInstance().getStateNode().attachChild(ballSpatial);

    SphereCollisionShape ballShape =
            new SphereCollisionShape(GlobalConstants.BALL_RADIUS);

    // init Physics
    ballPhysics = new RigidBodyControl(ballShape, GlobalConstants.BALL_MASS);
    ballSpatial.addControl(ballPhysics);
    GameState.getInstance().getBulletAppState().getPhysicsSpace().add(ballPhysics);
    ballPhysics.setFriction(GlobalConstants.BALL_FRICTION);
    ballPhysics.setRestitution(GlobalConstants.BALL_BOUNCYNESS);
    ballPhysics.setSleepingThresholds(GlobalConstants.STOP_LINEAR_TRESHOLD, GlobalConstants.STOP_ANGULAR_TRESHOLD);
    ballPhysics.setDamping(GlobalConstants.BALL_LINEARDUMPING, GlobalConstants.BALL_ANGULARDUMPING);
    ballPhysics.setPhysicsLocation(LevelManager.getInstance().getLevel().getStartPoint());
    ballPhysics.setCollisionGroup(GlobalConstants.COLLISION_GROUP_BALLS);
    ballPhysics.setCollideWithGroups(GlobalConstants.COLLISION_GROUP_BALLS);

    p.setBall(this);
}

public Player getPlayer() {
    return owner;
}

}
[/java]

Try having MyCustomControl inherit from a GhostControl instead of a RigidBodyControl. GhostControl is designed to detect collisions without interacting physically with other bodys.

1 Like

Thx for the quick reply.

I already tried that, but with ghostcontroll i got collitions with the level all the time. this problem is described here http://hub.jmonkeyengine.org/forum/topic/ghost-control-always-reporting-collision-with-scene/ and it seems there is no solution with using ghostcontroll.

so i have to try a differen approach.

any other ideas.

the text here https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:advanced:physics_listeners says

Note that after the collision() method ends, the PhysicsCollisionEvent is cleared. You must get all objects and values you need within the collision() method.
but why are there any collitions after the collition-method? is that a bug or habe i done something wrong? maybe there is a race condition or something like that.

Your going to detect a collision when your projectile hits the ball, that’s why the ball moves, regardless if you remove the control when the collision happens.

You can use a sweep test to detect collisions before the RigidBodyControl collides with the ball if the GhostControl doesn’t suite your needs.

But I would think that using a GhostControl on a small projectile, should work fine :s. You can make the shape for the ghost control smaller if needed, and even move it to the front of the projectile

If i use a GhostControl it would collide all the time with my level(CompoundCollisionShape) because the CompoundCollisionShape is seen as a box(with the bounds of the level) while calculating collition detection via ghost controll(if i got that right). but i need the also the collitions with the CompoundCollisionShape so that i can remove the projectile if it hits the walls(of the levels). i think the size of the ghost controll doesn’t matter i that case. if i use a very small ghostcontroll can it happen that the projectile don’t realize a collition?

Tomorrow i’ll try it with a sweep test. maybe it’s possible to combine the sweep test for level ball collition and my approach for level collition.

is there a best practice for sweep test, i think of how far i have to move my projectile before i sweep test? does it depend on the average frame rate or something like that?

I suggest doing a sweep test every physics pre-tick when the bullet is active.

Also you may want to set the mass of the bullet to a very low number, so if it does interact the ball, the force will be very small.

Hey,

i played around with ghostcontroll again and now the collision(damn typos) works very well.
the MyCustomControl looks now like this:

[java]
public class MyCustomControl extends GhostControl implements PhysicsCollisionListener, PhysicsTickListener {

    MyCustomControl me;

    public MyCustomControl(BoxCollisionShape b, float mass) {
        super(b);
        me = this;
    }

    public void collision(PhysicsCollisionEvent event) {
        System.out.println("collition!");
        Object other = null;
        if (event.getObjectA() == this) {
            other = event.getObjectB();
        } else if (event.getObjectB() == this) {
            other = event.getObjectA();
        }
        if(other==null){
            return;
        }
        System.out.println("collition "+other.getClass());
        if(other instanceof RigidBodyControl && ((RigidBodyControl) other).getUserObject() instanceof Ball){                
            ((Ball) ((RigidBodyControl) other).getUserObject()).getPlayer().decHealth(DAMAGE);
            owner.incPoints(DAMAGE);
            System.out.println("Party");
        }
        
        GameState.getInstance().getApp().enqueue(new Callable() {
            public Object call() throws Exception {
                GameState.getInstance().getBulletAppState().getPhysicsSpace().removeCollisionListener(me);
                GameState.getInstance().getBulletAppState().getPhysicsSpace().remove(me);
                GameState.getInstance().getStateNode().detachChild(bullet);
                return null;
            }
        });
    }

    public void prePhysicsTick(PhysicsSpace space, float tpf) {
        //this.clearForces();
        final float finalTpf = tpf;
        GameState.getInstance().getApp().enqueue(new Callable() {
            public Object call() throws Exception {
                bullet.move(direction.mult(finalTpf));
                
                return this;
            }
        });



    }

    public void physicsTick(PhysicsSpace space, float tpf) {
    }
}

[/java]

i don’t know why it didn’t worked in the first place with ghostcontroll.

thank you very much for your help. you guys were very helpfull, perhabs i can use sweep test somewere else.