Object Collision Issues?

I have a game where the level is generated out of block objects, each block has it’s own health (3hp at the moment), and when shot will lose 1 health. And when health is <= 0, then the block will be ‘destroyed’. Or at least that is what’s supposed to happen. Instead upon hitting one block with one bullet, all the blocks on screen end up getting destroyed. I’m not sure if the issue lies in the collision, or the creation of the blocks themselves.
I have the code for creating the blocks:

[java]public lvlBlock(AssetManager manage, float x, float y, float z)
{
this.x = x;
this.y = y;
this.z = z;
blockNd = new Node();
blk_phy = new RigidBodyControl();
bulletAppState = new BulletAppState();
manager = manage;
initMaterials();
initBlock();
}

private void initMaterials()
{   
    blk_mat = new Material(manager, "Common/MatDefs/Misc/Unshaded.j3md");
    blk_mat.setColor("Color", ColorRGBA.Blue);
}

private void initBlock()
{
    block = new Box(0.5f, 0.5f, 0.5f);
    block.scaleTextureCoordinates(new Vector2f(1f, 1f)); 
    //block = new Box(.5f, .5f, .5f);
    geom = new Geometry("Box", block);
    geom.setLocalTranslation(x, y, z);
    blk_phy = new RigidBodyControl(0.0f);
    blk_phy.setCollideWithGroups(PhysicsCollisionObject.COLLISION_GROUP_03);
    geom.addControl(blk_phy);       

    Material mat = new Material(manager, "Common/MatDefs/Misc/Unshaded.j3md");
    mat.setColor("Color", ColorRGBA.Blue);
    geom.setMaterial(mat);
    
    
    blockNd.attachChild(geom);
    blockNd.setName("lvlBlk");
    Main.bulletAppState.getPhysicsSpace().add(blk_phy);
    
    Main.bulletAppState.getPhysicsSpace().addCollisionListener(this);
}[/java]

And it’s collision:

[java]@Override
public void collision(PhysicsCollisionEvent event)
{

    if(event.getNodeA().getName().equals("Bullet"))
    {
        System.out.println("Hit with bullet, healt = " + Health);
        Health = Health - 1;
    }
    else if(event.getNodeB().getName().equals("Bullet"))
    {
        System.out.println("Hit with bullet, healt = " + Health);
        Health = Health - 1;
    }

    if(this.Health &lt;= 0)
    {
        this.destroyBlock();
    }
} [/java]

And then the block’s destroyBlock() method:

[java]private void destroyBlock()
{
System.out.println("Destroying block: " + this);
Main.bulletAppState.getPhysicsSpace().remove(blk_phy);
blockNd.removeFromParent();
}[/java]

For some reason once a bullet object hits a block, all the block’s Health variables begin to decrement continuously, even after the bullet has been removed from the game. The bullet object’s removal method is the same as the destroyBlock() method, it’s collision() method is also the same format, only it just calls destroyBullet() when it collides with a block.

Any help/advice would be appreciated.

Well, you register every block as a collision listener, so every block gets notified when some block gets hit by a bullet and counts down its health. Inside your collision handler, you not only have to check whether one of the collision objects is the bullet, you also have to check whether the other collision object is the current block.

Also, I think your collision handler will be called for every contact point in a collision, so it might get called several times for what looks like one single collision if there are multiple contact points.

In case you intend to do a “block world” type of game, this isn’t really the ideal way of approaching that topic. A block world is (not very intuitively) not made out of blocks. (check the forum for hints on the topic) Just sayin’ though, from your description its not clear what you want to do. Just wanted you to avoid running into a wall with this approach in case you do want to create a “block world”.

@christophtraut said: Well, you register every block as a collision listener, so every block gets notified when some block gets hit by a bullet and counts down its health. Inside your collision handler, you not only have to check whether one of the collision objects is the bullet, you also have to check whether the other collision object is the current block.

Thanks, I didn’t even think about that! I added [java]event.getNodeB().getParent().equals(this.getBlock()[/java]
and it works, for the most part, the only problem is the block at (0,0,0) (which is the one the player spawns on) is getting destroyed the first time I shoot a bullet, no matter where I’m standing.

@normen said: In case you intend to do a "block world" type of game, this isn't really the ideal way of approaching that topic. A block world is (not very intuitively) not made out of blocks. (check the forum for hints on the topic) Just sayin' though, from your description its not clear what you want to do. Just wanted you to avoid running into a wall with this approach in case you do want to create a "block world".

Sorry, I’m not making a Minecraft-style world, it’s just a path that’s 1 block wide and a max of 10 blocks high (usually spawns with less) that gets randomly generated as the player traverses it. Because of that, and the limited variety of blocks I’m using, I figured this was the simplest way to do it.

Well apparently using:

[java]rootNode.attachChild(new Bullet(…).getBullet());[/java]

instead of:
[java]
Bullet bullet = new Bullet(assetManager, target, origin, mouse);
rootNode.attachChild(bullet.getBullet());[/java]

Was causing the block at (0,0,0) to be destroyed whenever I fired the first bullet in the game. I’m not entirely sure why though, if someone could explain that one to me.

Also, any suggestions/advice/links for getting an object to detect a collision with another object only once?

@MKthot said: Well apparently using:

[java]rootNode.attachChild(new Bullet(…).getBullet());[/java]

instead of:
[java]
Bullet bullet = new Bullet(assetManager, target, origin, mouse);
rootNode.attachChild(bullet.getBullet());[/java]

Was causing the block at (0,0,0) to be destroyed whenever I fired the first bullet in the game. I’m not entirely sure why though, if someone could explain that one to me.


Not sure whats happening here without seeing the rest of the code. But this change shouldn’t really make a difference. I mean, this code doesn’t have anything to do with physics as far as I can tell.

If the block at the origin always gets hit by a new bullet, then maybe you don’t set your bullet’s position correctly when you create it. Try to enable the physics debug view, maybe you can see what is happening. It is also always helpful to step through your code with a debugger to check your assumptions: Try setting a breakpoint in your collision handler and check the positions of your collision pair and the contact points.

Also, any suggestions/advice/links for getting an object to detect a collision with another object only once?
What I probably would do, is to have a single, central collision handler appstate, which is the only registered collision handler. When it detects a collision between a block and a bullet, it adds the block to a set of colliding blocks (Java's Set collection can be helpful here). In its update() call, it notifies all the blocks in its set about a collision and then clears the set. This separates your collision handling code from your blocks, which don't really need to know any of the details about how collisions are handled. It also might be more efficient, since you don't call a huge number of collision handlers, that do basically the same checks over and over again, but just one handler that checks the collision once.

Okay, so I have my Bullet object’s code:

[java] Sphere b = new Sphere(30, 30, 0.5f);

    Geometry bullet = new Geometry("Bullet", b);
    
    bullet.setMaterial(blt_mat);
    bullet.scale(0.2f);
    bullet.updateGeometricState();
    
    
    BoundingBox box = (BoundingBox) bullet.getWorldBound();
    final Vector3f extent = box.getExtent(null);
    BoxCollisionShape boxShape = new BoxCollisionShape(extent);
    
    gBullet = new GhostControl(boxShape);
    gBullet.setCollisionGroup(PhysicsCollisionObject.COLLISION_GROUP_03);
    gBullet.setCollideWithGroups(PhysicsCollisionObject.COLLISION_GROUP_03);   
    
    bullet.addControl(gBullet);
    if(mode.equals("blaster"))
    {
        bullet.setName("Bullet");
    }
    else
    {
        bullet.setName("Bolt");
    }

    System.out.println("Makeing bullet at: " + bullet.getWorldTranslation() + " and: " + bullet.getLocalTranslation());
    bullet.addControl(new bltControl(manager, mode, target, origin, mouse));

    
    bNode.attachChild(bullet);
    bNode.setLocalTranslation(origin.x, origin.y + .5f, 0.0f);

    Main.bulletAppState.getPhysicsSpace().add(gBullet);
    Main.bulletAppState.getPhysicsSpace().addCollisionListener(this);[/java]

And my bullet’s collision method:

[java] @Override
public void collision(PhysicsCollisionEvent event)
{
System.out.println(event.getNodeA().getParent() + ", " + event.getNodeB());
//System.out.println(event.getNodeA().getParent().getName().equals(“lvlBlk”) + ", " + event.getNodeB().getParent().equals(this.getBullet()));
if(event.getNodeA().getName().equals(“lvlBlk”) && event.getNodeB().getParent().equals(this.getBullet()))
{
System.out.println(“Bullet hit block.”);
destroyBullet();
mkBlk((int) bNode.getWorldTranslation().x, (int) bNode.getWorldTranslation().y);
}
else if(event.getNodeB().getName().equals(“lvlBlk”) && event.getNodeA().getParent().equals(this.getBullet()))
{
System.out.println(“Bullet hit block.”);
destroyBullet();
mkBlk((int) bNode.getWorldTranslation().x, (int) bNode.getWorldTranslation().y);
}
}[/java]

I’m posting this of two reasons:
1.) To see if anyone can tell why using [java]rootNode.attachChild(new Bullet(…).getBullet());[/java] is having the effects mentioned above, while using:
[java]Bullet bullet = new Bullet(…);
rootNode.attachChild(bullet.getBullet());[/java]
works fine.

2.) The S.O.P line in the bullet’s collision method is coming back with

lvlBlk (Node), Player (player)
, even after I set the bullet to collide with COLLISION_GROUP_03. when I set the block object to collide with COLLISION_GROUP_03, then the player will fall through the stage, unless I set the boxes to collide with COLLISION_GROUP_01 as well. Why doesn’t this work the same for the bullet object? Am I missing a step? Or do collision groups work differently with ghost controls and rigid bodies? (The code for setting the block’s collision groups is literally a copy/paste of the bullet’s code with name changes for the block’s rigid body control)

@MKthot said: I'm posting this of two reasons: 1.) To see if anyone can tell why using [java]rootNode.attachChild(new Bullet(...).getBullet());[/java] is having the effects mentioned above, while using: [java]Bullet bullet = new Bullet(...); rootNode.attachChild(bullet.getBullet());[/java] works fine.

Those are identical. You are mistaken if you think that is the cause of some difference. Unless in the latter case you are then doing something else with bullet… but I still stand by the fact that those are functionally equivalent.

It’s trivial to test:
[java]
boolean test = true;
if( test ) {
rootNode.attachChild(new Bullet(…).getBullet());
} else {
Bullet bullet = new Bullet(…);
rootNode.attachChild(bullet.getBullet());
}
[/java]

Then try it once with test = true and once with test = false. The curly braces will limit the scope of “bullet” which can be the only possible thing causing differences between the two blocks.

Also note:
Main.bulletAppState.getPhysicsSpace().addCollisionListener(this);
…the way you have this setup means that EVERY listener is called for EVERY collision. It’s not really the way collision listeners are supposed to be used. Register just one for all of the bullets. Then change its logic to operate on the bullet instead of unnecessary encapsulation.

@MKthot said: 2.) The S.O.P line in the bullet's collision method is coming back with , even after I set the bullet to collide with COLLISION_GROUP_03. when I set the block object to collide with COLLISION_GROUP_03, then the player will fall through the stage, unless I set the boxes to collide with COLLISION_GROUP_01 as well.
Correct me if I'm wrong, but I think your main point of confusion is that you assume that Bullet somehow knows about your java objects and decides which collision handlers to call based on that knowledge. But in fact, all it knows about are the objects in the physics simulation and the collision handlers you registered. It doesn't know anything about how those collision handlers relate to the objects in the simulation. So whenever a collision occurs, it will faithfully call every collision handler to notify it of this collision. What you are seeing is expected behaviour. You set the player and the blocks in your world to collide, so they can collide and all collision handlers will be notified of this, even your bullet. Changing the collision group of the bullet will not change this fact.
@pspeed said: Those are identical. You are mistaken if you think that is the cause of some difference. Unless in the latter case you are then doing something else with bullet... but I still stand by the fact that those are functionally equivalent.

I’m not trying to argue about it, but the fact is, when I switched from:
[java]rootNode.attachChild(new Bullet(…).getBullet());[/java]
to:
[java] Bullet bullet = new Bullet(…);
rootNode.attachChild(bullet.getBullet());[/java]
The problem stopped occurring, and when I switched back, the problem persisted until I reverted back again. I did this several times with the same results, each time the only lines of code modified were the lines above. Hence my reasoning that they are the cause. I will admit, however, that it may simply have been a glitch with Windows, jMonkey, or something else, as I have been unable to even recreate the problem since reading your post.

As for the collisions, I’m afraid I’m at a loss, I understand what I did wrong, but I don’t have a clue how to fix it. I’ve gone through the tutorials, but they don’t really cover what I’m trying to do. And I’ve read the help docs about advanced physics and such, but without actually seeing a working example of how it’s supposed to all go together, I don’t even know where to begin. I’ve tried doing research online and in the forums, but I haven’t found anything relevant yet. If anyone can point me in the right direction, it would be much appreciated.

@MKthot said: I'm not trying to argue about it, but the fact is, when I switched from: [java]rootNode.attachChild(new Bullet(…).getBullet());[/java] to: [java] Bullet bullet = new Bullet(…); rootNode.attachChild(bullet.getBullet());[/java] The problem stopped occurring, and when I switched back, the problem persisted until I reverted back again. I did this several times with the same results, each time the only lines of code modified were the lines above. Hence my reasoning that they are the cause. I will admit, however, that it may simply have been a glitch with Windows, jMonkey, or something else, as I have been unable to even recreate the problem since reading your post.

Windows, jme, etc. will not glitch in this way. So it MUST have been code that was after that… as those two blocks are identical other than that one “leaks” a variable name that might have been used later accidentally overriding a field or something.

I don’t know what to tell you about the collision listeners. I can say that you should absolutely only be registering ONE listener and not one per object. Adjust accordingly.

Okay, so using the block and bullet objects I from above, I’ve been able to get the collision to work “properly” (as far as I can tell) by registering the collision listener in the main class (the right objects appear to be colliding), and using the PhysicsCollisionEvent object. But is there anyway to call methods from the lvlBlock/Bullet classes from the event object? I’ve tried:

[java]event.getObjectB().getUserObject().getClass().getMethod(“destroyBullet”);[/java]

as well as several other variations, but none of them are able to find the destroyBlock() or destroyBullet() methods from the lvlBlock and Bullet classes. What is the proper way to do this? Is there a way to do this? My knowledge of coding collision events is lacking, so I’m not sure where to go from here.

Also note: right now I’m focusing solely on the Bullet object, I’ve changed

[java]bullet.addControl(gBullet);[/java]

to:

[java]this.addControl(gBullet);[/java]

and also, in the constructor, I added the line:

[java]this.setName(“pBullet”);[/java]

Using S.O.P lines, I can tell that:
[java]event.getNodeB().getName().equals(“pBullet”)[/java]
returns a value of true and that:
[java]event.getObjectB().getUserObject()[/java]
returns a value of:

pBullet (Bullet)

Okay so I’ve got it working now, but apparently I still haven’t set up my collisions incorrectly, because it’s still detecting a collision between the bullets and blocks, even when the player is nowhere near them. Help or advice anyone?