Particles only appear when ActionListener used to create them

Hello!

I am very new to jMonkey, so please forgive me if this is obvious!

I have a vehicle for which I want to have some particle effects to simulate dust flying up from the base of the chassis/wheels. I have a method inside the vehicle’s class which is used to instantiate and attach the particle effect to the main vehicle node.

However, the effect only seems to be visible IF/WHEN I call the particle construction method inside an action listener (eg. by pressing the space bar on the keyboard). If I all the method as part of the constructor, or separately inside the world class (vehicle.setUpParticles();), it does not show anything!

I was wondering if you might be able to help me out? I am clearly doing something wrong!

[java]
public void setUpParticles()
{
Material dustKickParticlesmaterial = new Material(aM, “Common/MatDefs/Misc/Particle.j3md”);
dustKickParticlesmaterial.setTexture(“Texture”, aM.loadTexture(“Textures/Particles/ground_dust_kick.png”));
dustKickParticlesmaterial.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha);
dustKickParticlesmaterial.getAdditionalRenderState().setDepthWrite(false);

    backWheelLParticles = new ParticleEmitter("dustKickTwo", ParticleMesh.Type.Triangle, 50);
    backWheelLParticles.setMaterial(dustKickParticlesmaterial);
    backWheelLParticles.setShape(new EmitterSphereShape(new Vector3f(0,0,0), 1));
    backWheelLParticles.setImagesX(3);
    backWheelLParticles.setImagesY(3); // 2x2 texture animation
    backWheelLParticles.setSelectRandomImage(true);
    
     
    backWheelLParticles.setStartColor(new ColorRGBA(1f, 1f, 1f, 1f));
    backWheelLParticles.setEndColor(new ColorRGBA(1f, 1f, 1f, 1f));
    backWheelLParticles.setStartSize(0.5f);
    backWheelLParticles.setEndSize(2f);
    backWheelLParticles.setGravity(0, 23f, 0);
    backWheelLParticles.setLowLife(0.2f);
    backWheelLParticles.setHighLife(1f);
    backWheelLParticles.getParticleInfluencer().setInitialVelocity(new Vector3f(0,7,0));
    backWheelLParticles.setParticlesPerSec(40);
    
    
    
    
    vehicleNode.attachChild(backWheelLParticles);

    System.out.println("Completed the setup of particles");
    
    
    
}

[/java]

(The only way of getting particles to appear:)

[java]
public void onAction(String name, boolean isPressed, float tpf) {

    if (name.equals("Space") && isPressed)
    {
        playerVehicle.setUpParticles();
    }

}
[/java]

…As soon as I hit space, particles begin flying out from the vehicle, as intended.

(This, for example, does NOT work:)

[java]
private void spawnPlayer()
{

    Spatial model = getPlayerVehicle(); 
    
    rootNode.attachChild(playerVehicle.getVehicleNode());
    bulletAppState.getPhysicsSpace().add(playerVehicle.getControl());
    
    ChaseCamera chaseCam = new ChaseCamera(cam, inputManager);
    playerVehicle.getVehicle().addControl(chaseCam);
    
    playerVehicle.setUpParticles();
    
    
    
    
}

[/java]

One cause could be that you create two vehicleNodes (impossible to tell from the code) and confuse them so only one of them is attached to the scene.

Hello Johan,

Thanks for your response. Even if I call setUpParticles(); in the constructor of the concrete playerVehicle class, no particles render. By doing this, surely even if I had accidentally created two or more playerVehicles, they would all have emitters attached to them?

Besides, I added some print statements to show which objects were being used. The resuts are as follows:

Player Vehicle created: mygame.PlayerTukTuk@19500b26
Setting up particles on playerVehicle: mygame.PlayerTukTuk@19500b26
Completed the setup of particles on: mygame.PlayerTukTuk@19500b26
Completed the setup of particles on: mygame.PlayerTukTuk@19500b26 <-- I should point out that this line will be printed when I hit space. (Using PlayerTukTuk@19500b26 the whole time).

I should also mention that PlayerTukTuk extends PlayerVehicle.

[java]
private void spawnPlayer()
{
//slightly changed since last time. Added in print statements too
playerVehicle = getPlayerVehicle();
System.out.println("Player Vehicle created: "+playerVehicle.toString());
Spatial model = playerVehicle.getVehicle();

    rootNode.attachChild(playerVehicle.getVehicleNode());
    bulletAppState.getPhysicsSpace().add(playerVehicle.getControl());
    
    //...///
    
    System.out.println("Setting up particles on playerVehicle: "+playerVehicle.toString());
    playerVehicle.setUpParticles();
    
    
    
    
}

[/java]

[java]
public void setUpParticles()
{

    // Wheel Grit
    
    

    //... particle emitter &amp; material settings here (see above if necessary) ...//

    vehicleNode.attachChild(backWheelLParticles);


    System.out.println("Completed the setup of particles on: "+this.toString());
    
    
    
}

[/java]

I’m fairly new to JMonkey is well so my suggestion may be incorrect but maybe the particle emission occurs but the screen does not load up in time to show it. Maybe increase the high life of the particles to test this.

Hi robi1,

I’m fairly sure this isn’t the problem, because I CAN get the particles to appear, but ONLY by pressing space! :slight_smile:

[java]

public void someMethod()
{
	playerVehicle = getPlayerVehicle();
	rootNode.attachChild(playerVehicle.getVehicleNode());
	bulletAppState.getPhysicsSpace().add(playerVehicle.getControl());
	
	playerVehicle.setUpParticles(); //This does NOT work - particles don't appear.
	
	
	
}

public void setupTestKeys()
{
    inputManager.addMapping("Space", new KeyTrigger(KeyInput.KEY_SPACE));
    inputManager.addListener(this, "Space");
}

public void onAction(String name, boolean isPressed, float tpf)
{
		
		if (name.equals("Space") &amp;&amp; isPressed)
		{
			playerVehicle.setUpParticles(); //This DOES work - particles do appear.
		}

}

[/java]

I am still having trouble with this, so any help would be appreciated! If you need me to post some code, please just ask!

Maybe you could post all the code and then I could take a look?

I have found the cause of the problem, but not the solution. In my scene, I have some water which uses the SimpleWaterProcessor (see below).

If I remove the line which calls initSimpleWater(), the particles suddenly work just as they should do. However, this is undesirable as I want the water to render!

:arrow: Do you know any way to get around this?

robi1, I have included some code for you!

This is part of the scene class:

[java]
private void initSimpleWater(){

    SimpleWaterProcessor waterProcessor = new SimpleWaterProcessor(assetManager);
    waterProcessor.setReflectionScene(sceneNode);

    Vector3f waterLocation=new Vector3f(0,0,0);
    waterProcessor.setPlane(new Plane(Vector3f.UNIT_Y, waterLocation.dot(Vector3f.UNIT_Y)));
   


    waterProcessor.setWaterDepth(20);         // transparency of water
    waterProcessor.setDistortionScale(0.04f); // strength of waves
    waterProcessor.setWaveSpeed(0.04f);       // speed of waves
    waterProcessor.setLightPosition(lightDir);
    //waterProcessor.setWaterTransparency(0.5f);
    viewPort.addProcessor(waterProcessor);
    Quad quad = new Quad(800,800);
    quad.scaleTextureCoordinates(new Vector2f(25f,25f));

    
    Geometry water=  new Geometry("water", quad);
    water.setLocalRotation(new Quaternion().fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_X));
    water.setLocalTranslation(-400, -2, 400);
    //water.setShadowMode(ShadowMode.Receive);
    Material waterMaterial = waterProcessor.getMaterial();
    water.setMaterial(waterMaterial);
    rootNode.attachChild(water);
    
    FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
    //fpp.addFilter(water);
    TranslucentBucketFilter tbf = new TranslucentBucketFilter(true);
    fpp.addFilter(tbf);
    fpp.addFilter(createFog());
    viewPort.addProcessor(fpp); 

}
[/java]

This is where the particles are created, in the vehicle class:

[java]

//Import statements and various unused/irrelevant methods have been omitted.

public class PlayerTukTuk extends PlayerVehicle{

Spatial vehicleModel;
VehicleControl control;
CollisionShape carCollisionBox;
Node vehicleNode = new Node("tuktukNode");
Node wheelNode1, wheelNode2, wheelNode3;
Spatial wheel1, wheel2, wheel3;
Material vehicleMaterial;
AssetManager aM;
PhysicsSpace pS;
InputManager gameInputManager;
ParticleEmitter backWheelLParticles, backWheelRParticles, frontWheelParticles, dustCloud, exhaust_1;

final float stiffness = 80f;
float steeringValue = 0;
float steeringAmount = 0.3f;
float accelerationForce = 2000;
float decelerationForce = 20;
float accelerationValue =0;
float brakeForce = 50;
float compValue = 0.1f;
float dampValue = 0.2f;
boolean moving = false;
Vector3f wheel1Vector = new Vector3f(0f, 1f, 4f);
Vector3f wheel2Vector = new Vector3f(1.3f, 1f, -2.4f);
Vector3f wheel3Vector = new Vector3f(-1.3f, 1f, -2.4f);




public PlayerTukTuk(AssetManager a, PhysicsSpace physicsSpace, InputManager i)
{
    vehicleNode.setLocalTranslation(new Vector3f(0, 5, 0));
    
    //Setup the main vehicle and physics
    aM = a;
    gameInputManager = i;
    vehicleModel = aM.loadModel("Models/Vehicles/Tuktuk/TukTuk.j3o");
    vehicleModel.setLocalScale(0.7f);
    CompoundCollisionShape compoundShape = new CompoundCollisionShape();
    carCollisionBox = CollisionShapeFactory.createDynamicMeshShape(vehicleModel);
    control = new VehicleControl(carCollisionBox, 600f);
    vehicleNode.addControl(control);
    vehicleNode.attachChild(vehicleModel);
    //pS = physicsSpace;
    
    
    
    vehicleMaterial = new Material(aM, "Common/MatDefs/Misc/Unshaded.j3md");
    vehicleMaterial.setTexture("ColorMap", aM.loadTexture("Models/Vehicles/Tuktuk/baked_tuktuk.png"));
    
    //Setup the wheels
    wheelNode1 = new Node("wheel 1 node");
    wheel1 = aM.loadModel("Models/Vehicles/Tuktuk/TukTuk Wheel.j3o");
    wheel1.setLocalScale(0.7f);
    wheelNode1.attachChild(wheel1);
    wheel1.rotate(0, FastMath.HALF_PI, 0);
    vehicleNode.attachChild(wheelNode1);
    
    wheelNode2 = new Node("wheel 2 node");
    wheel2 = aM.loadModel("Models/Vehicles/Tuktuk/TukTuk Wheel.j3o");
    wheel2.setLocalScale(0.7f);
    wheelNode2.attachChild(wheel2);
    wheel2.rotate(0, FastMath.HALF_PI, 0);
    vehicleNode.attachChild(wheelNode2);
    
    wheelNode3 = new Node("wheel 3 node");
    wheel3 = aM.loadModel("Models/Vehicles/Tuktuk/TukTuk Wheel.j3o");
    wheel3.setLocalScale(0.7f);
    wheelNode3.attachChild(wheel3);
    wheel3.rotate(0, FastMath.HALF_PI, 0);
    vehicleNode.attachChild(wheelNode3);

    
    //Setup the physical properties of the vehicle
    control.setSuspensionStiffness(stiffness);
    control.setMaxSuspensionForce(10000.0f);
    control.setSuspensionCompression(compValue * 2.0f * FastMath.sqrt(stiffness));
    control.setSuspensionDamping(dampValue * 2.0f * FastMath.sqrt(stiffness));
    control.setAngularDamping(0.8f);

    
    control.addWheel(wheelNode1, wheel1Vector, new Vector3f(0, -1, 0), new Vector3f(-1, 0, 0), 0.1f, 0.8f, true);
    control.addWheel(wheelNode2, wheel2Vector, new Vector3f(0, -1, 0), new Vector3f(-1, 0, 0), 0.1f, 0.8f, false);
    control.addWheel(wheelNode3, wheel3Vector, new Vector3f(0, -1, 0), new Vector3f(-1, 0, 0), 0.1f, 0.8f, false);

    
    Material dustKickParticlesmaterial = new Material(aM, "Common/MatDefs/Misc/Particle.j3md");
    dustKickParticlesmaterial.setTexture("Texture", aM.loadTexture("Textures/Particles/ground_dust_kick.png"));
    dustKickParticlesmaterial.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha);
    dustKickParticlesmaterial.getAdditionalRenderState().setDepthWrite(false);
    
    
    
    setUpParticles();
    
    
    
}

@Override
public void setUpParticles()
{
    
    // Wheel Grit
    Material dustKickParticlesmaterial = new Material(aM, "Common/MatDefs/Misc/Particle.j3md");
    dustKickParticlesmaterial.setTexture("Texture", aM.loadTexture("Textures/Particles/ground_dust_kick.png"));
    dustKickParticlesmaterial.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha);
    dustKickParticlesmaterial.getAdditionalRenderState().setDepthWrite(false);

    backWheelLParticles = new ParticleEmitter("dustKickTwo", ParticleMesh.Type.Triangle, 100);
    backWheelLParticles.setMaterial(dustKickParticlesmaterial);
    backWheelLParticles.setShape(new EmitterSphereShape(new Vector3f(0,0,0), 1));
    backWheelLParticles.setImagesX(3);
    backWheelLParticles.setImagesY(3); // 2x2 texture animation
    backWheelLParticles.setSelectRandomImage(true);
    backWheelLParticles.setStartColor(new ColorRGBA(1f, 1f, 1f, 1f));
    backWheelLParticles.setEndColor(new ColorRGBA(1f, 1f, 1f, 0f));
    backWheelLParticles.setStartSize(0.3f);
    backWheelLParticles.setEndSize(1.2f);
    backWheelLParticles.setGravity(0, 40f, 0);
    backWheelLParticles.setLowLife(0.3f);
    backWheelLParticles.setHighLife(0.6f);
    backWheelLParticles.getParticleInfluencer().setInitialVelocity(new Vector3f(0,7,-6));
    backWheelLParticles.setParticlesPerSec(60);
    backWheelLParticles.setLocalTranslation(wheel2Vector);
    
    vehicleNode.attachChild(backWheelLParticles);

    System.out.println("Completed the setup of particles on: "+this.toString());
    
    
    
}

}

[/java]

Just out of curiosity can you get the particles to work in the update method or can you ONLY get them to work when pressing space.

If I call playerVehicle.setUpParticles(); in the update method, every time the update method is run, it will create hundreds of thousands of emitters (the equivalent of running setUpParticles() for every frame), but it does ‘work’.

If, however, I try and call playerVehicle.setUpParticles(); just once in the first update call so as to create the desired effect, it won’t work at all!

Every thing you do, even the action listener, is being called as part of update. So if it’s not working in one update but is working in another then it sounds like some setup has not been done before the first update that is already done by the time the other is done. Maybe it’s not attached yet, maybe something else. We don’t really have any of the relevant code so it’s kind of up to you to debug it.

You may want to step through in the debugger for the different paths and see what’s different.

Hi pspeed,

You’re right, if I place the following code in the simpleUpdate() method:

[java]
if(updateNo == 1000)
{
spawnPlayer();
playerVehicle.setUpParticles();
}

    updateNo++;

[/java]

…it will correctly spawn the vehicle with it’s particles attached and visible.

May I ask, please, how it is that having a simpleInitApp() method (as with mine, below) will NOT work? (It will not work, regardless of whether or not I create the water first/last). Doesn’t simpleInitApp() run before any update is called? If it works after 1000 updates, why can’t it work before the first update? I have other particle systems which are directly attached to the root node which are created pre the first update.

[java]
public void simpleInitApp() {
stateManager.attach(bulletAppState);
bulletAppState.getPhysicsSpace().setGravity(globalGravity);

    initScene();
   
    spawnPlayer();
    playerVehicle.setUpParticles();
    
    
    initPPcWaterFogandSoftParticles();
    
    initSimpleWater();
    //Test Methods:
    setupTestKeys();
    
}

[/java]

:!: By having this info, I now know that if I want the vehicle to spawn correctly, I shall have to give a few seconds (not even that) before it’s created. It’s a workaround, but it doesn’t solve the problem as such. :lol:

@pspeed said: You may want to step through in the debugger for the different paths and see what's different.