For loop causing problem in control

The for loops I added is giving me an error.

[java]public void collision(PhysicsCollisionEvent event) {
if (space == null) {
return;
}

    if (event.getNodeA().getName().contains("laser") && event.getNodeB().getName().contains("rock")) {
        if (effect != null && event.getNodeB().getParent() != null) {
            //curTime = 0;
            effect.setLocalTranslation(event.getNodeB().getLocalTranslation());
            event.getNodeB().getParent().attachChild(effect);
            //effect.setEnabled(true);
            effect.emitAllParticles();
        }
        space.remove(event.getObjectB());
        event.getNodeB().removeFromParent();
        
        if (rock01 != null) {
            for (int i = 1; i < 4; i++) {
                rock01.setLocalTranslation(spatial.getLocalTranslation());
                rock01.setLocalScale((float) Math.random() * 2);
                rock01.addControl(rockC);
                space.add(rockC);
                spatial.getParent().attachChild(rock01);
            }
        }
        
        
    } else if (event.getNodeB().getName().contains("laser") && event.getNodeA().getName().contains("rock")) {
        if (effect != null && event.getNodeA().getParent() != null) {
            //curTime = 0;
            effect.setLocalTranslation(event.getNodeA().getLocalTranslation());
            event.getNodeA().getParent().attachChild(effect);
            //effect.setEnabled(true);
            effect.emitAllParticles();
        }
        space.remove(event.getObjectA());
        event.getNodeA().removeFromParent();
        
        if (rock01 != null) {
            for (int i = 1; i < 4; i++) {
                rock01.setLocalTranslation(spatial.getLocalTranslation().add((float) Math.random(), (float) Math.random(), (float) Math.random()));
                rock01.setLocalScale((float) Math.random() * 2);
                rock01.addControl(rockC);
                space.add(rockC);
                spatial.getParent().attachChild(rock01);
            }
        }
    }
}[/java] 

Here is the error…

name:LEFT; keyPressed:true
Feb 7, 2013 8:59:15 PM com.jme3.scene.Node attachChild
INFO: Child (Emitter) attached to this node (Root Node)
Feb 7, 2013 8:59:15 PM com.jme3.bullet.PhysicsSpace removeRigidBody
INFO: Removing RigidBody com.bulletphysics.dynamics.RigidBody@580c5da6 from physics space.
Feb 7, 2013 8:59:15 PM com.jme3.scene.Node detachChildAt
INFO: Root Node (Node): Child removed.
Feb 7, 2013 8:59:15 PM com.jme3.bullet.PhysicsSpace addRigidBody
INFO: Adding RigidBody com.bulletphysics.dynamics.RigidBody@1667a232 to physics space.
Feb 7, 2013 8:59:15 PM com.jme3.scene.Node attachChild
INFO: Child (Models/rock01/rock01-scene_node) attached to this node (Root Node)
Feb 7, 2013 8:59:15 PM com.jme3.app.Application handleError
SEVERE: Uncaught exception thrown in Thread[LWJGL Renderer Thread,5,main]
java.util.ConcurrentModificationException
at java.util.LinkedList$ListItr.checkForComodification(LinkedList.java:761)
at java.util.LinkedList$ListItr.next(LinkedList.java:696)
at com.jme3.bullet.PhysicsSpace.distributeEvents(PhysicsSpace.java:332)
at com.jme3.bullet.BulletAppState.update(BulletAppState.java:173)
at com.jme3.app.state.AppStateManager.update(AppStateManager.java:255)
at com.jme3.app.SimpleApplication.update(SimpleApplication.java:238)
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:680)
Feb 7, 2013 8:59:15 PM com.jme3.renderer.lwjgl.LwjglRenderer cleanup
INFO: Deleting objects and invalidating state
Feb 7, 2013 8:59:15 PM com.jme3.scene.Node detachChildAt
INFO: Gui Node (Node): Child removed.
Feb 7, 2013 8:59:15 PM com.jme3.scene.Node detachChildAt
INFO: Gui Node (Node): Child removed.
Feb 7, 2013 8:59:15 PM com.jme3.input.lwjgl.LwjglMouseInput destroy
INFO: Mouse destroyed.
Feb 7, 2013 8:59:15 PM com.jme3.input.lwjgl.LwjglKeyInput destroy
INFO: Keyboard destroyed.
Feb 7, 2013 8:59:15 PM com.jme3.system.lwjgl.LwjglAbstractDisplay deinitInThread
INFO: Display destroyed.
BUILD SUCCESSFUL (total time: 20 seconds)

I think this means I need to do something with threads, I have no experience with them, can someone tell me where to add what please. The code is from within a control.

You probably detach the child that the control is on so while the update loop loops though the children you modify that list.
The content of this post is meant to be read as a straight information or question without an implicit dismissive stance or interest in having the other party feel offended unless theres emotes that hint otherwise or theres an increased use of exclamation marks and all-capital words.

@normen said: You probably detach the child that the control is on so while the update loop loops though the children you modify that list. The content of this post is meant to be read as a straight information or question without an implicit dismissive stance or interest in having the other party feel offended unless theres emotes that hint otherwise or theres an increased use of exclamation marks and all-capital words.

Which is fine on the scene graph side. You can remove nodes during any of these loops… but maybe the physics space has an issue.

To the OP, it looks like this is from a collision listener? If so, why is it a control when the physics listener is basically global? I mean, I read the code and it seems like there is nothing node specific and I’m remember the other thread where you found it was being called for every rock. (pretty sure it was you).

Anyway, even if it’s just a listener it may cause problems for bullet if you modify the space while it’s operating. I don’t know what the proper way to do that is because I’ve never looked at the bullet code. Maybe Normen has an idea.

Then it can only be the listener itself really but I don’t see that removed anywhere in the code?
The content of this post is meant to be read as a straight information or question without an implicit dismissive stance or interest in having the other party feel offended unless theres emotes that hint otherwise or theres an increased use of exclamation marks and all-capital words.

It’s hard to say what’s going on. I see lots of dodgy looking code… like the same control being added to four different nodes and stuff.

Edit: No… same control being added to the node 4 times. I have no idea what those loops are doing, actually. They do four things to the same spatial. It’s weird.

I did change the code because I was having problems with collision between physical and non physical nodes. Here is my whole rock control, (ps I just changed it again):

[java]public class RockControl extends RigidBodyControl implements PhysicsCollisionListener {
//Any local variables should be encapsulated by getters/setters so they
//appear in the SDK properties window and can be edited.
//Right-click a local variable to encapsulate it with getters and setters.

private ParticleEmitter effect;
private Spatial rock01;
private RigidBodyControl rockC;

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

public RockControl(AssetManager manager, CollisionShape shape, float mass) {
    super(shape, mass);
    prepareEffect(manager);
    rock01 = manager.loadModel("/Models/rock01/rock01.j3o");
    CollisionShape rockShape;
    rockShape = CollisionShapeFactory.createDynamicMeshShape(rock01);
    rockC = new RockControl(rockShape, 10f);
}

public void prepareEffect(AssetManager assetManager) {
    effect = new ParticleEmitter("Emitter", ParticleMesh.Type.Triangle, 100);
    effect.setShape(new EmitterSphereShape(Vector3f.ZERO, 50f));
    effect.setGravity(0, 0, 0);
    effect.setLowLife(2);
    effect.setHighLife(2);
    effect.setStartColor(ColorRGBA.DarkGray);
    effect.setEndColor(ColorRGBA.Black);
    effect.setStartSize(0);
    effect.setEndSize(10);
    effect.setInitialVelocity(new Vector3f(10, 0, 0));
    effect.setImagesX(15);
    effect.setParticlesPerSec(0);
    effect.setRandomAngle(true);
    effect.getParticleInfluencer().setVelocityVariation(1f);
    Material mat = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md");
    effect.setMaterial(mat);
    
}

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

public void collision(PhysicsCollisionEvent event) {
    if (space == null) {
        return;
    }

    if (event.getNodeA().getName().contains("laser") && event.getNodeB().getName().contains("rock")) {
        if (effect != null && event.getNodeB().getParent() != null) {
            //curTime = 0;
            effect.setLocalTranslation(event.getNodeB().getLocalTranslation());
            event.getNodeB().getParent().attachChild(effect);
            //effect.setEnabled(true);
            effect.emitAllParticles();
        }
        space.remove(event.getObjectB());
        event.getNodeB().removeFromParent();
        
        
    } else if (event.getNodeB().getName().contains("laser") && event.getNodeA().getName().contains("rock")) {
        if (effect != null && event.getNodeA().getParent() != null) {
            //curTime = 0;
            effect.setLocalTranslation(event.getNodeA().getLocalTranslation());
            event.getNodeA().getParent().attachChild(effect);
            //effect.setEnabled(true);
            effect.emitAllParticles();
        }
        space.remove(event.getObjectA());
        event.getNodeA().removeFromParent();
        
    }
}


@Override
public void update(float tpf) {
    super.update(tpf);
    if (effect != null && effect.getNumVisibleParticles() > 0 && effect.getNumVisibleParticles() < 10) {
        effect.removeFromParent();
        //space.remove(spatial.getControl(RockControl.class));
        //spatial.removeFromParent();
    } else if(effect.getNumVisibleParticles() == 100) {
        if (rock01 != null) {
            for (int i = 1; i < 4; i++) {
                rock01.setLocalTranslation(spatial.getLocalTranslation().add((float) Math.random(), (float) Math.random(), (float) Math.random()));
                rock01.setLocalScale((float) Math.random() * 2);
                rock01.addControl(rockC);
                space.add(rockC);
                spatial.getParent().attachChild(rock01);
            }
        }
    }
}

@Override
public void read(JmeImporter im) throws IOException {
    super.read(im);
    InputCapsule in = im.getCapsule(this);
    //TODO: load properties of this Control, e.g.
    //this.value = in.readFloat("name", defaultValue);
}

@Override
public void write(JmeExporter ex) throws IOException {
    super.write(ex);
    OutputCapsule out = ex.getCapsule(this);
    //TODO: save properties of this Control, e.g.
    //out.write(this.value, "name", defaultValue);
}

}
[/java]

Ummmm…

What do you think a loop like this is actually doing?
[java]
for (int i = 1; i < 4; i++) {
rock01.setLocalTranslation(spatial.getLocalTranslation().add((float) Math.random(), (float) Math.random(), (float) Math.random()));
rock01.setLocalScale((float) Math.random() * 2);
rock01.addControl(rockC);
space.add(rockC);
spatial.getParent().attachChild(rock01);
}
[/java]

Also, based on my limited understanding, it’s crazy to make a control also a collision listener in this case. Since every one will be called every time for every collision. You only need one… not one for each rock… just ONE.

@pspeed: hehe, yeah that looks nasty… Actually it should set the control to the new rock each time but it seems that object some object instances are not the way the creator intended them to be I guess ^^
The content of this post is meant to be read as a straight information or question without an implicit dismissive stance or interest in having the other party feel offended unless theres emotes that hint otherwise or theres an increased use of exclamation marks and all-capital words.

I don’t follow how I can have one, isn’t this what controls are for? the for loop is to spawn new rock after one has been hit.

@enigma101 said: I don't follow how I can have one, isn't this what controls are for? the for loop is to spawn new rock after one has been hit.

The for loop calls methods on the same spatial 4 times.

Controls are meant for things that are spatial-specific. Collision listeners are global. You should set one up in an app state or in your main class or something.

1 Like

Yep, @pspeed is right. It simply lacks the new rock01 (or the clone) in the loop. Thus the same rock is added 4 times, and a new control is added to it each time.

As for the exception, I don’t understand it. On current version line 332 of physicsSpace is outside of any method. distributeEvents iterates on a collection of collisions. So removing spatials/controls from the scene / the physics space should be safe

Ok, so how can I go about spawning multiple new rocks from within my control? Should I copy over assetmanager to a private var for my control and load the model each time in my loop? I tried using clone but that didn’t work.

[java] @Override
public void update(float tpf) {
super.update(tpf);
if (effect != null && effect.getNumVisibleParticles() > 0 && effect.getNumVisibleParticles() < 10) {
effect.removeFromParent();
//space.remove(spatial.getControl(RockControl.class));
//spatial.removeFromParent();
} else if(effect != null) {
if (rock01 != null && effect.getNumVisibleParticles() == 100) {
for (int i = 1; i < 4; i++) {
int rndX = (int)(Math.random() * ((25) + 1));
int rndY = (int)(Math.random() * ((25) + 1));
int rndZ = (int)(Math.random() * ((25) + 1));
Spatial myrock = rock01.clone();
myrock.setLocalTranslation(effect.getLocalTranslation().add((float) rndX, (float) rndY, (float) rndZ));
myrock.setLocalScale((float) Math.random() * 3);
myrock.addControl(rockC);
space.add(rockC);
effect.getParent().attachChild(myrock);
}
}
}
}[/java]
I changed the logic to get rid of the errors but I still need to properly spawn several new rocks.

Yes, the easiest is to use the assetManager to load them each time. Its internal cache will do the magic…

1 Like