[SOLVED] Strange NPE

I have a class where I set up a BulletAppState and use it, then later I access the same variable from another class and suddenly it is null. I’m gonna be a bit annoyed if this is just a stupid mistake from my inexperience with java, but honestly that is what I expect.

First class (GameAppState)
[java]
public GameAppState(AppStateManager appStateManager, InputManager inputManager, AssetManager assetManager, Node rootNode, Camera cam) {
this.assetManager=assetManager;
this.rootNode=rootNode;
this.inputManager=inputManager;
this.appStateManager=appStateManager;

    /** Set up Physics */
    bulletAppState = new BulletAppState();
    appStateManager.attach(bulletAppState);
    //bulletAppState.getPhysicsSpace().enableDebug(assetManager);
    
    CapsuleCollisionShape capsuleShape = new CapsuleCollisionShape(1.5f, 6f, 1);
    player = new CharacterControl(capsuleShape, 0.05f);
    player.setJumpSpeed(20);
    player.setFallSpeed(30);
    player.setGravity(30);
    player.setPhysicsLocation(new Vector3f(0, 10, 0));
    
    //bulletAppState.getPhysicsSpace().add(landscape);
    bulletAppState.getPhysicsSpace().add(player);
}

public void addControl(Object obj) {
if(bulletAppState==null) {
System.out.println(“Null at addControl”);
}
bulletAppState.getPhysicsSpace().add(obj);
}

public BulletAppState getAppState() {
    System.out.print("AppState returning.");
    return bAppState;
}

[/java]

Second class (ChunkLoader),
Then in another class (I use the appstate on lines 50, 64, 120, and 122),
[java]package mygame;

import java.io.*;
import java.util.Arrays;
import java.util.Random;
import com.jme3.asset.AssetManager;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.collision.shapes.CollisionShape;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.bullet.util.CollisionShapeFactory;
import com.jme3.light.DirectionalLight;
import com.jme3.math.Vector3f;
import com.jme3.scene.BatchNode;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.debug.WireFrustum;
import java.util.Scanner;

/**
*

  • @author Isaac
    */
    public class ChunkLoader {

    private float R = 1.01f;
    private float W;
    private float S;
    private Double h;
    private float H;
    private float X;
    private float Z;
    private int o;
    private int p;

    public BatchNode batch2;
    private Spatial hexModel;
    private RigidBodyControl landscape;
    WireFrustum frustum;
    Geometry frustumMdl;
    private Vector3f[] points;
    private AssetManager assetManager;
    private Node rootNode;
    private BulletAppState bulletAppState;
    private GameAppState gAppState;
    public ChunkLoader(AssetManager assetManager, Node rootNode) {
    this.assetManager=assetManager;
    this.rootNode=rootNode;

     gAppState = new GameAppState();
    

    }

    String[] hexBuild = new String[32768];
    private int columnCounter;
    private int rowCounter;
    private int verticleCounter;
    private Integer currentHex;
    private String toStringVar = “0”;

    public void loadChunk(String fileName) throws IOException {

     batch2 = new BatchNode("theBatchNode1");
     
     bulletAppState = gAppState.getAppState();
     
     columnCounter = 0;
     rowCounter = 0;
     verticleCounter = 0;
     
     String file = fileName;
     SystemSave chunkLoad = new SystemSave();
     
     try {
         hexBuild = chunkLoad.gridBuilder(file);
     } catch(IOException a) {
         System.out.println("Chunk load failed.");
     }
     
     for(int l = 0; l<32768; l++) {
         rowCounter++;
         if(rowCounter == 63) {
             columnCounter++;
             rowCounter = 0;
         }
         if(columnCounter == 63) {
             verticleCounter++;
             columnCounter = 0;
         }
         
         toStringVar = hexBuild[l];
         currentHex = Integer.parseInt(toStringVar);
         
         if(currentHex==1) {
             makeHex();
         }
     }
     
     DirectionalLight sun = new DirectionalLight();
     sun.setDirection(new Vector3f(-0.1f, -0.7f, -1.0f).normalizeLocal());
     rootNode.addLight(sun);
     
     batch2.batch();
     rootNode.attachChild(batch2);
    

    }

    private void makeHex() {

     hexModel = assetManager.loadModel("Models/hexfade_02/hexfade_02.j3o");
     
     CollisionShape sceneShape =
         CollisionShapeFactory.createMeshShape(hexModel);
     landscape = new RigidBodyControl(sceneShape, 0);
     
     batch2.attachChild(hexModel);
     hexLocation();
     hexModel.setLocalTranslation(Z, (verticleCounter*.25f)+.01f, X);
     hexModel.addControl(landscape);
     if (bulletAppState==null) {
         System.out.println("bulletAppState null in ChunkLoader");
         gAppState.getAppState();
     }
     gAppState.addControl(landscape);
    

    }

    private void hexLocation() {

     W = 2*R;
     S = 1.5f*R;
     h = Math.sqrt(3)*R;
     H = h.floatValue();
     X = ((rowCounter))*S;
     Z = (((columnCounter))*H)+(((rowCounter))%2)*(H/2);
    

    }
    }
    [/java]

I've tried changing my hierarchy so that they all inherit from my main method, and I've tried several arrangements of methods and code. Any help is appreciated.

The issue looks like your class with the NPE never sets things up properly… which is ok because really it should probably have a reference passed in from somewhere else.

The app state you post at the top has a constructor with lots of parameters but when you create it inside the other class you are using a constructor with no parameters… so it can’t possibly have any of the useful references it needs.

These are really basic object oriented programming issues (not even Java specific).

Programming a 3D game is hard. Learning Java is hard. Doing both at the same time is nearly impossible.

@pspeed lol, I don’t think I messed up quite that bad (sorry for not including this in the first post). Here is a very relevant section from my main. This happens before the empty constructor is called. I included the empty constructor so I wouldn’t remake the BulletAppState. Was that okay to do?

[java]if (gameState == false) // attach appstate only once
{
GameAppState g = new GameAppState(appStateManager, inputManager, assetManager, rootNode, cam);
stateManager.attach(g);
g.initialize(stateManager, this);
g.setEnabled(true);

        gameState = true;
    }[/java] 

And trust me, I realize its hard. But the best way to learn something is dive in and do it. That or help other people learn and I don’t quite feel competent enough to give back to the community here. Give me a another few months and I’ll be there though, I think.

In your “other class”, the one you say has all of the NPEs, you have:
gAppState = new GameAppState();

That gAppState cannot possible have all of the stuff that it needs to not have NPEs. Either pass in the proper gAppState (instead of recreating it) or get it from the state manager.

Or if this is not the real code in which case we can’t possibly help.

This is my full GameAppState code, I tried to avoid putting it all on here…but here goes. It seems like what you are saying is that even if I use the full constructor earlier, if I don’t include all the same information in a later constructor I will get a NPE.

[java]package mygame;

import com.jme3.app.SimpleApplication;
import com.jme3.app.Application;
import com.jme3.app.state.AppState;
import com.jme3.app.state.AppStateManager;
import com.jme3.app.state.AbstractAppState;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.AnalogListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.input.InputManager;
import com.jme3.asset.AssetManager;
import com.jme3.scene.Node;
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.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera;
/**
*

  • @author Isaac
    */
    public class GameAppState extends AbstractAppState {

    protected Camera cam;
    private SimpleApplication app;
    protected boolean initialized = false;
    protected AppStateManager menuAppState;
    protected boolean active = true;
    private InputManager inputManager;
    private AssetManager assetManager;
    private Node rootNode;
    private boolean worldBuilt = false;
    private BulletAppState bulletAppState;
    public BulletAppState bAppState;
    private AppStateManager appStateManager;
    private CharacterControl player;
    private Vector3f walkDirection = new Vector3f();
    private boolean left = false, right = false, up = false, down = false;

    @Override
    public void initialize(AppStateManager stateManager, Application app) {
    super.initialize(stateManager, app);
    this.app = (SimpleApplication)app;
    }

    @Override
    public void cleanup() {
    super.cleanup();
    }

    @Override
    public void setEnabled(boolean enabled) {
    super.setEnabled(enabled);
    if(enabled){
    initKeys();
    } else {

     }
    

    }

    public GameAppState(AppStateManager appStateManager, InputManager inputManager, AssetManager assetManager, Node rootNode, Camera cam) {
    this.assetManager=assetManager;
    this.rootNode=rootNode;
    this.inputManager=inputManager;
    this.appStateManager=appStateManager;

     /** Set up Physics */
     bulletAppState = new BulletAppState();
     appStateManager.attach(bulletAppState);
     //bulletAppState.getPhysicsSpace().enableDebug(assetManager);
     
     CapsuleCollisionShape capsuleShape = new CapsuleCollisionShape(1.5f, 6f, 1);
     player = new CharacterControl(capsuleShape, 0.05f);
     player.setJumpSpeed(20);
     player.setFallSpeed(30);
     player.setGravity(30);
     player.setPhysicsLocation(new Vector3f(0, 10, 0));
     
     //bulletAppState.getPhysicsSpace().add(landscape);
     bulletAppState.getPhysicsSpace().add(player);
    

    }

    public GameAppState() {
    bAppState = bulletAppState;
    }

    private void initKeys() {
    if(inputManager!=null) {
    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(actionListener, new String[]{"Left"});
         inputManager.addListener(actionListener, new String[]{"Right"});
         inputManager.addListener(actionListener, new String[]{"Up"});
         inputManager.addListener(actionListener, new String[]{"Down"});
         inputManager.addListener(actionListener, new String[]{"Jump"});
     }
    

    }

    private boolean keyPressed = false;

    private ActionListener actionListener = new ActionListener() {

     @Override
    

    public void onAction(String name, boolean keyPressed, float tpf) {
    if (name.equals(“Pause”) && !keyPressed) {
    keyPressed = !keyPressed;
    }
    }
    };

    /public void onAction(String binding, boolean value, float tpf) {
    if (binding.equals(“Left”)) {
    left = value;
    } else if (binding.equals(“Right”)) {
    right = value;
    } else if (binding.equals(“Up”)) {
    up = value;
    } else if (binding.equals(“Down”)) {
    down = value;
    } else if (binding.equals(“Jump”)) {
    player.jump();
    }
    }
    /

    private void makeWorld() {

     if(worldBuilt==false) {
         
         SimpleInit newWorld = new SimpleInit(assetManager, rootNode);
         newWorld.makeGrid();
         worldBuilt = true;
         
     }
    

    }

    public void addControl(Object obj) {
    if(bulletAppState==null) {
    System.out.println(“Null at addControl”);
    }
    bulletAppState.getPhysicsSpace().add(obj);
    }

    public BulletAppState getAppState() {
    System.out.print(“AppState returning.”);
    return bAppState;
    }

    @Override
    public void update(float tpf) {

     if(cam!=null) {
         Vector3f camDir = cam.getDirection().clone().multLocal(0.6f);
         Vector3f camLeft = cam.getLeft().clone().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());
         System.out.println("cam");
     }
    

    }

}[/java]

Please run through some basic Java tutorials.

When you instantiate an object with a constructor it is NOT THE SAME OBJECT as one instantiated with a different constructor. These are two different objects.

I don’t know how to explain it any better than that. This is an extremely basic OOP concept.

And actually, that is even a bit misleading. Every time you call “new” you are creating a completely new (get it?) and different object.

Yes, I get it. Thanks, I’ll read up some more on class constructors. I guess I missed something.

So for anyone who finds this thread later and has the same issue, I think the right solution is to use getState (JME Advanced: App_States). Watch out though, one bit of code on here has app.getStateManager, and app kept returning null for me (likely my fault). It works if you pass your State Manager down to the class, however.

[java]bulletAppState = _appStateManager.getState(BulletAppState.class);[/java]

I believe it returns whatever app state you are trying to retrieve (but only the first one, so multiple copies = bad). In my case that was the bulletappstate, it should allow you to use just a single app state rather than multiple instances of one type. The reason this whole mess took place is I was trying to avoid making multiple BulletAppStates, which the above code should help with…should. If someone wants to correct me, feel free.