This tutorial shows how to set up an IDE (integrated development environment) to create Java 3D games with the jMonkeyEngine framework (jME). An IDE integrates all your development tools (compiler, debugger, profiler, editor, docs, etc) into one graphical interface and spares you some of the complications of the commandline.
New: The 2.0.1 release is an update of the platform independent game engine that also supports Solaris, additionally to Windows (32 and 64 bit), Linux (32 and 64 bit), and Mac OS X. Since different native libraries now have the same name, the set-up instructions have now changed compared to jME2.0, to accomodate the new directory structure.
This tutorial is intended to work with jME 2.0.1 and NetBeans IDE 6.5 or better. Download the NetBeans IDE for Java SE bundle for free from http://www.netbeans.org.
See also: all_netbeans_tutorials
This is a simplified overview of the file structure we are going to set up by going through this tutorial.
lwjgl.jar and lwjgl.dll as examples. hello3d/test/HelloWorld.java.
NetBeansProjects/
Hello3D/
build/classes/hello3d/test/HelloWorld.class
build.xml
dist/
HelloApp.jar
Hello3D.jar
lib/ ... (many JAR files)
natives/ ... (many native files)
one-jar-ant-task.xml
one-jar.mf
src/hello3d/test/HelloWorld.java
jME2/
jME2_0_1-Stable
src/
lib/
jme.jar (and more JARs...)
lib/
lwjgl
lwjgl.jar (and more JARs...)
natives/
windows/
lwjgl.dll (and more natives...)
...
OneJar/
one-jar-ant-task-0.96.jar
nbjme/
dist/javadoc
...
We will download two files: The archive jME2_0_1-Stable contains all JARs, sources, and native libraries needed to use jME 2.0.1. I recommend to also download the optional archive jME_2.0_JavaDoc. It contains jME developer documentation and is very helpful.
Steps:
NetBeansProjects/jME2.NetBeansProjects/jME2 directory.
Next we create a project and configure its class path and java library path.
We will set up an empty NetBeans project. We'll configure it to find jME libraries on the classpath and to find native dynamic libraries on the java.library.path.
In NetBeans:
File > New Project from the menu. Java > Java Application. Click Next.NetBeansProjects dirctory. On Windows this is at C:\Users\Joe\Documents\NetBeansProjects\The Hello3D project now opens in the Projects window.
Next we add all jME JAR libraries to the project's classpath:
jME2\jME2_0_1-Stable\lib\ directory. Multi-select all .jar files (ctrl-click). jME2\jME2_0_1-Stable\lib\lib (!) directory. Browse into each subdirectory lwjgl, junit, jorbis, jogl. jME2_0_1-Stable/lib/lib/swt/*/.jarsLook into the Projects window and open the library node: Here you see the JAR libraries on your project's classpath.
Next we add all native dynamic libraries to the Java Library Path:
-Djava.library.path="..\jME2\jME2_0_1-Stable\lib\lib\lwjgl\native\windows\;..\jME2\jME2_0_1-Stable\lib\lib\jogl\native\windows_i586\"
-Djava.library.path="../jME2/jME2_0_1-Stable/lib/lib/lwjgl/native/macosx/:../jME2/jME2_0_1-Stable/lib/lib/jogl/native/macosx/"
-Djava.library.path="../jME2/jME2_0_1-Stable/lib/lib/lwjgl/native/linux/:../jME2/jME2_0_1-Stable/lib/lib/jogl/native/linux_i586/
-Djava.library.path="../jME2/jME2_0_1-Stable/lib/lib/lwjgl/native/solaris/:../jME2/jME2_0_1-Stable/lib/lib/jogl/native/solaris_i586/"
Tip: Since Java is platform independent, it makes sense to concatenate these lines to a platform independent java library path: You can let your application know where it can find native libraries for any operating system, in one line:
-Djava.library.path="../jME2/jME2_0_1-Stable/lib/lib/lwjgl/native/macosx/:../jME2/jME2_0_1-Stable/lib/lib/jogl/native/macosx/:../jME2/jME2_0_1-Stable/lib/lib/lwjgl/native/linux/:../jME2/jME2_0_1-Stable/lib/lib/jogl/native/linux_i586/:../jME2/jME2_0_1-Stable/lib/lib/lwjgl/native/solaris/:../jME2/jME2_0_1-Stable/lib/lib/jogl/native/solaris_i586/:../jME2/jME2_0_1-Stable/lib/lib/lwjgl/native/windows/:../jME2/jME2_0_1-Stable/lib/lib/jogl/native/windows_i586/"
Yup, looks ugly, but that's what I'm using and it has worked for me. (If you're using 64 bit architecture, replace linux_i568 or windows_i568, with linux_amd64 or windows_amd64.) If you are typing this into NetBeans on Windows, you have to replace / with \ and : with ;. So for Windows it should be
-Djava.library.path="..\jME2\lib\lib\lwjgl\native\macosx\;..\jME2\lib\lib\jogl\native\macosx\;..\jME2\lib\lib\lwjgl\native\linux\;..\jME2\lib\lib\jogl\native\linux_i586\;..\jME2\lib\lib\lwjgl\native\solaris\;..\jME2\lib\lib\jogl\native\solaris_i586\;..\jME2\lib\lib\lwjgl\native\windows\;..\jME2\lib\lib\jogl\native\windows_i586\"
Next we fill in test code and run the project.
To test the set-up, we will use the HelloWorld sample file from the jME tutorial.
In NetBeans:
hello3d.test. hello3d.test node, and select “New > Java class”. HelloWorld.java. package jmetest.TutorialGuide; to package hello3d.test;
This file is all you need to create a fully working jME application. Let's build and run the HelloWorld sample.
You can copy any of the files from TutorialGuide in the same way and run any sample code that has a main method. (Note: TestPongCool.java also requires ExplosionFactory.java to work.)
First we will create a NetBeans project for the jME sources. Here I describe how to get started quickly with the static snapshot of the sources.
nbjme as project name, and NetBeansProjects as project folder. Leave the rest as it is, and click Next.jME/jME2_0_1-Stable/src. Click Add and then Finish.Clean and Build. Wait.Run. jmetest.TestChooser! Click OK.
You have now built jME from the sources. When you run it, a useful test chooser will open: Use it to browse bundled examples of various jME features. You can find the example's source code in the nbjme/src/jmetest directory (under Source Packages in the IDE's Project window). Read the sample's source file to learn how to use a feature.
Advanced tip: If you live on the bleeding edge of development, you can check out the svn repository with the very latest sources (instead of using the static src directory). It should work the same, you just have to add the Source Package Folder from the checked out directory instead of jME/jME2_0_1-Stable/src. Also in other situations described in this tutorial, you have to replace jME/jME2_0_1-Stable/src with the path to your checked out sources.
In this step, you will learn how to activate useful IDE features, such as automatic code completion and javadoc pop-ups.
First we have to build the javadoc from the sources (if they release the javadocs as extra file in the future, then you can skip this step).
Build javadoc.nbjme/dist/javadoc. Note that if you ever clean the nbjme project, you also have to rebuild the javadoc. Practically you should never have to clean your copy of the nbjme project, because it never changes.
If you are a bleeding-edge developer and got the project's source code from the svn repository instead of using this snapshot, then you will have to rebuild the javadoc regularly.
Now we configure NetBeans to find jME's developer documentation.
jme.jar entry, and click Edit.dist/javadoc.
Configuring NetBeans to find the Javadoc activates handy development features: You are now able to use automatic code completion and documentation pop-ups in this jME project in the IDE.
Next we will give the NetBeans Navigator access to the jME sources in JME2/jME2_0_1-Stable/src.
jme.jar entry, and click Edit.../jME2/jME2_0_1-Stable/src.Configuring NetBeans to find the sources allows you to learn a lot from reading the actual code.
Let's try out some of the IDE's productivity features:
SimpleGame). Press ctrl-space to see available methods and documentation. rootNode) to open the source file where it was defined.Learn more form http://www.netbeans.org/kb/.
OneJAR (http://one-jar.sourceforge.net/) provides a way to package your classes, liberaries and native libs in one jar! Here is how to set up NetBeans to automate the process. Let's call the single-JAR file HelloApp.jar (stand-alone) to distinguish it from the previously created Hello3D.jar (not fully stand-alone because of the necessary libraries).
OneJar next to the Hello3D directory.one-jar-ant-task-0.96.jar from one-jar-sdk to OneJar. one-jar-ant-task.xml from one-jar-sdk to Hello3DHello3D/one-jar-ant-task.xml to say value="../OneJar"
Create a file onejar.mf in the Hello3D directory, with the following content:
Manifest-Version: 1.0 Ant-Version: Apache Ant 1.7.1 Main-Class: com.simontuffs.onejar.Boot Class-Path: lib/gluegen-rt.jar lib/jinput.jar lib/jme-audio.jar lib/jme-awt.jar lib/jme-collada.jar lib/jme-colladabinding-src.jar lib/jme-colladabinding.jar lib/jme-editors.jar lib/jme-effects.jar lib/jme-font.jar lib/jme-gamestates.jar lib/jme-model.jar lib/jme-ogrexml.jar lib/jme-scene.jar lib/jme-swt.jar lib/jme-terrain.jar lib/jme.jar lib/jogl.jar lib/jorbis-0.0.17.jar lib/junit-4.1.jar lib/lwjgl.jar lib/lwjgl_util.jar lib/lwjgl_util_applet.jar One-Jar-Main-Class: hello3d.test.HelloWorld
Open your project's build.xml and add the following before the closing </project> tag:
<import file="one-jar-ant-task.xml" /> <!-- provide a path where executable distros should be saved --> <property name="release.dir" value="${basedir}/release"/> <!-- provide the path to the shared native libraries directory --> <property name="natives.lwjgl.dir" value="../jME2/jME2_0_1-Stable/lib/lib/lwjgl/native/" /> <property name="natives.jogl.dir" value="../jME2/jME2_0_1-Stable/lib/lib/jogl/native/" /> <!-- provide a base name for your executable. --> <property name="standalone.jar.name" value="Polygonesia"/> <import file="one-jar-ant-task.xml" /> <target name="dist-onejar" depends="jar" description="Bundles a stand-alone OneJAR distribution"> <echo>Bundling: OneJAR is copying natives to ${dist.jar.dir}/natives </echo> <copy todir="${dist.jar.dir}/natives/windows_i586"> <fileset dir="${natives.lwjgl.dir}/windows/" includes="*.dll"/> <fileset dir="${natives.jogl.dir}/windows_i586/" includes="*.dll"/> </copy> <copy todir="${dist.jar.dir}/natives/windows_amd64"> <fileset dir="${natives.lwjgl.dir}/windows/" includes="*.dll"/> <fileset dir="${natives.jogl.dir}/windows_amd64/" includes="*.dll"/> </copy> <copy todir="${dist.jar.dir}/natives/linux_i586"> <fileset dir="${natives.lwjgl.dir}/linux/" includes="*.so"/> <fileset dir="${natives.jogl.dir}/linux_i586/" includes="*.so"/> </copy> <copy todir="${dist.jar.dir}/natives/linux_amd64"> <fileset dir="${natives.lwjgl.dir}/linux/" includes="*.so"/> <fileset dir="${natives.jogl.dir}/linux_amd64/" includes="*.so"/> </copy> <copy todir="${dist.jar.dir}/natives/macosx"> <fileset dir="${natives.lwjgl.dir}/macosx/" includes="*.dylib"/> <fileset dir="${natives.lwjgl.dir}/macosx/" includes="*.jnilib"/> <fileset dir="${natives.jogl.dir}/macosx/" includes="*.dylib"/> <fileset dir="${natives.jogl.dir}/macosx/" includes="*.jnilib"/> </copy> <copy todir="${dist.jar.dir}/natives/solaris_i586"> <fileset dir="${natives.lwjgl.dir}/solaris/" includes="*.so"/> <fileset dir="${natives.jogl.dir}/solaris_i586/" includes="*.so"/> </copy> <echo>Bundling: OneJAR is composing ${standalone.jar.name}-all.jar</echo> <one-jar destfile="${dist.jar.dir}/${standalone.jar.name}-all.jar" manifest="onejar.mf" update="true"> <main> <fileset dir="${build.classes.dir}/" /> </main> <lib> <fileset file="${dist.jar.dir}/lib/*.*" /> </lib> <binlib> <fileset file="${dist.jar.dir}/natives/windows_amd64/*.*" /> <fileset file="${dist.jar.dir}/natives/windows_i586/*.*" /> <fileset file="${dist.jar.dir}/natives/linux_i586/*.*" /> <fileset file="${dist.jar.dir}/natives/linux_amd64/*.*" /> <fileset file="${dist.jar.dir}/natives/macosx/*.*" /> <fileset file="${dist.jar.dir}/natives/solaris_i586/*.*" /> </binlib> <fileset file="${basedir}/properties.cfg"></fileset><!-- optional --> </one-jar> <echo file="${dist.jar.dir}/README.txt" append="true"> Run the stand-alone distribution from the command line using: java -jar -Xmx256m ${standalone.jar.name}-all.jar </echo> <echo>Bundling: OneJAR is preparing ${standalone.jar.name}-win32.jar</echo> <one-jar destfile="${dist.jar.dir}/${standalone.jar.name}-win32.jar" manifest="onejar.mf" update="true"> <main> <fileset dir="${build.classes.dir}/" /> </main> <lib> <fileset file="${dist.jar.dir}/lib/*.*" /> </lib> <binlib> <fileset file="${dist.jar.dir}/natives/windows_i586/*.*" /> </binlib> </one-jar> <echo>Bundling: OneJAR is preparing ${standalone.jar.name}-win64.jar</echo> <one-jar destfile="${dist.jar.dir}/${standalone.jar.name}-win64.jar" manifest="onejar.mf" update="true"> <main> <fileset dir="${build.classes.dir}/" /> </main> <lib> <fileset file="${dist.jar.dir}/lib/*.*" /> </lib> <binlib> <fileset file="${dist.jar.dir}/natives/windows_amd64/*.*" /> </binlib> </one-jar> <echo>Bundling: OneJAR is preparing ${standalone.jar.name}-linux32.jar</echo> <one-jar destfile="${dist.jar.dir}/${standalone.jar.name}-linux32.jar" manifest="onejar.mf" update="true"> <main> <fileset dir="${build.classes.dir}/" /> </main> <lib> <fileset file="${dist.jar.dir}/lib/*.*" /> </lib> <binlib> <fileset file="${dist.jar.dir}/natives/linux_i586/*.*" /> </binlib> </one-jar> <echo>Bundling: OneJAR is preparing ${standalone.jar.name}-linux64.jar</echo> <one-jar destfile="${dist.jar.dir}/${standalone.jar.name}-linux64.jar" manifest="onejar.mf" update="true"> <main> <fileset dir="${build.classes.dir}/" /> </main> <lib> <fileset file="${dist.jar.dir}/lib/*.*" /> </lib> <binlib> <fileset file="${dist.jar.dir}/natives/linux_amd64/*.*" /> </binlib> </one-jar> <echo>Bundling: OneJAR is preparing ${standalone.jar.name}-mac.jar</echo> <one-jar destfile="${dist.jar.dir}/${standalone.jar.name}-mac.jar" manifest="onejar.mf" update="true"> <main> <fileset dir="${build.classes.dir}/" /> </main> <lib> <fileset file="${dist.jar.dir}/lib/*.*" /> </lib> <binlib> <fileset file="${dist.jar.dir}/natives/macosx/*.*" /> </binlib> </one-jar> <echo>Bundling: OneJAR is preparing ${standalone.jar.name}-solaris.jar</echo> <one-jar destfile="${dist.jar.dir}/${standalone.jar.name}-solaris.jar" manifest="onejar.mf" update="true"> <main> <fileset dir="${build.classes.dir}/" /> </main> <lib> <fileset file="${dist.jar.dir}/lib/*.*" /> </lib> <binlib> <fileset file="${dist.jar.dir}/natives/solaris_i586/*.*" /> </binlib> </one-jar> <echo>Bundling: OneJARs are done.</echo> </target>
Go to the Run menu and Clean and Build the project (or use the toolbar button). A stand-alone HelloApp-all.jar is now automatically created in the dist directory everytime you build.
You can customize the build dependency of this ant target if you want to speed up your development build cycle. To call the dist-onejar target manually:
build.xml filebuild.xml and select Run Target > Other Targets > dist-onejar
You can also assign a shortcut to your custom target.
build.xml filebuild.xml to list all targets.
HelloApp.bat in the dist directory, with the content:java -jar -Xmx256m HelloApp-win32.jar
HelloApp-linux32.sh in the dist directory, with the content:#!/bin/sh java -jar -Xmx256m HelloApp-linux32.jar
When you have created the JAR with OneJAR as described above, doubleclick the JAR to start it in Mac OS X.