Can't move object from a private class extending InputAction (Phys #3) [Solved]

I dont think this is a physics problem so I am posting this here instead.



I am continuing to play with the physics lesson 3 code and I am trying to spawn spheres with a key-press.  I tied 'I' to a private class that calls createBall() (copy of createBox for spheres) and then does a getLocalTranslation().set(x,y,z) on the new sphere. I've printed out the location vector3f before and after the set and I see it going in, but no matter what I try the ball shows up at 0,0,0 (underneath the floor at that point) and falls for eternity.  Is there something I need to do for objects created this way?



Apologies for the lame question, this is one of those 'its obvious' things, but Ive stared at it for the last 4 hours and I'm caught in tunnel vision.  :oops:



Code:


package client;

import java.util.logging.Level;
import java.util.logging.Logger;


import com.jme.input.InputHandler;
import com.jme.input.KeyInput;
import com.jme.input.action.InputAction;
import com.jme.input.action.InputActionEvent;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.renderer.Renderer;
import com.jme.scene.Spatial;
import com.jme.scene.shape.Box;
import com.jme.scene.shape.Sphere;
import com.jme.scene.state.AlphaState;
import com.jme.scene.state.MaterialState;
import com.jmex.physics.DynamicPhysicsNode;
import com.jmex.physics.PhysicsSpace;
import com.jmex.physics.PhysicsUpdateCallback;
import com.jmex.physics.StaticPhysicsNode;
import com.jmex.physics.contact.MutableContactInfo;
import com.jmex.physics.material.Material;
import com.jmex.physics.util.SimplePhysicsGame;

/**
 * Learn about physics materials, friction, bounciness etc.
 *
 * @author Irrisor
 */
public class FrontEndGui extends SimplePhysicsGame {
   private DynamicPhysicsNode ball1;
   private InputHandler physicsStepInputHandler;

   private static final float ballForce = 750f;

    protected void simpleInitGame() {

      //root static object node
      StaticPhysicsNode staticNode = getPhysicsSpace().createStaticNode();
      rootNode.attachChild( staticNode );

      // first we will create the floor
      final Box visualFloorBox = new Box( "floor", new Vector3f(), 5, 0.25f, 10 );
      //tilt it a bit
      visualFloorBox.getLocalRotation().fromAngleNormalAxis( 0.3f, new Vector3f( 0, 0, -1 ) );
      staticNode.attachChild( visualFloorBox );

      // and create another part below
      final Box visualFloorBox2 = new Box( "floor", new Vector3f(), 5, 0.25f, 10 );
      visualFloorBox2.getLocalTranslation().set( 9.7f, -1.5f, 0 );
      staticNode.attachChild( visualFloorBox2 );

      //another part
      final Box visualFloorBox3 = new Box("floor", new Vector3f(),5,0.25f,10);
      visualFloorBox3.getLocalRotation().fromAngleNormalAxis(0.3f,new Vector3f(0,0,1));
      visualFloorBox3.getLocalTranslation().set( 19.4f, 0, 0 );
      staticNode.attachChild( visualFloorBox3 );

      //wall 1
      final Box visualWall1 = new Box("wall", new Vector3f(),15f,6,0.25f);
      visualWall1.getLocalTranslation().set(10f,0,-10);
      staticNode.attachChild(visualWall1);

      //wall 2
      final Box visualWall2 = new Box("wall", new Vector3f(),15f,6,0.25f);
      visualWall2.getLocalTranslation().set(10f,0,10);
      staticNode.attachChild(visualWall2);

      //wall 3
      final Box visualWall3 = new Box("wall", new Vector3f(),0.25f,2.5f,10);
      visualWall3.getLocalTranslation().set(-5f,3,0);
      staticNode.attachChild(visualWall3);

      //wall 4
      final Box visualWall4 = new Box("wall", new Vector3f(),0.25f,2.5f,10);
      visualWall4.getLocalTranslation().set(24f,3,0);
      staticNode.attachChild(visualWall4);

      //create the physics for the current static node
      staticNode.generatePhysicsGeometry();

      cam.setLocation(new Vector3f(0,10,10));
      cam.lookAt(new Vector3f(10,0,0),new Vector3f(0,1,0));


      // second we create a box - as we create multiple boxes this time the code moved into a separate method
      DynamicPhysicsNode dynamicNode = createBox();
      dynamicNode.computeMass();
      // the first box gets in the center above the floor
      dynamicNode.getLocalTranslation().set( 0, 5, 0 );
      // this box keeps the default material

      // ok first we will explore some predefined materials
      // lets create an ice block...
      final DynamicPhysicsNode iceQube = createBox();
      iceQube.setMaterial( Material.ICE );
      // changing material means changing desity
      // you may choose to compute the mass from the volume and density of an object
      iceQube.computeMass();
      // color the visual representation in transparent blue
      color( iceQube, new ColorRGBA( 0.5f, 0.5f, 0.9f, 0.6f ) );
      // move the iceQube besides the first box
      iceQube.getLocalTranslation().set( 0, 5, 1.5f );

      // ... a rubber ...
      final DynamicPhysicsNode rubber = createBox();
      rubber.setMaterial( Material.RUBBER );
      rubber.computeMass();
      // color the visual representation in yellow
      color( rubber, new ColorRGBA( 0.9f, 0.9f, 0.3f, 1 ) );
      // move the rubber on the other side of the first box
      rubber.getLocalTranslation().set( 0, 5, -1.5f );


      ball1 = createBall();
      ball1.getLocalTranslation().set(20,10,1);
      ball1.setMaterial(Material.RUBBER);
      ball1.computeMass();
      color(ball1,new ColorRGBA( 0.9f, 0.9f, 0.3f, 0.6f ));

      // forces must be applied for each physics step if you want a constant force applied
      // thus we create an input handler that gets invoked each physics step
      physicsStepInputHandler = new InputHandler();
      getPhysicsSpace().addToUpdateCallbacks( new PhysicsUpdateCallback() {
         public void beforeStep( PhysicsSpace space, float time ) {
            physicsStepInputHandler.update( time );
         }
         public void afterStep( PhysicsSpace space, float time ) {

         }
      } );

      // now we add an input action to move the sphere while a key is pressed
      physicsStepInputHandler.addAction( new MyInputAction( new Vector3f( ballForce, 0, 0 ) ),
         InputHandler.DEVICE_KEYBOARD, KeyInput.KEY_K, InputHandler.AXIS_NONE, true );

      physicsStepInputHandler.addAction( new MyInputAction( new Vector3f( -ballForce, 0, 0 ) ),
         InputHandler.DEVICE_KEYBOARD, KeyInput.KEY_H, InputHandler.AXIS_NONE, true );

      physicsStepInputHandler.addAction( new MyInputAction( new Vector3f( 0, 0, ballForce ) ),
         InputHandler.DEVICE_KEYBOARD, KeyInput.KEY_J, InputHandler.AXIS_NONE, true );

      physicsStepInputHandler.addAction( new MyInputAction( new Vector3f( 0, 0, -ballForce ) ),
         InputHandler.DEVICE_KEYBOARD, KeyInput.KEY_U, InputHandler.AXIS_NONE, true );

      physicsStepInputHandler.addAction( new SpawnNewBall(new Vector3f(0,20,0)),
         InputHandler.DEVICE_KEYBOARD, KeyInput.KEY_I, InputHandler.AXIS_NONE,true);

      // start paused - press P to start the action :)
      pause = true;
    }

    /**
     * Little helper method to color a spatial.
     *
     * @param spatial the spatial to be colored
     * @param color   desired color
     */
    private void color( Spatial spatial, ColorRGBA color ) {
      final MaterialState materialState = display.getRenderer().createMaterialState();
      materialState.setDiffuse( color );
      if ( color.a < 1 ) {
         final AlphaState alphaState = display.getRenderer().createAlphaState();
         alphaState.setEnabled( true );
         alphaState.setBlendEnabled( true );
         alphaState.setSrcFunction( AlphaState.SB_SRC_ALPHA );
         alphaState.setDstFunction( AlphaState.DB_ONE_MINUS_SRC_ALPHA );
         spatial.setRenderState( alphaState );
         spatial.setRenderQueueMode( Renderer.QUEUE_TRANSPARENT );
      }
      spatial.setRenderState( materialState );
    }

    /**
     * Create a box like known from Lesson2.
     *
     * @return a physics node containing a box
     */
    private DynamicPhysicsNode createBox() {
      DynamicPhysicsNode dynamicNode = getPhysicsSpace().createDynamicNode();
      rootNode.attachChild( dynamicNode );
      final Box visualFallingBox = new Box( "falling box", new Vector3f(), 0.5f, 0.5f, 0.5f );
      dynamicNode.attachChild( visualFallingBox );
      dynamicNode.generatePhysicsGeometry();
      return dynamicNode;
    }

    public DynamicPhysicsNode createBall() {
      DynamicPhysicsNode dynamicNode = getPhysicsSpace().createDynamicNode();
      rootNode.attachChild( dynamicNode );
      final Sphere visualFallingSphere = new Sphere( "falling sphere", 10, 10, 1.0f);
      dynamicNode.attachChild( visualFallingSphere );
      dynamicNode.generatePhysicsGeometry();
      return dynamicNode;
    }

    public void createNewBoulder() {
      final DynamicPhysicsNode ballNode = createBall();
      System.out.println("before set: " + ballNode.getLocalTranslation().toString());
      ballNode.getLocalTranslation().set(new Vector3f(10,20,0));
      System.out.println("after set: " + ballNode.getLocalTranslation().toString());
      ballNode.setMaterial(Material.IRON);
      ballNode.computeMass();
      color(ballNode,new ColorRGBA(0.7f,0.7f,0.7f,1.0f));
   }

   /** Class to spawn a ball
   */
   private class SpawnNewBall extends InputAction {

      private Vector3f location = null;
      private long lastTimeFired = new java.util.Date().getTime();

      public SpawnNewBall(Vector3f location) {
         this.location = location;
      }

      public void performAction(InputActionEvent evt) {
         long time = new java.util.Date().getTime();
         if((time - lastTimeFired) > 1000) {
            createNewBoulder();
            lastTimeFired = time;
         }
      }
   }


   /**
   * An action that get's invoked while a key is down.
   */
   private class MyInputAction extends InputAction {
      private final Vector3f direction;
      private final Vector3f appliedForce = new Vector3f();

      /**
      * The action get the node it should move and the direction it should move in.
      *
      * @param direction force that should be applied on each invocation of the action
      */
      public MyInputAction( Vector3f direction ) {
         // simply remember in member variables
         this.direction = direction;
      }

      /**
      * This method gets invoked upon key event
      *
      * @param evt more data about the event (we don't need it)
      */
      public void performAction( InputActionEvent evt ) {
         appliedForce.set( direction ).multLocal( evt.getTime() );
         // the really important line: apply a force to the moved node
         ball1.addForce( appliedForce );
      }
   }


    /**
     * The main method to allow starting this class as application.
     *
     * @param args command line arguments
     */
    public static void main( String[] args ) {
      Logger.getLogger( "" ).setLevel( Level.WARNING ); // to see the important stuff
      new FrontEndGui().start();
    }
}

Been messing with this more and I found a workaround which makes me ponder object creation in general.  I got it working by creating the ball ahead of time and setActive(false), then when I wanted it to show up I setActive(true).  This works if I am only after 1 ball, what if I want to create hundreds of balls when the user presses a key. Do I have to have them all generated up front ahead of time?  I cannot believe that, unless I create one ball and can clone it as many times as desired? Looking into that now…

hi there,

you are missing an

rootNode.updateGeometricState(0, true);



at the end of createNewBoulder().



If your create a new Object, add it to the scenegraph and move its location, you need to call updateGeometricState() once, or the object will stay at its intitial location.

Thank you!  Works as it should now.  :smiley: