Program structure

Before I started using JME, every element of a game I programmed (in java) had to have its own class. Now moving on to JME, I find that I can create a decent game (without menu, pause, etc) in only one class, albeit that class being 500+ lines of code.

So I’m wondering what kinds of things you guys create classes for and why it’s beneficial to have a class for it (if there is a specific reason). I’d prefer to know more about non-control and non-appState classes if possible.

Thanks! :slightly_smiling_face:

4 Likes

when you have dupplicated code, dont want have too many lines of code in single file, or you need OOP style or if want have more control over debugging/logging/profiling, you add more classes.

not sure what to add more :wink:

its all about “clean code” that everyone will understand.
you can have game with 10000 lines in 1 file, but no reason to do so.

3 Likes

So, Generally saying for me , it depends upon the nature of the game , usually i separate my code in classes or block code or entities (or call it as you like) if i have code that does one of the following :

  • A game state like nitros , doughnuts , explosions ,gun flashes or smoke,gun reloading event, events that need to be fired at specific time & inerted or shutted down at a specific time as well according to your needs & it’s usually tied to the update loop of the main game thread , usually this class extends BaseAppState unless you made your own enitity system that’s not based on JME(not a recommended way).

  • A Collision Listeners classes that listens for objects’ collsions , like a ball hitting the goal or car rushes into the wall , generally for smaller games it’s handled by one class only that implements PhysicsCollisionListener interface that would override void collision(evt) for your with an event parameter to check for single or group collsioned objects that have specific IDs(thier names).

  • Networking , you can have a class for Networking that holds 2-4 interfaces for example according to your needs , like : OnConnectionEstablished(event) , OnConnectionFailed(event) , OnDataTransfer(event) , OnDataRecieved(event) , that are linked to APIs like Spring Boot or FireBase(if android or web).

  • A class that holds main player controls using JmE action listeners , analog physical devices or even serial devices & Digital electronics , like arduinos or raspiberry pi through a couple of interfaces , Encapsulation(setters/getters) & of course OOP.

  • A class that holds the cosmetics , like shaders calls, material definitions applied to materials that you will often apply to multiple objects in your scenes , & by this way you minimize your code calls , & that can also create a clean & effecient code for reading & writing changes like @oxplay2 has said.

  • A maths Utility class for holding heavy mathematical stuffs(commonly vector based maths) & calculations if need in projects like Airplane Simulators or Car Simulators , you can have multiple static subclasses inside to handle different things.

  • A BaseAppState or a Control based class or a network calls based class that moves a NPC for you using game loops or values received from other players through your network helper library, or a couple of rocks/objects/etc .

  • A front-end menus class that holds the screen controls instead of action listeners(android).

...etc....etc

Sometimes these classes are called … HelperLibraries like NetworkHelper ,PhysicsHelper , etc , if i missed something or mis-understood something please let me know! :grinning:

3 Likes

For my games, I have a single “Main” class that is responsible for getting things set up. However, besides “initialization” code, I generally have very little in there. The individual systems (networking, physics, spatial management, GUI management, user input, etc) are put into their own classes implementing AppState, with each one dedicated to one task. I would use controls to help with animations (i.e., making sure the character is holding the right weapon, rotating the head and neck bones to look at a target, ect), but I generally don’t use those outside of that.

However, to answer your specific question, I often create non-appstate classes if I need to group a bunch of data together. For example, I have an account system similar to how Terraria or Plants vs. Zombies handles it (albiet with the possibility of splitscreen in mind). While I do have an AccountState to manage in-game accounts and logins and such. However, considering that a single account has a lot of information like UUID, name, high scores, controller preferences, etc., I put all that information in an Account object that I make.

Also, if I weren’t using @pspeed’s beloved Entity System and instead using OOP to manage all my in-game objects like enemies and such (:astonished: heresy!), I would generally have a class for each type of enemy (generally with a lot of interfaces and inheritance).

On the other hand, entity components are themselves objects. They are generally a lot simpler (most of mine rely a lot on Strings, primitives, UUIDs, and specialized enumes), but there are nevertheless a lot of them. The same applies to network messages (for those applications where you aren’t using RMI). In any case, I also use an individual class for every type of screen I have (although my Screen base class is technically another app state with a bunch of extra methods that my ScreenManagerState can work with).

Another type of class that I work a lot with is interfaces and abstract classes. For varied stuff like screens and RMI networking, I usually have a base class for the general Screen or RMI interface, as well as extended implementations for specific screens and RMI types. In the case of RMI, these themselves are actually interfaces that I implement separately on each client/server. This is where I really use the strengths of inheritance in OOP.

In short, a general rule of thumb is: if I have a bunch of data that I need to treat as a unit, or if I have a bunch of similar things with specialized implementations (GUI screens), I make a class.
What I don’t often do is make classes containing nothing but static fields and methods. They have their place, but unless I have a bunch of related fields and methods, I’ll just put them in the Application implementation.

5 Likes

For my game, I use Control. This way of working is more in line with scripts, similar to the way Unity mounts scripts to GameObject.
Generally I will be divided into several modules:
GameLogicAppState, GuiLogicAppState, HudLogicAppState, BulletAppState.
Control is used for all other parts, which are connected to the designated Node to achieve logical control.
And combined with the observer mode or entity component system management GameObject.

2 Likes


This is my way of organization, AppState acts as a layering, and Control controls specific entity logic. Hope it helps you.

4 Likes

Thanks @oxplay2, @Pavl_G, @Markil3, and @JhonKkk! I think I have a better grasp of program structure now! :sunglasses: :+1:

One thing I don’t get is how to use materials effectively in a class since it doesn’t extend SimpleApplication. I’ve tried to get already initialized materials through the class constructor, though it’s really finicky and difficult to change. Are there any better ways?

4 Likes

what do you mean via “initialized materials” ?

if you mean create them, then it would be better if you store them as .j3m file and just load.

if you mean pre-load, then create simple class to which you provide names to load.

2 Likes

This is an example of what I consider “initializing materials”:

Material m = new Material(assetManager, "Common/MatDefs/Misc/Unshaded");
m.setTexture("ColorMap", assetManager.loadTexture("Texture/example.jpg"));

I cannot do this outside SimpleApplication.

1 Like

what is purpose of initializing it in code?

you are doing some Custom Mesh?

ok, so now full answer:

  • You can do it in different Classes. But you need make sure this classes contructor/method that create materials, is executed in/after app init in SimpleApplication.
    (you just cant initialize/load them before, because there is no assetManager, just remember pass assetManager to different class constructor or into method that will have materials init you need)

  • when it comes to number of lines like this, it would be really low, since most materials you should already have within model files. Its only needed when you create custom mesh/etc.

2 Likes

AppStates.

public class MyClass extends BaseAppState {
   ....
}

Then attach it to application’s stateManager.

…then you have access to asset manager, cameras, etc…

4 Likes

hehe, i answer question directly, but yes, most proper is Paul AppStates way.

I’d got the impression from the Application States Tutorial that BaseAppState was more for scenes and pausing.

1 Like

I use AppStates for lots of things. I rarely ever use controls.

I have an app state for running background threads. I have an app state for moving the camera (or anything, really). I have an app state for a debug HUD. Lots and lots of reusable app states that I just chunk into my application whenever I need them.

A very typical super() constructor for my apps looks like this… actually, I’ll include the whole boiler play for what my main application class almost always looks like:

public class Main extends SimpleApplication {

    static Logger log = LoggerFactory.getLogger(Main.class);

    public static void main( String... args ) throws Exception {

        Main main = new Main();
        AppSettings settings = new AppSettings(true);

        // Set some defaults that will get overwritten if
        // there were previously saved settings from the last time the user
        // ran.
        settings.setWidth(1280);
        settings.setHeight(720);
        settings.setVSync(true);

        String title = "MyApp";
        settings.load(title);
        settings.setTitle(title);

        settings.setUseJoysticks(true);

        main.setSettings(settings);

        main.start();
    }

    public Main() {
        super(new StatsAppState(), new DebugKeysAppState(), new BasicProfilerState(false),
              new DebugHudState(),
              new MemoryDebugState(),
              new OptionPanelState(), // from Lemur
              new MessageState(),
              new CommandConsoleState(),
              new MainMenuState(),
              new ScreenshotAppState("", System.currentTimeMillis()));
    }

    public void simpleInitApp() {

        setPauseOnLostFocus(false);
        setDisplayFps(false);
        setDisplayStatView(false);

        GuiGlobals.initialize(this);

        GuiGlobals globals = GuiGlobals.getInstance();

        MainGameFunctions.initializeDefaultMappings(globals.getInputMapper());

        BaseStyles.loadGlassStyle();
        globals.getStyles().setDefaultStyle("glass");
        globals.setCursorEventsEnabled(false);
    }
}

For applications that don’t have a main menu, I’d add a MovementState, SkyState, LightingState, etc… But in this particular application those are children of the CompositeAppState that’s run when the game starts.

Edit: and here is the GameSessionState that is attached when the game starts for that particular application:

public class GameSessionState extends CompositeAppState {

    static Logger log = LoggerFactory.getLogger(GameSessionState.class);

    private boolean hostIsLocal = false;

    public GameSessionState() {
        super(new CameraMovementState(),
              new CameraState(),
              new LightingState(),
              new SkyState(true),
              new PostProcessingState(),
              new SkySettingsState(),
              new BuilderState(4, 4),
              new WorldViewState(),
              new ModelViewState()
              );

        addChild(new HelpState(), true);
        addChild(new SettingsState(), true);
        addChild(new ChatState(), true);
        addChild(new ToolState(), true);
    }
    
    @Override
    protected void initialize( Application app ) {
        getState(CameraState.class).setFieldOfView(60);
    }
    
    @Override
    protected void cleanup( Application app ) {
    }
    
    @Override
    protected void onEnable() {
    }
    
    @Override
    protected void onDisable() {
    }
}
6 Likes

I have a question, for controlling a specific object, using AppState does not seem very specific. For example, for various types of bots, the logic of using multiple controls to combine bots seems more reasonable?

My understanding of AppState is that AppState can get all the information that contains the application, and Control can only directly get the currently attached Node. I use a global singleton, and then access some information of the App in the Control, such as accessing the AssetManager.

For me, the game objects are not spatials. So my bots get controlled elsewhere and then there is an app state the makes the spatials match where the bots are.

That way I can have bots that aren’t rendered… maybe they are too far away or hidden for some other reason, etc…

But my games are all ECS based now so other than the built in JME controls for animation, etc. I have barely any use for controls. An AI system moves the entities around. If these entities have a visual then the ModelViewState makes sure the spatials are up to date with the entity.

Edit: but note that I will easily have maybe 20 app states… probably half of which are off the shelf utilities from SiO2, or SimFX, etc.

1 Like

I think I understand, thanks.

Is that another way to add AppStates to the stateManager?

1 Like