Managing NPCS

Hey guys.

I’m currently just working on a basic free-roam game and I have reached the stage in which I want to start fighting enemies. My first issue in regards to programming NPCs (Non-Player Characters) is I’m unsure exactly how to approach it and what the best way is. Currently, for testing purposes I am making it so when a key is pressed, an NPC is created at a set position.



To do this, I have simple made a new class called NPC.java. However, I’m not sure whether I should be creating the actual model in the NPC class or not. Basically the call I am making from when the key is pressed is as follows:

[java]NPC.spawnNPC();[/java]



However, within NPC.java to get nodes to work I have to import SimpleApplication. So in any class that I want to produce a model in the scene graph, I will have to extend SimpleApplication, which to me just doesn’t seem right. So I’m just wondering if there would be a better way to manage this. Also if I do that, would I have 2 seperate rootNodes, and therefore 2 different scene graphs, which would cause problems.



As an example, this is my NPC class:



[java]package roaming;



import com.jme3.app.SimpleApplication;

import com.jme3.scene.Node;



/**

*

  • @author Pat

    */

    public class NPC extends SimpleApplication {



    Node npc_model;



    NPC() {

    }



    public void spawnNPC() {

    npc_model = (Node)assetManager.loadModel("Models/Ninja/Ninja.mesh.xml");

    npc_model.setLocalScale(0.09f);

    npc_model.getLocalTranslation().addLocal(0, 0, 0);

    rootNode.attachChild(npc_model);

    }

    }



    @Override

    public void simpleInitApp() {

    System.out.println("ffff");

    }



    }

    [/java]



    And this is the call for the spawnNPC method:



    [java]public void onAction(String name, boolean pressed, float k) {

    if (name.equals("Spawn")) {

    NPC.spawnNPC();

    }

    }[/java]



    That quick example produces an error, which is to be expected, as shown in:



    [java]SEVERE: Uncaught exception thrown in Thread[LWJGL Renderer Thread,5,main]

    java.lang.NullPointerException

    at roaming.NPC.spawnNPC(NPC.java:18)

    at roaming.Gameplay.onAction(Gameplay.java:262)

    at com.jme3.input.InputManager.invokeActions(InputManager.java:169)

    at com.jme3.input.InputManager.onKeyEventQueued(InputManager.java:455)

    at com.jme3.input.InputManager.processQueue(InputManager.java:833)

    at com.jme3.input.InputManager.update(InputManager.java:885)

    at com.jme3.app.Application.update(Application.java:606)

    at com.jme3.app.SimpleApplication.update(SimpleApplication.java:230)

    at com.jme3.system.lwjgl.LwjglAbstractDisplay.runLoop(LwjglAbstractDisplay.java:151)

    at com.jme3.system.lwjgl.LwjglDisplay.runLoop(LwjglDisplay.java:185)

    at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:228)

    at java.lang.Thread.run(Thread.java:722)[/java]



    I was just wondering a way in which I could do this. Or a bit of guidance. Just anything that could point me in the right direction as I am not too confident with using classes, especially now that I am developing with jMonkey.



    All help is appreciated,



    Thank you.
@embattled said:
[java]
public class NPC extends SimpleApplication
[/java]


This is wrong. You only want one application in your application. You need to learn to pass the things you need as parameters. It's not enough for the IDE just to tell you a variable is available, it has to have been initialized, etc. The reason these things are initialized in SimpleApplication normally is because you started the application. Your other applications in your application (see how sill that sounds?) are not properly initialized... since they are not applications. They are just erroneously extending application.

General advice: Learning to write code in Java is pretty hard (any language actually). Learning to write a game is also really hard. Learning to write a 3D game is also super hard. Trying to do all of those at the same time is nearly impossible. It is better to learn Java first before attempting to tackle more complicated things.
General advice: Learning to write code in Java is pretty hard (any language actually). Learning to write a game is also really hard. Learning to write a 3D game is also super hard. Trying to do all of those at the same time is nearly impossible. It is better to learn Java first before attempting to tackle more complicated things.


just like here, beacuse your problem is actually on Java level. or you just do not read JME wiki, so you dont know what SimpleApplication is.

As said here, you should have only one SimpleApplication class.



From the sdk, create a new project (file/new project/jme3/BasicGame. It will create a class that extends SimpleApplication, with a main method to launch your application (main).



In the initialize method of that SimpleApplication class, initialize what you need at start.

Then, see what you can regroup in classes. Regroup by purposes. If you are going to have a circuit, make a Circuit class. If that class is going to need to access content of SimpleApplication, have your constructor method of Circuit have a SimpleApplication parameter, so when you “create” your circuit, it is created with what it is going to need to work correctly.

Since java passes object parameters by reference, you will be getting the same SimpleApplication object and therefore, you can access the rootNode of YOUR application.



Since your application may want to access methods of your circuit, save a reference to your circuit in your application.

Ideally, have your class variables be private and only access them through methods. You may need to use protected instead if descendants will need them.



Basically:



[java]

public class MyApplication extends SimpleApplication {



private Circuit circuit;



public static void main(String[] args) {

MyApplication app = new MyApplication();

app.start();

}



@Override

public void simpleInitApp() {

circuit = new Circuit(this, “Francorchamps”);

circuit.doSomething();

System.out.println(circuit.getName());

}

}



public class Circuit {



private SimpleApplication application;

private String name;



public Circuit(SimpleApplication application, String name) {

this.application = application;

this.name = name;

}



public void doSomething() {

Node node = new Node(“wewt”);

//do something

name = name + “_whoopsie”;

application.getRootNode().attachChild(node);

}



public String getName() {

return name;

}

}

[/java]



You should really spend a week reading a good java book, if you are serious. I found this one great: “Thinking in Java”. You can find it here for free: http://www.mindviewinc.com/Books/downloads.html. Focus on the basics. You can forget concurrent threads/spring and so on, as a starter.



NB: I didn’t add the import statements. Netbeans does that for you when you press the shortcut for that. I use eclipse shortcuts so not sure what the default shortcut is.

1 Like