Hello animation null pointer exception may have been solved at last

.getControl(AnimControl.class);
returns null
how i can make it works?

You get the control from the spatial that has the control. The one you are trying to get it from does not have it.

https://jmonkeyengine.gitbooks.io/wiki-jmonkeyengine/advanced/traverse_scenegraph.html

can you tell from what you need to get control

or write code example

ogre exporter:
test.001.mesh.xml
try to get control from test.001

  playerModel = (Node)assetManager.loadModel("/Models/character.glb");
    sceneModel.setLocalScale(0.2f);
    rootNode.attachChild(playerModel);
    control = playerModel.getChild("test.001").getControl(AnimControl.class);
    
    playerModel.move(0, 0, 7f);

null

Now we see this question from time to time.

Yes, JME 3.3 uses a new animation system.
When you load an animated gltf/glb/ogre model with JME 3.3 it automatically loads them with the new animation system. You should look for AnimComposer instead of AnimControl.

You can find a bunch of examples here

You can find more examples if you search for AnimComposer in the JME GitHub page and this forum.

Edit:

See these as well:

can you write example for wiki with new animation api?
new hello animation

Actually we do have one done by nehon (he was the author of new animation system) but we have never put it on wiki I guess!

You are welcome to add it to the wiki and submit a PR if you want :slightly_smiling_face:

bug report
please make it vorks.

It’s not a bug. It’s a language barrier. You’re doing it wrong. You need to access the control from the spatial that holds the control.

You can not call .getControl from anywhere and expect it to find it. There may be many controls of the same type. You need to get it from the spatial that has the control.

This is about as good as it gets without someone coding it for you.

Edit: I will add that adding a breaking change right after deprecation is crap though.

from root node?
from level and character control?
forom level node?

package mygame;

import com.jme3.animation.AnimChannel;
import com.jme3.animation.AnimControl;
import com.jme3.animation.AnimEventListener;
import mygame.PlayerListener;
import com.jme3.animation.LoopMode;
import com.jme3.app.SimpleApplication;
import com.jme3.asset.plugins.ZipLocator;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
import com.jme3.bullet.collision.shapes.CollisionShape;
import com.jme3.bullet.control.CharacterControl;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.bullet.util.CollisionShapeFactory;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.light.AmbientLight;
import com.jme3.light.DirectionalLight;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Matrix3f;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.SceneGraphVisitor;
import com.jme3.scene.Spatial;
import java.util.ArrayList;
/**
 * This is the Main Class of your Game. You should only do initialization here.
 * Move your Logic into AppStates or Controls
 * @author normenhansen
 */



public class Main extends SimpleApplication  implements ActionListener, AnimEventListener {
  private Spatial sceneModel;
  private Node playerModel;
  private float rotationYOld;
  
  private BulletAppState bulletAppState;
  private RigidBodyControl landscape;
  private CharacterControl player;
  private Vector3f walkDirection = new Vector3f();
  private boolean left = false, right = false, up = false, down = false;
AnimChannel channel_walk;

  
  
  //Temporary vectors used on each frame.
  //They here to avoid instanciating new vectors on each frame
  private Vector3f camDir = new Vector3f();
  private Vector3f camLeft = new Vector3f();
  

    public static void main(String[] args) {
        Main app = new Main();
        app.start();
    }

    public void simpleInitApp() {
    /** Set up Physics */
    bulletAppState = new BulletAppState();
    stateManager.attach(bulletAppState);
    //bulletAppState.setDebugEnabled(true);

    // We re-use the flyby camera for rotation, while positioning is handled by physics
    viewPort.setBackgroundColor(new ColorRGBA(0.7f, 0.8f, 1f, 1f));
    flyCam.setMoveSpeed(100);
    setUpKeys();
    setUpLight();

    // We load the scene from the zip file and adjust its size.
    //assetManager.registerLocator("new-scene.zip", ZipLocator.class);
    sceneModel = assetManager.loadModel("/Models/untitled.glb");
    sceneModel.setLocalScale(2f);
    
    playerModel = (Node)assetManager.loadModel("/Models/character.glb");
    sceneModel.setLocalScale(0.2f);
    rootNode.attachChild(playerModel);
    
    playerModel.move(0, 0, 7f);
    

  //playerControl.addListener( this);
  /**
     * ANIMATION
     */


    
  

    //playerModel = assetManager.loadModel("Models/character.glb");
    
    // 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(sceneModel);
    landscape = new RigidBodyControl(sceneShape, 0);
    sceneModel.addControl(landscape);
    
    /**
     * We set up collision detection for the player by creating
     * a capsule collision shape and a CharacterControl.
     * The CharacterControl offers extra settings for
     * size, stepheight, jumping, falling, and gravity.
     * We also put the player in its starting position.
     */
    CapsuleCollisionShape capsuleShape = new CapsuleCollisionShape(1.5f, 3f, 1);
    player = new CharacterControl(capsuleShape, 0.05f);
    player.setJumpSpeed(50);
    player.setFallSpeed(50);

    
    // We attach the scene and the player to the rootnode and the physics space,
    // to make them appear in the game world.
    rootNode.attachChild(sceneModel);

    
    player.setSpatial(playerModel);

    bulletAppState.getPhysicsSpace().add(landscape);
    bulletAppState.getPhysicsSpace().add(player);

    // You can change the gravity of individual physics objects before or after
    //they are added to the PhysicsSpace, but it must be set before MOVING the
    //physics location.
    player.setGravity(new Vector3f(0,-30f,0));
    player.setPhysicsLocation(new Vector3f(4, 12, 4));
    
    
  }
    
        private void setUpLight() {
       // We add light so we see the scene
       AmbientLight al = new AmbientLight();
       al.setColor(ColorRGBA.White.mult(0.5f));
       rootNode.addLight(al);

       DirectionalLight dl = new DirectionalLight();
       dl.setColor(ColorRGBA.White);
       dl.setDirection(new Vector3f(2.8f, -2.8f, -2.8f).normalizeLocal());
       rootNode.addLight(dl);
  }
     
     private void setUpKeys() {
    inputManager.addMapping("Left", new KeyTrigger(KeyInput.KEY_A));
    inputManager.addMapping("Right", new KeyTrigger(KeyInput.KEY_D));
    inputManager.addMapping("Up", new KeyTrigger(KeyInput.KEY_W));
    
    
    
    
    inputManager.addMapping("Down", new KeyTrigger(KeyInput.KEY_S));
    inputManager.addMapping("Jump", new KeyTrigger(KeyInput.KEY_SPACE));
    inputManager.addListener(this, "Left");
    inputManager.addListener(this, "Right");
    inputManager.addListener(this, "Up");
    inputManager.addListener(this, "Down");
    inputManager.addListener(this, "Jump");
  }
     
  
  
  
  
       /** These are our custom actions triggered by key presses.
   * We do not walk yet, we just keep track of the direction the user pressed. */
  public void onAction(String binding, boolean isPressed, float tpf) {
    if (binding.equals("Left")) {
      left = isPressed;
    } else if (binding.equals("Right")) {
      right= isPressed;
    } else if (binding.equals("Up")) {
      up = isPressed;
    } else if (binding.equals("Down")) {
      down = isPressed;
    } else if (binding.equals("Jump")) {
      if (isPressed) { player.jump(new Vector3f(0,20f,0));}
    }
  }

    @Override
    public void simpleUpdate(float tpf) {
        camDir.set(cam.getDirection()).multLocal(0.6f);
        camLeft.set(cam.getLeft()).multLocal(0.4f);
        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());
        }
        player.setWalkDirection(walkDirection);
        cam.setLocation(player.getPhysicsLocation());
        
        //Quaternion  playerRotation =  new Quaternion(walkDirection.x,walkDirection.y,walkDirection.z,0);
        //playerModel.setLocalRotation(playerRotation);
       
       //player.setPhysicsLocation(player.getPhysicsLocation());
        playerModel.setLocalTranslation (player.getPhysicsLocation().x , player.getPhysicsLocation().y, player.getPhysicsLocation().z);
        
        
        /**
         * Rotation camera with chacarter
         */
        float[] angles = new float[3];
        cam.getRotation().toAngles(angles); // we get the cam angles here
        angles[0] = 0; // you don't want to rotate along the x-axis, so we set it to 0
        angles[2] = 0; // you don't want to rotate along the z-axis, so we set it to 0
        playerModel.setLocalRotation(playerModel.getLocalRotation().fromAngles(angles));

        //playerModel.setLocalRotation(q);
    }

    @Override
    public void onAnimCycleDone(AnimControl ac, AnimChannel ac1, String string) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void onAnimChange(AnimControl ac, AnimChannel ac1, String string) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }




    
    
    
}
playerModel = (Node)assetManager.loadModel("/Models/character.glb");

This is ok for testing but not for in game.

If you read the links from @Ali_RS you will see you need to convert the model to j3o using the binary exporter or SDK. Using 3.2.4 or earlier versions. This will add the AnimControl to the model.

This is a .glb file and you are loading it without converting so it is loaded with AnimComposer control. You can change your code to use the new system, or convert the model and use the old system.

Your control is under the playerModel node somewhere,

playerModel = (Node)assetManager.loadModel("/Models/character.glb");

You can also traverse this Node using a SceneGraphVisitorAdapter, edit for your use case,

        spatial.depthFirstTraversal(new SceneGraphVisitorAdapter() {
            @Override
            public void visit(Node node) {
                if (node.getControl(AnimControl.class) != null) {
                    animControl = node.getControl(AnimControl.class);
                    animControl.addListener(new AnimationEventListener());
                    animChannel = animControl.createChannel();
                }
            }
        });

The wiki will be updated on its v3.3.0 release. The current wiki is 3.2.4.

Thanks.

My old video

j3o -> armature -> object : control

 playerModel.depthFirstTraversal(new SceneGraphVisitorAdapter() {
            @Override
            public void visit(Node node) {
                if (node.getControl(AnimControl.class) != null) {
                    animControl = node.getControl(AnimControl.class);
                    animControl.addListener(new AnimationEventListener());
                    animChannel = animControl.createChannel();
                }
            }
        });
    
     animChannel.setAnim("run");  

 animChannel.setAnim("run");  

returns null

  playerModel = (Node)assetManager.loadModel("/Models/character.glb");
    sceneModel.setLocalScale(0.2f);
    rootNode.attachChild(playerModel);
    
    playerModel.move(0, 0, 7f);
    

  //playerControl.addListener( this);
  /**
     * ANIMATION
     */
 
        animControl = playerModel.getChild("test.001").getControl(AnimControl.class);
         animControl.addListener((AnimEventListener) this);
         animChannel = animControl.createChannel();

null

As @Ali_RS said it’s AnimComposer not AnimControl.

You are full of energy to code but must slow down to read. Relax. Slow down.

1 Like

My character model -> to j3o
don’t have aramature and anim control

how to fix it?

export bug? where anim control?

image
image
image
image
image