I’m trying to learn code Java in a more structural way. Normaly I have only code Java in form of classes in the same folder and not using java packages at all. But that will change from now.
So I have decided to rotate a cube so I split up the listener for keyboard in one class and model design in another class and of course Main class is the start up class.
The main class attach the two classes Models and KeyBoard. My question is simple. What is the best way to let KeyBoard.java class use the geometry geom from Models.java?
Notice that every class in each separate package.
public class Main extends SimpleApplication {
public static void main(String[] args) {
Main app = new Main();
app.start();
}
@Override
public void simpleInitApp() {
stateManager.attach(new Models(this));
stateManager.attach(new KeyBoard(this));
}
}
KeyBoard class
public class KeyBoard extends AbstractAppState {
private final Node rootNode;
private final Node localRootNode;
private final InputManager inputManager;
public KeyBoard(SimpleApplication app){
rootNode = app.getRootNode();
inputManager = app.getInputManager();
localRootNode = new Node();
rootNode.attachChild(localRootNode);
}
@Override
public void initialize(AppStateManager stateManager, Application app){
// You can map one or several inputs to one named action
inputManager.addMapping("Pause", new KeyTrigger(KeyInput.KEY_P));
inputManager.addMapping("Left", new KeyTrigger(KeyInput.KEY_J));
inputManager.addMapping("Right", new KeyTrigger(KeyInput.KEY_K));
inputManager.addMapping("Rotate", new KeyTrigger(KeyInput.KEY_SPACE));
// Add the names to the action listener.
inputManager.addListener(actionListener, "Pause");
inputManager.addListener(analogListener, "Left", "Right", "Rotate");
}
private final ActionListener actionListener = new ActionListener() {
@Override
public void onAction(String name, boolean keyPressed, float tpf) {
}
};
private final AnalogListener analogListener = new AnalogListener() {
@Override
public void onAnalog(String name, float value, float tpf) {
}
};
}
And Models class
public class Models extends AbstractAppState {
private final Node rootNode;
private final AssetManager assetManager;
private final Node localRootNode;
// Model
private static Geometry geom;
public Models(SimpleApplication app){
rootNode = app.getRootNode();
assetManager = app.getAssetManager();
localRootNode = new Node();
rootNode.attachChild(localRootNode);
}
@Override
public void initialize(AppStateManager stateManager, Application app) {
Box b = new Box(1, 1, 1);
geom = new Geometry("Box", b);
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat.setColor("Color", ColorRGBA.Blue);
geom.setMaterial(mat);
localRootNode.attachChild(geom);
}
@Override
public void cleanup(){
}
Use a mediator class that incapsulates Keyboard and Models and let them communicate their shared fields, even main may do that passing them to constructors.
As i said if you application is really simple you can do that in your Main, if you plan to extend it more not using a specific mediating class could result in future troubles. Think about using an InGame app state which incapsulates Models and Keyboard
So you really recommend to learn to create Mediators? Is that a new thing in Java? If the answer is yes, then I have to learn it.
By the way. I set a field to public static in a class and then import it to another class. Look at the KeyBoard class. This didn’t work. Null pointer exception.
public class KeyBoard extends AbstractAppState {
private final Node rootNode;
private final Node localRootNode;
private final InputManager inputManager;
public static Geometry geom;
public KeyBoard(SimpleApplication app){
rootNode = app.getRootNode();
inputManager = app.getInputManager();
localRootNode = new Node();
rootNode.attachChild(localRootNode);
geom = Models.geom; // <-------- geom is static in Models.java.
}
@Override
public void initialize(AppStateManager stateManager, Application app){
// You can map one or several inputs to one named action
inputManager.addMapping("Pause", new KeyTrigger(KeyInput.KEY_P));
inputManager.addMapping("Left", new KeyTrigger(KeyInput.KEY_J));
inputManager.addMapping("Right", new KeyTrigger(KeyInput.KEY_K));
inputManager.addMapping("Rotate", new KeyTrigger(KeyInput.KEY_SPACE));
// Add the names to the action listener.
inputManager.addListener(actionListener, "Pause");
inputManager.addListener(analogListener, "Left", "Right", "Rotate");
}
private final ActionListener actionListener = new ActionListener() {
@Override
public void onAction(String name, boolean keyPressed, float tpf) {
if(name.equals("Left") && keyPressed){
geom.rotate(0,0,0.1f);
}
}
};
private final AnalogListener analogListener = new AnalogListener() {
@Override
public void onAnalog(String name, float value, float tpf) {
}
};
In your model appstate write an accessor for the geometry you create (a get method).
In your keyboard state use getState(ModelState.class).getMyAccessor();
You access other states using the getState(AppState) method from within other states.
Also, most times I extend BaseAppState and not AbstractAppState.
In this case, order of addition to the stateManager is important.
You will want to add the modelstate first, so the constructor and initialise parts of an appstate are called first, then the keyboard state will have something to use when it calls it.
NEVER do that in Java. Non-final attributes are always private/protected, then create a getter and a setter method to get its value or modify it.
You should study some OOP before digging into videogames development, you must be confident with java basic programming to understand jME’s data structures.
Not it’s working. But it seems that the geometry is null. Due to the
public class KeyBoard extends BaseAppState {
private final Node rootNode;
private final Node localRootNode;
private final InputManager inputManager;
//private Geometry geom;
public KeyBoard(SimpleApplication app){
rootNode = app.getRootNode();
inputManager = app.getInputManager();
localRootNode = new Node();
rootNode.attachChild(localRootNode);
}
@Override
public void initialize(Application app){
// You can map one or several inputs to one named action
inputManager.addMapping("Pause", new KeyTrigger(KeyInput.KEY_P));
inputManager.addMapping("Left", new KeyTrigger(KeyInput.KEY_J));
inputManager.addMapping("Right", new KeyTrigger(KeyInput.KEY_K));
inputManager.addMapping("Rotate", new KeyTrigger(KeyInput.KEY_SPACE));
And
public class Main extends SimpleApplication {
public static void main(String[] args) {
Main app = new Main();
app.start();
}
@Override
public void simpleInitApp() {
stateManager.attach(new Models(this));
stateManager.attach(new KeyBoard(this));
}
}
package Start;
import GameDesign.Models;
import GameLogic.KeyBoard;
import com.jme3.app.SimpleApplication;
/**
* 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 {
public static void main(String[] args) {
Main app = new Main();
app.start();
}
@Override
public void simpleInitApp() {
stateManager.attach(new Models(this));
stateManager.attach(new KeyBoard());
}
}
Models.java
package GameDesign;
import com.jme3.app.Application;
import com.jme3.app.SimpleApplication;
import com.jme3.app.state.AbstractAppState;
import com.jme3.app.state.AppStateManager;
import com.jme3.asset.AssetManager;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.shape.Box;
/**
*
* @author spektrakon
*/
public class Models extends AbstractAppState {
private final Node rootNode;
private final AssetManager assetManager;
private final Node localRootNode;
private Geometry geom;
public Models(SimpleApplication app){
rootNode = app.getRootNode();
assetManager = app.getAssetManager();
localRootNode = new Node();
rootNode.attachChild(localRootNode);
}
@Override
public void initialize(AppStateManager stateManager, Application app) {
Box b = new Box(1, 1, 1);
geom = new Geometry("Box", b);
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat.setColor("Color", ColorRGBA.Blue);
geom.setMaterial(mat);
localRootNode.attachChild(geom);
}
@Override
public void cleanup(){
}
public Geometry getGeometry(){
return geom;
}
}
KeyBoard.java
package GameLogic;
import com.jme3.app.Application;
import com.jme3.app.SimpleApplication;
import com.jme3.app.state.AbstractAppState;
import com.jme3.app.state.AppStateManager;
import com.jme3.input.InputManager;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.AnalogListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import GameDesign.Models;
import com.jme3.app.state.BaseAppState;
/**
*
* @author spektrakon
*/
public class KeyBoard extends BaseAppState {
private Node rootNode;
private Node localRootNode;
private InputManager inputManager;
private Geometry geom;
@Override
public void initialize(Application app){
// You can map one or several inputs to one named action
inputManager.addMapping("Pause", new KeyTrigger(KeyInput.KEY_P));
inputManager.addMapping("Left", new KeyTrigger(KeyInput.KEY_J));
inputManager.addMapping("Right", new KeyTrigger(KeyInput.KEY_K));
inputManager.addMapping("Rotate", new KeyTrigger(KeyInput.KEY_SPACE));
// Add the names to the action listener.
inputManager.addListener(actionListener, "Pause");
inputManager.addListener(analogListener, "Left", "Right", "Rotate");
// Add geometry
geom = getState(Models.class).getGeometry();
}
private final ActionListener actionListener = new ActionListener() {
@Override
public void onAction(String name, boolean keyPressed, float tpf) {
}
};
private final AnalogListener analogListener = new AnalogListener() {
@Override
public void onAnalog(String name, float value, float tpf) {
if(name.equals("Left")){
System.out.println("dsfsd");
geom.rotate(0,0,0.1f);
}
}
};
@Override
protected void cleanup(Application app) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
protected void onEnable() {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
protected void onDisable() {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
}