Cannonball

I have a 3rd person cube, an RigidBodyControl cannonball and a RigidBodyControl cube. I shoot a cannonball from the 3rd person cube and when it hits the RigidBodyControl cube it bounces off. How can I make the cannonball disappear when it hits the RigidBodyControl cube and make a little explosion?

The key is to use collision listeners. When you are setting up your physics, add a physics listener.

getStateManager().getPhysicsSpace().addCollisionListener(new PhysicsCollisionListener() {
    public void collision(PhysicsCollisionEvent collisionData) {
        // Collision Callback code
    }
});

This callback will be called every time a collision happens. What you need to do is check to see if at least one of the involved nodes is a cannonball (I’m going to use my imaginary method EntityUtils.isCannonball(Spatial), but you do whatever is needed for your game).

getStateManager().getPhysicsSpace().addCollisionListener(new PhysicsCollisionListener() {
    public void collision(PhysicsCollisionEvent collisionData) {
        Spatial cannonball = null;
        if (EntityUtils.isCannonball(collisionData.getNodeA())) {
            cannonball = collisionData.getNodeA();
        }
        else if (EntityUtils.isCannonball(collisionData.getNodeB())) {
            cannonball = collisionData.getNodeB();
        }
        else {
            cannonball = null;
        }
        if (cannonball != null) {
            // TODO - Remove cannonball spatial, create explosion
        }
    }
});

Whatever you replace the TODO with will trigger whenever a cannonball hits something (this includes any ghost objects as well, so you may want to filter whatever the other node is). As for the explosion, I find that creating an expanding rigid object works well.

RigidBodyControl explosionControl = new RigidBodyControl(new SphereCollisionShape(2F), 0F);
// Make sure that scaling the entity applies
explosionControl.setApplyScale(true);
Spatial explosionForce = new Node();
explosionForce.addControl(explosionControl);

At this point, you can add a second control to explosionForce that gradually scales the spatial for about half a second (I would recommend a logarithmic function of some sort to handle how much you expand each tick, as this works well for creating a flattening curve so that farther objects are pushed with less force). Nearby objects will be pushed away.

2 Likes

I get an error:
cannot find symbol
symbol: variable EntityUtils

I also get another error on the first line:
cannot find symbol
symbol: method getPhysicsSpace()

you need read carefully what Markil3 said.

see:

(I’m going to use my imaginary method EntityUtils.isCannonball(Spatial) , but you do whatever is needed for your game).

so generally you just replace it(this EntityUtils) with own code

1 Like

Right, I messed that up.

getStateManager().getAppState(BulletAppState.class).getPhysicsSpace()

That should fix that error.

I still get an error.
cannot find symbol
symbol: method getAppState

The idea is to gain access to your app’s state manager, and then to get the BulletAppState state from that. The BulletAppState has a method called getPhysicsSpace(), which returns a PhysicsSpace object that contains many of the physics-related methods you need for interacting with your game world.

@DoSt you need read JME wiki and learn about AppStates - know your own code to know how to reference to it.

its something we can only guess. stateManager is accessible by default, so its something you need to fix.

The method is called “getState()”.

Some people post answers from memory expecting that you know how to resolve simple naming issues by looking at the javadoc.

As general advice: for a java developer, the javadoc should be open already or only one click away (in the IDE it’s one click away). Developing without javadoc handy is like deciding your are just going to type with your nose and one pinky finger. Doable, sure… but why make things a million times harder unnecessarily.

2 Likes

What is the collisionData?
And what is EntityUtils.isCannonball?

They are imaginary , use your own code for this point instead ( your code of checking whether the collider is the canon ball or not ie it returns true/false if the getNodeA().getName().equals(“canonBall”); ) , btw , the collionData is a mandatory param passed from OnCollision(param) listener when implementing the PhysicsListener Interface so you get your collidor A & collider B easily (childs of the physics space) or access a control used by them .

1 Like

I used the following code:

        public void collision(PhysicsCollisionEvent event) {
        if ( event.getNodeA().getName().equals("cannonball") && event.getNodeB().getName().equals("target")) {
            //final Node node = event.getNodeA();
            /** ... do something with the node ... */
            rootNode.detachChild(cubeTarget);
        } 
        }

I want the target to dissapear (cubeTarget )when it is hit by a cannonball but nothing happens.

There is probability that the cannonBall might be NodeA or NodeB & the target as well it might be nodeA or nodeB so it’s better to put that probability into your list .

So,

if(
(event.getNodeA().getName().equals("cannonBall") || event.getNodeB().getName().equals("cannonBall") )

&&

(event.getNodeA().getName().equals("Target") || event.getNodeB().getName().equals("Target") )

){

//Do something
}

Sounds ridiculous :stuck_out_tongue_winking_eye: , but makes sense

There are also multiple easier ways of doing this .

EDIT
let me give you another example of a more clearer & functional form of code :

->in my J-Pluto game , i have created a physics entity class to make me able to assign a PrimaryCollider & a SecondaryCollider

Code ,very Simple:

 /*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package Mars_Map;

import com.jme3.bullet.collision.PhysicsCollisionEvent;

/**
 *
 * @author twisted
 * 
 * 
 */
 public abstract class CollisionerCondition{
     /**
      * Create an Instance that checks for 2 Collisioned Objects & shares information.
      * @param pce the physics event listener instance.
      * @param firstCollisioner the first collisioner object name.
      * @param secondCollisioner the second collisioner object name.
      */
     public CollisionerCondition(PhysicsCollisionEvent pce,String firstCollisioner,String secondCollisioner){
        if(pce.getNodeA().getName().equals(firstCollisioner) || pce.getNodeB().getName().equals(firstCollisioner)){
            if(pce.getNodeA().getName().equals(secondCollisioner) || pce.getNodeB().getName().equals(secondCollisioner)){
                    execute();
            }
        }
     }
     /**
      * Override that to do what you want if a condition of 2 desired objects collisions met.
      */
     public abstract void execute();
}

the FirstCollisioner is the PrimaryCollisioner , the SecondCollisioner is the SecondaryCollisioner which in turn lies in the sub-condition of the 1st collision & so on , execute() can be replaced with an interface for more clearer style , but i sticked to that for simplicity.

1 Like