Best Practices For jME3 Developers

A collection of recommendations and expert tips. Feel free to add your own! If you are a beginner, you should first game development. We cannot cover all general tips here.

Requirements Gathering

As a quick overview, answer yourself the following questions:

Planning Development Milestones

  1. Pre-Alpha
    1. Lay out the overall application flow using mock-ups or stock art. E.g. switching between intro screen / options screen / game screen.
    2. Get one typical level working. E.g. if it's a "Jump'n'Run", jumping and running must work before you can call it an Alpha.
  2. Alpha
    1. Run internal tests, debug, optimize (issue tracker).
    2. Replace all mock-ups with first drafts of real media and levels.
    3. Feature Freeze: Avoid a bottomless pit of side effects causing new issues.
  3. Beta
    1. Have external people review and "beta test" it (issue tracker).
    2. Even out the kinks in the code – don't add any more new features.
    3. Fill in all final content.
  4. Gamma, Delta = Release Candidates
    1. Last chance to find a horrible bug.
  5. Omega = Final Release

How you actually name or number these milestones is up to you. People use the words "milestone", Greek letters, version numbers, or combinations thereof. Every milestone is made up of a development phase and a test phase. Here are some best practices:

Development Phase

Where to Start?

You have a list of features that you want in game, but which one do you implement first? You will keep adding features to a project that grows more and more complex, how can you minimize the amount of rewriting required?

  1. Start with implementing the most complex game feature first – the one that imposes most constraints on the structure of your project (for instance, networking.)
  2. Make sure the game's high-level frame (screen switching, networking, physics, loading/saving) is sound and solid before you implement low-level details of gameplay.
  3. Only add one larger feature at a time. If there are complex interactions (such as "networking + physics"), start with a small test case ("one cube") and work your way up, don't start with a whole scene.
  4. Test for side-effects on existing code before you add the next feature.

Acknowledge whether you want a feature because it is necessary for gameplay, or simply because "everyone else has it". Successful high-performance games are the ones where someone made smart decisions what to keep and what to drop.
Consider this: Everybody wants "full physics, AI, post-rendering effects, and multi-player networking"… Make certain you truly understand what that requires (e.g. client-server synchonization)! Your goal should be to bring out the essence of your game idea, don't water down gameplay but attempting to make it "do everything, but better".

Extend SimpleApplication

Typically, developers extend a custom base class off of jME3's com.jme3.app.SimpleApplication. For all your games you will want a certain basic frame – for example methods for loading and saving scenes, physics, networking, and multi-player logon screen, switching to settings screen, etc. Then you reuse (extend) your own generic game class and create a specific game, for example a racing game, or a space game, or a shooter.
Follow these steps:

  1. Create a generic game class for your own "game development business":
    1. Create a jME3-based project with all necessary JARs on the classpath.
    2. Create a class in this package and name it something like my.company.MyBaseGame.java.
    3. Make MyBaseGame extend com.jme3.app.SimpleApplication.
      1. Include generic assets (company logo, reusable GUI elements in your company style, etc) in the MyBaseGame's assets directory.
      2. Implement generic features in the MyBaseGame class: Screen switching, GUI, game saving, etc.
  2. Create your actual game, e.g. a shooter:
    1. Create a another JME3-based project with all necessary JME3 JARs on the classpath.
    2. Create a package for the game, e.g. my.company.zombieshooter.MyGame.java.
    3. Add your MyBaseGame.jar to the classpath of MyGame.java.
    4. Make MyGame.java's main class extend MyBaseGame.
      1. The specific assets (scenes, models) of this game go into MyGame's own assets folder.
      2. Now implement this specific game's mechanics and levels – without having to worry about logon&settings screens and all the other features that you already dealt with in MyBaseGame.

Store Custom Data in Spatials Using setUserData()

Game elements often carry custom data with them. For example, players have health, gold coins, an inventory, equipment, etc. jME3 lets you store custom Java objects in Spatials. This way, your custom data is accessible where ever the Spatial is accessible. Read the Spatial documentation to learn more about how to use the setUserData() method on Nodes and Geometries.

Controls and AppStates -- The Smart Way to Implement Game Logic

As your SimpleApplication-based game grows more advanced, you may find yourself putting more and more tests in the simpleUpdate() loop, passing around lots of object references, and your simpleInitApp() methods grows longer and longer….

Move game behaviour into reusable classes of their own. In jME3 these resuable classes are Controls and AppStates.

Controls and AppStates can work together:

Both Control and AppState automatically hook into the main update loop.

Read more about Custom Controls and Application States here.

Optimize Application Performance

Use an Assets Folder

Put your assets into subfolders of your project's assets directory. This is the default path where the AssetManager looks for files.

jMonkeyProjects/MyGame/assets/    # Store assets in subfolders here!
jMonkeyProjects/MyGame/build/     # jMP generates built classes here *
jMonkeyProjects/MyGame/build.xml  # Customize Ant build script here
jMonkeyProjects/MyGame/nbproject/ # jMP stores default build.xml and meta data *
jMonkeyProjects/MyGame/dist/      # jMP generates executables here *
jMonkeyProjects/MyGame/src/       # Store Java sources here
jMonkeyProjects/MyGame/test/      # Store test classes here (optional)
(*) managed by jMonkeyPlatform, don't edit

Here is an example of a commonly used directory structure for various file types:

jMonkeyProjects/MyGame/assets/Interface/ # .font, .jpg, .png, .xml
jMonkeyProjects/MyGame/assets/MatDefs/   # .j3md
jMonkeyProjects/MyGame/assets/Materials/ # .j3m
jMonkeyProjects/MyGame/assets/Models/    # .j3o
jMonkeyProjects/MyGame/assets/Scenes/    # .j3o
jMonkeyProjects/MyGame/assets/Shaders/   # .vert, .frag
jMonkeyProjects/MyGame/assets/Sounds/    # .ogg, .wav
jMonkeyProjects/MyGame/assets/Textures/  # .mesh.xml+.material, .mtl+.obj, .jpg, .png

See also: Asset Packs and Asset Manager.

Don't Mess With Geometric State

Here are some tips especially for users who already know jME2. Automatic handling of the Geometric State has improved in jME3, and it is now a best practice to not mess with it.

Maintain Internal Documentation

It's unlikely you will be willing to fully document every class you write. You should at minimum javadoc the most crucial methods/parameters in a meaningful way.

Treat javadoc as messages to your future self. "genNextVal() generates the next value" and "@param float factor A factor influencing the result" do not count as documentation.

Use File Version Control

Whether you work in a team or alone, keeping a version controlled repository of your code will help you roll-back buggy changes, or recover old code that someone deleted and that is now needed again.

Convert Models to .j3o Format

From the beta on, convert all models and scenes (Ogre mesh and Wavefront and Blender) to jME3's binary .j3o format. Use the jMonkeyPlatform for the conversion, and save the .j3o files into the Models directory.

See also: Model Loader and Viewer

Debugging and Test Phase

Test

Unit Tests () have a different status in 3D graphics development than in other types of software. You cannot write any assertions that automatically test whether the rendered image looks correct, or whether interactions are intuitive. Still you should create simple test cases for individual game features such as loaders, content generators, effects. Run the test cases now and then to see whether they still work as intended – or whether they are affected by side effects. Keep the test classes in a test directory in the project, but don't include them in the distribution.

Quality Assurance (QA) means maintaining a clear list of steps that must always work, and checking them. It will always happen that there are hard-to-find bugs in the gameplay somewhere – but basic tasks such as installing and de-installing, saving and loading, starting/pausing/quitting the game, must work, no excuse. After every milestone, you go through the QA list again, on every supported operating system, and systematically look for regressions or newly introduced bugs.

Alpha and Beta Testing means that you ask someone to try to install and run your game. It should be a real user situation, where they are left to figure it out by themselves (you only can include the usual read-me and help docs). Provide the testers with an easy method to report back descriptions of their problems, or why they gave up. Evaluate whether these problems are exceptions or must be fixed for the game to be playable.

Debug

A Java Debugger is included in the jMonkeyPlatform. It allows you to set a break point in your code near the point where an exception happens. Then you step through the execution line by line and watch object and variable states to detect where the bug starts.

Use the Logger to print status messages during the development and debugging phase, instead of System.out.println(). The logger can be switched off with one line of code, whereas commenting out your println()s takes a while.

Enhance Performance

You can add a Java Profiler to the jMonkeyPlatform via Tools → Plugins → Available. The profiler presents statistics on the lifecycle of methods and objects. Performance problems may be caused by just a few methods that take long, or are called too often. If object creation and garbage collection counts keep increasing, you are looking at a memory leak.

Release Phase

Pre-Release To-Do List

Distributable Executable

The jMonkeyPlatform SDK helps you with deployment (unless you used another IDE, then consult the IDE's documentation). Do you want to release your game as WebStart, Desktop JAR, or Applet? Each has its pros and cons.

DistributionProsCons
Desktop Launcher
(.EXE, .app, .jar+.sh)
This is the standard way of distributing desktop applications. The jMonkeyPlatform can be configured to automatically create zipped launchers for each operating system. You need to offer three separate, platform-dependent downloads.
Desktop Application
(.JAR)
Platform independent desktop application. User must have Java configured to run JARs when they are opened; or user must know how to run JARs from command line; or you must provide a custom JAR wrapper.
Web Start
(.JNLP)
The user accesses a URL, saves the game as one executable file. Easy process, no installer required. You can allow the game to be played offline.Users need network connection to install the game. Downloading bigger games takes a while as opposed to running them from a CD.
Browser Applet
(.HTML+.JAR)
Easy to access and play game via most web browsers. Userfriendly solution for quick small games.Game only runs in the browser. Game or settings cannot be saved to disk. Some restrictions in default camera navigation (jME cannot capture mouse.)
Android
(.APK)
Game runs on Android devicesAndroid devices do not support post-procesor effects.

Which ever method you choose, a Java-Application works on the main operating systems: Windows, Mac OS, Linux, Android.

view online version