title: How to make my character walk properly?
body: <p>I'm making a small 3D scene and the character can walk by pressing the WASD buttons but the animations that are playing are not correct and the character turns around so it looks like he is moonwalking when moving.
  <img src="https://i.stack.imgur.com/Icg1R.png" alt="enter image description here" /></p>
  <p>The control code for the buttons are</p>
  <pre><code>private void setupKeys() {
      inputManager.addMapping(&quot;wireframe&quot;, new KeyTrigger(KeyInput.KEY_T));
      inputManager.addListener(this, &quot;wireframe&quot;);
      inputManager.addMapping(&quot;CharLeft&quot;, new KeyTrigger(KeyInput.KEY_A));
      inputManager.addMapping(&quot;CharRight&quot;, new KeyTrigger(KeyInput.KEY_D));
      inputManager.addMapping(&quot;CharUp&quot;, new KeyTrigger(KeyInput.KEY_W));
      inputManager.addMapping(&quot;CharDown&quot;, new KeyTrigger(KeyInput.KEY_S));
      inputManager.addMapping(&quot;CharSpace&quot;,
              new KeyTrigger(KeyInput.KEY_RETURN));
      inputManager
              .addMapping(&quot;CharShoot&quot;, new KeyTrigger(KeyInput.KEY_SPACE));
      inputManager.addListener(this, &quot;CharLeft&quot;);
      inputManager.addListener(this, &quot;CharRight&quot;);
      inputManager.addListener(this, &quot;CharUp&quot;);
      inputManager.addListener(this, &quot;CharDown&quot;);
      inputManager.addListener(this, &quot;CharSpace&quot;);
      inputManager.addListener(this, &quot;CharShoot&quot;);
  }
  </code></pre>
  <p>And the update loop looks like this</p>
  <pre><code>public void simpleUpdate(float tpf) {
      Vector3f camDir = cam.getDirection().clone().multLocal(0.1f);
      Vector3f camLeft = cam.getLeft().clone().multLocal(0.1f);
      camDir.y = 0;
      camLeft.y = 0;
      walkDirection.set(0, 0, 0);
      if (left) {
          walkDirection.addLocal(camLeft);
      }
      if (right) {
          walkDirection.addLocal(camLeft.negate());
      }
      if (up) {
          walkDirection.addLocal(camDir);
      }
      if (down) {
          walkDirection.addLocal(camDir.negate());
      }
      if (!character.onGround()) {
          airTime = airTime + tpf;
      } else {
          airTime = 0;
      }
      if (walkDirection.length() == 0) {
          if (!&quot;Idle1&quot;.equals(animationChannel.getAnimationName())) {
              animationChannel.setAnim(&quot;Idle1&quot;, 1f);
          }
      } else {
          character.setViewDirection(walkDirection);
          if (airTime &gt; .3f) {
              if (!&quot;stand&quot;.equals(animationChannel.getAnimationName())) {
                  animationChannel.setAnim(&quot;stand&quot;);
              }
          } else if (!&quot;Walk&quot;.equals(animationChannel.getAnimationName())) {
              animationChannel.setAnim(&quot;Walk&quot;, 0.7f);
          }
      }
      character.setWalkDirection(walkDirection);
  }
  </code></pre>
  <p>I don't understand what is wrong since it is actually so close to working, all I need is that the character doesn't turns around and plays the correct animation when walking. Do you have any idea what the problem might be?</p>
  <p>The entire program is</p>
  <pre><code>package adventure;
  
  import java.applet.Applet;
  import com.jme3.math.Quaternion;
  import com.jme3.math.FastMath;
  import java.applet.AudioClip;
  import java.awt.BorderLayout;
  import java.awt.Dimension;
  import java.awt.Image;
  import java.awt.TextArea;
  import java.net.MalformedURLException;
  import java.net.URL;
  import java.util.ArrayList;
  import java.util.List;
  import com.jme3.material.RenderState.FaceCullMode;
  import javax.swing.JFrame;
  import javax.swing.JPanel;
  import com.jme3.renderer.queue.RenderQueue.ShadowMode;
  import com.jme3.animation.AnimChannel;
  import com.jme3.animation.AnimControl;
  import com.jme3.animation.AnimEventListener;
  import com.jme3.animation.LoopMode;
  import com.jme3.app.SimpleApplication;
  import com.jme3.asset.BlenderKey;
  import com.jme3.asset.TextureKey;
  import com.jme3.asset.plugins.ZipLocator;
  import com.jme3.bullet.BulletAppState;
  import com.jme3.bullet.PhysicsSpace;
  import com.jme3.bullet.collision.PhysicsCollisionEvent;
  import com.jme3.bullet.collision.PhysicsCollisionListener;
  import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
  import com.jme3.bullet.collision.shapes.CollisionShape;
  import com.jme3.bullet.collision.shapes.SphereCollisionShape;
  import com.jme3.bullet.control.CharacterControl;
  import com.jme3.bullet.control.RigidBodyControl;
  import com.jme3.bullet.util.CollisionShapeFactory;
  import com.jme3.effect.ParticleEmitter;
  import com.jme3.effect.ParticleMesh.Type;
  import com.jme3.effect.shapes.EmitterSphereShape;
  import com.jme3.input.ChaseCamera;
  import com.jme3.input.KeyInput;
  import com.jme3.input.controls.ActionListener;
  import com.jme3.input.controls.KeyTrigger;
  import com.jme3.light.DirectionalLight;
  import com.jme3.material.Material;
  import com.jme3.math.ColorRGBA;
  import com.jme3.math.Vector2f;
  import com.jme3.math.Vector3f;
  import com.jme3.post.FilterPostProcessor;
  import com.jme3.post.filters.BloomFilter;
  import com.jme3.renderer.Camera;
  import com.jme3.renderer.queue.RenderQueue.ShadowMode;
  import com.jme3.scene.Geometry;
  import com.jme3.scene.Node;
  import com.jme3.scene.Spatial;
  import com.jme3.scene.shape.Box;
  import com.jme3.scene.shape.Sphere;
  import com.jme3.scene.shape.Sphere.TextureMode;
  import com.jme3.system.AppSettings;
  import com.jme3.system.JmeCanvasContext;
  import com.jme3.terrain.geomipmap.TerrainLodControl;
  import com.jme3.terrain.geomipmap.TerrainQuad;
  import com.jme3.terrain.heightmap.AbstractHeightMap;
  import com.jme3.terrain.heightmap.ImageBasedHeightMap;
  import com.jme3.texture.Texture;
  import com.jme3.texture.Texture.WrapMode;
  import com.jme3.util.SkyFactory;
  
  public class MountainWorld extends SimpleApplication implements ActionListener,
          PhysicsCollisionListener, AnimEventListener, Playable {
      
      
      
      
      
      
        /** Prepare Materials */
        Material wall_mat;
        Material stone_mat;
        Material floor_mat;
       
        /** Prepare geometries and physical nodes for bricks and cannon balls. */
        private RigidBodyControl    brick_phy;
        private static final Box    box;
        private RigidBodyControl    ball_phy;
        private static final Sphere sphere;
        private RigidBodyControl    floor_phy;
        private static final Box    floor;
       
        /** dimensions used for bricks and wall */
        private static final float brickLength = 0.48f;
        private static final float brickWidth  = 0.24f;
        private static final float brickHeight = 0.12f;
       
        static {
          /** Initialize the cannon ball geometry */
          sphere = new Sphere(32, 32, 0.4f, true, false);
          sphere.setTextureMode(TextureMode.Projected);
          /** Initialize the brick geometry */
          box = new Box(Vector3f.ZERO, brickLength, brickHeight, brickWidth);
          box.scaleTextureCoordinates(new Vector2f(1f, .5f));
          /** Initialize the floor geometry */
          floor = new Box(Vector3f.ZERO, 100f, 0.1f, 50f);
          floor.scaleTextureCoordinates(new Vector2f(3, 6));
        }
      
      
      
      
      
      
      
      private static World world;
      private static Person person;
      private static Player dplayer;
      private static TextArea textarea;
      private BulletAppState bulletAppState;
      private AnimChannel channel;
      private AnimControl control;
      // character
      CharacterControl character;
      Node model;
      // temp vectors
      Vector3f walkDirection = new Vector3f();
      // terrain
      TerrainQuad terrain;
      RigidBodyControl terrainPhysicsNode;
      // Materials
      Material matRock;
      Material matBullet;
      // animation
      AnimChannel animationChannel;
      AnimChannel shootingChannel;
      AnimControl animationControl;
      float airTime = 0;
      // camera
      boolean left = false, right = false, up = false, down = false;
      ChaseCamera chaseCam;
      // bullet
      Sphere bullet;
      SphereCollisionShape bulletCollisionShape;
      // explosion
      ParticleEmitter effect;
      // brick wall
      Box brick;
      float bLength = 0.8f;
      float bWidth = 0.4f;
      float bHeight = 0.4f;
      FilterPostProcessor fpp;
      private Spatial sceneModel;
  
      private RigidBodyControl landscape;
      public static void main(String[] args) {
          java.awt.EventQueue.invokeLater(new Runnable() {
              public void run() {
                  AppSettings settings = new AppSettings(true);
                  settings.setWidth(850);
                  settings.setHeight(440);
  
                  MountainWorld canvasApplication = new MountainWorld();
                  canvasApplication.setSettings(settings);
                  canvasApplication.createCanvas(); // create canvas!
                  JmeCanvasContext ctx = (JmeCanvasContext) canvasApplication
                          .getContext();
                  ctx.setSystemListener(canvasApplication);
                  Dimension dim = new Dimension(640, 480);
                  ctx.getCanvas().setPreferredSize(dim);
  
                  JFrame window = new JFrame(&quot;Mountain World&quot;);
                  window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  
                  JPanel panel = new JPanel(new BorderLayout()); // a panel
                  world = new DungeonWorld(canvasApplication);
                  person = new Person(world, &quot;You&quot;, null);
                  dplayer = new Player(world, person);
                  Commands commands = new Commands(person);
                  textarea = new TextArea(&quot;&quot;, 10, 60,
                          TextArea.SCROLLBARS_VERTICAL_ONLY);
                  textarea.append(&quot;You are in a mountain. The trolls live here.\n&quot;);
                  textarea.setEditable(false);
                  panel.add(&quot;West&quot;, ctx.getCanvas());
                  panel.add(&quot;East&quot;, commands);
                  panel.add(&quot;South&quot;, textarea);
                  window.add(panel);
                  window.pack();
                  window.setVisible(true);
                  canvasApplication.startCanvas();
  
              }
          });
      }
  
      @Override
      public void simpleInitApp() {
          bulletAppState = new BulletAppState();
          bulletAppState.setThreadingType(BulletAppState.ThreadingType.PARALLEL);
          stateManager.attach(bulletAppState);
          setupKeys();
          //prepareBullet();
          //prepareEffect();
          createLight();
          //createSky();
          initMaterials();
          initFloor();
          //createTerrain();
          //createWall();
          createCharacters();
          setupChaseCamera();
          setupAnimationController();
          setupFilter();
      }
       /** Make a solid floor and add it to the scene. */
        public void initFloor() {
          Geometry floor_geo = new Geometry(&quot;Floor&quot;, floor);
          floor_geo.setMaterial(floor_mat);
          floor_geo.setLocalTranslation(0, -0.1f, 0);
          this.rootNode.attachChild(floor_geo);
          /* Make the floor physical with mass 0.0f! */
          floor_phy = new RigidBodyControl(0.0f);
          floor_geo.addControl(floor_phy);
          bulletAppState.getPhysicsSpace().add(floor_phy);
        }
      
        /** Initialize the materials used in this scene. */
        public void initMaterials() {
          wall_mat = new Material(assetManager, &quot;Common/MatDefs/Misc/Unshaded.j3md&quot;);
          TextureKey key = new TextureKey(&quot;Textures/Terrain/BrickWall/BrickWall.jpg&quot;);
          key.setGenerateMips(true);
          Texture tex = assetManager.loadTexture(key);
          wall_mat.setTexture(&quot;ColorMap&quot;, tex);
       
          stone_mat = new Material(assetManager, &quot;Common/MatDefs/Misc/Unshaded.j3md&quot;);
          TextureKey key2 = new TextureKey(&quot;Textures/Terrain/Rock/Rock.PNG&quot;);
          key2.setGenerateMips(true);
          Texture tex2 = assetManager.loadTexture(key2);
          stone_mat.setTexture(&quot;ColorMap&quot;, tex2);
       
          floor_mat = new Material(assetManager, &quot;Common/MatDefs/Misc/Unshaded.j3md&quot;);
          TextureKey key3 = new TextureKey(&quot;Textures/Terrain/Pond/Pond.jpg&quot;);
          key3.setGenerateMips(true);
          Texture tex3 = assetManager.loadTexture(key3);
          tex3.setWrap(WrapMode.Repeat);
          floor_mat.setTexture(&quot;ColorMap&quot;, tex3);
        }
        
        
      private void setupFilter() {
          FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
          BloomFilter bloom = new BloomFilter(BloomFilter.GlowMode.Objects);
          fpp.addFilter(bloom);
          viewPort.addProcessor(fpp);
      }
  
      private PhysicsSpace getPhysicsSpace() {
          return bulletAppState.getPhysicsSpace();
      }
  
      private void setupKeys() {
          inputManager.addMapping(&quot;wireframe&quot;, new KeyTrigger(KeyInput.KEY_T));
          inputManager.addListener(this, &quot;wireframe&quot;);
          inputManager.addMapping(&quot;CharLeft&quot;, new KeyTrigger(KeyInput.KEY_A));
          inputManager.addMapping(&quot;CharRight&quot;, new KeyTrigger(KeyInput.KEY_D));
          inputManager.addMapping(&quot;CharUp&quot;, new KeyTrigger(KeyInput.KEY_W));
          inputManager.addMapping(&quot;CharDown&quot;, new KeyTrigger(KeyInput.KEY_S));
          inputManager.addMapping(&quot;CharSpace&quot;,
                  new KeyTrigger(KeyInput.KEY_RETURN));
          inputManager
                  .addMapping(&quot;CharShoot&quot;, new KeyTrigger(KeyInput.KEY_SPACE));
          inputManager.addListener(this, &quot;CharLeft&quot;);
          inputManager.addListener(this, &quot;CharRight&quot;);
          inputManager.addListener(this, &quot;CharUp&quot;);
          inputManager.addListener(this, &quot;CharDown&quot;);
          inputManager.addListener(this, &quot;CharSpace&quot;);
          inputManager.addListener(this, &quot;CharShoot&quot;);
      }
  
      private void createWall() {
          float xOff = -144;
          float zOff = -40;
          float startpt = bLength / 4 - xOff;
          float height = 6.1f;
          brick = new Box(Vector3f.ZERO, bLength, bHeight, bWidth);
          brick.scaleTextureCoordinates(new Vector2f(1f, .5f));
          for (int j = 0; j &lt; 15; j++) {
              for (int i = 0; i &lt; 4; i++) {
                  Vector3f vt = new Vector3f(i * bLength * 2 + startpt, bHeight
                          + height, zOff);
                  addBrick(vt);
              }
              startpt = -startpt;
              height += 1.01f * bHeight;
          }
      }
  
      private void addBrick(Vector3f ori) {
          Geometry reBoxg = new Geometry(&quot;brick&quot;, brick);
          reBoxg.setMaterial(matBullet);
          reBoxg.setLocalTranslation(ori);
          reBoxg.addControl(new RigidBodyControl(1.5f));
          reBoxg.setShadowMode(ShadowMode.CastAndReceive);
          this.rootNode.attachChild(reBoxg);
          this.getPhysicsSpace().add(reBoxg);
      }
  
      private void prepareBullet() {
          bullet = new Sphere(32, 32, 0.4f, true, false);
          bullet.setTextureMode(TextureMode.Projected);
          bulletCollisionShape = new SphereCollisionShape(0.4f);
          matBullet = new Material(getAssetManager(),
                  &quot;Common/MatDefs/Misc/Unshaded.j3md&quot;);
          matBullet.setColor(&quot;Color&quot;, ColorRGBA.Green);
          // matBullet.setColor(&quot;m_GlowColor&quot;, ColorRGBA.Green);
          getPhysicsSpace().addCollisionListener(this);
      }
  
      private void prepareEffect() {
          int COUNT_FACTOR = 1;
          float COUNT_FACTOR_F = 1f;
          effect = new ParticleEmitter(&quot;Flame&quot;, Type.Triangle, 32 * COUNT_FACTOR);
          effect.setSelectRandomImage(true);
          effect.setStartColor(new ColorRGBA(1f, 0.4f, 0.05f,
                  (float) (1f / COUNT_FACTOR_F)));
          effect.setEndColor(new ColorRGBA(.4f, .22f, .12f, 0f));
          effect.setStartSize(1.3f);
          effect.setEndSize(2f);
          effect.setShape(new EmitterSphereShape(Vector3f.ZERO, 1f));
          effect.setParticlesPerSec(0);
          effect.setGravity(0, -5, 0);
          effect.setLowLife(.4f);
          effect.setHighLife(.5f);
          effect.setInitialVelocity(new Vector3f(0, 7, 0));
          effect.setVelocityVariation(1f);
          effect.setImagesX(2);
          effect.setImagesY(2);
          Material mat = new Material(assetManager,
                  &quot;Common/MatDefs/Misc/Particle.j3md&quot;);
          mat.setTexture(&quot;Texture&quot;,
                  assetManager.loadTexture(&quot;Effects/Explosion/flame.png&quot;));
          effect.setMaterial(mat);
          // effect.setLocalScale(100);
          rootNode.attachChild(effect);
      }
  
      private void createLight() {
          Vector3f direction = new Vector3f(-0.1f, -0.7f, -1).normalizeLocal();
          DirectionalLight dl = new DirectionalLight();
          dl.setDirection(direction);
          dl.setColor(new ColorRGBA(1f, 1f, 1f, 1.0f));
          rootNode.addLight(dl);
      }
  
      private void createSky() {
          rootNode.attachChild(SkyFactory.createSky(assetManager,
                  &quot;Textures/Sky/Bright/BrightSky.dds&quot;, false));
      }
  
      private void createTerrain2() {
          matRock = new Material(assetManager,
                  &quot;Common/MatDefs/Terrain/TerrainLighting.j3md&quot;);
          matRock.setBoolean(&quot;useTriPlanarMapping&quot;, false);
          matRock.setBoolean(&quot;WardIso&quot;, true);
          matRock.setTexture(&quot;AlphaMap&quot;,
                  assetManager.loadTexture(&quot;Textures/Terrain/splat/alphamap.png&quot;));
          Texture heightMapImage = assetManager
                  .loadTexture(&quot;Textures/Terrain/splat/mountains512.png&quot;);
          Texture grass = assetManager
                  .loadTexture(&quot;Textures/Terrain/splat/grass.jpg&quot;);
          grass.setWrap(WrapMode.Repeat);
          matRock.setTexture(&quot;DiffuseMap&quot;, grass);
          matRock.setFloat(&quot;DiffuseMap_0_scale&quot;, 64);
          Texture dirt = assetManager
                  .loadTexture(&quot;Textures/Terrain/splat/dirt.jpg&quot;);
          dirt.setWrap(WrapMode.Repeat);
          matRock.setTexture(&quot;DiffuseMap_1&quot;, dirt);
          matRock.setFloat(&quot;DiffuseMap_1_scale&quot;, 16);
          Texture rock = assetManager
                  .loadTexture(&quot;Textures/Terrain/splat/road.jpg&quot;);
          rock.setWrap(WrapMode.Repeat);
          matRock.setTexture(&quot;DiffuseMap_2&quot;, rock);
          matRock.setFloat(&quot;DiffuseMap_2_scale&quot;, 128);
          Texture normalMap0 = assetManager
                  .loadTexture(&quot;Textures/Terrain/splat/grass_normal.jpg&quot;);
          normalMap0.setWrap(WrapMode.Repeat);
          Texture normalMap1 = assetManager
                  .loadTexture(&quot;Textures/Terrain/splat/dirt_normal.png&quot;);
          normalMap1.setWrap(WrapMode.Repeat);
          Texture normalMap2 = assetManager
                  .loadTexture(&quot;Textures/Terrain/splat/road_normal.png&quot;);
          normalMap2.setWrap(WrapMode.Repeat);
          matRock.setTexture(&quot;NormalMap&quot;, normalMap0);
          matRock.setTexture(&quot;NormalMap_1&quot;, normalMap2);
          matRock.setTexture(&quot;NormalMap_2&quot;, normalMap2);
  
          AbstractHeightMap heightmap = null;
          try {
              heightmap = new ImageBasedHeightMap(heightMapImage.getImage(),
                      0.25f);
              heightmap.load();
  
          } catch (Exception e) {
              e.printStackTrace();
          }
  
          terrain = new TerrainQuad(&quot;terrain&quot;, 65, 513, heightmap.getHeightMap());
          List&lt;Camera&gt; cameras = new ArrayList&lt;Camera&gt;();
          cameras.add(getCamera());
          TerrainLodControl control = new TerrainLodControl(terrain, cameras);
          terrain.addControl(control);
          terrain.setMaterial(matRock);
          terrain.setLocalScale(new Vector3f(2, 2, 2));
  
          terrainPhysicsNode = new RigidBodyControl(
                  CollisionShapeFactory.createMeshShape(terrain), 0);
          terrain.addControl(terrainPhysicsNode);
          rootNode.attachChild(terrain);
          getPhysicsSpace().add(terrainPhysicsNode);
      }
  
      private void createTerrain() {
  
  
           assetManager.registerLocator(&quot;town.zip&quot;, ZipLocator.class);
           sceneModel = assetManager.loadModel(&quot;main.scene&quot;);
          //sceneModel = assetManager.loadModel(&quot;Scenes/ManyLights/Main.scene&quot;);
          sceneModel.setLocalScale(2f);
          //initFloor();
          // We set up collision detection for the scene by creating a
          // compound collision shape and a static RigidBodyControl with mass
          // zero.
          CollisionShape sceneShape = CollisionShapeFactory
                  .createMeshShape((Node) sceneModel);
          landscape = new RigidBodyControl(sceneShape, 0);
          sceneModel.addControl(landscape);
          List&lt;Camera&gt; cameras = new ArrayList&lt;Camera&gt;();
          cameras.add(getCamera());
          rootNode.attachChild(sceneModel);
      }
      
      private void createCharacters() {
          CapsuleCollisionShape capsule = new CapsuleCollisionShape(0.0f, 0.0f);
          character = new CharacterControl(capsule, 0.01f);
          model = (Node) assetManager.loadModel(&quot;Models/Ninja/Ninja.mesh.xml&quot;);
          float scale = 0.25f;
          model.scale(0.05f, 0.05f, 0.05f);
          model.addControl(character);
          character.setPhysicsLocation(new Vector3f(0, 0f, 0));
          model.setShadowMode(ShadowMode.CastAndReceive);
          character.setViewDirection(new Vector3f(1, 0, 0));
          rootNode.attachChild(model);
          getPhysicsSpace().add(character);
  
          //BlenderKey blenderKey = new BlenderKey(&quot;Models/Oto/Oto.mesh.xml&quot;);
  
          //Spatial man = (Spatial) assetManager.loadModel(blenderKey);
          //man.setLocalTranslation(new Vector3f(-140, 12.5f, -10));
  
          // man.setShadowMode(ShadowMode.CastAndReceive);
          //rootNode.attachChild(man);
  
      }
  
      private void setupChaseCamera() {
          flyCam.setEnabled(false);
          chaseCam = new ChaseCamera(cam, model, inputManager);
      }
  
      private void setupAnimationController() {
          animationControl = model.getControl(AnimControl.class);
          animationControl.addListener(this);
          animationChannel = animationControl.createChannel();
          // shootingChannel = animationControl.createChannel();
          // shootingChannel.addBone(animationControl.getSkeleton().getBone(
          // &quot;uparm.right&quot;));
          // shootingChannel.addBone(animationControl.getSkeleton().getBone(
          // &quot;arm.right&quot;));
          // shootingChannel.addBone(animationControl.getSkeleton().getBone(
          // &quot;hand.right&quot;));
      }
  
      @Override
      public void simpleUpdate(float tpf) {
          Vector3f camDir = cam.getDirection().clone().multLocal(0.1f);
          Vector3f camLeft = cam.getLeft().clone().multLocal(0.1f);
          camDir.y = 0;
          camLeft.y = 0;
          walkDirection.set(0, 0, 0);
          if (left) {
              walkDirection.addLocal(camLeft);
          }
          if (right) {
              walkDirection.addLocal(camLeft.negate());
          }
          if (up) {
              walkDirection.addLocal(camDir);
          }
          if (down) {
              walkDirection.addLocal(camDir.negate());
          }
          if (!character.onGround()) {
              airTime = airTime + tpf;
          } else {
              airTime = 0;
          }
          if (walkDirection.length() == 0) {
              if (!&quot;Idle1&quot;.equals(animationChannel.getAnimationName())) {
                  animationChannel.setAnim(&quot;Idle1&quot;, 1f);
              }
          } else {
              character.setViewDirection(walkDirection);
              if (airTime &gt; .3f) {
                  if (!&quot;stand&quot;.equals(animationChannel.getAnimationName())) {
                      animationChannel.setAnim(&quot;stand&quot;);
                  }
              } else if (!&quot;Walk&quot;.equals(animationChannel.getAnimationName())) {
                  animationChannel.setAnim(&quot;Walk&quot;, 0.7f);
              }
          }
          character.setWalkDirection(walkDirection);
      }
  
      public void onAction(String binding, boolean value, float tpf) {
          if (binding.equals(&quot;CharLeft&quot;)) {
              if (value) {
                  left = true;
              } else {
                  left = false;
              }
          } else if (binding.equals(&quot;CharRight&quot;)) {
              if (value) {
                  right = true;
              } else {
                  right = false;
              }
          } else if (binding.equals(&quot;CharUp&quot;)) {
              if (value) {
                  up = true;
              } else {
                  up = false;
              }
          } else if (binding.equals(&quot;CharDown&quot;)) {
              if (value) {
                  down = true;
              } else {
                  down = false;
              }
          } else if (binding.equals(&quot;CharSpace&quot;)) {
              character.jump();
          } else if (binding.equals(&quot;CharShoot&quot;) &amp;&amp; !value) {
              bulletControl();
          }
      }
  
      private void bulletControl() {
          shootingChannel.setAnim(&quot;Dodge&quot;, 0.1f);
          shootingChannel.setLoopMode(LoopMode.DontLoop);
          Geometry bulletg = new Geometry(&quot;bullet&quot;, bullet);
          bulletg.setMaterial(matBullet);
          bulletg.setShadowMode(ShadowMode.CastAndReceive);
          bulletg.setLocalTranslation(character.getPhysicsLocation().add(
                  cam.getDirection().mult(5)));
          RigidBodyControl bulletControl = new BombControl(bulletCollisionShape,
                  1);
          bulletControl.setCcdMotionThreshold(0.1f);
          bulletControl.setLinearVelocity(cam.getDirection().mult(80));
          bulletg.addControl(bulletControl);
          rootNode.attachChild(bulletg);
          getPhysicsSpace().add(bulletControl);
      }
  
      public void collision(PhysicsCollisionEvent event) {
          if (event.getObjectA() instanceof BombControl) {
              final Spatial node = event.getNodeA();
              effect.killAllParticles();
              effect.setLocalTranslation(node.getLocalTranslation());
              effect.emitAllParticles();
          } else if (event.getObjectB() instanceof BombControl) {
              final Spatial node = event.getNodeB();
              effect.killAllParticles();
              effect.setLocalTranslation(node.getLocalTranslation());
              effect.emitAllParticles();
          }
      }
  
      public void onAnimCycleDone(AnimControl control, AnimChannel channel,
              String animName) {
          if (channel == shootingChannel) {
              channel.setAnim(&quot;stand&quot;);
          }
      }
  
      public void onAnimChange(AnimControl control, AnimChannel channel,
              String animName) {
      }
  
      // Load an image from the net, making sure it has already been
      // loaded when the method returns
      public Image loadPicture(String imageName) {
          return null;
      }
  
      // Load and play a sound from /usr/local/hacks/sounds/
  
      public void playSound(String name) {
          URL u = null;
  
          try {
              u = new URL(&quot;file:&quot; + &quot;/usr/local/hacks/sounds/&quot; + name + &quot;.au&quot;);
          } catch (MalformedURLException e) {
          }
  
          AudioClip a = Applet.newAudioClip(u);
          a.play();
      }
  }
  </code></pre>
  <h2>Update</h2>
  <p>I changed one line of code to include the transform I had to do at the beginning:
  <code>character.setViewDirection(walkDirection.add(new Vector3f(1, 0, 0)));</code>
  i.e. I added the <code>Vector3f(1, 0, 0)</code> and that seems to have helped, now my character can move forward and backward seemingly perfectly.
  <img src="https://i.stack.imgur.com/JTvQN.png" alt="enter image description here" />
  But it is still not perfect when moving sideways although the &quot;moonwalking&quot; disappeared and maybe you can confirm that I did the right thing using the add method of the vector?</p>
  <h2>Update 2</h2>
  <p>When changing the vector to negate the Ninja is starting to move like he should!
  <code>character.setViewDirection(walkDirection.negate());</code></p>
  <p>e.g. in the update code</p>
  <pre><code>public void simpleUpdate(float tpf) {
      Vector3f camDir = cam.getDirection().clone().multLocal(0.1f);
      Vector3f camLeft = cam.getLeft().clone().multLocal(0.1f);
      camDir.y = 0;
      camLeft.y = 0;
      walkDirection.set(0, 0, 0);
      if (left) {
          walkDirection.addLocal(camLeft);
      }
      if (right) {
          walkDirection.addLocal(camLeft.negate());
      }
      if (up) {
          walkDirection.addLocal(camDir);
      }
      if (down) {
          walkDirection.addLocal(camDir.negate());
      }
      if (!character.onGround()) {
          airTime = airTime + tpf;
      } else {
          airTime = 0;
      }
      if (walkDirection.length() == 0) {
          if (!&quot;Idle1&quot;.equals(animationChannel.getAnimationName())) {
              animationChannel.setAnim(&quot;Idle1&quot;, 1f);
          }
      } else {            
          System.out.println(&quot;setting walk direction &quot; + walkDirection);
          character.setViewDirection(walkDirection.negate());
  
          if (airTime &gt; .3f) {
              if (!&quot;stand&quot;.equals(animationChannel.getAnimationName())) {
                  animationChannel.setAnim(&quot;stand&quot;);
              }
          } else if (!&quot;Walk&quot;.equals(animationChannel.getAnimationName())) {
              System.out.println(&quot;in walk Walk &quot;);
              animationChannel.setAnim(&quot;Walk&quot;, 0.7f);
          }
      }
      character.setWalkDirection(walkDirection);
  }
  </code></pre>
  <p><img src="https://i.stack.imgur.com/SiMC4.jpg" alt="enter image description here" /></p>
  <p>Now a remaining problem is to make the char jump and move over stairs.</p>