I have a class named PowerUp and i wanna know what i did bad/wrong. At first i tried extending PhysicsNode but i came across some problem. Don’t remember what it was but i ended up not extending anything and using the getPhysicsNode() method when adding the object in my BulletAppState. PowerUp now extends PhysicsNode .The step(float tpf) method is called every frame to make it spin and to do the a fade-out animation when you pick up the PowerUp.
Here is how the look in my game:
And here is a video of it: http://www.youtube.com/watch?v=AJd5QfZcSjk
I also have a question. I use getOverlappingObjects() to check for collisions with the PowerUps which returns a List of PhysicsCollisionObject. I then loop through the list and use PhysicsCollisionObject.getName().startsWith(“pup”) to see if my character has collided with a PowerUp. Notice name = “pup”+instance++; in my constructor (PowerUps are named pup1, pup2, …). I then brute force my ArrayList with PowerUps to see which one has the name i collided with, then I call my startFadeOut() method on that PowerUp. I’m sure this is a really bad way to do it but that’s the only thing i came up with. So my question is, which is the best way to go from a PhysicsCollisionObject to the PowerUp (which extends PhysicsNode)?
BallGuy is the main class. BallGuy.am is the AssetManager. BallGuy.enableMegaBounce(); is what happens when you pick up a PowerUp.
fadeval is the state of the PowerUp. -1 is the normal state which just rotates. -2 means remove the Node. And anything in between is the fade-out animation.
Aside from the bad coding, I’m happy about how it performs ingame.
The class:
[java]package mygame;
import com.jme3.bullet.collision.shapes.BoxCollisionShape;
import com.jme3.scene.Node;
import com.jme3.bullet.nodes.PhysicsNode;
import com.jme3.material.Material;
import com.jme3.material.RenderState.BlendMode;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Sphere;
public class PowerUp extends PhysicsNode{
private Node n;
private static int instance=0;
private float fadeval=-1f;
private Material redMat, blueMat;
public PowerUp(Vector3f location){
super(new BoxCollisionShape(new Vector3f(.1f, .1f, .1f)), 0f);
n = new Node(“PowerUpNode”);
Sphere redBall = new Sphere(8, 8, .2f);
Geometry redGeo = new Geometry(“redBall”, redBall);
redMat = new Material(BallGuy.am, “Common/MatDefs/Misc/SolidColor.j3md”);
redMat.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
redMat.setColor(“m_Color”, new ColorRGBA(1f, 0f, 0f, 1f));
redGeo.setMaterial(redMat);
redGeo.setLocalTranslation(-.15f, 0f, 0f);
Sphere blueBall = new Sphere(8, 8, .2f);
Geometry blueGeo = new Geometry(“blueBall”, blueBall);
blueMat = new Material(BallGuy.am, “Common/MatDefs/Misc/SolidColor.j3md”);
blueMat.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
blueMat.setColor(“m_Color”, new ColorRGBA(0f, 0f, 1f, 1f));
blueGeo.setMaterial(blueMat);
blueGeo.setLocalTranslation(.15f, 0f, 0f);
n.attachChild(redGeo);
n.attachChild(blueGeo);
attachChild(n);
setName(“pup”+instance++);
setShadowMode(ShadowMode.CastAndReceive);
setLocalTranslation(location);
}
public void step(float tpf){
if(fadeval!=-1f && fadeval!=-2f){
fadeval+=tpf;
n.setLocalTranslation(0, fadeval, 0);
if(1f-fadeval>0f){
blueMat.setColor(“m_Color”, new ColorRGBA(0f, 0f, 1f, 1f-fadeval));
redMat.setColor(“m_Color”, new ColorRGBA(1f, 0f, 0f, 1f-fadeval));
}
else{
fadeval=-2f;
}
}
tpf*=2f;
n.rotate(tpf, tpf, tpf);
}
public void startFadeOut() {
BallGuy.enableMegaBounce();
fadeval=0f;
}
public boolean removeCheck() {
return fadeval==-2f;
}
}[/java]
In the current version of physics the PhysicsCollisionObjects do not extend Node anymore, so this will not work anymore anyway. You can now set a “user object” to the physics control or object that you can store all kinds of info about your physics object in. By default that is the Spatial but you can set anything to it, so maybe some info object with a isPowerUp() method or something.
I wrote this at the end of my PowerUp constructor:
[java]pn.setUserData(“blabla”, this);[/java]
But i got “java.lang.IllegalArgumentException: Unsupported type: mygame.PowerUp”. And after checking the sources i see why, so i guess that i am supposed to setUserData that way.
Shall i use any of these two on my game loop? If my Java knowledge is correct they do the exact same thing.
[java] for(PhysicsCollisionObject x : playerPhys.getOverlappingObjects()){
try {
PowerUp pw = (PowerUp)x.getUserData(“blabla”);
//tell pw it collided
} catch (Exception e) {
//x is not a PowerUp
}
}[/java]
[java] for(PhysicsCollisionObject x : playerPhys.getOverlappingObjects()){
Object pwo = x.getUserData(“blabla”);
if(pwo!=null){
if(pwo instanceof PowerUp){
PowerUp pw = (PowerUp)pwo;
//tell pw it collided
}
}
}[/java]
if(pwo!=null){
is probaly the reason the first crashes What happens if you do this:
[java]
for(PhysicsCollisionObject x : playerPhys.getOverlappingObjects()){
try {
if(x.getUserData(“blabla”) != null){
PowerUp pw = (PowerUp)x.getUserData(“blabla”);
//tell pw it collided
}
} catch (Exception e) {
//x is not a PowerUp
}
}
[/java]
Also I highly belive that there is a better way to recive collision events than that (I don’t use that physic binding so I’m not sure tho)
The crash is from pn.setUserData(“blabla”, this); at the PowerUp constructor, not in any of those loops. I’ve never reached them since it crashes before the game starts. And checking if an Object is null should not give an exception.
I tried another way to check for collisions before but i failed somehow and when i found this method it worked instantly so this is probably the method i will use.
I wouldn’t throw & catch exceptions in a loop that can go over a fair amount of objects as it seems it is somwhat slow.
Keep in mind ‘null instanceOf AnyClass’ returns false, your check is useless unless you want to take some action if its null.
Do you still have a crash?
Edit: My class now extends PhysicsNode.
Yes, the crash is from pn.setUserData(“blabla”, this); and not from the for-loops i wrote, which i havnt tested yet because it crashes before. When I check the sources it seems that UserData can only be int/float/string/boolean, which is why it crashes.
I don’t see what’s wrong with my null check. I store getUserData(“blabla”) in Object pwo. If there is no data with the key “blabla”, pwo will be null. I then check if pwo is null. If it is not i check if it’s a PowerUp, and if it’s a PowerUp i tell it that it collided.
To go back to my main question: Which is the best way to go from PhysicsCollisionObject to PowerUp (which now extends PhysicsNode)?
I would update my jme install from svn to be able to store any object in UserData :
normen said:
You can now set a "user object" to the physics control or object that you can store all kinds of info about your physics object in.
Personally i would have an Enum somewhere with all CollectableType and i would pass a value of that enum to my UserData. Then, if obj==CollectableType.POWERUP, downcast to POwerUp and launch your animation. The test should be fast enough even with lots of objects.
And i would add another enu in your PowerUp class for different powerup types, and a method public PowerUpType getPowerUpType().
I probably would also make my class Powerup abstract with different poweruptypes implementing it, because i guess they all have different textures/effect. It depends on you handle them.
Sounds good, I actually just committed a change that changes the spatial userObject handling… Before the userObject would always be set to the spatial when the physics controller was added to it, now it doesn’t overwrite it when its set otherwise.