Particles invisible in FixedLogirateGame

I can make particle effects load fine in a SimpleGame extension, but they don't show up at all in my FixedLogicrateGame. I do have models loading fine. Is there something in particular a particle system depends upon being initialized that SimpleGame does that FixedLogicrateGame doesn't?

Okay, maybe some simple test code could better illustrate the problem? Those kinds of posts seem to be getting more answers.



First, I've made a layered particle effect in the editor. I wrote a static loader method for it:


package testing;

import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import com.jme.scene.Node;
import com.jme.scene.Spatial.LightCombineMode;
import com.jme.scene.state.ZBufferState;
import com.jme.scene.state.ZBufferState.TestFunction;
import com.jme.system.DisplaySystem;
import com.jme.util.export.binary.BinaryImporter;
import com.jme.util.resource.ResourceLocatorTool;
import com.jme.util.resource.SimpleResourceLocator;

public class StaticLoader {
   
   /**
    * Imports a particle effect created with the editor.
    * @param effect the saved particle effect file.
    * @param textureDir the directory with the particle's
    * texture file(s). Can be null if effect requires no texture.
    * @return Node with the effect
    */
   public static Node loadJmeParticleSystem(
         File effect, File textureDir) {
      Node output = null;
      try {         
         if (textureDir != null) {
            final SimpleResourceLocator location =
               new SimpleResourceLocator(textureDir.toURI().toURL());
            ResourceLocatorTool.addResourceLocator(
                     ResourceLocatorTool.TYPE_TEXTURE, location );
         } output = (Node)
            BinaryImporter.getInstance().load(effect);
      } catch (IOException e) {
         e.printStackTrace();
         System.err.println("file not found at: "+effect);
      } catch (URISyntaxException e) {
         e.printStackTrace();
         System.err.println("unable to load image at: "+textureDir);
      }
      ZBufferState zs = DisplaySystem.getDisplaySystem(
            ).getRenderer().createZBufferState();
      // turn off lighting?
      output.setLightCombineMode(LightCombineMode.Off);
      zs.setWritable(false);
      zs.setFunction(TestFunction.LessThan);
      output.setRenderState(zs);
      output.updateRenderState();
      
      return output;
   }

}



To test this loader, I used a SimpleGame extension class:

package testing;


import java.io.File;


import com.jme.app.SimpleGame;
import com.jme.scene.Node;

public class SimpleMain extends SimpleGame {

   public static void main(String[] args) {
      //Instantiate
      SimpleMain myTest = new SimpleMain();
      //Always show dialog to set resolution
      myTest.setConfigShowMode(ConfigShowMode.AlwaysShow);
      //Begin the game
      myTest.start();
   }

   @Override
   protected void simpleInitGame() {
      Node foo = StaticLoader.loadJmeParticleSystem(
            new File("particle/purplefirejetflare.jme"),
            new File("particle/"));
      foo.setLocalScale(.1f);
      foo.setLocalTranslation(0,0,-50);
      this.rootNode.attachChild(foo);
   }
   
   @Override
   protected void simpleUpdate() {
      
   }
}

The effect appears as expected, although it doesn't look quite as good as in the editor.

I try basically the same thing in a FixedLogicRateGame extension:

package testing;


// Java
import java.io.File;
import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;


// jME
import com.jme.app.FixedLogicrateGame;
import com.jme.input.KeyBindingManager;
import com.jme.input.KeyInput;
import com.jme.light.DirectionalLight;
import com.jme.math.FastMath;
import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.jme.renderer.Camera;
import com.jme.renderer.ColorRGBA;
import com.jme.scene.CameraNode;
import com.jme.scene.Node;
import com.jme.scene.Spatial.LightCombineMode;
import com.jme.scene.state.LightState;
import com.jme.scene.state.MaterialState;
import com.jme.scene.state.ZBufferState;
import com.jme.system.DisplaySystem;
import com.jme.system.GameSettings;
import com.jme.system.JmeException;
import com.jme.system.PreferencesGameSettings;
import com.jme.util.Timer;

public class FixedLogicrateMain extends FixedLogicrateGame
{
   //variable declarations
   private int width, height, depth, freq;
   private boolean fullscreen;
   private Camera cam;
   private static Node sceneRoot;
   protected Timer timer;
   private CameraNode camNode;
   private ZBufferState buf;

   private MaterialState mat;

// *** Main entry point
   
   public static void main(String[] args) {
      FixedLogicrateMain app = new FixedLogicrateMain();
      app.setConfigShowMode(FixedLogicrateMain.ConfigShowMode.AlwaysShow);

      try {
         app.start();
      } catch (Exception e) {
         // we will want to know what happened.
         e.printStackTrace();
      }
      
   }
   
// *** Private helper methods

   @Override
   protected void initSystem() {
      //store the properties information
      width = this.settings.getWidth();
      height = this.settings.getHeight();
      depth = this.settings.getDepth();
      freq = this.settings.getFrequency();
      fullscreen = this.settings.isFullscreen();         
   
      //cam init
      initCam();
      
      KeyBindingManager.getKeyBindingManager().set("exit",
            KeyInput.KEY_ESCAPE);
   }

   @Override
      protected void initGame() {
         // generate basic scene and logic elements
         initialize();
         
//         // testing particles
         Node foo = StaticLoader.loadJmeParticleSystem(
               new File("particle/purplefirejetflare.jme"),
               new File("particle/"));
         foo.setLocalScale(100f);
//         foo.setLocalTranslation(0,0,0);
         sceneRoot.attachChild(foo);         
         
         // commit.
         sceneRoot.updateRenderState();
         sceneRoot.updateGeometricState(0, true);
         
      }

   /**
    * Called once by initSystem()
    */
   private void initCam() {
      try {
         display = DisplaySystem.getDisplaySystem(
               this.getNewSettings().getRenderer());         
         display.createWindow(width, height, depth, freq, fullscreen);

         cam = display.getRenderer().createCamera(width, height);
      } catch (JmeException e) {
         e.printStackTrace();
         System.exit(1);
      }

      //set the background to black
      display.getRenderer().setBackgroundColor(ColorRGBA.black);

      display.getRenderer().setCamera(cam);
      cam.setFrustumPerspective(45.0f,
            (float)display.getWidth()/(float)display.getHeight(),
            1, 1000);

      cam.setFrame(
            new Vector3f(0,12,0),
            Vector3f.UNIT_X,
            Vector3f.UNIT_Y,
            Vector3f.UNIT_Z);
      cam.setFrustumFar(10000);
      cam.update();
   }

   /**
    * Called once by initGame()
    */
   private void initialize() {
      display.setTitle("Space Arena");
      sceneRoot = new Node();
      sceneRoot.setLightCombineMode(LightCombineMode.CombineClosestEnabled);
      buildOverheadCamera();
      setLogicTicksPerSecond(20);
      // private helper methods
      initZBuf();
      // does this even do anything?
      initMat();
      initLight();

      // apply the render states
      sceneRoot.updateRenderState();
   }
   
   /**
    * Called by initialize()
    */
   private void buildOverheadCamera()
   //uses a camNode
   {
      camNode = new CameraNode("Camera Node", cam);
      Quaternion q = new Quaternion();
      float angle = 0;
      angle -= 180;
      angle *= -1 * FastMath.DEG_TO_RAD;
      q.fromAngleAxis(angle, Vector3f.UNIT_Y);
      camNode.setLocalRotation(q);
      camNode.setCamera(cam);
      camNode.setLocalTranslation(new Vector3f(0, 0, 200));
   }

   /**
    * Called once by initialize()
    */
   private void initZBuf() {
      buf = display.getRenderer().createZBufferState();
      buf.setEnabled(true);
      buf.setFunction(ZBufferState.TestFunction.LessThan);
      sceneRoot.setRenderState(buf);
   }

   /**
    * Called once by initialize()
    */
   private void initMat() {
      // add a material state?
      mat = display.getRenderer().createMaterialState();
      mat.setEnabled(true);
      sceneRoot.setRenderState(mat);
   }

   /**
    * Called once by initialize()
    */
   private void initLight() {
      //Create a Basic Directional Light?
      DirectionalLight dl = new DirectionalLight();
      dl.setDirection(Vector3f.UNIT_Z);
      // does this even do anything?
      dl.setDiffuse(new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f));
      dl.setAmbient(new ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f));
      dl.setEnabled(true);
      // add a light state?
      LightState ls = display.getRenderer().createLightState();
      ls.setEnabled(true);
      ls.attach(dl);
      sceneRoot.setRenderState(ls);
      sceneRoot.updateRenderState();
      
   }

// *** Overrides
   
   @Override
   protected void render(float interpolation) {
      //update Overhead Camera
      camNode.updateWorldData(interpolation);
      // Clear the screen
      display.getRenderer().flush();
      display.getRenderer().clearBuffers();
      display.getRenderer().draw(sceneRoot);
   }

   @Override
   protected void update(float interpolation)
   {
      //check for keyboard input
      if (KeyBindingManager.getKeyBindingManager().isValidCommand("exit"))
      {
         finished = true;
      }

      
      sceneRoot.updateGeometricState(interpolation, true);   
   }

   @Override
   protected void reinit()
   {
      display.recreateWindow(width, height, depth, freq, fullscreen);
   }

   @Override
   protected void quit()
   {
      super.quit();
      System.exit(0);
   }

   @Override
   protected void cleanup()
   {
      // So far, unused?
   }

   @Override
   protected GameSettings getNewSettings()
   {
      boolean newNode = true;
      Preferences userPrefsRoot = Preferences.userRoot();
      try
      {
         newNode = !userPrefsRoot.nodeExists("");
      }
      catch (BackingStoreException bse) { }

      return new PreferencesGameSettings(userPrefsRoot.node(""), newNode,
         "game-defaults.properties");

   }
}

However, nothing appears at all! I even tried various translations and scaling factors. What am I doing wrong here?

Compare your code with BaseSimpleGame and see whats different.

Maybe a BlendState , ZBuffer or Light problem

I wouldn't suggest using FixedLogicrateGame at all. It has not been touched since a very long time and it's possible that its not compatible with many new changes in jME. I am sure that it's possible to extent StandardGame or any other variant to support fixed update intervals. The issue here is probably that the interpolation variable given to the root node update is sent as 0.0 which means that time never progresses -> particles never updated.

I dont know what could be incompatible, since you implement most things yourself anyway.

I think the problem is your update cycle.

FixedLogirateGame passes -1 as interpolation value into your update() method, so don't use that value.



public abstract class FixedLogicrateGame extends AbstractGame {
<snip>
            //main loop
            while (!finished && !display.isClosing()) {
                time1 = timer.getTime();
                loops = 0;

                while ((time1 - time0) > tickTime && loops < MAX_LOOPS) {
                    //handle input events prior to updating the scene
                    // - some applications may want to put this into update of the game state
                    InputSystem.update();

                    //update game state, do not use interpolation parameter
                    update(-1.0f);
                    time0 += tickTime;
                    loops++;
                }

                //If the game logic takes far too long, discard the pending
                // time
                if ((time1 - time0) > tickTime) time0 = time1 - tickTime;

                float percentWithinTick = Math.min(1.0f,
                        (float) (time1 - time0) / tickTime);
                //render scene with interpolation value
                render(percentWithinTick);

                //swap buffers
                display.getRenderer().displayBackBuffer();

                Thread.yield();
            }
<snip>