-
-Like Shapes, 3D models are also made up of Meshes, but models are more complex than Shapes. While Shapes are built into jME3, you typically create models in external 3D Mesh Editors.
-
Export the 3D model in Ogre XML or Wavefront OBJ format. Export Scenes as Ogre DotScene format.
-
-
Save the files into a subdirectory of your jME3 project's assets directory.
-
-
In your code, you use the Asset Manager to load models as Spatials into a jME application.
Spatial model = assetManager.loadModel(
- "Models/MonkeyHead/MonkeyHead.mesh.xml" );
-
-
(For the release build:) Use the jMonkeyPlatform to convert models to .j3o format. You don't need this step as long you still develop and test the aplication within the jMonkeyPlatform.
-
-To create 3D models and scenes, you need a 3D Mesh Editor such as , with an OgreXML Exporter plugin.
-
-
-
-Tip: Consider creating for more complex models, it looks more professional.
-
-
-
-3D mesh editors are third-party products, so please consult their documentation for instructions how to use them. Here is an example workflow for Blender users:
-
-
-
-To export your models as Ogre XML meshes with materials:
-
-
-
Open the menu File > Export > OgreXML Exporter to open the exporter dialog.
-
-
In the Export Materials field: Give the material the same name as the model. For example, the model something.mesh.xml goes with something.material, plus (optionally) something.skeleton.xml, and some JPG files.
-
-
In the Export Meshes field: Select a target subdirectory of your assets/Models/ directory. E.g. assets/Models/something/.
Like Shapes, 3D models are also made up of Meshes, but models are more complex than Shapes. While Shapes are built into jME3, you typically create models in external 3D Mesh Editors.
Export the 3D model in Ogre XML or Wavefront OBJ format. Export Scenes as Ogre DotScene format.
Save the files into a subdirectory of your jME3 project's assets directory.
In your code, you use the Asset Manager to load models as Spatials into a jME application.
Spatial model = assetManager.loadModel(
+ "Models/MonkeyHead/MonkeyHead.mesh.xml" );
(For the release build:) Use the jMonkeyPlatform to convert models to .j3o format. You don't need this step as long you still develop and test the aplication within the jMonkeyPlatform.
To create 3D models and scenes, you need a 3D Mesh Editor such as Blender, with an OgreXML Exporter plugin.
Tip: Consider creating UV textures for more complex models, it looks more professional.
3D mesh editors are third-party products, so please consult their documentation for instructions how to use them. Here is an example workflow for Blender users:
To export your models as Ogre XML meshes with materials:
Open the menu File > Export > OgreXML Exporter to open the exporter dialog.
In the Export Materials field: Give the material the same name as the model. For example, the model something.mesh.xml goes with something.material, plus (optionally) something.skeleton.xml, and some JPG files.
In the Export Meshes field: Select a target subdirectory of your assets/Models/ directory. E.g. assets/Models/something/.
\ No newline at end of file
diff --git a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/animation.html b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/animation.html
index 2c2417c9f..a3b4d2ad0 100644
--- a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/animation.html
+++ b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/animation.html
@@ -1,267 +1,157 @@
-
-
-
-In 3D games, you do not only load static 3D models, you also want to be able to trigger animations in the model from the Java code. Animated models must be created in an external mesh editor (for example, Blender).
-
-
-
-What is required for the model?
-
-
-
For each model, you have to define a skeleton (bones rigging).
-
-
For each motion, you have to specify how it distorts the model (skinning).
-
-
For each animation, you have to specify a series of snapshots of how the bones are positioned (keyframes).
-
-
One model can contain several animations. You give every animation a name when you save it in the mesh editor.
As many channels per controller as you need to play several animations in parallel. In simple cases one channel is enough, sometimes you need two or more per model.
-
-Create one com.jme3.animation.AnimControl object in your JME3 application for each animated model that you want to control. You have to register each animated model to one of these Animation Controllers. The control object gives you access to the available animation sequences in the model.
-
-
AnimControl playerControl; // you need one controller per model
+
In 3D games, you do not only load static 3D models, you also want to be able to trigger animations in the model from the Java code. Animated models must be created in an external mesh editor (for example, Blender).
What is required for the model?
For each model, you have to define a skeleton (bones rigging).
For each motion, you have to specify how it distorts the model (skinning).
For each animation, you have to specify a series of snapshots of how the bones are positioned (keyframes).
One model can contain several animations. You give every animation a name when you save it in the mesh editor.
As many channels per controller as you need to play several animations in parallel. In simple cases one channel is enough, sometimes you need two or more per model.
Create one com.jme3.animation.AnimControl object in your JME3 application for each animated model that you want to control. You have to register each animated model to one of these Animation Controllers. The control object gives you access to the available animation sequences in the model.
AnimControl playerControl; // you need one controller per model
Node player = (Node) assetManager.loadModel("Models/Oto/Oto.mesh.xml"); // load a model
playerControl = player.getControl(AnimControl.class); // get control over this model
- playerControl.addListener(this); // add listener
-
-A controller has several animation channels (com.jme3.animation.AnimChannel). Each channel can play one animation sequence at a time.
-
-
-
-There often are situations where you want to run several animation sequences at the same time, e.g. “shooting while walking” or “boxing while jumping”. In this case, you create several channels, assign an animation to each, and play them in parallel.
-
-
-
A controller has several animation channels (com.jme3.animation.AnimChannel). Each channel can play one animation sequence at a time.
There often are situations where you want to run several animation sequences at the same time, e.g. "shooting while walking" or "boxing while jumping". In this case, you create several channels, assign an animation to each, and play them in parallel.
-
-The following properties are set per AnimChannel.
-
-
-
-
-
AnimChannel Property
Usage
-
-
-
setLoopMode(LoopMode.Loop);
From now on, the animation on this channel will repeat from the beginning when it ends.
-
-
-
setLoopMode(LoopMode.DontLoop);
From now on, the animation on this channel will play once, and the freeze at the last keyframe.
-
-
-
setLoopMode(LoopMode.Cycle);
From now on, the animation on this channel will play forward, then backward, then again forward, and so on.
-
-
-
setSpeed(1f);
From now on, play this animation slower (<1f) or faster (>1f), or with default speed (1f).
-
-
-
setTime(1.3f);
Fast-forward or rewind to a certain moment in time of this animation.
-
-
-
-
-
-The following information is available for a channel.
-
-
-
-
-
AnimChannel Property
Usage
-
-
-
getAnimationName()
The name of the animation playing on this channel. Returns null when no animation is playing.
-
-
-
getLoopMode()
The current loop mode on this channel. The returned com.jme3.animation enum can be LoopMode.Loop, LoopMode.DontLoop, or LoopMode.Cycle.
-
-
-
getAnimMaxTime()
The total length of the animation on this channel. Or 0f if nothing is playing.
-
-
-
getTime()
How long the animation on this channel has been playing. It returns 0f if the channel has not started playing yet, or a value up to getAnimMaxTime().
-
-
-
getControl()
The AnimControl that belongs to this AnimChannel.
-
-
-
-
-
-Use the following methods to add or remove individual bones to an AnimChannel. This is useful when you play two animations in parallel on two channels, and each controls a subset of the bones (e.g. one the arms, and the other the legs).
-
-
-
-
-
AnimChannel Methods
Usage
-
-
-
addAllBones()
Add all the bones of the model's skeleton to be influenced by this animation channel. (default)
-
-
-
addBone(“bone1”)
- addBone(bone1)
Add a single bone to be influenced by this animation channel.
-
-
-
addToRootBone(“bone1”)
- addToRootBone(bone1)
Add a series of bones to be influenced by this animation channel: Add all bones, starting from the given bone, to the root bone.
-
-
-
addFromRootBone(“bone1”)
- addFromRootBone(bone1)
Add a series of bones to be influenced by this animation channel: Add all bones, starting from the given root bone, going towards the children bones.
-
-Animations are played by channel. Note: Whether the animation channel plays continuously or only once, depends on the Loop properties you have set.
-
-
-
-
-
Channel Method
Usage
-
-
-
channel_walk.setAnim(“Walk”,0.50f);
Start the animation named “Walk” on channel channel_walk.
- The float value specifies the time how long the animation should overlap with the previous one on this channel. If set to 0f, then no blending will occur and the new animation will be applied instantly.
-
-
-
-
-
-Tip: Use the AnimEventLister below to react at the end or start of an animation cycle.
-
From now on, the animation on this channel will repeat from the beginning when it ends.
setLoopMode(LoopMode.DontLoop);
From now on, the animation on this channel will play once, and the freeze at the last keyframe.
setLoopMode(LoopMode.Cycle);
From now on, the animation on this channel will play forward, then backward, then again forward, and so on.
setSpeed(1f);
From now on, play this animation slower (<1f) or faster (>1f), or with default speed (1f).
setTime(1.3f);
Fast-forward or rewind to a certain moment in time of this animation.
The following information is available for a channel.
AnimChannel Property
Usage
getAnimationName()
The name of the animation playing on this channel. Returns null when no animation is playing.
getLoopMode()
The current loop mode on this channel. The returned com.jme3.animation enum can be LoopMode.Loop, LoopMode.DontLoop, or LoopMode.Cycle.
getAnimMaxTime()
The total length of the animation on this channel. Or 0f if nothing is playing.
getTime()
How long the animation on this channel has been playing. It returns 0f if the channel has not started playing yet, or a value up to getAnimMaxTime().
getControl()
The AnimControl that belongs to this AnimChannel.
Use the following methods to add or remove individual bones to an AnimChannel. This is useful when you play two animations in parallel on two channels, and each controls a subset of the bones (e.g. one the arms, and the other the legs).
AnimChannel Methods
Usage
addAllBones()
Add all the bones of the model's skeleton to be influenced by this animation channel. (default)
addBone("bone1") addBone(bone1)
Add a single bone to be influenced by this animation channel.
addToRootBone("bone1") addToRootBone(bone1)
Add a series of bones to be influenced by this animation channel: Add all bones, starting from the given bone, to the root bone.
addFromRootBone("bone1") addFromRootBone(bone1)
Add a series of bones to be influenced by this animation channel: Add all bones, starting from the given root bone, going towards the children bones.
Animations are played by channel. Note: Whether the animation channel plays continuously or only once, depends on the Loop properties you have set.
Channel Method
Usage
channel_walk.setAnim("Walk",0.50f);
Start the animation named "Walk" on channel channel_walk. The float value specifies the time how long the animation should overlap with the previous one on this channel. If set to 0f, then no blending will occur and the new animation will be applied instantly.
Tip: Use the AnimEventLister below to react at the end or start of an animation cycle.
In this short example, we define the space key to trigger playing the "Walk" animation on channel2.
public void simpleInitApp() {
...
inputManager.addMapping("Walk", new KeyTrigger(KeyInput.KEY_SPACE));
inputManager.addListener(actionListener, "Walk");
@@ -277,77 +167,36 @@ In this short example, we define the space key to trigger playing the “Walk”
}
}
}
- };
-
-The onAnimCycleDone() event is invoked when an animation cycle has ended. For non-looping animations, this event is invoked when the animation is finished playing. For looping animations, this even is invoked each time the animation loop is restarted.
-
-
-
-You have access to the following objects:
-
-
-
The controller to which the listener is assigned.
-
-
The animation channel being played.
-
-
The name of the animation that has just finished playing.
The onAnimCycleDone() event is invoked when an animation cycle has ended. For non-looping animations, this event is invoked when the animation is finished playing. For looping animations, this even is invoked each time the animation loop is restarted.
You have access to the following objects:
The controller to which the listener is assigned.
The animation channel being played.
The name of the animation that has just finished playing.
public void onAnimCycleDone(AnimControl control, AnimChannel channel, String animName) {
// test for a condition you are interested in, e.g. ...
if (animName.equals("Walk")) {
// respond to the event here, e.g. ...
channel.setAnim("Stand", 0.50f);
}
- }
The onAnimChange() event is invoked every time before an animation is set by the user to be played on a given channel (channel.setAnim()).
You have access to the following objects
The controller to which the listener is assigned.
The animation channel being played.
The name of the animation that will start playing.
public void onAnimChange(AnimControl control, AnimChannel channel, String animName) {
// test for a condition you are interested in, e.g. ...
if (animName.equals("Walk")) {
// respond to the event here, e.g. ...
channel.setAnim("Reset", 0.50f);
}
- }
\ No newline at end of file
diff --git a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/application_states.html b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/application_states.html
index 8e126bb2e..dc94574ad 100644
--- a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/application_states.html
+++ b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/application_states.html
@@ -1,109 +1,62 @@
-
-
-
-com.jme3.app.state.AppState is a customizable jME3 interface that allows you to control the global game logic (game mechanics). To control the behaviour of a type of Spatial, see Custom Controls instead – both can be used together.
-
-
-
-To implement game logic:
-
-
-
You define a custom AppState and implement its behaviour in the AppState's update() method.
-
-
You can pass arguments and manipulate everything inside the app's scope.
-
-
-
-
Attach the AppState to your application's AppStateManager (stateManager.attach(myAppState);) to activate it.
-
-
Create one AppState for each type of game behavior. When you add several AppStates to one Application, they will be executed in the order they were added.
-
-JME3 comes with a BulletAppState that implements Physical behaviour (using the jBullet library). You, for example, could write an Artificial Intelligence AppState to control all your enemy units. Existing examples in the code base include:
-
-
-
-
controls physical behaviour in PhysicsControl'ed Spatials.
-
-The AbstractAppState class already implements some common methods and makes creation of custom AppStates a bit easier: isInitialized(), setActive(), isActive(), cleanUp(). Just extend it and override the remaining AppState methods.
-
-
-
-
-Definition:
-
-
public class MyAppState extends AbstractAppState {
+
com.jme3.app.state.AppState is a customizable jME3 interface that allows you to control the global game logic (game mechanics). To control the behaviour of a type of Spatial, see Custom Controls instead – both can be used together.
To implement game logic:
You define a custom AppState and implement its behaviour in the AppState's update() method.
You can pass arguments and manipulate everything inside the app's scope.
Attach the AppState to your application's AppStateManager (stateManager.attach(myAppState);) to activate it.
Create one AppState for each type of game behavior. When you add several AppStates to one Application, they will be executed in the order they were added.
JME3 comes with a BulletAppState that implements Physical behaviour (using the jBullet library). You, for example, could write an Artificial Intelligence AppState to control all your enemy units. Existing examples in the code base include:
BulletAppState controls physical behaviour in PhysicsControl'ed Spatials.
The AbstractAppState class already implements some common methods and makes creation of custom AppStates a bit easier: isInitialized(), setActive(), isActive(), cleanUp(). Just extend it and override the remaining AppState methods.
Definition:
public class MyAppState extends AbstractAppState {
private Node x = new Node("x"); // some class field
public Node getX(){
@@ -114,11 +67,7 @@ Definition:
public void update(float tpf) {
x.doSomething(); // implement behaviour
}
-}
-
-Usage:
-
-
public class TestAppStates extends Application {
+}
Usage:
public class TestAppStates extends Application {
public static void main(String[] args){
TestAppStates app = new TestAppStates();
app.start();
@@ -139,73 +88,20 @@ Usage:
stateManager.render(renderManager);
renderManager.render(tpf);
}
-}
-
-Note: If you use the AppState together with a SimpleApplication-based class, then this update() loop is already set up.
-
-
-The com.jme3.app.state.AppStateManager holds the list of AppStates for an application. AppStateManager ensures that active AppStates are updated and rendered. When an AppState is attached, AppStateManager calls its stateAttached() method. When an AppState is detached, AppStateManager calls its stateDetached() method.
-
-
-
-There is one AppStateManager per application. You can attach several AppStates to one AppStateManager, but the same state can only be attached once.
-
-
-
-
-
AppStateManager Method
Usage
-
-
-
hasState(s)
Is AppState s attached?
-
-
-
getState(Class<T> stateClass)
Returns the first state that is an instance of a subclass of the specified class.
-
-
-
-
-
-The AppStateManager's update(), render(), postRender(), and cleanUp() methods are internal, users never call them directly.
-
-
-You can only change AppStates, or read and write to them, from certain places: In a Control's update() method, in an AppState's update() method, and it the SimpleApplication's simpleUpdate() loop (or the Application's update() loop).
-
-
-To trigger a one-off method in the AppState MyAppState:
-
-
-
app.getState(MyAppState.class).doSomeMoreStuff();
-
-Don't mess with the AppState from other places, because from other methods you have no control over the order of updates. You don't know when (during which half-finished step of an update), your call was received.
-
-
-
-
+}
Note: If you use the AppState together with a SimpleApplication-based class, then this update() loop is already set up.
The com.jme3.app.state.AppStateManager holds the list of AppStates for an application. AppStateManager ensures that active AppStates are updated and rendered. When an AppState is attached, AppStateManager calls its stateAttached() method. When an AppState is detached, AppStateManager calls its stateDetached() method.
There is one AppStateManager per application. You can attach several AppStates to one AppStateManager, but the same state can only be attached once.
AppStateManager Method
Usage
hasState(s)
Is AppState s attached?
getState(Class<T> stateClass)
Returns the first state that is an instance of a subclass of the specified class.
The AppStateManager's update(), render(), postRender(), and cleanUp() methods are internal, users never call them directly.
You can only change AppStates, or read and write to them, from certain places: In a Control's update() method, in an AppState's update() method, and it the SimpleApplication's simpleUpdate() loop (or the Application's update() loop).
To trigger a one-off method in the AppState MyAppState:
app.getState(MyAppState.class).doSomeMoreStuff();
Don't mess with the AppState from other places, because from other methods you have no control over the order of updates. You don't know when (during which half-finished step of an update), your call was received.
\ No newline at end of file
diff --git a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/asset_manager.html b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/asset_manager.html
index 1a3d04e82..b41cbf147 100644
--- a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/asset_manager.html
+++ b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/asset_manager.html
@@ -1,38 +1,7 @@
-
-
-
-JME3 has an integrated an asset manager that helps you keep your project assets organized. By assets we mean media files, such as 3D models, materials, textures, scenes, shaders, sounds, and fonts. Think of the asset manager as the filesystem of your game, independent of the actual deployment platform. It also manages the appropriate managing of OpenGL objects like textures so that they are e.g. not uploaded to the graphics card multiple times when multiple models use them.
-
-
-
-The assetManager object is an com.jme3.asset.AssetManager instance that every com.jme3.app.Application can access. It maintains a root that also includes your project's classpath by default, so you can load any asset that's on the classpath, that is, the top level of your project directory.
-
-
-
-You can use the inherited assetManager object directly, or use the accessor getAssetManager().
-
-
-
-Here is an example how you load assets using the AssetManager. This lines loads a default Material from the Common directory:
-
-
Material mat = (Material) assetManager.loadAsset(
- new AssetKey("Common/Materials/RedColor.j3m"));
-
-The Material is “somewhere” in the jME3 JAR, but the default Asset Manager is configured to handle a Common/… path correctly, so you don't have to specify the whole path.
-
-
-
-Additionally, You can configure the Asset Manager and add any path to its root. This means, you can load assets from any project directory you specify.
-
-
-
-In project created with jMonkeyPlatform, jME3 searches for models in the assets directory of your project by default. This is our recommended directory structure for storing assets:
-
JME3 has an integrated an asset manager that helps you keep your project assets organized. By assets we mean media files, such as 3D models, materials, textures, scenes, shaders, sounds, and fonts. Think of the asset manager as the filesystem of your game, independent of the actual deployment platform. It also manages the appropriate managing of OpenGL objects like textures so that they are e.g. not uploaded to the graphics card multiple times when multiple models use them.
The assetManager object is an com.jme3.asset.AssetManager instance that every com.jme3.app.Application can access. It maintains a root that also includes your project's classpath by default, so you can load any asset that's on the classpath, that is, the top level of your project directory.
You can use the inherited assetManager object directly, or use the accessor getAssetManager().
Here is an example how you load assets using the AssetManager. This lines loads a default Material from the Common directory:
Material mat = (Material) assetManager.loadAsset(
+ new AssetKey("Common/Materials/RedColor.j3m"));
The Material is "somewhere" in the jME3 JAR, but the default Asset Manager is configured to handle a Common/… path correctly, so you don't have to specify the whole path.
Additionally, You can configure the Asset Manager and add any path to its root. This means, you can load assets from any project directory you specify.
In project created with jMonkeyPlatform, jME3 searches for models in the assets directory of your project by default. This is our recommended directory structure for storing assets:
// Creating a material instance with the definition "Unshaded.j3md".
+Material mat_brick = new Material(
assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
// Applying a texture to the material
-mat_brick.setTexture("ColorMap",
+mat_brick.setTexture("ColorMap",
assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall.jpg"));
// Loading a font
@@ -69,86 +29,45 @@ Spatial ninja = assetManager.loadModel("Models/Ninja/Ninja.mesh.xml&quo
// Loading a scene from an Ogre3D dotScene file stored inside a zip
assetManager.registerLocator("town.zip", ZipLocator.class.getName());
Spatial scene = assetManager.loadModel("main.scene");
-rootNode.attachChild(scene);
-
-Here is a HttpZipLocator that can stream models from a zip file online:
-
If you have a model without materials, you have to add a default material to make it visible.
Spatial teapot = assetManager.loadModel("Models/Teapot/Teapot.obj");
Material mat = new Material(assetManager, "Common/MatDefs/Misc/ShowNormals.j3md");
teapot.setMaterial(mat);
-rootNode.attachChild(teapot);
-
-
-
Load a scene
You load scenes just like you load models:
Spatial scene = assetManager.loadModel("Scenes/house/main.scene");
-rootNode.attachChild(scene);
-
-An error mesage similar to the following can occur in the console when you run executables, even if the game runs fine when started from the jMoneykPlatform.
-
An error mesage similar to the following can occur in the console when you run executables, even if the game runs fine when started from the jMoneykPlatform.
-
-If you are using another IDE than jMonkeyPlatform, you can create a codeless project in the jMonkeyPlatform to maintain assets. This method will not meddle with your sources or custom build scripts, but you can still browse your assets, and preview, arrange, and convert models. You can, for example, give the designers in your team access to such a codeless project.
-
-
-
+java.lang.NullPointerException
Reason: If you use the default build script created by the jMonkeyPlatform then the original OgreXML files are not included in the executable.
For a stand-alone build, you work with .j3o files only. The default build script makes sure to include .j3o files in the executable.
If you are using another IDE than jMonkeyPlatform, you can create a codeless project in the jMonkeyPlatform to maintain assets. This method will not meddle with your sources or custom build scripts, but you can still browse your assets, and preview, arrange, and convert models. You can, for example, give the designers in your team access to such a codeless project.
\ No newline at end of file
diff --git a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/audio.html b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/audio.html
index 74804dd20..b108db81c 100644
--- a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/audio.html
+++ b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/audio.html
@@ -1,148 +1,141 @@
-
-
-
-There are two ways to handle audio data: Short audio files are to be stored entirely in memory, while long audio files (music) is streamed from the hard drive as it is played.
-
-
-
-Place audio files in the assets/Sound/ directory of your project. jME3 supports Ogg Vorbis (.ogg) and Wave (.wav) formats.
-
-Alternatively you can create a com.jme3.audio.Environment object to specify custom environment factors. Activate your custom environment settings in the Environment constructor:
-
-
audioRenderer.setEnvironment(
- new Environment( density, diffusion, gain, gainHf, decayTime, decayHf,
- reflGain, reflDelay, lateGain, lateDelay ) );
There are two ways to handle audio data: Short audio files are to be stored entirely in memory, while long audio files (music) is streamed from the hard drive as it is played.
+Place audio files in the assets/Sound/ directory of your project. jME3 supports Ogg Vorbis (.ogg) and Wave (.wav) formats.
The main class to look at is com.jme3.audio.AudioNode.
+By default, a new audio node is buffered, i.e. JME loads the whole file into memory before playing:
AudioNode boom = new AudioNode(audioRenderer, assetManager, "Sound/boom.wav");
If it is a long file, you set the boolean to true to stream the audio.
AudioNode music = new AudioNode(audioRenderer, assetManager, "Sound/music.wav", true);
Returns either Status.Playing, Status.Stopped, or Status.Paused.
setVolume(1)
Sets the volume gain. 1 is the default volume, 2 is twice as loud, 0 is mute.
setPitch(1)
Makes the sound play in a higher or lower pitch. Default is 1.
AudioNode Method
Usage
setLooping(false)
Configures the sound that, if it is played, it plays once and stops. This is the default.
setLooping(true)
Configures the sound that, if it is played, it plays repeats from the beginning, until stop() or pause() are called. Good for ambient background noises.
setPositional(false) setDirectional(false)
All 3D effects switched off. This sound is global and comes from everywhere. Good for environmental ambient sounds and background music.
setTimeOffset(0.5f)
Start playing the sound after waiting the given amount of seconds. Default is 0.
setMaxDistance(100f)
Maximum distance the sound can be heard, in world units. Default is 20.
Activates 3D audio, the sound appears to come from a certain position, where it is loudest. Position the AudioNode in the 3D scene if you have setPositional() true. Position it with mobile players or NPCs.
setReverbEnabled(true)
A 3D echo effect that only makes sense to use with moving positional AudioNodes. The reverb effect is influenced by the environment that the audio renderer is in. See "Setting Environment Properties" below.
Activates 3D audio. This sound can only be heard from a certain direction. Specify the direction and angle in the 3D scene if you have setDirectional() true. Good for noises that should not be heard through a wall.
setInnerAngle() setOuterAngle()
Set the angle in degrees for the directional audio. The angle is relative to the direction. By default, both angles are 360° and the sound can be heard from all directions.
Optionally, You can choose from the following environmental presets from com.jme3.audio.Environment. This presets influence subtle echo effects that evoke associations of different environments in your users. You use it together with setReverbEnbaled(true) mentioned above.
Environment
density
diffusion
gain
gainHf
decayTime
decayHf
reflGain
reflDelay
lateGain
lateDelay
Garage
1.00f
1.0f
1.0f
1.00f
0.90f
0.5f
0.751f
0.0039f
0.661f
0.0137f
Dungeon
0.75f
1.0f
1.0f
0.75f
1.60f
1.0f
0.950f
0.0026f
0.930f
0.0103f
Cavern
0.50f
1.0f
1.0f
0.50f
2.25f
1.0f
0.908f
0.0103f
0.930f
0.0410f
AcousticLab
0.50f
1.0f
1.0f
1.00f
0.28f
1.0f
0.870f
0.0020f
0.810f
0.0080f
Closet
1.00f
1.0f
1.0f
1.00f
0.15f
1.0f
0.600f
0.0025f
0.500f
0.0006f
Activate the preset with setEnvironment(). E.g. in a dungeon environment:
A sound engineer can create a custom com.jme3.audio.Environment object and specify custom environment factors. Activate your custom environment settings in the Environment constructor:
audioRenderer.setEnvironment(
+ new Environment( density, diffusion, gain, gainHf, decayTime, decayHf,
+ reflGain, reflDelay, lateGain, lateDelay ) );
\ No newline at end of file
diff --git a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/bloom_and_glow.html b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/bloom_and_glow.html
index 49d0822fa..259d1517b 100644
--- a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/bloom_and_glow.html
+++ b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/bloom_and_glow.html
@@ -1,96 +1,61 @@
-
-
-
-Bloom is a popular shader effect in 3D games industry. It usually consist in displaying a glowing halo around light sources or bright areas of a scene.
-In practice, the bright areas are extracted from the rendered scene, blurred and finally added up to the render.
-
-
-
-Those images gives an idea of what bloom does. The left image has no bloom effect, the right image does.
-
-
-
Bloom is a popular shader effect in 3D games industry. It usually consist in displaying a glowing halo around light sources or bright areas of a scene.
+In practice, the bright areas are extracted from the rendered scene, blurred and finally added up to the render.
Those images gives an idea of what bloom does. The left image has no bloom effect, the right image does.
-
-Let's take the hover tank example bundled with JME3 test data.
-
-Here you can see the diffuse map of the tank, and the associated glow map that only contains the parts of the texture that will glow and their glowing color:
-
-
-
-
-
-
-Glow maps works with Lighting.j3md, Particles.j3md and SolidColor.j3md material definitions.
-The tank material looks like that :
-
-
-
-Material My Material : Common/MatDefs/Light/Lighting.j3md {
+ viewPort.addProcessor(fpp);
Here are the parameters that you can tweak :
Parameter
Method
Default
Description
blur scale
setBlurScale(float)
1.5f
the scale of the bloom effect, but be careful, high values does artifacts
exposure Power
setExposurePower(float)
5.0f
the glowing channel color is raised to the value power
exposure cut-off
setExposureCutOff(float)
0.0f
the threshold of color to bloom during extraction
bloom intensity
setBloomIntensity(float)
2.0f
the resulting bloom value is multiplied by this intensity
You'll probably need to adjust those parameters depending on your scene.
Let's take the hover tank example bundled with JME3 test data. Here you can see the diffuse map of the tank, and the associated glow map that only contains the parts of the texture that will glow and their glowing color:
Glow maps works with Lighting.j3md, Particles.j3md and SolidColor.j3md material definitions.
+The tank material looks like that :
Material My Material : Common/MatDefs/Light/Lighting.j3md {
MaterialParameters {
SpecularMap : Models/HoverTank/tank_specular.png
Shininess : 8
@@ -102,194 +67,77 @@ Material My Material : Common/MatDefs/Light/Lighting.j3md {
Diffuse : 1.0 1.0 1.0 1.0
Specular : 1.0 1.0 1.0 1.0
}
-}
-
-
-
-
-The glow map is defined here : GlowMap : Models/HoverTank/tank_glow_map_highres.png
-
Create a material for your object and set the GlowColor parameter
Create a FilterPostProcessor
Create a BloomFilter with the GlowMode.Objects parameter
Add the filter to the processor
Add the processor to the viewPort
Material mat = new Material(getAssetManager(), "Common/MatDefs/Misc/SolidColor.j3md");
mat.setColor("Color", ColorRGBA.Green);
mat.setColor("GlowColor", ColorRGBA.Green);
fpp=new FilterPostProcessor(assetManager);
- bloom= new BloomFilter(BloomFilter.GlowMode.Objects);
+ bloom= new BloomFilter(BloomFilter.GlowMode.Objects);
fpp.addFilter(bloom);
- viewPort.addProcessor(fpp);
-
-
-
-Here is the result on Oto's plasma ball (before and after) :
-
-
-
-
-
-The glow render is sampled on a texture that has the same dimensions as the viewport.
-You can reduce the size of the bloom sampling just by using the setDownSamplingFactor method like this :
-
-
-
-
-In this example the sampling size is divided by 4 (width/2,height/2), resulting in less work to blur the scene.
-The resulting texture is then up sampled to the screen size using hardware bilinear filtering. this results in a wider blur range.
-
-let's say you want a global bloom on your scene, but you have also a glowing object on it.
-You can use only one bloom filter for both effects like that
-
-
-Let's say you have made a custom material on your own, and that you want it to support glow maps and glow color.
-In your material definition you need to add those lines in the MaterialParameters section :
-
The glow render is sampled on a texture that has the same dimensions as the viewport.
+You can reduce the size of the bloom sampling just by using the setDownSamplingFactor method like this :
In this example the sampling size is divided by 4 (width/2,height/2), resulting in less work to blur the scene.
+The resulting texture is then up sampled to the screen size using hardware bilinear filtering. this results in a wider blur range.
let's say you want a global bloom on your scene, but you have also a glowing object on it.
+You can use only one bloom filter for both effects like that
Let's say you have made a custom material on your own, and that you want it to support glow maps and glow color.
+In your material definition you need to add those lines in the MaterialParameters section :
MaterialParameters {
....
-
// Texture of the glowing parts of the material
Texture2D GlowMap
// The glow color of the object
Color GlowColor
- }
-
\ No newline at end of file
diff --git a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/camera.html b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/camera.html
index d202c5082..1413036f3 100644
--- a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/camera.html
+++ b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/camera.html
@@ -1,172 +1,132 @@
-
-
-
-The flyby camera is an extension of the default camera in com.jme3.app.SimpleApplication. It is preconfigured to respond to the WASD keys for walking forwards and backwards, and for strafing to the sides. Move the mouse to rotate the camera, scroll the mouse wheel for zooming in or out. The QZ keys raise or lower the camera.
-
-
-
-
-
Method
Usage
-
-
-
flyCam.setEnabled(true);
Activate the flyby cam
-
-
-
flyCam.setMoveSpeed(10);
Control the move speed
-
-
-
flyCam.setRotationSpeed(10);
Control the rotation speed
-
-
-
flyCam.setDragToRotate(true)
Must keep mouse button pressed to rotate camera. Used e.g. for Applets. if false, all mouse movement will be captured and interpreted as rotations.
-
-jME3 also supports a Chase Cam that can follow a moving target Spatial (com.jme3.input.ChaseCamera). Click and hold the mouse button to rotate around the target.
-
-
flyCam.setEnabled(false);
-ChaseCamera chaseCam = new ChaseCamera(cam, target, inputManager);
-
-
Method
Usage
-
-
-
chaseCam.setSmoothMotion(true);
Interpolates a smoother acceleration/deceleration when the camera moves.
-
-
-
chaseCam.setChasingSensitivity(5f)
The lower the chasing sensitivity, the slower the camera will follow the target when it moves.
-
-
-
chaseCam.setTrailingSensitivity(0.5f)
The lower the traling sensitivity, the slower the camera will begin to go after the target when it moves. Default is 0.5;
-
-
-
chaseCam.setRotationSensitivity(5f)
The lower the sensitivity, the slower the camera will rotate around the target when the mosue is dragged. Default is 5.
-
-
-
chaseCam.setTrailingRotationInertia(0.1f)
This prevents the camera to stop too abruptly when the target stops rotating before the camera has reached the target's trailing position. Default is 0.1f.
-
-
-
chaseCam.setDefaultDistance(40);
The default distance to the target at the start of the application.
-
-
-
chaseCam.setMaxDistance(40);
The maximum zoom distance. Default is 40f.
-
-
-
chaseCam.setMinDistance(1);
The minimum zoom distance. Default is 1f.
-
-
-
chaseCam.setMinVerticalRotation(-FastMath.PI/2);
The minimal vertical rotation angle of the camera around the target. Default is 0.
The flyby camera is an extension of the default camera in com.jme3.app.SimpleApplication. It is preconfigured to respond to the WASD keys for walking forwards and backwards, and for strafing to the sides. Move the mouse to rotate the camera, scroll the mouse wheel for zooming in or out. The QZ keys raise or lower the camera.
Method
Usage
flyCam.setEnabled(true);
Activate the flyby cam
flyCam.setMoveSpeed(10);
Control the move speed
flyCam.setRotationSpeed(10);
Control the rotation speed
flyCam.setDragToRotate(true)
Must keep mouse button pressed to rotate camera. Used e.g. for Applets. if false, all mouse movement will be captured and interpreted as rotations.
jME3 also supports a Chase Cam that can follow a moving target Spatial (com.jme3.input.ChaseCamera). Click and hold the mouse button to rotate around the target.
flyCam.setEnabled(false);
+ChaseCamera chaseCam = new ChaseCamera(cam, target, inputManager);
Method
Usage
chaseCam.setSmoothMotion(true);
Interpolates a smoother acceleration/deceleration when the camera moves.
chaseCam.setChasingSensitivity(5f)
The lower the chasing sensitivity, the slower the camera will follow the target when it moves.
chaseCam.setTrailingSensitivity(0.5f)
The lower the traling sensitivity, the slower the camera will begin to go after the target when it moves. Default is 0.5;
chaseCam.setRotationSensitivity(5f)
The lower the sensitivity, the slower the camera will rotate around the target when the mosue is dragged. Default is 5.
chaseCam.setTrailingRotationInertia(0.1f)
This prevents the camera to stop too abruptly when the target stops rotating before the camera has reached the target's trailing position. Default is 0.1f.
chaseCam.setDefaultDistance(40);
The default distance to the target at the start of the application.
chaseCam.setMaxDistance(40);
The maximum zoom distance. Default is 40f.
chaseCam.setMinDistance(1);
The minimum zoom distance. Default is 1f.
chaseCam.setMinVerticalRotation(-FastMath.PI/2);
The minimal vertical rotation angle of the camera around the target. Default is 0.
\ No newline at end of file
diff --git a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/cinematics.html b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/cinematics.html
index a3980b515..98fcb881a 100644
--- a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/cinematics.html
+++ b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/cinematics.html
@@ -1,184 +1,128 @@
-
-
-
-JME3 cinematics (com.jme.cinematic) allow you to remote control nodes and cameras in a 3D game. You use cinematics to script and record scenes. Use it for example to create of your game.
-
-
-
-Cinematics are implemented as AppStates. Attach the scene that you want to be visible in the cinematic to one Node. You create a Cinematic object, and add individual CinematicEvents to it.
-
-
-There are several kinds of cinematic events:
-
-
-
-
-
CinematicEvent
Description
-
-
-
MotionTrack
Use this to move a Spatial non-linearly over time. A motionPath is a list of several waypoints added to a MotionPath. The path is interpolated using Catmull-Rom Splines between waypoints.
-
-
-
PositionTrack
Use this to move a Spatial linearly over time. It translates the Spatial to a destination in the given amount of time by linearly interpolating the positions.
-
-
-
RotationTrack
Use this to change the rotation of a Spatial over time. It rotates the Spatial in the given amount of time by linearly interpolating the rotation.
-
-
-
ScaleTrack
Use this to change the size of a Spatial over time. It scales the Spatial in the given amount of time by linearly interpolating the scale.
-
-
-
SoundTrack
Use this to play a sound at a given time for the given duration.
-
-
-
GuiTrack
Displays a Nifty GUI at a given time for the given duration. Use it to display subtitles or HUD elements. Bind the Nifty GUI XML to the cinematic using cinematic.bindUi(“path/to/nifty/file.xml”);
-
-
-
AnimationTrack
Use this to start playing a model animation at a given time (a character walking animation for example)
-
-
-
-
-
-We will add more types of track implementions over time.
-
-
-
-Each CinematicEvent supports the following methods to control the event.
-
-
-
-
-
CinematicEvent method
Usage
-
-
-
play()
Starts playing the cinematic.
-
-
-
stop()
Stops playing the cinematic.
-
-
-
pause()
Pauses the cinematic.
-
-
-
-
-
-Those methods, must be called on the Cinematic and are propagated to the events. Don't use them directly on a sub cinematic event
-
-
-You can register a MotionPathListener to the MotionPath to track whether waypoints have been reached, and then trigger a custom action. In this example we just print the status. The onWayPointReach() method of the interface gives you access to the MotionTrack object control, and an integer value representing the current wayPointIndex.
-
JME3 cinematics (com.jme.cinematic) allow you to remote control nodes and cameras in a 3D game. You use cinematics to script and record scenes. Use it for example to create cutscenes of your game.
Cinematics are implemented as AppStates. Attach the scene that you want to be visible in the cinematic to one Node. You create a Cinematic object, and add individual CinematicEvents to it.
Use this to move a Spatial non-linearly over time. A motionPath is a list of several waypoints added to a MotionPath. The path is interpolated using Catmull-Rom Splines between waypoints.
PositionTrack
Use this to move a Spatial linearly over time. It translates the Spatial to a destination in the given amount of time by linearly interpolating the positions.
RotationTrack
Use this to change the rotation of a Spatial over time. It rotates the Spatial in the given amount of time by linearly interpolating the rotation.
ScaleTrack
Use this to change the size of a Spatial over time. It scales the Spatial in the given amount of time by linearly interpolating the scale.
SoundTrack
Use this to play a sound at a given time for the given duration.
GuiTrack
Displays a Nifty GUI at a given time for the given duration. Use it to display subtitles or HUD elements. Bind the Nifty GUI XML to the cinematic using cinematic.bindUi("path/to/nifty/file.xml");
AnimationTrack
Use this to start playing a model animation at a given time (a character walking animation for example)
We will add more types of track implementions over time.
Each CinematicEvent supports the following methods to control the event.
CinematicEvent method
Usage
play()
Starts playing the cinematic.
stop()
Stops playing the cinematic.
pause()
Pauses the cinematic.
Those methods, must be called on the Cinematic and are propagated to the events. Don't use them directly on a sub cinematic event
You can register a MotionPathListener to the MotionPath to track whether waypoints have been reached, and then trigger a custom action. In this example we just print the status. The onWayPointReach() method of the interface gives you access to the MotionTrack object control, and an integer value representing the current wayPointIndex.
path.addListener( new MotionPathListener() {
public void onWayPointReach(MotionTrack control, int wayPointIndex) {
if (path.getNbWayPoints() == wayPointIndex + 1) {
println(control.getSpatial().getName() + "Finished!!! ");
@@ -186,175 +130,88 @@ You can register a MotionPathListener to the MotionPath to track whether waypoin
println(control.getSpatial().getName() + " Reached way point " + wayPointIndex);
}
}
-});
-
-You can extend individual CinematicEvents. The shows how to extend a GuiTrack to script subtitles. See how the subtitles are used in the .
-
-
-
-You can also create new CinematicEvent by extending . An AbstractCinematicEvent implements the CinematicEvent interface and provides duration, time, speed, etc… management. Look at the is to use this for a custom fadeIn/fadeOut effect in combination with a com.jme3.post.filters.FadeFilter.
-
Use activateCamera() to give the control of the camera to this node. You now see the scene from this camera's point of view. For example to see through the camera node named “top view”, 6 seconds after the start of the cinematic, you'd write
cinematic.activateCamera(6, "topView");
-
-
If desired, attach the camNode to a MotionTrack to let it travel along waypoints. This is demonstrated in the .
You can also create new CinematicEvent by extending AbstractCinematicEvent. An AbstractCinematicEvent implements the CinematicEvent interface and provides duration, time, speed, etc… management. Look at the TestCinematic.java example is to use this for a custom fadeIn/fadeOut effect in combination with a com.jme3.post.filters.FadeFilter.
Use activateCamera() to give the control of the camera to this node. You now see the scene from this camera's point of view. For example to see through the camera node named "top view", 6 seconds after the start of the cinematic, you'd write
cinematic.activateCamera(6, "topView");
If desired, attach the camNode to a MotionTrack to let it travel along waypoints. This is demonstrated in the TestCameraMotionPath.java example.
\ No newline at end of file
diff --git a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/collision_and_intersection.html b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/collision_and_intersection.html
index 7a9851e2c..e45ba7fdc 100644
--- a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/collision_and_intersection.html
+++ b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/collision_and_intersection.html
@@ -1,125 +1,66 @@
-
-
-
-The term collision can be used to refer to physical interactions (where physical objects collide and bump off one another), and also to non-physical intersections. This article is about non-physical (mathematical) collisions.
-
-
-
-Non-physical collisions are interesting because they take less resources than physical ones. You cn optimize your game if you find a way to simulate a certain effect in a non-physical way, using mathematical techniques such as ray casting.
-
-
-
-One example for an optimization is a physical vehicle's wheels. You could make the wheels fully physical disks, and have jME calculate every tiny force – sounds very accurate, but is total overkill. An more performant solution is to cast four rays down from the vehicle and calculate the intersections with the floor and other obstacles. These non-physical wheels require (in the simplest case) only four calculations to achieve an effect that players can hardly distinguish from the real thing.
-
-
-A com.jme3.bounding.BoundingVolume is an interface for dealing with containment of a collection of points. All BoundingVolumes are Collidable and are used as optimization to calculate non-physical collisions more quickly: It's faster to calculate an intersection between simple shapes like spheres and boxes than between complex shapes. In cases where precision is not relevant, you wrap a complex model in a simpler shape to improve collision detection performance.
-
-
-
-
Type.Sphere: com.jme3.bounding.BoundingSphere is a sphere used as a container for a group of vertices of a piece of geometry. A BoundingSphere has a center and a radius.
-
-
Type.AABB = Axis-aligned bounding box. A com.jme3.bounding.BoundingBox is an axis-aligned cuboid used as a container for a group of vertices of a piece of geometry. A BoundingBox has a center and extents from that center along the x, y and z axis.
-
-
Type.OBB = Oriented bounding box. (not in use)
-
-
Type.Capsule
-
-
-
-
-
-Note: Physical objects have their own “bounding volumes” called CollisionShapes.
-
-
-The interface com.jme3.collision.Collidable declares one method that returns how many collisions were found between two Collidables: collideWith(Collidable other, CollisionResults results).
-
-
-
-A com.jme3.collision.CollisionResults object is an ArrayList of comparable com.jme3.collision.CollisionResult objects.
-
-
-
-You can iterate over the CollisionResults to identify the other parties involved in the collision. Note that jME counts all collisions, this means a ray intersecting a box will be counted as two hits, one on the front where the ray enters, and one on the back where the ray exits.
-
-
-
-
-
CollisionResults Method
Usage
-
-
-
size()
Returns the number of CollisionResult objects.
-
-
-
getClosestCollision()
Returns the CollisionResult with the lowest distance.
-
-
-
getFarthestCollision()
Returns the CollisionResult with the farthest distance.
-
-
-
getCollision(i)
Returns the CollisionResult at index i.
-
-
-
-
-
-A CollisionResult object contains information about the second party of the collision event.
-
-
-
-
-
CollisionResult Method
Usage
-
-
-
getContactPoint()
Returns the contact point coordinate on the second party, as Vector3f.
-
-
-
getContactNormal()
Returns the Normal vector at the contact point, as Vector3f.
-
-
-
getDistance()
Returns the distance between the Collidable and the second party, as float.
-
-
-
getGeometry()
Returns the Geometry of the second party.
-
-
-
getTriangle(t)
Binds t to the triangle t on the second party's mesh that was hit.
-
-
-
getTriangleIndex()
Returns the index of the triangle on the second party's mesh that was hit. (?)
-
-
-
-
-Assume you have two collidables a and b and want to detect collisions between them. The collision parties can be Geometries, Nodes with Geometries attached (including the rootNode), Planes, Quads, Lines, or Rays.
-
-
-
-The following code snippet can be triggered by listeners (e.g. after an input action such as a click), or timed in the update loop.
-
The term collision can be used to refer to physical interactions (where physical objects collide and bump off one another), and also to non-physical intersections. This article is about non-physical (mathematical) collisions.
+Non-physical collisions are interesting because they take less resources than physical ones. You cn optimize your game if you find a way to simulate a certain effect in a non-physical way, using mathematical techniques such as ray casting.
+One example for an optimization is a physical vehicle's wheels. You could make the wheels fully physical disks, and have jME calculate every tiny force – sounds very accurate, but is total overkill. An more performant solution is to cast four rays down from the vehicle and calculate the intersections with the floor and other obstacles. These non-physical wheels require (in the simplest case) only four calculations to achieve an effect that players can hardly distinguish from the real thing.
A com.jme3.bounding.BoundingVolume is an interface for dealing with containment of a collection of points. All BoundingVolumes are Collidable and are used as optimization to calculate non-physical collisions more quickly: It's faster to calculate an intersection between simple shapes like spheres and boxes than between complex shapes. In cases where precision is not relevant, you wrap a complex model in a simpler shape to improve collision detection performance.
Type.Sphere: com.jme3.bounding.BoundingSphere is a sphere used as a container for a group of vertices of a piece of geometry. A BoundingSphere has a center and a radius.
Type.AABB = Axis-aligned bounding box. A com.jme3.bounding.BoundingBox is an axis-aligned cuboid used as a container for a group of vertices of a piece of geometry. A BoundingBox has a center and extents from that center along the x, y and z axis.
Type.OBB = Oriented bounding box. (not in use)
Type.Capsule
Note: Physical objects have their own "bounding volumes" called CollisionShapes.
The interface com.jme3.collision.Collidable declares one method that returns how many collisions were found between two Collidables: collideWith(Collidable other, CollisionResults results).
+A com.jme3.collision.CollisionResults object is an ArrayList of comparable com.jme3.collision.CollisionResult objects.
+You can iterate over the CollisionResults to identify the other parties involved in the collision. Note that jME counts all collisions, this means a ray intersecting a box will be counted as two hits, one on the front where the ray enters, and one on the back where the ray exits.
CollisionResults Method
Usage
size()
Returns the number of CollisionResult objects.
getClosestCollision()
Returns the CollisionResult with the lowest distance.
getFarthestCollision()
Returns the CollisionResult with the farthest distance.
getCollision(i)
Returns the CollisionResult at index i.
A CollisionResult object contains information about the second party of the collision event.
CollisionResult Method
Usage
getContactPoint()
Returns the contact point coordinate on the second party, as Vector3f.
getContactNormal()
Returns the Normal vector at the contact point, as Vector3f.
getDistance()
Returns the distance between the Collidable and the second party, as float.
getGeometry()
Returns the Geometry of the second party.
getTriangle(t)
Binds t to the triangle t on the second party's mesh that was hit.
getTriangleIndex()
Returns the index of the triangle on the second party's mesh that was hit. (?)
Assume you have two collidables a and b and want to detect collisions between them. The collision parties can be Geometries, Nodes with Geometries attached (including the rootNode), Planes, Quads, Lines, or Rays. The following code snippet can be triggered by listeners (e.g. after an input action such as a click), or timed in the update loop.
// Calculate Results
CollisionResults results = new CollisionResults();
a.collideWith(b, results);
-
- System.out.println("Number of Collisions between" + a.getName()+ " and "
+ System.out.println("Number of Collisions between" + a.getName()+ " and "
+ b.getName() " : " + results.size());
-
// Use the results
if (results.size() > 0) {
CollisionResult closest = results.getClosestCollision();
@@ -129,17 +70,11 @@ The following code snippet can be triggered by listeners (e.g. after an input ac
} else {
// how to react when no collision occured
}
-}
-
-You can also loop over all results and trigger different reactions depending on what was hit and where it was hit. In this example, we simply print info about them.
-
-
// Calculate Results
+}
You can also loop over all results and trigger different reactions depending on what was hit and where it was hit. In this example, we simply print info about them.
// Calculate Results
CollisionResults results = new CollisionResults();
a.collideWith(b, results);
-
- System.out.println("Number of Collisions between" + a.getName()+ " and "
+ System.out.println("Number of Collisions between" + a.getName()+ " and "
+ b.getName() " : " + results.size());
-
// Use the results
for (int i = 0; i < results.size(); i++) {
// For each hit, we know distance, impact point, name of geometry.
@@ -148,64 +83,90 @@ You can also loop over all results and trigger different reactions depending on
String party = results.getCollision(i).getGeometry().getName();
int tri = results.getCollision(i).getTriangleIndex();
Vector3f norm = results.getCollision(i).getTriangle(new Triangle()).getNormal();
-
System.out.println("Details of Collision #" + i + ":");
System.out.println(" Party " + party + " was hit at " + pt + ", " + dist + " wu away.");
System.out.println(" The hit triangle #" + tri + " has a normal vector of " + norm);
- }
-
-Knowing the distance of the collisions is useful for example when you intersect Lines and Rays with other objects.
-
-
-A com.jme3.math.Ray is an infinite line with a beginning, a direction, and no end; whereas a com.jme3.math.Line is an infinite line with only a direction (no beginning, no end).
-
-
-
-Rays are used to detect where a 3D object is “looking” and whether one object can “see” the other.
-
-
-
You can determine where a user has clicked by casting a ray from the camera in the direction of the camera. Now identify the closest collision of the ray with e.g. the rootNode.
-
-
Or you cast a ray from a player in the direction of another player. Then you detect all collisions of this ray with other entities (walls, foliage, window panes) and use this to calculate whether one can see the other.
-
-
-
-
-
-These simple ray-surface intersection tests are called Ray Casting. (As opposed to the more advanced Ray Tracing, Ray Casting does not follow a ray's reflection after the first hit, but the ray goes straight on.)
-
-
-A com.jme3.collision.SweepSphere implements a collidable “stretched” sphere that is shaped like a capsule (an upright cylinder with half a sphere on top and the second half at the bottom).
-
-
-
-This shape is usually used to simulate simple non-physcial collisions for character entities in games. The sweep sphere can be used to check collision against a triangle or another sweep sphere.
-
-
-
+ }
Knowing the distance of the collisions is useful for example when you intersect Lines and Rays with other objects.
A com.jme3.math.Ray is an infinite line with a beginning, a direction, and no end; whereas a com.jme3.math.Line is an infinite line with only a direction (no beginning, no end).
+Rays are used to detect where a 3D object is "looking" and whether one object can "see" the other.
You can determine where a user has clicked by casting a ray from the camera in the direction of the camera. Now identify the closest collision of the ray with e.g. the rootNode.
Or you cast a ray from a player in the direction of another player. Then you detect all collisions of this ray with other entities (walls, foliage, window panes) and use this to calculate whether one can see the other.
These simple ray-surface intersection tests are called Ray Casting. (As opposed to the more advanced Ray Tracing, Ray Casting does not follow a ray's reflection after the first hit, but the ray goes straight on.)
This pick target input mapping implements an action that determines what a user clicked (if you map this to a mouse click). It assumes that there are crosshairs in the center of the screen, and the user aims the crosshairs at an object in the scene. We use a ray casting approach to determine the geometry that was picked by the user. You can extend this code to do whatever with the identified target (shoot it, take it, move it, …)
+Use this together with inputManager.setCursorVisible(false).
private AnalogListener analogListener = new AnalogListener() {
+ public void onAnalog(String name, float intensity, float tpf) {
+ if (name.equals("pick target")) {
+ // Reset results list.
+ CollisionResults results = new CollisionResults();
+ // Aim the ray from camera location in camera direction
+ // (assuming crosshairs in center of screen).
+ Ray ray = new Ray(cam.getLocation(), cam.getDirection());
+ // Collect intersections between ray and all nodes in results list.
+ rootNode.collideWith(ray, results);
+ // Print the results so we see what is going on
+ for (int i = 0; i < results.size(); i++) {
+ // For each “hit”, we know distance, impact point, geometry.
+ float dist = results.getCollision(i).getDistance();
+ Vector3f pt = results.getCollision(i).getContactPoint();
+ String target = results.getCollision(i).getGeometry().getName();
+ System.out.println("Selection #" + i + ": " + target + " at " + pt + ", " + dist + " WU away.");
+ }
+ // 5. Use the results -- we rotate the selected geometry.
+ if (results.size() > 0) {
+ // The closest result is the target that the player picked:
+ Geometry target = results.getClosestCollision().getGeometry();
+ // Here comes the action:
+ if(target.getName().equals("Red Box"))
+ target.rotate(0, - intensity, 0);
+ else if(target.getName().equals("Blue Box"))
+ target.rotate(0, intensity, 0);
+ }
+ } // else if ...
+ }
+ };
This pick target input mapping implements an action that determines what a user clicked (if you map this to a mouse click). It assumes that the cursor is visible, and the user aims the cursor at an object in the scene. We use a ray casting approach to determine the geometry that was picked by the user. You can extend this code to do whatever with the identified target (shoot it, take it, move it, …) Use this together with inputManager.setCursorVisible(true).
private AnalogListener analogListener = new AnalogListener() {
+ public void onAnalog(String name, float intensity, float tpf) {
+ if (name.equals("pick target")) {
+ // Reset results list.
+ CollisionResults results = new CollisionResults();
+ // Convert screen click to 3d position
+ Vector2f click2d = inputManager.getCursorPosition();
+ Vector3f click3d = cam.getWorldCoordinates(new Vector2f(click2d.x, click2d.y), 0f).clone();
+ Vector3f dir = cam.getWorldCoordinates(new Vector2f(click2d.x, click2d.y), 1f).subtractLocal(click3d);
+ // Aim the ray from the clicked spot forwards.
+ Ray ray = new Ray(click3d, dir);
+ // Collect intersections between ray and all nodes in results list.
+ rootNode.collideWith(ray, results);
+ // (Print the results so we see what is going on:)
+ for (int i = 0; i < results.size(); i++) {
+ // (For each “hit”, we know distance, impact point, geometry.)
+ float dist = results.getCollision(i).getDistance();
+ Vector3f pt = results.getCollision(i).getContactPoint();
+ String target = results.getCollision(i).getGeometry().getName();
+ System.out.println("Selection #" + i + ": " + target + " at " + pt + ", " + dist + " WU away.");
+ }
+ // Use the results -- we rotate the selected geometry.
+ if (results.size() > 0) {
+ // The closest result is the target that the player picked:
+ Geometry target = results.getClosestCollision().getGeometry();
+ // Here comes the action:
+ if (target.getName().equals("Red Box")) {
+ target.rotate(0, -intensity, 0);
+ } else if (target.getName().equals("Blue Box")) {
+ target.rotate(0, intensity, 0);
+ }
+ }
+ } // else if ...
+ }
+ };
A com.jme3.collision.SweepSphere implements a collidable "stretched" sphere that is shaped like a capsule (an upright cylinder with half a sphere on top and the second half at the bottom).
+This shape is usually used to simulate simple non-physcial collisions for character entities in games. The sweep sphere can be used to check collision against a triangle or another sweep sphere.
\ No newline at end of file
diff --git a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/combo_moves.html b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/combo_moves.html
index ba3273443..852cab759 100644
--- a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/combo_moves.html
+++ b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/combo_moves.html
@@ -1,174 +1,83 @@
-
-
-The ComboMoves class allows you to define combinations of inputs that trigger special actions. Entering an input combo correctly can bring the player incremental rewards, such as an increased chance to hit, an increased effectiveness, or decreased change of being blocked, whatever the game designer chooses.
-
-
-
-Combos are usually a series of inputs, in a fixed order: For example a keyboard combo can look like: “press Down, then Down+Right together, then Right”.
-
-
-
-Usage:
-
-
-
Create input triggers
-
-
Define combos
-
-
Detect combos in ActionListener
-
-
Execute combos in update loop
-
-
-
-
-
-Copy the two classes ComboMoveExecution.java and ComboMove.java into your application and adjust them to your package paths.
-
-
-First you define your game's inputs as you usually do: Implement the com.jme3.input.controls.ActionListener interface for your class, and add triggers mappings such as com.jme3.input.controls.KeyTrigger and com.jme3.input.KeyInput.
-
-
-
-For example:
-
-
inputManager.addMapping("Left", new KeyTrigger(KeyInput.KEY_LEFT));
+
The ComboMoves class allows you to define combinations of inputs that trigger special actions. Entering an input combo correctly can bring the player incremental rewards, such as an increased chance to hit, an increased effectiveness, or decreased change of being blocked, whatever the game designer chooses. More background info
Combos are usually a series of inputs, in a fixed order: For example a keyboard combo can look like: "press Down, then Down+Right together, then Right".
Usage:
Create input triggers
Define combos
Detect combos in ActionListener
Execute combos in update loop
Copy the two classes ComboMoveExecution.java and ComboMove.java into your application and adjust them to your package paths.
First you define your game's inputs as you usually do: Implement the com.jme3.input.controls.ActionListener interface for your class, and add triggers mappings such as com.jme3.input.controls.KeyTrigger and com.jme3.input.KeyInput.
For example:
inputManager.addMapping("Left", new KeyTrigger(KeyInput.KEY_LEFT));
inputManager.addMapping("Right", new KeyTrigger(KeyInput.KEY_RIGHT));
inputManager.addMapping("Up", new KeyTrigger(KeyInput.KEY_UP));
inputManager.addMapping("Down", new KeyTrigger(KeyInput.KEY_DOWN));
inputManager.addMapping("Attack1", new KeyTrigger(KeyInput.KEY_SPACE));
...
-inputManager.addListener(this, "Left", "Right", "Up", "Down", "Attack1");
-
-For each of your combo moves, you specify the series of inputs that will trigger it. The order in which you define them is the order the player has to press them for the step to be recorded. When all steps have been recorded, the combo is triggered.
-
-
-
-The following example shows how a fireball combo move is triggered by pressing the navigation keys for “down, down+right, right”, in this order.
-
For each of your combo moves, you specify the series of inputs that will trigger it. The order in which you define them is the order the player has to press them for the step to be recorded. When all steps have been recorded, the combo is triggered.
The following example shows how a fireball combo move is triggered by pressing the navigation keys for "down, down+right, right", in this order.
Combo step is recorded a certain time after A and not B is entered.
- etc, etc …
-
-
-
setPriority(0.5f);
If there is an ambiguity, a high-priority combo will trigger instead of a low-priority combo. This prevents that a similar looking combo step “hijacks” another Combo. Use only once per ComboMove.
This is the final command of the series.
- False: Do not wait on a final state, chain combo steps. (?)
- True: This is the final state, do not chain combo steps. (?)
-
-
-
-
-
-The press() and notPress() methods accept sets of Input Triggers, e.g. fireball.press(“A”,”B”,”C”).done().
-
-
-
-The following getters give you more information about the game state:
-
-
-
-
-
ComboMove Method
Usage
-
-
-
getCastTime()
Returns the time since the last step has been recorded. (?)
-
-Now that you have specified the combo steps, you want to detect them. You do that in the onAction() method that you get from the ActionListener interface.
-
-
-
-Create a HashSet pressMappings to track curently pressed mappings, and a ComboMove object currentMove to track the current move.
-
-
-
-We also track the cast time of a combo to determine if it has timed out (see update loop below).
-
-
private HashSet<String> pressedMappings = new HashSet<String>();
+fireball.setUseFinalState(false);
Also create a ComboMoveExecution object for each ComboMove. You need it later to execute the detected combo.
ComboMoveExecution fireballExec = new ComboMoveExecution(fireball);
Combo step is recorded a certain time after A and not B is entered. etc, etc …
setPriority(0.5f);
If there is an ambiguity, a high-priority combo will trigger instead of a low-priority combo. This prevents that a similar looking combo step "hijacks" another Combo. Use only once per ComboMove.
setUseFinalState(false); setUseFinalState(true);
This is the final command of the series. False: Do not wait on a final state, chain combo steps. (?) True: This is the final state, do not chain combo steps. (?)
The press() and notPress() methods accept sets of Input Triggers, e.g. fireball.press("A","B","C").done().
The following getters give you more information about the game state:
ComboMove Method
Usage
getCastTime()
Returns the time since the last step has been recorded. (?)
Now that you have specified the combo steps, you want to detect them. You do that in the onAction() method that you get from the ActionListener interface.
Create a HashSet pressMappings to track curently pressed mappings, and a ComboMove object currentMove to track the current move.
We also track the cast time of a combo to determine if it has timed out (see update loop below).
Now that you have detected the current move, you want to execute it. You do that in the update loop.
@Override
public void simpleUpdate(float tpf){
time += tpf;
- fireballExec.updateExpiration(time);
+ fireballExec.updateExpiration(time);
// ... update more ComboExecs here....
if (currentMove != null){
@@ -233,32 +134,15 @@ public void simpleUpdate(float tpf){
currentMove = null;
}
}
-}
-
-Test currentMove.getMoveName() and proceed to call methods that implement any special actions and bonuses. This is up to you and depends individually on your game.
-
-
-Depending on the game genre, the designer can reward the players' intrinsical or extrinsical skills:
-
-
-
-
(intrinsical:) RPGs typically calculate the success of an attack from the character's in-game training level: The player plays the role of a character whose skill level is defined in numbers. RPGs typically do not offer any Combos.
-
-
(extrinsical:) Sport and fighter games typically choose to reward the player's “manual” skills: The success of a special move solely depends on the player's own dexterity. These games typically offer optional Combos.
Test currentMove.getMoveName() and proceed to call methods that implement any special actions and bonuses. This is up to you and depends individually on your game.
Depending on the game genre, the designer can reward the players' intrinsical or extrinsical skills:
(intrinsical:) RPGs typically calculate the success of an attack from the character's in-game training level: The player plays the role of a character whose skill level is defined in numbers. RPGs typically do not offer any Combos.
(extrinsical:) Sport and fighter games typically choose to reward the player's "manual" skills: The success of a special move solely depends on the player's own dexterity. These games typically offer optional Combos.
\ No newline at end of file
diff --git a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/custom_controls.html b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/custom_controls.html
index 4156e984c..aac964973 100644
--- a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/custom_controls.html
+++ b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/custom_controls.html
@@ -1,107 +1,48 @@
-
-
-
-A com.jme3.scene.control.Control is a customizable jME3 interface that allows you to cleanly implement game logic, such as game rules, or artificially intelligent behaviour in NPCs. You use Controls to control the behaviour of types of spatials. To control global game behaviour see Application States – you can use both together.
-
-
-
-To control the behaviour of types of entities:
-
-
-
Create one control for each type of behavior. When you add several controls to one spatial, they will be executed in the order they were added.
- For example, an NPC can be controlled by a PhysicsControl and an AIControl.
-
-
You define a custom control and implement its behaviour in the Control's update() method.
-
-
In the control, you can pass arguments and manipulate the spatial in any way: Modify its transformation (move, scale, rotate), play animations, check for enemies around it and react, etc.
-
-
-
-
Add the control to a spatial and the Spatial's game state is updated automatically from now on.
- spatial.addControl(myControl)
-
-
-
-
-
-To implement game logic for a type of spatial, you will either extend AbstractControl, or implement the Control interface, as explained in this article.
-
-
-For example, you could write a CharacterAnimControl that animates a character accordingly while it is being moved by a CharacterControl. Or you can write an AIControl that remote-controls NPC behaviour in fight situatons. Or you could write a DestructionControl that automatically replaces a structure with an appropriate piece of debris after collision with a projectile… The possibilities are endless.
-
-
-
-Existing examples in the code base include:
-
-
-
-
allows manipulation of skeletal animation, including blending and multiple channels.
-
-
allows you to sync the camera position with the position of a given spatial.
-
-
displays a flat picture orthogonally, e.g. a speech bubble or informational dialog.
-
-
subclasses (such as CharacterControl, RigidBodyControl, VehicleControl) allow you to add physical properties to any spatial. PhysicsControls tie into capabilities provided by the BulletAppState.
-
-The interface can be found under com.jme3.scene.control.Control. It has the following method signatures:
-
-
-
-
cloneForSpatial(Spatial): Clones the Control and attaches it to a clone of the given Spatial.
-
-
setEnabled(boolean): Enable or disable the control. If disabled, update() does nothing. Goes with accessor isEnabled();.
-
-
There are also some internal methods that you do not call from user code: setSpatial(Spatial s), update(float tpf);, render(RenderManager rm, ViewPort vp).
-
-
-
-
-
-If you want to create a Control that also extends an existing class, then create a custom extension of the Control Interface. Usage example:
-
A com.jme3.scene.control.Control is a customizable jME3 interface that allows you to cleanly implement game logic, such as game rules, or artificially intelligent behaviour in NPCs. You use Controls to control the behaviour of types of spatials. To control global game behaviour see Application States – you can use both together.
+To control the behaviour of types of entities:
Create one control for each type of behavior. When you add several controls to one spatial, they will be executed in the order they were added. For example, an NPC can be controlled by a PhysicsControl and an AIControl.
You define a custom control and implement its behaviour in the Control's update() method.
In the control, you can pass arguments and manipulate the spatial in any way: Modify its transformation (move, scale, rotate), play animations, check for enemies around it and react, etc.
Add the control to a spatial and the Spatial's game state is updated automatically from now on. spatial.addControl(myControl)
To implement game logic for a type of spatial, you will either extend AbstractControl, or implement the Control interface, as explained in this article.
For example, you could write a CharacterAnimControl that animates a character accordingly while it is being moved by a CharacterControl. Or you can write an AIControl that remote-controls NPC behaviour in fight situatons. Or you could write a DestructionControl that automatically replaces a structure with an appropriate piece of debris after collision with a projectile… The possibilities are endless. Existing examples in the code base include:
AnimControl.java allows manipulation of skeletal animation, including blending and multiple channels.
CameraControl.java allows you to sync the camera position with the position of a given spatial.
BillboardControl.java displays a flat picture orthogonally, e.g. a speech bubble or informational dialog.
PhysicsControl subclasses (such as CharacterControl, RigidBodyControl, VehicleControl) allow you to add physical properties to any spatial. PhysicsControls tie into capabilities provided by the BulletAppState.
The interface can be found under com.jme3.scene.control.Control. It has the following method signatures:
cloneForSpatial(Spatial): Clones the Control and attaches it to a clone of the given Spatial. The AssetManager uses this method if the same spatial is loaded twice. You can specify which fields you want your object to reuse (e.g. collisionshapes) in this case.
setEnabled(boolean): Enable or disable the control. If disabled, update() does nothing. Goes with accessor isEnabled();.
There are also some internal methods that you do not call from user code: setSpatial(Spatial s), update(float tpf);, render(RenderManager rm, ViewPort vp).
If you want to create a Control that also extends an existing class, then create a custom extension of the Control Interface. Usage example:
+1. Create a custom control interface
public interface MyControl extends Control {
public void setSomething(int x); // add your custom methods
-}
-
-
-2. Create custom classes implementing your control interface
-
-
-
public class ControlledThing extends MyThing implements MyControl {
-
+}
2. Create custom classes implementing your control interface
public class ControlledThing extends MyThing implements MyControl {
protected Spatial spatial;
protected boolean enabled = true;
-
public ControlledThing() { }
-
public ControlledThing(int x) {
super(x);
}
-
@Override
public void update(float tpf) {
if (enabled && spatial != null) {
@@ -109,12 +50,10 @@ If you want to create a Control that also extends an existing class, then create
// Write custom code to control the spatial here!
}
}
-
@Override
public void render(RenderManager rm, ViewPort vp) {
// optional, e.g. to display a debug shape
}
-
@Override
public Control cloneForSpatial(Spatial spatial) {
ControlledThing control = new ControlledThing(y);
@@ -122,23 +61,19 @@ If you want to create a Control that also extends an existing class, then create
spatial.setControl(control);
return control;
}
-
@Override
public void setEnabled(boolean enabled) {
this.enabled = enabled;
// ...
}
-
@Override
public boolean isEnabled() {
return enabled;
}
-
@Override
public void setSomething(int z) {
// your custom method ...
}
-
@Override
public void write(JmeExporter ex) throws IOException {
super.write(ex);
@@ -147,7 +82,6 @@ If you want to create a Control that also extends an existing class, then create
oc.write(spatial, "spatial", null);
// write custom variables ....
}
-
@Override
public void read(JmeImporter im) throws IOException {
super.read(im);
@@ -155,87 +89,53 @@ If you want to create a Control that also extends an existing class, then create
enabled = ic.readBoolean("enabled", true);
spatial = (Spatial) ic.readSavable("spatial", null);
// read custom variables ....
- }
-}
Tip: Use the getControl() accessor to get Control objects from Spatials. No need to pass around lots of object references.
+Here an example from the MonkeyZone code:
public class CharacterAnimControl implements Control {
...
public void setSpatial(Spatial spatial) {
...
@@ -243,38 +143,16 @@ Here an example from the
Again, note that the path starts relative to the assets/… directory.
Clean, Build and run the project. Again, you should see the Ninja+wall+teapot standing in a town.
What is the difference between loading Scenes/town/main.j3o and Scenes/town/main.scene?
You can work with *.scene and .xml files during the development phase: When your designer pushes updated files to the asset directory, you can quickly review the latest version in your development environment.
Create and load *.j3o files for QA and release builds: .j3o is a binary format for jME3 applications, and .j3o files will be automatically included in the distributable JAR file. When you do QA test builds or are ready to release, use the jMonkeyPlatform to convert all .scene and .xml files to .j3o files, and load these.
Now you know how to populate the scenegraph with static shapes and models, and how to build scenes. You have learned how to load assets using the assetManager and you have seen that the paths start relative to your project directory. Another important thing you have learned is to convert models to .j3o format for the JAR builds.
Let's add some action to the scene and continue with the Update Loop.
\ No newline at end of file
diff --git a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/beginner/hello_audio.html b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/beginner/hello_audio.html
index 79a0b1203..7ca318843 100644
--- a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/beginner/hello_audio.html
+++ b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/beginner/hello_audio.html
@@ -1,23 +1,12 @@
-
-
-This tutorial explains how to add 3D sound to a game, and how to trigger when sounds are to be played. We will use an Audio Listener, an Audio Renderer, two Audio Nodes, and an Action Listener.
-
Previous: Hello Terrain,
+Next: Hello Effects This tutorial explains how to add 3D sound to a game, and how make sounds play together with other game events. We learn how to use the Audio Renderer, an Audio Listener, and Audio Nodes. We also make use of an Action Listener and a MouseButtonTrigger from the previous Hello Input tutorial to make a mouse click trigger a gun shot sound.
-
-In the game's initSampleApp() method, we create a simple blue cube geometry called player and attach it to the scene – it's just sample content so you see something when running the audio sample.
-
-
-
+}
When you run the sample, you should see a blue cube, and hear nature ambient sounds. When you click you hear a loud shot.
In the game's initSampleApp() method, we create a simple blue cube geometry called player and attach it to the scene – it's just sample content so you see something when running the audio sample.
From initSampleApp(), we initialize the game by calling the two custom methods initKeys() and initAudio(). You could call the lines of code in these two methods directly from initSampleApp(); we simply moved them into extra methods to keep the code more readable.
-
-
-
-Let's look at initKeys(): As we learned in previous tutorials, we use jme's inputManager to respond to user input. We add a mapping for a left mouse button click, and we name this new action Shoot.
-
-
/** Declaring the "Shoot" action and mapping to a trigger. */
+Let's look at initKeys(): As we learned in previous tutorials, we use jme's inputManager to respond to user input. We add a mapping for a left mouse button click, and we name this new action Shoot.
/** Declaring the "Shoot" action and mapping to a trigger. */
private void initKeys() {
// click to shoot
inputManager.addMapping("Shoot", new MouseButtonTrigger(0));
inputManager.addListener(actionListener, "Shoot");
- }
-
-Setting up the ActionListener should also be familiar from previous tutorials. We declare that, when the trigger (the mouse button) is pressed and released, we want to play a gun sound.
-
-
/** Defining the "Shoot" action: play a sound. */
+ }
Setting up the ActionListener should also be familiar from previous tutorials. We declare that, when the trigger (the mouse button) is pressed and released, we want to play a gun sound.
/** Defining the "Shoot" action: play a sound. */
private ActionListener() {
@Override
public void onAction(String name, boolean keyPressed, float tpf) {
@@ -138,154 +91,69 @@ Setting up the ActionListener should also be familiar from previous tutorials. W
audioRenderer.playSource(audio_gun);
}
}
- };
-
-Next we have a closer look at initAudio() to learn how to use the AudioRenderer and AudioNodes.
-
-
-Using audio is quite simple. Save your audio files into your assets/Sound directory. jME3 supports both Ogg Vorbis (.ogg) and Wave (.wav) files.
-
-
-
-For each sound you create an audio node. A sound node can be used like any node in the jME scene graph. We create one node for a gunshot sound, and one for a nature sound.
-
-Look at initAudio(): Here we initialize the sound objects and set some parameters.
-
-
audio_gun = new AudioNode(assetManager, "Sound/Effects/Gun.wav", false);
- audio_nature = new AudioNode(assetManager, "Sound/Environment/Nature.ogg", true);
-
-
-These two lines create new sound nodes from the given audio files in the assetManager. The Boolean parameter specifies whether you want to stream the sound or not. The nature sound is quite long, so we set this to true because we want to stream it.
-
-
-
-In the next lines we specify that we want the gunshot sound to play only once (do not loop) and we specify its volume on a scale of 0.1 to 1.0. At 0, it is muted.
-
-The nature sound is different: We want it to loop continuously as background sound. We also make it a positional sound and give the node an explicit translation (Vector3f.ZERO stands for 0.0f,0.0f,0.0f). Since jME supports 3D audio, you will be able to hear this sound coming from a particular direction.
-
Using audio is quite simple. Save your audio files into your assets/Sound directory. jME3 supports both Ogg Vorbis (.ogg) and Wave (.wav) files.
+For each sound you create an audio node. A sound node can be used like any node in the jME scene graph. We create one node for a gunshot sound, and one for a nature sound.
Look at our custom initAudio() method: Here we initialize the sound objects and set their parameters.
audio_gun = new AudioNode( audioRenderer, assetManager, "Sound/Effects/Gun.wav");
+ ...
+ audio_nature = new AudioNode( audioRenderer, assetManager, "Sound/Environment/Nature.ogg");
These two lines create new sound nodes from the given audio files in the assetManager.
+In the next lines we specify that we want the gunshot sound to play only once – we don't want it to loop. We specify its volume as gain factor (at 0, sound is muted, at 2, it is twice as loud, etc.).
The nature sound is different: We want it to loop continuously as background sound. This is why we set looping to true, and we already call the play() method on the node. We also choose to set its volume to 3.
-
-To keep up the 3D audio effect, jME needs to know the position of the sound source, and the position of the audio listener. The listener is a built-in object in a SimpleApplication and it is not related to an ActonListener.
-
-
-
-I order to make the most of 3D audio, we use the simpleUpdate() method to move the listener with the camera.
-
-
-In this example, we defined the nature sound as coming from a certain position, but not the gunshot sound. This means the gunshot can be heard everywhere with the same volume.
-
-
-
-
In a game with moving enemies you maight want to make the audio_gun node positional, and move it to the location of the shooting enemy before playing it – this way a player with stereo speakers could hear from which direction the gunshot is coming.
-
-
Similarly, you may have game levels where you want one background sound to play globally, in this case, you would not make the audio_nature a positional sound.
-
-
-
-
-
-In short, you must choose in every situation whether you want a sound to be global or positional.
-
-
-You now know how to add two types of sound to your game: global sounds and positional sounds. You can play sounds in two ways: Either as loop or just once. You also learned to use sound files that are in either .ogg or .wav format.
-
-
-
-Tip: jME's Audio implementation also supports more advanced effects such as reverberation and the Doppler effect. Find out more about these from the sample code included in the jme3test directory.
-
-
-
-Want some fire and explosions to go with your sounds? Read on to learn more about effects.
-
-
+ audioRenderer.playSource(audio_nature); // play continuously!
+ }
We can choose to make the audio_nature a positional sound that comes from a certain place. We have to give the node an explicit translation, in this example we choose Vector3f.ZERO (which stands for the coordinates 0.0f,0.0f,0.0f, the center of the scene.) Since jME supports 3D audio, you will be able to hear this sound coming from this particular location. Making the sound positional is optional.
To keep up the 3D audio effect, jME needs to know the position of the sound source, and the position of the ears of the player. The ear is represented by an 3D Audio Listener object. The listener is a built-in object in a SimpleApplication (it is not related to any other Java Listeners, such as the input manager's ActionListener).
+In order to make the most of the 3D audio effect, we use the simpleUpdate() method to move and rotate the listener (the player's ears) together with the camera (the player's eyes).
public void simpleUpdate(float tpf) {
+ listener.setLocation(cam.getLocation());
+ listener.setRotation(cam.getRotation());
+}
In this example, we defined the nature sound as coming from a certain position, but not the gunshot sound. This means our gunshot is global and can be heard everywhere with the same volume. JME3 also supports directional sounds, that can only be heard from a certain direction (More about Audio here). How do you make this decision?
In a game with moving enemies you may want to make the gun shot or footsteps positional sounds. In these cases you must move the audio nodes to the location of the enemy before playing it. This way a player with stereo speakers could hear from which direction the steps or gun shots are coming.
Similarly, you may have game levels where you want one background sound to play globally. In this case, you would make the audio_nature neither positional nor directional (set both to false).
If you want sound to be "absorbed by the walls" and only broadcast in one direction, you would make it directional. (More about Audio here.)
In short, you must choose in every situation whether you want a sound to be global, directional, or positional.
You now know how to add the two most common types of sound to your game: Global sounds and positional sounds. You can play sounds in two ways: Either continuously in a loop, or situationally just once. You also learned to use sound files that are in either .ogg or .wav format. Tip: jME's Audio implementation also supports more advanced effects such as reverberation and the Doppler effect. You can also create directional sounds, and stream long sound files instead of buffering first. Find out more about these features from the sample code included in the jme3test directory and from the advanced Audio docs.
+Want some fire and explosions to go with your sounds? Read on to learn more about effects.
\ No newline at end of file
diff --git a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/beginner/hello_collision.html b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/beginner/hello_collision.html
index 480e18c58..67052dea8 100644
--- a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/beginner/hello_collision.html
+++ b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/beginner/hello_collision.html
@@ -1,49 +1,20 @@
-
-
-This tutorial demonstrates how you load a scene model and give it solid walls and floors for a character to walk around.
-
-
-
-We will use a PhysicsNode for the static collidable scene, and a PhysicsCharacterNode for the mobile first-person character. We will also adapt the default first-person camera to work with physics-controlled navigation.
-
-
-
-The solution shown here can be used for first-person shooters, mazes, and similar games.
-
Previous: Hello Picking,
+Next: Hello Terrain This tutorial demonstrates how you load a scene model and give it solid walls and floors for a character to walk around.
+We will use a PhysicsNode for the static collidable scene, and a PhysicsCharacterNode for the mobile first-person character. We will also adapt the default first-person camera to work with physics-controlled navigation.
+The solution shown here can be used for first-person shooters, mazes, and similar games.
jMonkeyProjects$ ls -1 BasicGame
assets/
build.xml
town.zip
-src/
-
-
-Place town.zip in the root directory of your JME3 project.
-
-
package jme3test.helloworld;
-
+src/
Place town.zip in the root directory of your JME3 project.
package jme3test.helloworld;
import com.jme3.app.SimpleApplication;
import com.jme3.asset.plugins.ZipLocator;
import com.jme3.bullet.BulletAppState;
@@ -61,7 +32,6 @@ import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
-
/**
* Example 9 - How to make walls and floors solid.
* This version uses Physics and a custom Action Listener.
@@ -69,42 +39,35 @@ import com.jme3.scene.Spatial;
*/
public class HelloCollision extends SimpleApplication
implements ActionListener {
-
private Spatial sceneModel;
private BulletAppState bulletAppState;
private RigidBodyControl landscape;
private CharacterControl player;
private Vector3f walkDirection = new Vector3f();
private boolean left = false, right = false, up = false, down = false;
-
public static void main(String[] args) {
HelloCollision app = new HelloCollision();
app.start();
}
-
public void simpleInitApp() {
/** Set up Physics */
bulletAppState = new BulletAppState();
stateManager.attach(bulletAppState);
-
- // We re-use the flyby camera for rotation, while positioning is handled by physics
+ // We re-use the flyby camera control for rotation, while positioning is handled by physics
viewPort.setBackgroundColor(new ColorRGBA(0.7f,0.8f,1f,1f));
flyCam.setMoveSpeed(100);
setUpKeys();
setUpLight();
-
// We load the scene from the zip file and adjust its size.
assetManager.registerLocator("town.zip", ZipLocator.class.getName());
sceneModel = assetManager.loadModel("main.scene");
sceneModel.setLocalScale(2f);
-
// We set up collision detection for the scene by creating a
// compound collision shape and a static physics node with mass zero.
CollisionShape sceneShape =
CollisionShapeFactory.createMeshShape((Node) sceneModel);
landscape = new RigidBodyControl(sceneShape, 0);
sceneModel.addControl(landscape);
-
// We set up collision detection for the player by creating
// a capsule collision shape and a physics character node.
// The physics character node offers extra settings for
@@ -116,26 +79,22 @@ public class HelloCollision extends SimpleApplication
player.setFallSpeed(30);
player.setGravity(30);
player.setPhysicsLocation(new Vector3f(0, 10, 0));
-
// We attach the scene and the player to the rootnode and the physics space,
// to make them appear in the game world.
rootNode.attachChild(sceneModel);
bulletAppState.getPhysicsSpace().add(landscape);
bulletAppState.getPhysicsSpace().add(player);
}
-
private void setUpLight() {
// We add light so we see the scene
AmbientLight al = new AmbientLight();
al.setColor(ColorRGBA.White.mult(1.3f));
rootNode.addLight(al);
-
DirectionalLight dl = new DirectionalLight();
- dl.setColor(ColorRGBA.White);
+ dl.setColor(ColorRGBA.White);
dl.setDirection(new Vector3f(2.8f, -2.8f, -2.8f).normalizeLocal());
rootNode.addLight(dl);
}
-
/** We over-write some navigational key mappings here, so we can
* add physics-controlled walking and jumping: */
private void setUpKeys() {
@@ -150,7 +109,6 @@ public class HelloCollision extends SimpleApplication
inputManager.addListener(this, "Downs");
inputManager.addListener(this, "Jumps");
}
-
/** These are our custom actions triggered by key presses.
* We do not walk yet, we just keep track of the direction the user pressed. */
public void onAction(String binding, boolean value, float tpf) {
@@ -166,7 +124,6 @@ public class HelloCollision extends SimpleApplication
player.jump();
}
}
-
/**
* This is the main event loop--walking happens here.
* We check in which direction the player is walking by interpreting
@@ -186,193 +143,64 @@ public class HelloCollision extends SimpleApplication
player.setWalkDirection(walkDirection);
cam.setLocation(player.getPhysicsLocation());
}
-}
-
-Run the sample. You should see a town square with houses and a monument. Use the WASD keys and the mouse to navigate around in first person view. Run forward and jump by pressing W and Space. Note how you step over the sidewalk, and up the steps to the monument. You can walk in the alleys between the houses, but the walls are solid. Don't walk over the edge of the world!
-
-SimpleApplication is the base class for all jME3 games. We also have this class implement the ActionListener interface because we want to customize the navigational inputs later.
-
-
private Spatial sceneModel;
+}
Run the sample. You should see a town square with houses and a monument. Use the WASD keys and the mouse to navigate around in first person view. Run forward and jump by pressing W and Space. Note how you step over the sidewalk, and up the steps to the monument. You can walk in the alleys between the houses, but the walls are solid. Don't walk over the edge of the world!
SimpleApplication is the base class for all jME3 games. We also have this class implement the ActionListener interface because we want to customize the navigational inputs later.
private Spatial sceneModel;
private BulletAppState bulletAppState;
private RigidBodyControl landscape;
private CharacterControl player;
private Vector3f walkDirection = new Vector3f();
- private boolean left = false, right = false, up = false, down = false;
-
-We initialize a few private fields:
-
-
-
The BulletAppState gives this SimpleApplication access to physics features (such as collision detection) supplied by jME3's jBullet integration
-
-
The Spatial sceneModel is a normal OgreXML model loaded as a Spatial.
-
-
You use the model as the game's landscape by adding a RigidBodyControl to it.
-
-
The (invisible) first-person player is represented by a CharacterControl object.
-
-
The fields walkDirection and the four Booleans are used for physics-controlled navigation.
-We switch the background color from balck to light blue, since this is a scene with a sky.
-You repurpose the default flyCam camera as first-person camera and set its speed.
+ setUpLight();
We switch the background color from balck to light blue, since this is a scene with a sky.
+You repurpose the default camera control "flyCam" as first-person camera and set its speed.
The auxiliary method setUpLights() adds light sources.
-The auxiliary method setUpKeys() configures input mappings–we will look at it later.
-
-
-The first thing you do in every physics game is create a BulletAppState object. It gives you access to jME3's jBullet integration which handles physical forces and collisions.
-
-
bulletAppState = new BulletAppState();
- stateManager.attach(bulletAppState);
-
-For the scene, you load the sceneModel from a zip file, and adjust the size.
-
-
assetManager.registerLocator("town.zip", ZipLocator.class.getName());
+The auxiliary method setUpKeys() configures input mappings–we will look at it later.
The first thing you do in every physics game is create a BulletAppState object. It gives you access to jME3's jBullet integration which handles physical forces and collisions.
bulletAppState = new BulletAppState();
+ stateManager.attach(bulletAppState);
For the scene, you load the sceneModel from a zip file, and adjust the size.
-The file town.zip is included as a sample model in the JME3 sources – you can . (Optionally, use any OgreXML scene of your own.) For this sample, place the zip file in the application's top level directory (that is, next to src/, assets/, build.xml).
-
The file town.zip is included as a sample model in the JME3 sources – you can download it here. (Optionally, use any OgreXML scene of your own.) For this sample, place the zip file in the application's top level directory (that is, next to src/, assets/, build.xml).
-To use collision detection, you want to add a RigidBodyControl to the sceneModel Spatial. The RigidBodyControl for a complex model takes two arguments: A Collision Shape, and the object's mass.
-
-
-
-
JME3 offers a CollisionShapeFactory that precalculates a mesh-accurate collision shape for a Spatial. We choose to generate a CompoundCollisionShape, which has MeshCollisionShapes as its children. Note: This type of collision shape is optimal for immobile objects, such as terrain, houses, and whole shooter levels.
-
-
You set the mass to zero since a scene is static and its mass irrevelant.
-
-
-
-
-
-Add the control to the Spatial to make give it physical properties. Attach the sceneModel to the rootNode to make it visible.
-
-
rootNode.attachChild(sceneModel);
-
-Tip: Remember to always add a light source so you can see the scene.
-
-
-Next you set up collision detection for the first-person player.
-
-
CapsuleCollisionShape capsuleShape = new CapsuleCollisionShape(1.5f, 6f, 1);
-
-Again, you create a CollisionShape: This time we choose a CapsuleCollisionShape, a cylinder with a rounded top and bottom. Note: This shape is optimal for a person: It's tall and the roundness helps to get stuck less often on obstacles.
-
-
-
Supply the CapsuleCollisionShape constructor with the desired size of the bounding capsule to fit the shape of your character. In this example the character is 2*1.5f units wide, and 6f units tall.
-
-
The final integer argument specifies the orientation of the cylinder: 1 is the Y-axis, which fits an upright person. For many animals and vehicles you would use 0 or 2.
-
-
-
player = new CharacterControl(capsuleShape, 0.05f);
-
-Now you use the CollisionShape to create a CharacterControl that represents the player. The last argument of the CharacterControl constructor (here .05f) is the size of a step that the character should be able to surmount.
-
To use collision detection, you want to add a RigidBodyControl to the sceneModel Spatial. The RigidBodyControl for a complex model takes two arguments: A Collision Shape, and the object's mass.
JME3 offers a CollisionShapeFactory that precalculates a mesh-accurate collision shape for a Spatial. We choose to generate a CompoundCollisionShape, which has MeshCollisionShapes as its children. Note: This type of collision shape is optimal for immobile objects, such as terrain, houses, and whole shooter levels.
You set the mass to zero since a scene is static and its mass irrevelant.
Add the control to the Spatial to give it physical properties. Attach the sceneModel to the rootNode to make it visible.
rootNode.attachChild(sceneModel);
Tip: Remember to always add a light source so you can see the scene.
Next you set up collision detection for the first-person player.
CapsuleCollisionShape capsuleShape = new CapsuleCollisionShape(1.5f, 6f, 1);
Again, you create a CollisionShape: This time we choose a CapsuleCollisionShape, a cylinder with a rounded top and bottom. Note: This shape is optimal for a person: It's tall and the roundness helps to get stuck less often on obstacles.
Supply the CapsuleCollisionShape constructor with the desired size of the bounding capsule to fit the shape of your character. In this example the character is 2*1.5f units wide, and 6f units tall.
The final integer argument specifies the orientation of the cylinder: 1 is the Y-axis, which fits an upright person. For many animals and vehicles you would use 0 or 2.
player = new CharacterControl(capsuleShape, 0.05f);
Now you use the CollisionShape to create a CharacterControl that represents the player. The last argument of the CharacterControl constructor (here .05f) is the size of a step that the character should be able to surmount.
-Apart from step height and character size, the CharacterControl lets you configure jumping, falling, and gravity speeds. Adjust the values to fit your game situation.
-
-Finally we put the player in its starting position and update its state – remember to use setPhysicsLocation() instead of setLocalTranslation(). since you are dealing with a physical object.
-
-
-The default camera controller cam is a third-person camera. JME3 also offers a first-person controller, flyCam, which we use here to handle camera rotation.
-
-
-
+ player.setGravity(30);
Apart from step height and character size, the CharacterControl lets you configure jumping, falling, and gravity speeds. Adjust the values to fit your game situation.
Finally we put the player in its starting position and update its state – remember to use setPhysicsLocation() instead of setLocalTranslation(). since you are dealing with a physical object.
The default camera controller cam is a third-person camera. JME3 also offers a first-person controller, flyCam, which we use here to handle camera rotation.
However we must redefine how walking is handled for physics-controlled objects: When you navigate a physical node, you do not specify a target location, but a walk direction. The physics space calculates how far the character can actually go in the desired direction – or whether it will be stoped by an obstacle.
-
-
-
-This is why we must re-define the flyCam's navigational key mappings to use setWalkDirection() instead of setLocalTranslation(). Here are the steps:
-
-
-Configure the familiar WASD inputs for walking, and Space for jumping.
-
-
inputManager.addMapping("Lefts", new KeyTrigger(KeyInput.KEY_A));
+This is why we must re-define the flyCam's navigational key mappings to use setWalkDirection() instead of setLocalTranslation(). Here are the steps:
Configure the familiar WASD inputs for walking, and Space for jumping.
inputManager.addMapping("Lefts", new KeyTrigger(KeyInput.KEY_A));
inputManager.addMapping("Rights", new KeyTrigger(KeyInput.KEY_D));
inputManager.addMapping("Ups", new KeyTrigger(KeyInput.KEY_W));
inputManager.addMapping("Downs", new KeyTrigger(KeyInput.KEY_S));
@@ -381,21 +209,9 @@ Configure the familiar WASD inputs for walking, and Space for jumping.
inputManager.addListener(this, "Rights");
inputManager.addListener(this, "Ups");
inputManager.addListener(this, "Downs");
- inputManager.addListener(this, "Jumps");
-
-In the code sample above, this block of code was moved into an auxiliary method setupKeys() that is called from simpleInitApp()–this is just to keep the code more readable.
-
-
-Remember that we declared this class an ActionListener so we could customize the flyCam. The ActionListener interface requires us to implement the onAction() method: You re-define the actions triggered by navigation key presses to work with physics.
-
In the code sample above, this block of code was moved into an auxiliary method setupKeys() that is called from simpleInitApp()–this is just to keep the code more readable.
Remember that we declared this class an ActionListener so we could customize the flyCam. The ActionListener interface requires us to implement the onAction() method: You re-define the actions triggered by navigation key presses to work with physics.
public void onAction(String binding, boolean value, float tpf) {
if (binding.equals("Lefts")) {
left = value;
} else if (binding.equals("Rights")) {
@@ -407,94 +223,42 @@ Remember that we declared this class an ActionListener so we could
} else if (binding.equals("Jumps")) {
player.jump();
}
- }
-
-Every time the user presses one of the WASD keys, you keep track of the direction the user wants to go – by storing this info in four directional Booleans. We will use them soon.
-
-
-
-Note that no actual walking happens here – not yet!
-
-
-
-The only movement that you do not have to implement yourself is the jumping action. The call player.jump() is a special method that handles a correct jumping motion for your PhysicsCharacterNode.
-
-
-In onAction() you have determined in which direction the user wants to go in terms of “forward” or “left”.
-Now you need poll the current rotation of the camera to find to which vectors “forward” and “left” correspond in the coordinate system.
-This last and most important code snippet goes into the main event loop, simpleUpdate().
-
Every time the user presses one of the WASD keys, you keep track of the direction the user wants to go – by storing this info in four directional Booleans. We will use them soon.
+Note that no actual walking happens here – not yet!
+The only movement that you do not have to implement yourself is the jumping action. The call player.jump() is a special method that handles a correct jumping motion for your PhysicsCharacterNode.
In onAction() you have determined in which direction the user wants to go in terms of "forward" or "left".
+Now you need poll the current rotation of the camera to find to which vectors "forward" and "left" correspond in the coordinate system.
+This last and most important code snippet goes into the main event loop, simpleUpdate().
Vector3f camDir = cam.getDirection().clone().multLocal(0.6f);
Vector3f camLeft = cam.getLeft().clone().multLocal(0.4f);
walkDirection.set(0, 0, 0);
if (left) { walkDirection.addLocal(camLeft); }
if (right) { walkDirection.addLocal(camLeft.negate()); }
if (up) { walkDirection.addLocal(camDir); }
- if (down) { walkDirection.addLocal(camDir.negate()); }
-
-Reset the variable walkDirection to zero. Then add to it all latest motion vectors that you polled from the camera. It is posible for a character to move forward and to the left simultaneously.
-
-
player.setWalkDirection(walkDirection);
-
-This one line does the “walking” magic: Always use setWalkDirection() to make a physics-controlled object move continuously, and the physics engine automatically handles collision detection for you!
-
-
-
-Important: Do not use setLocalTranslation() to walk the player around. You may get it stuck by overlapping with another physical object. You can put the player in a start position with setPhysicalLocation() if you make sure to place it a bit above the floor and away from obstacles.
-
-
-
-Lastly, do not forget to make the first-person camera object move along with the physics-controlled player node:
-
-
-You have learned how to load a “solid” physical scene model and walk around in it with a first-person perspective.
-You had JME3 calculate the CollisionShapes, and you represented collidables as PhysicsNodes that you registered to the Physics Space.
+ if (down) { walkDirection.addLocal(camDir.negate()); }
Reset the variable walkDirection to zero. Then add to it all latest motion vectors that you polled from the camera. It is posible for a character to move forward and to the left simultaneously.
player.setWalkDirection(walkDirection);
This one line does the "walking" magic: Always use setWalkDirection() to make a physics-controlled object move continuously, and the physics engine automatically handles collision detection for you! Important: Do not use setLocalTranslation() to walk the player around. You may get it stuck by overlapping with another physical object. You can put the player in a start position with setPhysicalLocation() if you make sure to place it a bit above the floor and away from obstacles.
+Lastly, do not forget to make the first-person camera object move along with the physics-controlled player node:
You have learned how to load a "solid" physical scene model and walk around in it with a first-person perspective.
+You had JME3 calculate the CollisionShapes, and you represented collidables as PhysicsNodes that you registered to the Physics Space.
You also made certain to use player.setWalkDirection(walkDirection) to move physical characters around.
-
-There are also other possible solutions for this task that do not require physics.
-Have a look at (and SphereMotionAllowedListener.java).
-To learn more about complex physics scenes where several mobile physical objects bump into each other, read Hello Physics.
-
-
-
-Do you want to hear your player say “ouch!” when he bumps into a wall? Continue with learning how to add sound to your game.
-
-
+To learn more about different ways of loading models and scene have a look at Hello Asset,Scene Explorer and Scene Composer There are also other possible solutions for this task that do not require physics.
+Have a look at jme3test.collision.TestSimpleCollision.java (and SphereMotionAllowedListener.java).
+To learn more about complex physics scenes where several mobile physical objects bump into each other, read Hello Physics.
+Do you want to hear your player say "ouch!" when he bumps into a wall? Continue with learning how to add sound to your game.
\ No newline at end of file
diff --git a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/beginner/hello_effects.html b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/beginner/hello_effects.html
index 3f4001e8b..d3a49c755 100644
--- a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/beginner/hello_effects.html
+++ b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/beginner/hello_effects.html
@@ -1,57 +1,30 @@
-
-
-When you see one of the following in a game, then a particle system is likely behind it:
-
-
-
Fire, flames, sparks;
-
-
Rain, snow, waterfalls, leaves;
-
-
Explosions, debris, shockwaves;
-
-
Dust, fog, clouds, smoke;
-
-
Insects swarms, meteor showers;
-
-
Magic spells.
-
-
-
-
-
-These things typically cannot be modeled by meshes.
-In very simple terms:
-
-
-
The difference between an explosion and a dust cloud is the speed of the effect.
-
-
The difference between flames and a waterfall is the direction and the color of the effect.
-
-
-
-
-
-Particle effects can be animated (e.g. sparks, drops) and static (strands of grass, hair). Non-particle effects include bloom/glow, and motion blur/afterimage. In this tutorial we will look at animated particles (com.jme3.effect).
-
When you see one of the following in a game, then a particle system is likely behind it:
Fire, flames, sparks;
Rain, snow, waterfalls, leaves;
Explosions, debris, shockwaves;
Dust, fog, clouds, smoke;
Insects swarms, meteor showers;
Magic spells.
These things typically cannot be modeled by meshes.
+In very simple terms:
The difference between an explosion and a dust cloud is the speed of the effect.
The difference between flames and a waterfall is the direction and the color of the effect.
Particle effects can be animated (e.g. sparks, drops) and static (strands of grass, hair). Non-particle effects include bloom/glow, and motion blur/afterimage. In this tutorial we will look at animated particles (com.jme3.effect).
-Start by choosing a material texture for your effect. If you provide the emitter with a set of textures (see image), it can use them either for variation (random order), or as animation steps (fixed order).
-
-
-
-Setting emitter textures works just as you have already learned in previous chapters. This time we use the Particle.j3md default material. In the following example, we have a closer look at the Debris effect.
-
-
...
+}
You should see an explosion that sends debris flying, and a fire. More example code
Start by choosing a material texture for your effect. If you provide the emitter with a set of textures (see image), it can use them either for variation (random order), or as animation steps (fixed order).
Setting emitter textures works just as you have already learned in previous chapters. This time we use the Particle.j3md default material. In the following example, we have a closer look at the Debris effect.
...
Material debris_mat = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md");
debris_mat.setTexture("Texture", assetManager.loadTexture("Effects/Explosion/Debris.png"));
debris.setMaterial(debris_mat);
debris.setImagesX(3); // columns
debris.setImagesY(3); // rows
debris.setSelectRandomImage(true);
- ...
-
Load the texture in the emitter's material.
-
-
Tell the Emitter into how many animation steps (x*y) the texture is divided. 1×1 is default.
-
-
Optionally, tell the Emitter whether the animation steps are to be at random, or in order.
-
-
-
-
-
-As you see in the debris example, texture animations improve effects because each “flame” or “piece of debris” looks different. Also think of electric or magic effects, where you can create very interesting animations by using an ordered morphing series of lightning bolts; or flying leaves or snow flakes, for instance.
-
-
-For your game, you will likely create custom textures. Look at the fire example again.
-
-
ParticleEmitter fire = new ParticleEmitter("Emitter", ParticleMesh.Type.Triangle, 30);
+ ...
Load the texture in the emitter's material.
Tell the Emitter into how many animation steps (x*y) the texture is divided. 1x1 is default.
Optionally, tell the Emitter whether the animation steps are to be at random, or in order.
As you see in the debris example, texture animations improve effects because each "flame" or "piece of debris" looks different. Also think of electric or magic effects, where you can create very interesting animations by using an ordered morphing series of lightning bolts; or flying leaves or snow flakes, for instance.
For your game, you will likely create custom textures. Look at the fire example again.
ParticleEmitter fire = new ParticleEmitter("Emitter", ParticleMesh.Type.Triangle, 30);
Material mat_red = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md");
mat_red.setTexture("m_Texture", assetManager.loadTexture("Effects/Explosion/flame.png"));
fire.setMaterial(mat_red);
fire.setImagesX(2); // columns
fire.setImagesY(2); // rows
fire.setEndColor( new ColorRGBA(1f, 0f, 0f, 1f)); // red
- fire.setStartColor(new ColorRGBA(1f, 1f, 0f, 0.5f)); // yellow
-
-
-
-
-
Black parts of the image will be rendered transparent.
-
-
White/gray parts of the image are transparent and will be colored.
-
-
You set the color (here, a gradient from yellow to red) in the code.
-
-
By default the animation will be played in order (?) and loop.
-
-
-
-
-
-Create a grayscale texture in a graphic editor, and save it to your assets/Effects directory. If you split up one image file into x*y animation steps, make sure each animation step is of equal size–just as you see in the examples here.
-
Optional accessors that control in which direction particles face when flying.
-
-
-
lifetime
setLowLife() (3f)
- setHighLife() (7f)
Minimum and maximum time period before particles fade.
-
-
-
emission rate
setParticlesPerSec() (20)
How many new particles are emitted per second.
-
-
-
color
setStartColor()
- setEndColor() (gray)
Set to two different colors for gradient effects, or to same color.
-
-
-
size
setStartSize() (0.2f)
- setEndSize() (2f)
Set to two different values for shrink/grow effect, or to same size.
-
-
-
gravity
setGravity() (0.1f)
Whether particles falls down eventually. Set to 0f for zero-g effects.
-
-
-
-
-
-You can find details about effect parameters in the user guide.
-Add and modify one paramter at a time, and try different values until you get the effect you want. Tip: Use the jMonkeyPlatform SceneComposer to preview effects settings (instructions: TODO).
-
Black parts of the image will be rendered transparent.
White/gray parts of the image are transparent and will be colored.
You set the color (here, a gradient from yellow to red) in the code.
By default the animation will be played in order (?) and loop.
Create a grayscale texture in a graphic editor, and save it to your assets/Effects directory. If you split up one image file into x*y animation steps, make sure each animation step is of equal size–just as you see in the examples here.
Optional accessors that control in which direction particles face when flying.
lifetime
setLowLife() (3f) setHighLife() (7f)
Minimum and maximum time period before particles fade.
emission rate
setParticlesPerSec() (20)
How many new particles are emitted per second.
color
setStartColor() setEndColor() (gray)
Set to two different colors for gradient effects, or to same color.
size
setStartSize() (0.2f) setEndSize() (2f)
Set to two different values for shrink/grow effect, or to same size.
gravity
setGravity() (0.1f)
Whether particles falls down eventually. Set to 0f for zero-g effects.
You can find details about effect parameters in the user guide.
+Add and modify one paramter at a time, and try different values until you get the effect you want. Tip: Use the jMonkeyPlatform SceneComposer to preview effects settings (instructions: TODO).
\ No newline at end of file
diff --git a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/beginner/hello_input_system.html b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/beginner/hello_input_system.html
index b69e29383..b010249ad 100644
--- a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/beginner/hello_input_system.html
+++ b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/beginner/hello_input_system.html
@@ -1,26 +1,11 @@
-
-
-By default, SimpleApplication sets up an input system that allows you to steer the camera with the WASD keys, the arrow keys, and the mouse. You can use it as a flying first-person camera right away. But what if you need a third-person camera, or you want keys to trigger special game actions?
-
-
-
-Every game has its custom keybindings, and this tutorial explains how you define them. We first define the key presses and mouse events, and then we define the actions they should trigger.
-
By default, SimpleApplication sets up an input system that allows you to steer the camera with the WASD keys, the arrow keys, and the mouse. You can use it as a flying first-person camera right away. But what if you need a third-person camera, or you want keys to trigger special game actions?
Every game has its custom keybindings, and this tutorial explains how you define them. We first define the key presses and mouse events, and then we define the actions they should trigger.
First you register each mapping name with its trigger(s). Remember the following:
The trigger can be a key press or mouse action.
The mapping name is a string that you can choose. The name should describe the action, not the trigger.
One named mapping can have several triggers. The "Rotate" action can be triggered by a click and by pressing the spacebar.
Have a look at the code:
You register the mapping named "Rotate" to the Spacebar trigger new KeyTrigger(KeyInput.KEY_SPACE)).
In the same line, you also register "Rotate" to the mouse button trigger new MouseButtonTrigger(MouseInput.BUTTON_LEFT)
You map the Pause, Left, Right mappings to the P, J, K keys, respectively.
You register the (on/off) pause action to the ActionListener
You register the (gradual) movement actions to the AnalogListener
// 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));
@@ -157,40 +114,17 @@ Have a look at the code:
new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
// Add the names to the action listener.
inputManager.addListener(actionListener, new String[]{"Pause"});
- inputManager.addListener(analogListener, new String[]{"Left", "Right", "Rotate"});
-
-This code usually goes into the simpleInitApp() method. But since we will likely add many keybindings, we extract these lines and wrap them in an auxiliary method, initKeys(). The initKeys() method is not part of the Input Controls interface – so you can name it whatever you like. Just don't forget to call your method from the initSimpleApp() method.
-
-
-Now you have mapped action names to input triggers. Now you specify the actions themselves.
-
-
-
-The two important methods here are the ActionListener with its onAction() method, and the AnalogListener with its onAnalog() method. In these two methods, you test for each named mapping, and call the game action you want to trigger.
-
-
-
-In this example, we set the following mappings:
-
-
-
-
The Rotate mapping triggers the action player.rotate(0, value, 0).
-
-
The Left and Right mappings increase and decrease the player's x coordinate.
-
-
The Pause mapping flips a boolean isRunning.
-
-
We also want to check the boolean isRunning before any action (other than unpausing) is executed.
-
-
-
private ActionListener() {
+ inputManager.addListener(analogListener, new String[]{"Left", "Right", "Rotate"});
This code usually goes into the simpleInitApp() method. But since we will likely add many keybindings, we extract these lines and wrap them in an auxiliary method, initKeys(). The initKeys() method is not part of the Input Controls interface – so you can name it whatever you like. Just don't forget to call your method from the initSimpleApp() method.
Now you have mapped action names to input triggers. Now you specify the actions themselves.
The two important methods here are the ActionListener with its onAction() method, and the AnalogListener with its onAnalog() method. In these two methods, you test for each named mapping, and call the game action you want to trigger.
In this example, we set the following mappings:
The Rotate mapping triggers the action player.rotate(0, value, 0).
The Left and Right mappings increase and decrease the player's x coordinate.
The Pause mapping flips a boolean isRunning.
We also want to check the boolean isRunning before any action (other than unpausing) is executed.
private ActionListener() {
public void onAction(String name, boolean keyPressed, float tpf) {
if (name.equals("Pause") && !keyPressed) {
isRunning = !isRunning;
@@ -216,145 +150,76 @@ In this example, we set the following mappings:
System.out.println("Press P to unpause.");
}
}
- };
-
-It's okay to use only one of the two Listeners, and not implement the other one, if you are not using this type of interaction. In the following, we have a closer look how to decide which of the two listeners is best suited for which situation.
-
-
-Technically, every input can be an “Analog” or a “on-off Action”. Here is how you find out which listener is the right one for which type of input.
-
-
-
-Mappings registered to the AnalogListener are triggered repeatedly and gradually.
-
-
-
Parameters:
-
-
JME gives you access to the name of the triggered action.
-
-
JME gives you access to a gradual value between 0-9 how long the key has been pressed.
-
-
-
-
Example: Navigational events (e.g. Left, Right, Rotate, Run, Strafe), situations where you interact continuously.
-
-
-
-
-
-Mappings registered to the ActionListener are treated in an absolute way – “Pressed or released? On or off?”
-
-
-
Parameters:
-
-
JME gives you access to the name of the triggered action.
-
-
JME gives you access to a boolean whether the key is pressed or not.
-
-Tip: It's very common that you want an action to be only triggered once, in the moment when the key is released. For instance when opening a door, flipping a boolean state, or picking up an item. To achieve that, you use an ActionListener and test for … && !keyPressed. For an example, look at the Pause button code.
-
-
if (name.equals("Pause") && !keyPressed) {
+ };
It's okay to use only one of the two Listeners, and not implement the other one, if you are not using this type of interaction. In the following, we have a closer look how to decide which of the two listeners is best suited for which situation.
Tip: It's very common that you want an action to be only triggered once, in the moment when the key is released. For instance when opening a door, flipping a boolean state, or picking up an item. To achieve that, you use an ActionListener and test for … && !keyPressed. For an example, look at the Pause button code.
if (name.equals("Pause") && !keyPressed) {
isRunning = !isRunning;
- }
-
-You can find the list of input constants in the files src/core/com/jme3/input/KeyInput.java, JoyInput.java, and MouseInput.java. Here is an overview of the most common triggers constants:
-
-
-
-Tip: If you don't recall an input constant during development, you benefit from an IDE's code completion functionality: Place the caret after e.g. KeyInput.| and trigger code completion to select possible input identifiers.
-
You can find the list of input constants in the files src/core/com/jme3/input/KeyInput.java, JoyInput.java, and MouseInput.java. Here is an overview of the most common triggers constants:
Tip: If you don't recall an input constant during development, you benefit from an IDE's code completion functionality: Place the caret after e.g. KeyInput.| and trigger code completion to select possible input identifiers.
-
-You now how to add custom interactions to your game: You know now that you first have to define the key mappings, and then the actions for each mapping. You have learned to respond to mouse events and to the keyboard. You understand the difference between “analog” (gradually repeated) and “digital” (on/off) inputs.
-
-
-
-Now you can already write a little interactive game! But wouldn't it be cooler if these old boxes were a bit more fancy? Let's continue with learning about materials.
-
You now how to add custom interactions to your game: You know now that you first have to define the key mappings, and then the actions for each mapping. You have learned to respond to mouse events and to the keyboard. You understand the difference between "analog" (gradually repeated) and "digital" (on/off) inputs.
Now you can already write a little interactive game! But wouldn't it be cooler if these old boxes were a bit more fancy? Let's continue with learning about materials.
\ No newline at end of file
diff --git a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/beginner/hello_main_event_loop.html b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/beginner/hello_main_event_loop.html
index f4df08bf1..ac58aa2e0 100644
--- a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/beginner/hello_main_event_loop.html
+++ b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/beginner/hello_main_event_loop.html
@@ -1,22 +1,11 @@
-
-
-Now that you know how to load assets such as 3-D models, you want them to implement the actual gameplay. In this tutorial we look at the update loop. The update loop of your game is where the action happens.
-
Now that you know how to load assets such as 3-D models, you want them to implement the actual gameplay. In this tutorial we look at the update loop. The update loop of your game is where the action happens.
-
-Compared to our previous code samples you note that the player Geometry is now a class field. This is because we want the update loop to be able to access and transform this Geometry. As you can see, we initialize the player object in the simpleInitApp() method.
-
-
-
-Now have a closer look at the simpleUpdate() method, this is the update loop.
-
-
-
The player.rotate(0, 2*tpf, 0); line changes the rotation of the player object.
-
-
We use the tpf variable (“time per frame”) to time this action depending on the current frames per second rate. This means the cube rotates with the same speed on fast machines, and the game remains playable.
-
-A rotating object is just a simple example. In the update loop, you can update score and health points, check for collisions, make enemies calculate their next move, roll the dice whether a trap has been set off, play random ambient sounds, and much more.
-
-
-
-
The update loop starts after the simpleInitApp() method has set up the scenegraph and state variables.
-
-
JME executes everything in the simpleUpdate() method repeatedly, as fast as possible.
-
-
Use the loop to poll the game state and initiate actions.
-
-
Use the loop to trigger reactions and update the game state.
-
-
Use it wisely, because having too many calls in the loop also slows down the game.
-
-Now you are listening to the update loop, “the heart beat” of the game, and you can add all kinds of action to it.
-
-
-
-The next thing the game needs is some interaction! Continue learning how to respond to user input.
-
-
-
-
-See also: Advanced jME3 developers additionally use Application States and Custom Controls to implement more complex mechanics in their game loops. You will come across these topics later when you proceed to advanced documentation.
-
Compared to our previous code samples you note that the player Geometry is now a class field. This is because we want the update loop to be able to access and transform this Geometry. As you can see, we initialize the player object in the simpleInitApp() method.
Now have a closer look at the simpleUpdate() method, this is the update loop.
The player.rotate(0, 2*tpf, 0); line changes the rotation of the player object.
We use the tpf variable ("time per frame") to time this action depending on the current frames per second rate. This means the cube rotates with the same speed on fast machines, and the game remains playable.
A rotating object is just a simple example. In the update loop, you can update score and health points, check for collisions, make enemies calculate their next move, roll the dice whether a trap has been set off, play random ambient sounds, and much more.
The update loop starts after the simpleInitApp() method has set up the scenegraph and state variables.
JME executes everything in the simpleUpdate() method repeatedly, as fast as possible.
Use the loop to poll the game state and initiate actions.
Use the loop to trigger reactions and update the game state.
Use it wisely, because having too many calls in the loop also slows down the game.
Now you are listening to the update loop, "the heart beat" of the game, and you can add all kinds of action to it.
The next thing the game needs is some interaction! Continue learning how to respond to user input.
See also: Advanced jME3 developers additionally use Application States and Custom Controls to implement more complex mechanics in their game loops. You will come across these topics later when you proceed to advanced documentation.
\ No newline at end of file
diff --git a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/beginner/hello_material.html b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/beginner/hello_material.html
index b180c5136..fbb36cc54 100644
--- a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/beginner/hello_material.html
+++ b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/beginner/hello_material.html
@@ -1,27 +1,15 @@
-
-
-When we speak of Materials, we mean everything that influences what the surface of a 3D model looks like: The color, texture, and material (shininess, opacity/transparency). Simple coloring is covered in Hello Node. Loading models that come with materials is covered in Hello Asset. Here we focus on using and creating JME3 Material Definitions.
-
Previous: Hello Input System,
+Next: Hello Animation When we speak of Materials, we mean everything that influences what the surface of a 3D model looks like: The color, texture, and material (shininess, opacity/transparency). Simple coloring is covered in Hello Node. Loading models that come with materials is covered in Hello Asset. Here we focus on using and creating JME3 Material Definitions.
package jme3test.helloworld;
import com.jme3.app.SimpleApplication;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
@@ -34,21 +22,16 @@ import com.jme3.scene.shape.Sphere;
import com.jme3.texture.Texture;
import com.jme3.util.TangentBinormalGenerator;
import com.jme3.renderer.queue.RenderQueue.Bucket;
-
-
/** Sample 6 - how to give an object's surface a material and texture.
* How to make objects transparent, or let colors "leak" through partially
* transparent textures. How to make bumpy and shiny surfaces. */
public class HelloMaterial extends SimpleApplication {
-
public static void main(String[] args) {
HelloMaterial app = new HelloMaterial();
app.start();
}
-
@Override
public void simpleInitApp() {
-
/** A simple textured cube -- in good MIP map quality. */
Box(new Vector3f(-3f,1.1f,0f), 1f,1f,1f);
Geometry cube = new Geometry("My Textured Box", boxshape1);
@@ -57,38 +40,35 @@ public class HelloMaterial extends SimpleApplication {
mat_stl.setTexture("ColorMap", tex_ml);
cube.setMaterial(mat_stl);
rootNode.attachChild(cube);
-
/** A translucent/transparent texture, similar to a window frame. */
Box(new Vector3f(0f,0f,0f), 1f,1f,0.01f);
Geometry window_frame = new Geometry("window frame", boxshape3);
Material mat_tt = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
- mat_tt.setTexture("ColorMap",
+ mat_tt.setTexture("ColorMap",
assetManager.loadTexture("Textures/ColoredTex/Monkey.png"));
mat_tt.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
window_frame.setMaterial(mat_tt);
/** Objects with transparency need to be in the render bucket for transparent objects: */
- window_frame.setQueueBucket(Bucket.Transparent);
+ window_frame.setQueueBucket(Bucket.Transparent);
rootNode.attachChild(window_frame);
-
/** A cube with base color "leaking" through a partially transparent texture */
Box(new Vector3f(3f,-1f,0f), 1f,1f,1f);
Geometry cube_leak = new Geometry("Leak-through color cube", boxshape4);
Material mat_tl = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
- mat_tl.setTexture("ColorMap",
+ mat_tl.setTexture("ColorMap",
assetManager.loadTexture("Textures/ColoredTex/Monkey.png"));
mat_tl.setColor("Color", new ColorRGBA(1f,0f,1f, 1f)); // purple
cube_leak.setMaterial(mat_tl);
rootNode.attachChild(cube_leak);
-
/** A bumpy rock with a shiny light effect */
Sphere rock = new Sphere(32,32, 2f);
Geometry shiny_rock = new Geometry("Shiny rock", rock);
rock.setTextureMode(Sphere.TextureMode.Projected); // better quality on spheres
TangentBinormalGenerator.generate(rock); // for lighting effect
Material mat_lit = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
- mat_lit.setTexture("DiffuseMap",
+ mat_lit.setTexture("DiffuseMap",
assetManager.loadTexture("Textures/Terrain/Pond/Pond.png"));
- mat_lit.setTexture("NormalMap",
+ mat_lit.setTexture("NormalMap",
assetManager.loadTexture("Textures/Terrain/Pond/Pond_normal.png"));
mat_lit.setFloat("Shininess", 5f); // [0,128]
shiny_rock.setMaterial(mat_lit);
@@ -100,327 +80,187 @@ public class HelloMaterial extends SimpleApplication {
sun.setDirection(new Vector3f(1,0,-2).normalizeLocal());
sun.setColor(ColorRGBA.White);
rootNode.addLight(sun);
-
}
-}
-
-You should see
-
-
-
Left – A cube with a brown monkey texture.
-
-
Middle – A translucent monkey picture in front of a shiny rock.
-
-
Right – A cube with a purple monkey texture.
-
-
-
-
-Move around with the WASD keys to have a closer look at the translucency, and the rock's bumpiness.
-
-
-Typically you want to give objects in your scene textures: It can be rock, grass, brick, wood, water, metal, paper… A texture is a normal image file in JPG or PNG format. In this example, we create a box with a simple unshaded Monkey texture as material.
-
-
/** A simple textured cube. */
+}
You should see
Left – A cube with a brown monkey texture.
Middle – A translucent monkey picture in front of a shiny rock.
Right – A cube with a purple monkey texture.
Move around with the WASD keys to have a closer look at the translucency, and the rock's bumpiness.
Typically you want to give objects in your scene textures: It can be rock, grass, brick, wood, water, metal, paper… A texture is a normal image file in JPG or PNG format. In this example, we create a box with a simple unshaded Monkey texture as material.
/** A simple textured cube. */
Box(new Vector3f(-3f,1.1f,0f), 1f,1f,1f);
Geometry cube = new Geometry("My Textured Box", boxshape1);
Material mat_stl = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
Texture tex_ml = assetManager.loadTexture("Interface/Logo/Monkey.jpg");
mat_stl.setTexture("ColorMap", tex_ml);
cube.setMaterial(mat_stl);
- rootNode.attachChild(cube);
-
-Here is what we did:
-
-
-
Create a Geometry from a mesh. This geometry is a cube.
-
-
Create a Material based on jME3's default Unshaded.j3md material definition.
-
-
Create a texture from the Monkey.jpg file and load it into the material.
- The ColorMap is the material layer where textures go.
-
-
Apply the material to the cube and attach the cube to the rootnode.
-
-Monkey.png is the same texture as Monkey.jpg, but with an added alpha channel. The alpha channel allows you to specify which areas of the texture you want to be translucent: Black areas remain opaque, gray areas become translucent, and white areas become transparent. In combination with setting the texture blend mode to BlendMode.Alpha, this results in a partially translucent/transparent texture!
-
-
-
-You also need to set the render bucket of the object with the translucent texture to Bucket.Transparent. This ensures that the translucent object is drawn on top of objects behind it, and they show up correctly under the translucent parts. For non-translucent objects the drawing order is not so important, because the z-buffer keeps track of whether a pixel is behind something else or not, and the color of a pixel doesn't depend on the pixels under it, so they can be drawn in any order.
-
-
/** A translucent/transparent texture. */
+ rootNode.attachChild(cube);
Here is what we did:
Create a Geometry from a mesh. This geometry is a cube.
Create a Material based on jME3's default Unshaded.j3md material definition.
Create a texture from the Monkey.jpg file and load it into the material. The ColorMap is the material layer where textures go.
Apply the material to the cube and attach the cube to the rootnode.
Monkey.png is the same texture as Monkey.jpg, but with an added alpha channel. The alpha channel allows you to specify which areas of the texture you want to be translucent: Black areas remain opaque, gray areas become translucent, and white areas become transparent. In combination with setting the texture blend mode to BlendMode.Alpha, this results in a partially translucent/transparent texture!
+You also need to set the render bucket of the object with the translucent texture to Bucket.Transparent. This ensures that the translucent object is drawn on top of objects behind it, and they show up correctly under the translucent parts. For non-translucent objects the drawing order is not so important, because the z-buffer keeps track of whether a pixel is behind something else or not, and the color of a pixel doesn't depend on the pixels under it, so they can be drawn in any order.
/** A translucent/transparent texture. */
Box(new Vector3f(0f,0f,0f), 1f,1f,0.01f);
Geometry seethrough = new Geometry("see-through box", boxshape3);
Material mat_tt = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
- mat_tt.setTexture("ColorMap",
+ mat_tt.setTexture("ColorMap",
assetManager.loadTexture("Textures/ColoredTex/Monkey.png"));
mat_tt.getAdditionalRenderState().setBlendMode(BlendMode.Alpha); // activate transparency
seethrough.setMaterial(mat_tt);
- seethrough.setQueueBucket(Bucket.Transparent);
- rootNode.attachChild(seethrough);
-
-What we did it the same as before, with only one added step for the transparency.
-
-
-
Create a Geometry from a mesh. This Geometry is flat upright box.
-
-
Create a Material based on jME3's default Unshaded.j3md material definition.
-
-
Create a texture from the Monkey.png file and load it into the material.
- The ColorMap is the material layer where textures go. The PNG file must have an alpha layer.
-
-
Activate transparency in the material by setting the blend mode to Alpha!
-
-
Apply the material to the cube.
-
-
Set the QueueBucket of the cube to Bucket.Transparent to ensure that the translucent objects is drawn after objects behind it.
-
-
Attach the cube to the rootnode.
-
-
-
-
-
-Tip: Learn more about creating PNG images with an alpha layer in the help system of your graphic editor.
-
-
-But textures are not all. Have a look at the shiny bumpy sphere again – you cannot get such a nice material with just a texture. We will have a quick look at some advanced jme features here – lit materials:
-
-
-
-In a lit material, the standard texture layer is refered to as Diffuse Map, any material can have it. A lit material can additionally have lighting effects such as Shininess used together with the Specular Map layer, and even a realistically bumpy or cracked surface with help of the Normal Map layer.
-
-
-
-Let's have a look at the part of the code example where you create the shiny bumpy rock.
-
-
-
Create a Geometry from a mesh. This Geometrx is a normal smooth sphere.
Sphere rock = new Sphere(32,32, 2f);
- Geometry shiny_rock = new Geometry("Shiny rock", rock);
-
-
(Only for Spheres) Change the sphere's TextureMode to make the square texture project better onto the sphere.
Set the material's Shininess to a value between 0 and 127.
mat_lit.setFloat("Shininess", 5f); // [0,128]
-
-
-
-
Assign your newly created material to the rock.
shiny_rock.setMaterial(mat_lit);
-
-
Let's move and rotate the geometry a bit to position it better.
shiny_rock.setLocalTranslation(0,2,-2); // Move it a bit
+ seethrough.setQueueBucket(Bucket.Transparent);
+ rootNode.attachChild(seethrough);
What we did it the same as before, with only one added step for the transparency.
Create a Geometry from a mesh. This Geometry is flat upright box.
Create a Material based on jME3's default Unshaded.j3md material definition.
Create a texture from the Monkey.png file and load it into the material. The ColorMap is the material layer where textures go. The PNG file must have an alpha layer.
Activate transparency in the material by setting the blend mode to Alpha!
Apply the material to the cube.
Set the QueueBucket of the cube to Bucket.Transparent to ensure that the translucent objects is drawn after objects behind it.
Attach the cube to the rootnode.
Tip: Learn more about creating PNG images with an alpha layer in the help system of your graphic editor.
But textures are not all. Have a look at the shiny bumpy sphere again – you cannot get such a nice material with just a texture. We will have a quick look at some advanced jme features here – lit materials:
+In a lit material, the standard texture layer is refered to as Diffuse Map, any material can have it. A lit material can additionally have lighting effects such as Shininess used together with the Specular Map layer, and even a realistically bumpy or cracked surface with help of the Normal Map layer.
+Let's have a look at the part of the code example where you create the shiny bumpy rock.
Create a Geometry from a mesh. This Geometrx is a normal smooth sphere.
Sphere rock = new Sphere(32,32, 2f);
+ Geometry shiny_rock = new Geometry("Shiny rock", rock);
(Only for Spheres) Change the sphere's TextureMode to make the square texture project better onto the sphere.
-
-Look at the purple leak-through sample above again. It takes four lines to create and set the Material.
-
-
-
Note how it loads the Unshaded.j3md Material definition.
-
-
Note how it sets to Color parameter to purple (new ColorRGBA(1f,0f,1f,1f)).
-
-
Note how it sets the ColorMap to a texture path.
-
-
-
-
-If you want to use one custom material for several models, you can store it in a .j3m file, and save a few lines of code every time. Here is an example:
-
-
-
-Create a file assets/Materials/LeakThrough.j3m with the following content:
-
-
-
Material Leak Through : Common/MatDefs/Misc/Unshaded.j3md {
+ rootNode.attachChild(shiny_rock);
Note that any lighting material requires a light source.
Look at the purple leak-through sample above again. It takes four lines to create and set the Material.
Note how it loads the Unshaded.j3md Material definition.
Note how it sets to Color parameter to purple (new ColorRGBA(1f,0f,1f,1f)).
Note how it sets the ColorMap to a texture path.
If you want to use one custom material for several models, you can store it in a .j3m file, and save a few lines of code every time. Here is an example:
+Create a file assets/Materials/LeakThrough.j3m with the following content:
Material Leak Through : Common/MatDefs/Misc/Unshaded.j3md {
MaterialParameters {
Color : 1 0 1 1
ColorMap : Textures/ColoredTex/Monkey.png
}
-}
-
-
Note that Material is a keyword.
-
-
Note that Leak Through is a name that you can choose.
-
-
Note how it sets the same three properties, Color, ColorMap, and Unshaded.j3md.
-
-
-
-
-Using this new custom material LeakThrough.j3m only takes one line.
-
-
-
In the code sample, comment out the three lines with mat_tl in them.
-
-You have replaced the three lines of an on-the-fly material definition with one line that loads a custom material from a file. This method is very handy if you use the same material often.
-
-
-You have learned how to create a Material, specify its properties, and use it on a Geometry. You know how to load an image file (.png, .jpg) as texture into a material. You know to save texture files in a subfolder of your project's assets/Textures/ directory.
-
-
-
-You have also learned that a material can be stored in a .j3m file. The file references a built-in Material Definition and specifies values for properties of that MaterialDefinition. You know to save your custom .j3m files in your project's assets/Materials/ directory.
-
-
-
-Now that you know how to load models and how to assign good-looking materials to them, let's have a look at how to animate models in the next chapter, Hello Animation.
-
-
You have replaced the three lines of an on-the-fly material definition with one line that loads a custom material from a file. This method is very handy if you use the same material often.
You have learned how to create a Material, specify its properties, and use it on a Geometry. You know how to load an image file (.png, .jpg) as texture into a material. You know to save texture files in a subfolder of your project's assets/Textures/ directory.
+You have also learned that a material can be stored in a .j3m file. The file references a built-in Material Definition and specifies values for properties of that MaterialDefinition. You know to save your custom .j3m files in your project's assets/Materials/ directory.
+Now that you know how to load models and how to assign good-looking materials to them, let's have a look at how to animate models in the next chapter, Hello Animation.
Various Material screenshots (Not done with JME3, this is just to show the fantastic range of Material parameters in the hands of an expert, until we have a JME3 demo for it.)
\ No newline at end of file
diff --git a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/beginner/hello_node.html b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/beginner/hello_node.html
index b0cc1b87d..50bb846ba 100644
--- a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/beginner/hello_node.html
+++ b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/beginner/hello_node.html
@@ -1,27 +1,12 @@
-
-
-When creating a 3D game, you start out with creating a scene and some objects. You place the objects (player tokens, obstacles, etc) in the scene, and move, resize, rotate, color, and animate them.
-
-
-
-In this tutorial we will have a look at a simple 3D scene. You will learn that the 3D world is represented in a scene graph, and why the rootNode is important. You will learn how to create simple objects and how to transform them – move, scale, rotate. You will understand the difference between the two types of Spatials in the scene graph, Node and Geometry. For a visual introduction to the scene graph check out our Scene Graph for Dummies presentation.
-
When creating a 3D game, you start out with creating a scene and some objects. You place the objects (player tokens, obstacles, etc) in the scene, and move, resize, rotate, color, and animate them.
In this tutorial we will have a look at a simple 3D scene. You will learn that the 3D world is represented in a scene graph, and why the rootNode is important. You will learn how to create simple objects and how to transform them – move, scale, rotate. You will understand the difference between the two types of Spatials in the scene graph, Node and Geometry. For a visual introduction to the scene graph check out our Scene Graph for Dummies presentation.
package jme3test.helloworld;
import com.jme3.app.SimpleApplication;
import com.jme3.material.Material;
import com.jme3.math.Vector3f;
@@ -29,297 +14,203 @@ import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Box;
import com.jme3.math.ColorRGBA;
import com.jme3.scene.Node;
-
/** Sample 2 - How to use nodes as handles to manipulate objects in the scene graph.
* You can rotate, translate, and scale objects by manipulating their parent nodes.
* The Root Node is special: Only what is attached to the Root Node appears in the scene. */
public class HelloNode extends SimpleApplication {
-
public static void main(String[] args){
HelloNode app = new HelloNode();
app.start();
}
-
@Override
public void simpleInitApp() {
-
// create a blue box at coordinates (1,-1,1)
Box( new Vector3f(1,-1,1), 1,1,1);
Geometry blue = new Geometry("Box", box1);
Material mat1 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat1.setColor("Color", ColorRGBA.Blue);
blue.setMaterial(mat1);
-
// create a red box straight above the blue one at (1,3,1)
Box( new Vector3f(1,3,1), 1,1,1);
Geometry red = new Geometry("Box", box2);
Material mat2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat2.setColor("Color", ColorRGBA.Red);
red.setMaterial(mat2);
-
// create a pivot node at (0,0,0) and attach it to root
Node pivot = new Node("pivot");
rootNode.attachChild(pivot);
-
// attach the two boxes to the *pivot* node!
pivot.attachChild(blue);
pivot.attachChild(red);
// rotate pivot node: Both boxes have rotated!
pivot.rotate( 0.4f , 0.4f , 0.0f );
-
}
-}
-
-Build and run the code sample. You should see two colored boxes tilted at the same angle.
-
So what exactly happens in this code snippet? Note that we are using the simpleInitApp() method that was introduced in the first tutorial.
We create a box Geometry.
The box Geometry's extends are (1,1,1), that makes it 2x2x2 world units big.
We place the box at (1,-1,1)
We give it a solid blue material.
Box( new Vector3f(1,-1,1), 1,1,1);
Geometry blue = new Geometry("Box", box1);
Material mat1 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat1.setColor("Color", ColorRGBA.Blue);
- blue.setMaterial(mat1);
-
-
-
-
We create a second box Geometry.
-
-
This box Geometry is also 2x2x2 world units big.
-
-
We place the second box at (1,3,1). This is straight above the blue box, with a gap of 2 world units inbetween.
-
-
We give it a solid red material
Box( new Vector3f(1,3,1), 1,1,1);
+ blue.setMaterial(mat1);
We create a second box Geometry.
This box Geometry is also 2x2x2 world units big.
We place the second box at (1,3,1). This is straight above the blue box, with a gap of 2 world units inbetween.
We give it a solid red material
Box( new Vector3f(1,3,1), 1,1,1);
Geometry red = new Geometry("Box", box2);
Material mat2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat2.setColor("Color", ColorRGBA.Red);
- red.setMaterial(mat2);
-
-
-
-
We create a Node.
-
-
By default the Node is placed at (0,0,0).
-
-
We attach the Node to the rootNode.
-
-
An attached Node has no visible appearance in the scene.
Node pivot = new Node("pivot");
- rootNode.attachChild(pivot);
-
-
-
-
Note that we have not attached the two boxes to anything yet!
-
-
If we ran the application now, the scenegraph would appear empty.
-
-
-
-
We attach the two boxes to the node.
-
-
If we ran the app now, we would see two boxes: one straight above the other.
When we run the application now, we see two boxes on top of each other – but both are tilted at the same angle.
pivot.rotate( 0.4f , 0.4f , 0.0f );
-
-
-
-
-
-
-
-What has happened? We have attached two box Geometries to a Node. Then we used the Node as a handle to grab the two boxes and transform (rotate) both, in one step. This is a common task and you will use this method a lot in your games when you move game characters around.
-
When we run the application now, we see two boxes on top of each other – but both are tilted at the same angle.
pivot.rotate( 0.4f , 0.4f , 0.0f );
What has happened? We have attached two box Geometries to a Node. Then we used the Node as a handle to grab the two boxes and transform (rotate) both, in one step. This is a common task and you will use this method a lot in your games when you move game characters around.
Create a shape and give it a Material. For instance a box shape:
Box(Vector3f.ZERO, 1, 1, 1);
Geometry thing = new Geometry("thing", mesh);
Material mat = new Material(assetManager, "Common/MatDefs/Misc/ShowNormals.j3md");
-thing.setMaterial(mat);
-
-
-
Make an object appear in the scene
Attach the Spatial to the rootNode, or to any node that is attached to the rootNode.
rootNode.attachChild(thing);
-
-
-
Remove objects from the scene
Detach the Spatial from the rootNode, and from any node that is attached to the rootNode.
rootNode.detachChild(thing);
rootNode.detachAllChildren();
-
-
-
Find a Spatial in the scene by the object's name or ID
Look at the node's children.
Spatial thing = rootNode.getChild("thing");
Spatial twentythird = rootNode.getChild(22);
-
-
-
Specify what should be loaded at the start
Everything you initialize and attach to the rootNode in the simpleInitApp() method is part of the scene at the start of the game.
-
-There are three types of 3D transformation: Translation (moving), Scaling (resizing), and Rotation (turning).
-
-
-
-
-
Task?
Solution!
X
Y
Z
-
-
-
Position and move objects
Translation: Specify the new location in three dimensions: right/left, up/down, forward/backward.
- Example 1. To move an object to specific coordinates, such as (0,40.2f,-2), use:
thing.setLocalTranslation( new Vector3f( 0.0f, 40.2f, -2.0f ) );
-
-
- Example 2: To move an object by a certain amount, e.g. higher up (y=40.2f) and further back (z=-2.0f):
-
-
thing.move( 0.0f, 40.2f, -2.0f );
right/left
up/down
foreward/ backward
-
-
-
Resize objects
Scaling: To resize a Spatial, specify the scale factor in each dimension: length, height, width. A value between 0.0f and 1.0f will shrink the object; a value bigger than 1.0f will make it grow; and 1.0f will keep this dimension the same. Using the same value for each dimension scales an object proportionally, using different values stretches it.
- Example: Make it 10 times longer, one tenth of the height, same width:
thing.setLocalScale( 10.0f, 0.1f, 1.0f );
thing.scale( 10.0f, 0.1f, 1.0f );
length
height
width
-
-
-
Turn objects
Rotation: 3-D rotation is a bit tricky (learn details here). In short: You can rotate around three axes, pitch, yaw, and roll.
- Important: You do not specify the rotation in degrees from 0° to 360°, but in radians from 0.0f to 6.28f (FastMath.PI*2) !
- Example: To roll an object 180° around the z axis:
thing.rotate( 0f , 0f , FastMath.PI );
-
- Tip: If your game idea calls for a serious amount of rotations, it is worth looking into quaternions, a data structure that can combine and store rotations efficiently.
-
-
thing.setLocalRotation( new Quaternion(). fromAngleAxis(FastMath.PI/2, new Vector3f(1,0,0)));
-
-If you get unexpected results, check whether you made the following common mistakes:
-
-
-
-
-
Problem?
Solution!
-
-
-
Created Geometry does not appear in scene
Have you attached it to (a node that is attached to) the rootNode?
- Does it have a Material?
- What is its translation (positition)? Is it covered up by another Geometry?
-
-
-
Spatial rotates wrong
Did you use radian values, and not degrees?
- Did you rotate the intended pivot node?
- Did you rotate around the right axis?
-
-
-
Geometry has an unexpected Material
Did you reuse a Material from another Geometry and have inadvertently changed its properties?
-
-You have learned that the 3D world is a Scene Graph of Spatials: Visible Geometries and invisible Nodes. You can transform Spatials, or attach them to nodes and transform the nodes.
-
-
-
-Since standard shapes like spheres and boxes get old fast, continue with the next chapter where you learn to load assets, such as 3-D models.
-
There are three types of 3D transformation: Translation (moving), Scaling (resizing), and Rotation (turning).
Task?
Solution!
X
Y
Z
Position and move objects
Translation: Specify the new location in three dimensions: right/left, up/down, forward/backward. Example 1. To move an object to specific coordinates, such as (0,40.2f,-2), use:
thing.setLocalTranslation( new Vector3f( 0.0f, 40.2f, -2.0f ) );
Example 2: To move an object by a certain amount, e.g. higher up (y=40.2f) and further back (z=-2.0f):
thing.move( 0.0f, 40.2f, -2.0f );
right/left
up/down
forward/ backward
Resize objects
Scaling: To resize a Spatial, specify the scale factor in each dimension: length, height, width. A value between 0.0f and 1.0f will shrink the object; a value bigger than 1.0f will make it grow; and 1.0f will keep this dimension the same. Using the same value for each dimension scales an object proportionally, using different values stretches it. Example: Make it 10 times longer, one tenth of the height, same width:
thing.setLocalScale( 10.0f, 0.1f, 1.0f );
thing.scale( 10.0f, 0.1f, 1.0f );
length
height
width
Turn objects
Rotation: 3-D rotation is a bit tricky (learn details here). In short: You can rotate around three axes, pitch, yaw, and roll. Important: You do not specify the rotation in degrees from 0° to 360°, but in radians from 0.0f to 6.28f (FastMath.PI*2) ! Example: To roll an object 180° around the z axis:
thing.rotate( 0f , 0f , FastMath.PI );
If you do want to specify angles in degrees then multiply your degrees value with FastMath.DEG_TO_RAD Example:
Tip: If your game idea calls for a serious amount of rotations, it is worth looking into quaternions, a data structure that can combine and store rotations efficiently.
thing.setLocalRotation( new Quaternion(). fromAngleAxis(FastMath.PI/2, new Vector3f(1,0,0)));
If you get unexpected results, check whether you made the following common mistakes:
Problem?
Solution!
Created Geometry does not appear in scene
Have you attached it to (a node that is attached to) the rootNode? Does it have a Material? What is its translation (position)? Is it covered up by another Geometry? Is it too far from the camera? try cam.setFrustumFar(111111f);
Spatial rotates wrong
Did you use radian values, and not degrees? (if you used degrees multiply them with FastMath.DEG_TO_RAD to get them converted to radians) Did you rotate the intended pivot node? Did you rotate around the right axis?
Geometry has an unexpected Material
Did you reuse a Material from another Geometry and have inadvertently changed its properties? (if so, maybe consider cloning: mat2 = mat.clone(); )
You have learned that the 3D world is a Scene Graph of Spatials: Visible Geometries and invisible Nodes. You can transform Spatials, or attach them to nodes and transform the nodes.
Since standard shapes like spheres and boxes get old fast, continue with the next chapter where you learn to load assets, such as 3-D models.
\ No newline at end of file
diff --git a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/beginner/hello_physics.html b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/beginner/hello_physics.html
index b2618277f..e78b52ecb 100644
--- a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/beginner/hello_physics.html
+++ b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/beginner/hello_physics.html
@@ -1,51 +1,26 @@
-
-
-
-In the previous tutorials, we were using Geometries (boxes, spheres, and models) that we placed in the scene. Geometries can float in mid-air and even overlap – they are not affected by “gravity” and have no physical mass. This tutorial shows how to add physical properties to Geometries.
-
-
-
-As always, we start with a standard com.jme3.app.SimpleApplication. To activate physics, we create a com.jme3.bullet.BulletAppState, and and attach it to the SimpleApplication's application state manager.
-
-
public class HelloPhysics extends SimpleApplication {
+}
You should see a brick wall that is casting a shadow on a floor. Click to shoot cannon balls. Watch the bricks fall and bounce off one another!
In the previous tutorials, we were using Geometries (boxes, spheres, and models) that we placed in the scene. Geometries can float in mid-air and even overlap – they are not affected by "gravity" and have no physical mass. This tutorial shows how to add physical properties to Geometries.
As always, we start with a standard com.jme3.app.SimpleApplication. To activate physics, we create a com.jme3.bullet.BulletAppState, and and attach it to the SimpleApplication's application state manager.
public class HelloPhysics extends SimpleApplication {
private BulletAppState bulletAppState;
public void simpleInitApp() {
bulletAppState = new BulletAppState();
stateManager.attach(bulletAppState);
}
-}
-
-The BulletAppState gives the game access to a Physics Space. The Physics Space allows us to use com.jme3.bullet.control.PhysicsControls that add physical properties to Nodes.
-
-
-In this “shoot at the wall” example, we use Geometries such as cannon balls and bricks. A geometry just describes the shape and look of an object.
-
-
/** Prepare geometries and physical nodes for bricks and cannon balls. */
+}
The BulletAppState gives the game access to a Physics Space. The Physics Space allows us to use com.jme3.bullet.control.PhysicsControls that add physical properties to Nodes.
In this "shoot at the wall" example, we use Geometries such as cannon balls and bricks. A geometry just describes the shape and look of an object.
/** Prepare geometries and physical nodes for bricks and cannon balls. */
private static final Box box;
private static final Sphere sphere;
private static final Box floor;
@@ -317,31 +261,15 @@ In this “shoot at the wall” example, we use Geometries such as cannon balls
/** Initialize the floor geometry */
floor = new Box(Vector3f.ZERO, 10f, 0.1f, 5f);
floor.scaleTextureCoordinates(new Vector2f(3, 6));
- }
You will notice that the cannon ball is created in the same way:
The makeCannonBall() methods creates a physics node cannonballNode. The cannon ball shall have
a visible Geometry ball_geo
physical properties ball_phy
a mass of 1.0f.
public void makeCannonBall() {
/** Create a cannon ball geometry and attach to scene graph. */
Geometry ball_geo = new Geometry("cannon ball", sphere);
ball_geo.setMaterial(stone_mat);
@@ -407,47 +313,25 @@ The makeCannonBall() methods creates a physics node cannonbal
bulletAppState.getPhysicsSpace().add(ball_phy);
/** Accelerate the physcial ball to shoot it. */
ball_phy.setLinearVelocity(cam.getDirection().mult(25));
- }
-
-This code sample does the following:
-
-
-
We use a sphere shape as cannonball, and give it a stone material.
-
-
We attach the ball to the rootNode and position it where the camera is.
-
-
(Optionally, we activate a “Cast and Receive” shadow mode for the ball.)
-
-
We create a RigidBodyControl for the ball, add it to the ball Geometry, and register it to the PhysicsSpace.
-
-
Since are are shooting cannon balls here, we accelerate the ball in the direction the camera is looking, with a speed of 25f.
The (static) floor has one important difference compared to the (dynamic) bricks and cannonballs: A mass of zero.
As before, we write a custom initFloor() method that creates a flat box with a rock texture that we use as floor. The floor shall have:
a visible Geometry floor_geo
physical properties floor_phy
A mass of 0.0f!
private RigidBodyControl floor_phy;
...
public void initFloor() {
Box(Vector3f.ZERO, 10f, 0.1f, 5f);
@@ -461,144 +345,54 @@ As before, we write a custom initFloor() method that creates a flat
floor_phy = new RigidBodyControl(0.0f);
floor_geo.addControl(floor_phy);
bulletAppState.getPhysicsSpace().add(floor_phy);
-
-
-This code sample does the following:
-
-
-
We use a box shape as floor, and give it a floor material.
-
-
We attach the floor to the rootNode and position it a bit below the origin – to prevent overlap with other physical nodes.
-
-
(Optionally, we activate a “Receive” shadow mode for the floor. The floor does not cast any shadows, this saves computing time.)
-
-
Static objects such as floors are mass-less and are not affected by gravity! Therefor we create a RigidBodyControl with a mass of 0.0f.
-
-
We add the RigidBodyControl to the floor Geometry, and register it to the PhysicsSpace.
-
-Let's have a quick look at the remaining custom helper methods: initMaterial(), initShadows(), initCrossHairs(), and initWall().
-
-
-
-
initMaterial() – This method initializes all the materials we use in this demo.
-
-
initShadows() – (Optional) We deactivate the rootNode's default ShadowMode and use a JME SceneProcessor called BasicShadowRenderer from the com.jme3.shadow package. For every relevant scene node (floor, cannon balls, bricks) we specify individually what shadow behaviour we want, Cast, Receive, or both.
-
-
initWall() – A double loop that generates a wall by positioning brick objects: 15 rows high with 4 bricks per row. It's important to space the bricks so the do not overlap.
-
-
initCrossHairs() – This method simply displays a plus sign that we use as crosshairs for aiming. Note that screen elements such as crosshairs are attached to the guiNode, not the rootNode.
-
-
-
-
-
-These methods are each called once from the simpleInitApp() method at the start of the game. As you see, you write any number of custom methods to set up your game's scene.
-
Let's have a quick look at the remaining custom helper methods: initMaterial(), initShadows(), initCrossHairs(), and initWall().
initMaterial() – This method initializes all the materials we use in this demo.
initShadows() – (Optional) We deactivate the rootNode's default ShadowMode and use a JME SceneProcessor called BasicShadowRenderer from the com.jme3.shadow package. For every relevant scene node (floor, cannon balls, bricks) we specify individually what shadow behaviour we want, Cast, Receive, or both.
initWall() – A double loop that generates a wall by positioning brick objects: 15 rows high with 4 bricks per row. It's important to space the bricks so the do not overlap.
initCrossHairs() – This method simply displays a plus sign that we use as crosshairs for aiming. Note that screen elements such as crosshairs are attached to the guiNode, not the rootNode.
These methods are each called once from the simpleInitApp() method at the start of the game. As you see, you write any number of custom methods to set up your game's scene.
-In the moment the cannonball appears in the scene, it flies off with the velocity (and in the direction) that we have specified using setLinearVelocity() inside makeCannonBall(). The newly created cannon ball flies off, hits the wall, and exerts a physical force that shifts the individual bricks.
-
-The location of the spatial is defined by the RigidBodyControl, move that to move the spatial or if its a non-world-object set the RigidBodyControl to kinematic mode to have it move along with the spatial. This will make the RigidBody be unaffected by the physics but it will effect the physics objects around it based on its location and amount of movement that is applied. Note that a kinematic RigidBody needs to have a mass!
-
-What happens if you give a static node such as the floor a mass of more than 0.0f?
-
-
-
-Exercise 2
-
-
-
-Popular AAA games use a clever mix of physics, animation and prerendered graphics to give you the illusion of a real, “physical” world. Look at your favorite games and try to spot where and how the game designers trick you into believing that the whole scene is physical. – For example, a building “breaking” into 4-8 parts when falling apart is most likely being replaced by dynamic physics nodes only after it has been destroyed… Now that you start to implement game physics yourself, look behind the curtain.
-
-
-Using physics everywhere in a game sounds like a cool idea, but it is easily overused. Although the physics nodes are put to “sleep” when they are not moved, creating a world solely out of dynamic physics nodes will quickly bring you to the limits of your computer's capabilities.
-
-
-
-You have learned how to add a PhysicsSpace to an application by attaching a BulletAppState. You know how to create PhysicsNodes from a geometry, a collision shape, and a mass value. You have learned that physical objects are not only attached to the rootNode but also registered to the PhysicsSpace. You are aware that overusing physics has a huge performance impact.
-
-
-
-Additionally you have learned how to add shadows to a scene.
-
-
-
-
-
-This is the last beginner tutorial for now. Now you are ready to start combining what you learned to create a game of your own!
-
-
In the moment the cannonball appears in the scene, it flies off with the velocity (and in the direction) that we have specified using setLinearVelocity() inside makeCannonBall(). The newly created cannon ball flies off, hits the wall, and exerts a physical force that shifts the individual bricks.
The location of the spatial is defined by the RigidBodyControl, move that to move the spatial or if its a non-world-object set the RigidBodyControl to kinematic mode to have it move along with the spatial. This will make the RigidBody be unaffected by the physics but it will effect the physics objects around it based on its location and amount of movement that is applied. Note that a kinematic RigidBody needs to have a mass!
What happens if you give a static node such as the floor a mass of more than 0.0f?
Exercise 2
Popular AAA games use a clever mix of physics, animation and prerendered graphics to give you the illusion of a real, "physical" world. Look at your favorite games and try to spot where and how the game designers trick you into believing that the whole scene is physical. – For example, a building "breaking" into 4-8 parts when falling apart is most likely being replaced by dynamic physics nodes only after it has been destroyed… Now that you start to implement game physics yourself, look behind the curtain.
Using physics everywhere in a game sounds like a cool idea, but it is easily overused. Although the physics nodes are put to "sleep" when they are not moved, creating a world solely out of dynamic physics nodes will quickly bring you to the limits of your computer's capabilities.
You have learned how to add a PhysicsSpace to an application by attaching a BulletAppState. You know how to create PhysicsNodes from a geometry, a collision shape, and a mass value. You have learned that physical objects are not only attached to the rootNode but also registered to the PhysicsSpace. You are aware that overusing physics has a huge performance impact.
Additionally you have learned how to add shadows to a scene.
This is the last beginner tutorial for now. Now you are ready to start combining what you learned to create a game of your own!
\ No newline at end of file
diff --git a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/beginner/hello_picking.html b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/beginner/hello_picking.html
index ae090938e..044ca9457 100644
--- a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/beginner/hello_picking.html
+++ b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/beginner/hello_picking.html
@@ -1,39 +1,16 @@
-
-
Typical interactions in games include shooting, picking up objects, and opening doors.
From an implementation point of view, these apparently different interactions are very similar: The user first aims and selects a target in the 3D scene, and then triggers an action on it. We call this process picking.
-
-
-
-You can pick something by either pressing a key on the keyboard, or by clicking with the mouse. In either case, you identify the target by aiming a ray –a straight line– into the scene. This method to implement picking is called ray casting (which is not the same as ray tracing).
-
-
-
-
-
-
-
-This tutorial relies on what you have learned in the Hello Input tutorial.
-
package jme3test.helloworld;
-
+You can pick something by either pressing a key on the keyboard, or by clicking with the mouse. In either case, you identify the target by aiming a ray –a straight line– into the scene. This method to implement picking is called ray casting (which is not the same as ray tracing). This tutorial relies on what you have learned in the Hello Input tutorial.
package jme3test.helloworld;
import com.jme3.app.SimpleApplication;
import com.jme3.collision.CollisionResult;
import com.jme3.collision.CollisionResults;
@@ -50,25 +27,20 @@ import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.shape.Box;
import com.jme3.scene.shape.Sphere;
-
-/** Sample 8 - how to let the user pick (select) objects in the scene
+/** Sample 8 - how to let the user pick (select) objects in the scene
* using the mouse or key presses. Can be used for shooting, opening doors, etc. */
public class HelloPicking extends SimpleApplication {
-
public static void main(String[] args) {
HelloPicking app = new HelloPicking();
app.start();
}
-
Node shootables;
Geometry mark;
-
@Override
public void simpleInitApp() {
initCrossHairs(); // a "+" in the middle of the screen to help aiming
initKeys(); // load custom key mappings
initMark(); // a red sphere to mark the hit
-
/** create four colored boxes and a floor to shoot at: */
shootables = new Node("Shootables");
rootNode.attachChild(shootables);
@@ -78,7 +50,6 @@ public class HelloPicking extends SimpleApplication {
shootables.attachChild(makeCube("the Deputy", 1f, 0f,-4f));
shootables.attachChild(makeFloor());
}
-
/** Declaring the "Shoot" action and mapping to its triggers. */
private void initKeys() {
inputManager.addMapping("Shoot",
@@ -86,7 +57,6 @@ public class HelloPicking extends SimpleApplication {
new MouseButtonTrigger(0)); // trigger 2: left-button click
inputManager.addListener(actionListener, "Shoot");
}
-
/** Defining the "Shoot" action: Determine what was hit and how to respond. */
private ActionListener() {
@Override
@@ -98,7 +68,7 @@ public class HelloPicking extends SimpleApplication {
Ray ray = new Ray(cam.getLocation(), cam.getDirection());
// 3. Collect intersections between Ray and Shootables in results list.
shootables.collideWith(ray, results);
- // 4. Print the results.
+ // 4. Print the results.
System.out.println("----- Collisions? " + results.size() + "-----");
for (int i = 0; i < results.size(); i++) {
// For each hit, we know distance, impact point, name of geometry.
@@ -122,7 +92,6 @@ public class HelloPicking extends SimpleApplication {
}
}
};
-
/** A cube object for target practice */
protected Geometry makeCube(String name, float x, float y, float z) {
Box(new Vector3f(x, y, z), 1, 1, 1);
@@ -132,7 +101,6 @@ public class HelloPicking extends SimpleApplication {
cube.setMaterial(mat1);
return cube;
}
-
/** A floor to show that the "shot" can go through several objects. */
protected Geometry makeFloor() {
Box(new Vector3f(0,-4,-5), 15,.2f,15);
@@ -142,7 +110,6 @@ public class HelloPicking extends SimpleApplication {
floor.setMaterial(mat1);
return floor;
}
-
/** A red ball that marks the last spot that was "hit" by the "shot". */
protected void initMark() {
Sphere sphere = new Sphere(30, 30, 0.2f);
@@ -151,7 +118,6 @@ public class HelloPicking extends SimpleApplication {
mark_mat.setColor("Color", ColorRGBA.Red);
mark.setMaterial(mark_mat);
}
-
/** A centred plus sign to help the player aim. */
protected void initCrossHairs() {
guiNode.detachAllChildren();
@@ -164,104 +130,49 @@ public class HelloPicking extends SimpleApplication {
settings.getHeight()/2 + ch.getLineHeight()/2, 0);
guiNode.attachChild(ch);
}
-}
-
-You should see four colored cubes floating over a gray floor, and cross-hairs. Aim the cross-hairs and click, or press the spacebar to shoot. The last hit will be marked with a red dot.
-
-
-
-Keep an eye on the application's output stream, it will give you more details: The name of the mesh that was hit, the coordinates of the hit, and the distance.
-
-
-The methods makeCube(), makeFloor(), initMark(), and initCrossHairs, are custom helper methods. We call them from simpleInitApp() to initialize the scenegraph with sample content.
-
-
-
-
makeCube() creates simple colored boxes for “target practice”.
-
-
makeFloor() creates a gray floor node for “target practice”.
-
-
initMark() creates a red sphere (“mark”). We will use it later to mark the spot that was hit.
-
-
Note that the mark is not attached and therefor not visible at the start.
-
-
-
-
initCrossHairs() creates simple cross-hairs by printing a ”+” sign in the middle of the screen.
-
-
Note that the cross-hairs are attached to the guiNode, not to the rootNode.
-
-
-
-
-
-
-
-In this example, we attached all “shootable” objects to one custom node, Shootables. This is an optimization so the engine only has to calculate intersections with objects we are actually interested in. The Shootables node is attached to the rootNode as usual.
-
-
-Our goal is to determine which box the user “shot” (picked). In general, we want to determine which mesh the user has selected by aiming the cross-hairs at it. Mathematically, we draw a line from the camera and see whether it intersects with objects in the 3D scene. This line is called a ray.
-
-
-
-Here is our simple ray casting algorithm for picking objects:
-
-
-
-
Reset the results list.
-
-
Cast a ray from cam location into the cam direction.
-
-
Collect all intersections between the ray and Shootable nodes in the results list.
-
-
Use the results list to determine what was hit:
-
-
For each hit, JME reports its distance from the camera, impact point, and the name of the mesh.
-
-
Sort the results by distance.
-
-
Take the closest result, it is the mesh that was hit.
-
-First initialize some shootable nodes and attach them to the scene. You will use the mark object later.
-
-
Node shootables;
+}
You should see four colored cubes floating over a gray floor, and cross-hairs. Aim the cross-hairs and click, or press the spacebar to shoot. The last hit will be marked with a red dot.
+Keep an eye on the application's output stream, it will give you more details: The name of the mesh that was hit, the coordinates of the hit, and the distance.
The methods makeCube(), makeFloor(), initMark(), and initCrossHairs, are custom helper methods. We call them from simpleInitApp() to initialize the scenegraph with sample content.
makeCube() creates simple colored boxes for "target practice".
makeFloor() creates a gray floor node for "target practice".
initMark() creates a red sphere ("mark"). We will use it later to mark the spot that was hit.
Note that the mark is not attached and therefor not visible at the start.
initCrossHairs() creates simple cross-hairs by printing a "+" sign in the middle of the screen.
Note that the cross-hairs are attached to the guiNode, not to the rootNode.
In this example, we attached all "shootable" objects to one custom node, Shootables. This is an optimization so the engine only has to calculate intersections with objects we are actually interested in. The Shootables node is attached to the rootNode as usual.
Our goal is to determine which box the user "shot" (picked). In general, we want to determine which mesh the user has selected by aiming the cross-hairs at it. Mathematically, we draw a line from the camera and see whether it intersects with objects in the 3D scene. This line is called a ray.
+Here is our simple ray casting algorithm for picking objects:
Reset the results list.
Cast a ray from cam location into the cam direction.
Collect all intersections between the ray and Shootable nodes in the results list.
Use the results list to determine what was hit:
For each hit, JME reports its distance from the camera, impact point, and the name of the mesh.
Sort the results by distance.
Take the closest result, it is the mesh that was hit.
-
-Next you declare the shooting action. It can be triggered either by clicking, or by pressing the space bar. The initKeys() method is called from simpleInitApp() to set up these input mappings.
-
-
/** Declaring the "Shoot" action and its triggers. */
+ }
Next you declare the shooting action. It can be triggered either by clicking, or by pressing the space bar. The initKeys() method is called from simpleInitApp() to set up these input mappings.
/** Declaring the "Shoot" action and its triggers. */
private void initKeys() {
inputManager.addMapping("Shoot", // Declare...
new KeyTrigger(KeyInput.KEY_SPACE), // trigger 1: spacebar, or
new MouseButtonTrigger(0)); // trigger 2: left-button click
inputManager.addListener(actionListener, "Shoot"); // ... and add.
- }
-
-Next we implement the ActionListener that responds to the Shoot trigger with an action. The action follows the ray casting algorithm described above:
-
-
-
-
For every click or press of the spacebar, the Shoot action is triggered.
-
-
The action casts a ray forward and determines intersections with shootable objects (= ray casting).
-
-
For any target that has been hit, it prints name, distance, and coordinates of the hit.
-
-
Finally it attaches a red mark to the closest result, to highlight the spot that was actually hit.
-
-
When nothing was hit, the results list is empty, and the red mark is removed.
-
-
-
-
-
-Note how it prints a lot of output to show you which hits were registered.
-
-
/** Defining the "Shoot" action: Determine what was hit and how to respond. */
+ }
Next we implement the ActionListener that responds to the Shoot trigger with an action. The action follows the ray casting algorithm described above:
For every click or press of the spacebar, the Shoot action is triggered.
The action casts a ray forward and determines intersections with shootable objects (= ray casting).
For any target that has been hit, it prints name, distance, and coordinates of the hit.
Finally it attaches a red mark to the closest result, to highlight the spot that was actually hit.
When nothing was hit, the results list is empty, and the red mark is removed.
Note how it prints a lot of output to show you which hits were registered.
/** Defining the "Shoot" action: Determine what was hit and how to respond. */
private ActionListener() {
@Override
public void onAction(String name, boolean keyPressed, float tpf) {
@@ -347,118 +234,56 @@ Note how it prints a lot of output to show you which hits were registered.
}
}
}
- };
-
-Tip: Notice how you use the provided method results.getClosestCollision().getContactPoint() to determine the closest hit's location. If your game includes a “weapon” or “spell” that can hit multiple targets, you would instead loop over the list of results, and interact with each of them.
-
-
-After a hit was registered, the closest object is identified as target, and marked with a red dot.
-Modify the code sample to solve these exercises:
-
-
-Change the code as follows to simulate the player picking up objects into the inventory: When you click once, the closest target is identified and detached from the scene. When you click a second time, the target is reattached at the location that you have clicked. Here are some tips:
-
-
-
Create an inventory node to store the detached nodes.
-
-
The inventory node is not attached to the rootNode.
-
-
You can make the inventory visible by attaching the inventory node to the guiNode.
-
-You have learned how to use ray casting to solve the task of determining what object a user selected on the screen. You learned that this can be used for a variety of interactions, such as shooting, opening, picking up and dropping items, pressing a button or lever, etc.
-
-
-
-Use your imagination from here:
-
-
-
In your game, the click can trigger any action on the identified object: Detach it and put it into the inventory, attach something to it, trigger an animation or effect, open a door or crate, – etc.
-
-
In your game, you could replace the red mark with a particle emitter, add an explosion effect, play a sound, calculate the new score after each hit depending on what was hit – etc.
-
-
-
-
-
-Now, wouldn't it be nice if those targets and the floor were solid objects and you could walk among them? Let's continue with Collision Detection.
-
-
Tip: Notice how you use the provided method results.getClosestCollision().getContactPoint() to determine the closest hit's location. If your game includes a "weapon" or "spell" that can hit multiple targets, you would instead loop over the list of results, and interact with each of them.
Change the code as follows to simulate the player picking up objects into the inventory: When you click once, the closest target is identified and detached from the scene. When you click a second time, the target is reattached at the location that you have clicked. Here are some tips:
Create an inventory node to store the detached nodes.
The inventory node is not attached to the rootNode.
You can make the inventory visible by attaching the inventory node to the guiNode (which attaches it to the HUD). Note the following caveats:
If your nodes use a lit Material (not "Unshaded.j3md"), also add a light to the guiNode.
Size units are pixels in the HUD, therefor a 2-wu cube is displayed only 2 pixels wide. – Scale it.
Position the nodes: The bottom left corner of the HUD is (0f,0f), and the top right corner is at (settings.getWidth(),settings.getHeight()).
You have learned how to use ray casting to solve the task of determining what object a user selected on the screen. You learned that this can be used for a variety of interactions, such as shooting, opening, picking up and dropping items, pressing a button or lever, etc. Use your imagination from here:
In your game, the click can trigger any action on the identified object: Detach it and put it into the inventory, attach something to it, trigger an animation or effect, open a door or crate, – etc.
In your game, you could replace the red mark with a particle emitter, add an explosion effect, play a sound, calculate the new score after each hit depending on what was hit – etc.
Now, wouldn't it be nice if those targets and the floor were solid objects and you could walk among them? Let's continue with Collision Detection.
\ No newline at end of file
diff --git a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/beginner/hello_simpleapplication.html b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/beginner/hello_simpleapplication.html
index b7f0dbc3c..8736bd330 100644
--- a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/beginner/hello_simpleapplication.html
+++ b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/beginner/hello_simpleapplication.html
@@ -1,74 +1,36 @@
-
-
-
-This tutorial assumes that you have already downloaded and set up jMonkeyEngine3 in an IDE of your choice, and are able to run the bundled samples.
-
-
-
-You are ready to create your first jMonkeyEngine3 game! You can generally use the tutorials in this introductory series with any integrated development environment (IDE), such as the jMonkeyPlatform, NetBeans, Eclipse, or run them straight from the commandline.
-
This tutorial assumes that you have already downloaded and set up jMonkeyEngine3 in an IDE of your choice, and are able to run the bundled samples.
You are ready to create your first jMonkeyEngine3 game! You can generally use the tutorials in this introductory series with any integrated development environment (IDE), such as the jMonkeyPlatform, NetBeans, Eclipse, or run them straight from the commandline.
Replace the contents of the HelloJME3.java file with the following code:
package jme3test.helloworld;
import com.jme3.app.SimpleApplication;
import com.jme3.material.Material;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Box;
import com.jme3.math.ColorRGBA;
-
/** Sample 1 - how to get started with the most simple JME 3 application.
* Display a blue 3D cube and view from all sides by
* moving the mouse and pressing the WASD keys. */
public class HelloJME3 extends SimpleApplication {
-
public static void main(String[] args){
HelloJME3 app = new HelloJME3();
app.start();
}
-
@Override
public void simpleInitApp() {
Box(Vector3f.ZERO, 1, 1, 1);
@@ -78,176 +40,73 @@ public class HelloJME3 extends SimpleApplication {
geom.setMaterial(mat);
rootNode.attachChild(geom);
}
-}
-
-
-Build and run the HelloJME3 class. If a jme settings dialog pops up, confirm the default settings.
-
-
-
-
You should see a simple window displaying a 3-D cube.
-
-
Use the WASD keys and the mouse to navigate around.
-
-
Press Escape to close the application.
-
-
-
-
-
-Congratulations, it works! How did we do that?
-
-
-Note that the HelloJME3.java class extends com.jme3.app.SimpleApplication, which is a subclass of com.jme3.app.Application. Every JME3 game is an instance of com.jme3.app.Application (directly, or indirectly).
-
-
-
-To run a JME3 game, you first instantiate your Application-based class, and then call its start() method:
-
-
HelloJME3 app = new HelloJME3();
-app.start();
-
-Usually, you do that from your Java application's main method.
-
-
-
-Tip: Advanced Java developers may want to make a copy of SimpleApplication and use it as a template for a custom application class.
-
-
-This simple “game” consists of nothing but a cube. Here is how we create it, position it, give it a color, and attach it to the scene. (We will have a closer look at the details later.)
-
-
public void simpleInitApp() {
+}
Build and run the HelloJME3 class. If a jme settings dialog pops up, confirm the default settings.
You should see a simple window displaying a 3-D cube.
Use the WASD keys and the mouse to navigate around.
Note that the HelloJME3.java class extends com.jme3.app.SimpleApplication, which is a subclass of com.jme3.app.Application. Every JME3 game is an instance of com.jme3.app.Application (directly, or indirectly).
To run a JME3 game, you first instantiate your Application-based class, and then call its start() method:
HelloJME3 app = new HelloJME3();
+app.start();
Usually, you do that from your Java application's main method.
Tip: Advanced Java developers may want to make a copy of SimpleApplication and use it as a template for a custom application class.
This simple "game" consists of nothing but a cube. Here is how we create it, position it, give it a color, and attach it to the scene. (We will have a closer look at the details later.)
public void simpleInitApp() {
Box(Vector3f.ZERO, 1, 1, 1); // create cube shape
Geometry geom = new Geometry("Box", b); // create cube geometry from the shape
- Material mat = new Material(assetManager,
+ Material mat = new Material(assetManager,
"Common/MatDefs/Misc/Unshaded.j3md"); // create a simple material
mat.setColor("Color", ColorRGBA.Blue); // set color of material
geom.setMaterial(mat); // set the cube's material
rootNode.attachChild(geom); // attach the cube to the scene
- }
-
-The simpleInitApp() method is automatically called once at the beginning of every JME3 game. In this method you create or load game objects before the game starts! Here is the usual process:
-
-
-
-
Initialize game objects:
-
-
Create or load all objects, and position them.
-
-
To make a geometry (like the box) appear in the scene, attach it to the rootNode.
-
-
Examples: Load player, terrain, sky, enemies, obstacles, and place them in their start positions.
-
-
-
-
Initialize game variables
-
-
Game variables track the game state. Set them to their start values.
-
-
Examples: Here you set the score to 0, and health to 100%, and so on.
-
-
-
-
Initialize navigation
-
-
The following key bindings are pre-configured by default:
-
-
W,A,S,D keys – Move around
-
-
Mouse and arrow keys – Turn the camera
-
-
Escape key - Quit game
-
-
-
-
-
-
-
-
-
-The important part is: The JME3 Application has a rootNode object. Your game automatically inherits the rootNode. Everything attached to the rootNode appears in the scene. Or in other words: An object that has been created, but is not attached to the rootNode, remains invisible.
-
-
-These few lines of code do nothing but display a static object in 3-D, but they already allow you to navigate around in 3D. You have learned that a SimpleApplication is a good starting point because it provides you with:
-
-
-
-
a simpleInitApp() method to initialize the game objects
-
-
a rootNode where you attach geometries to make them appear in the scene
-
-
useful default navigation settings
-
-
-
-
-
-In a real game, you will want to:
-
-
-
-
Inititialize the game world,
-
-
Trigger actions in the event loop,
-
-
Respond to user input.
-
-
-
-
-
-In the following tutorials you will learn how these tasks are accomplished with the jMonkeyEngine 3!
-
-
-
-Continue with the Hello Node tutorial, where we will first show you more details about how to initialize the game world, also known as the scene graph.
-
-
The simpleInitApp() method is automatically called once at the beginning of every JME3 game. In this method you create or load game objects before the game starts! Here is the usual process:
Initialize game objects:
Create or load all objects, and position them.
To make a geometry (like the box) appear in the scene, attach it to the rootNode.
Examples: Load player, terrain, sky, enemies, obstacles, and place them in their start positions.
Initialize game variables
Game variables track the game state. Set them to their start values.
Examples: Here you set the score to 0, and health to 100%, and so on.
Initialize navigation
The following key bindings are pre-configured by default:
W,A,S,D keys – Move around
Mouse and arrow keys – Turn the camera
Escape key - Quit game
The important part is: The JME3 Application has a rootNode object. Your game automatically inherits the rootNode. Everything attached to the rootNode appears in the scene. Or in other words: An object that has been created, but is not attached to the rootNode, remains invisible.
These few lines of code do nothing but display a static object in 3-D, but they already allow you to navigate around in 3D. You have learned that a SimpleApplication is a good starting point because it provides you with:
a simpleInitApp() method to initialize the game objects
a rootNode where you attach geometries to make them appear in the scene
useful default navigation settings
In a real game, you will want to:
Initialize the game world,
Trigger actions in the event loop,
Respond to user input.
In the following tutorials you will learn how these tasks are accomplished with the jMonkeyEngine 3!
Continue with the Hello Node tutorial, where we will first show you more details about how to initialize the game world, also known as the scene graph.
\ No newline at end of file
diff --git a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/beginner/hello_terrain.html b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/beginner/hello_terrain.html
index 128836d97..c3c76f297 100644
--- a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/beginner/hello_terrain.html
+++ b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/beginner/hello_terrain.html
@@ -1,30 +1,13 @@
-
-
-One way to create a 3D landscape is to sculpt a huge terrain model. This will give you a lot of artistic freedom – but rendering such a huge model can be quite slow. jME supports heightmaps to solve this common performance issue of terrains.
-
-
-
-This tutorial explains how to create terrains from heightmaps and how to use splat textures to make the terrain look good.
-
One way to create a 3D landscape is to sculpt a huge terrain model. This will give you a lot of artistic freedom – but rendering such a huge model can be quite slow. jME supports heightmaps to solve this common performance issue of terrains.
This tutorial explains how to create terrains from heightmaps and how to use splat textures to make the terrain look good.
-
-Heightmaps are an efficient way of representing the shape of a hilly landscape. Picture a heightmap as a float array containing height values between 0f and 255f. Here is a very simple example of a heightmap with 25 height values.
-
-
-
-
-
-
-
-Important things to note:
-
-
-
Low values (e.g. 0 or 50) are valeys.
-
-
High values (e.g. 200, 255) are hills.
-
-
We only specified a few points, and the engine interpolates the rest. Interpolation is more efficient than creating a model with several millions of vertices.
-
-
-
-
-
-Now when looking at Java data types to hold an array of floats between 0 and 255, the Image class comes to mind. Storing a terrain's height values as a grayscale image has one big advantage: The outcome is a very userfriendly, almost topographical, representation of a landscape:
-
-
-
Low values (e.g. 0 or 50) are dark gray – these are valleys.
-
-
High values (e.g. 200, 255) are light grays – these are hills.
-
-
-
-
-
-Look at the next screenshot: In the top left you see the 128×128 grayscale image (heightmap) that was used as a base to generate the depicted terrain. To make the hilly shape better visible, the mountain tops are colored white, valleys brown, and the areas inbetween green:
-
-
-
-}
-
-
-
-In a real game, you will want to use more complex and smoother terrains than the simple heightmaps shown here. Heightmaps typically have square sizes of 512×512 or 1024×1024, and contain hundred thousands to 1 million height values. No matter which size, the concept is the same as described here.
-
-The first step is always to create the heightmap. You can create it yourself in any standard graphic application. Make sure it has the following properties:
-
-
-
The size must be square and a power of two
-
-
Examples: 128×128, 256×256, 512×512, 1024×1024
-
-
-
-
Color mode: 255 grayscales.
-
-
If you supply a color image, it will be converted to grayscale (with possibly weird results).
-
-
-
-
Save it as a normal .jpg or .png file
-
-
-
-
-
-The file mountains512.png that you see here is a typical example of a heightmap.
-
-
-
-Here is how you create the heightmap object in your jME code:
-
-
-
Create a Texture object
-
-
Load your prepared heightmap texture into the texture object
-
-
Create an AbstractHeightmap object from an ImageBasedHeightMap.
- ImageBasedHeightMap expects the following parameters:
-
-
An ImageToAwt.convert()ed image file
-
-
A boolean whether you are using 16 bit – here false.
-
-
A boolean whether you are using an alphamap – here true.
-
-
-
-
Load the heightmap.
-
-
-
final Texture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/mountains512.png");
+}
When you run this sample you should see a landscape with dirt mountains, grass plains, plus some winding roads in between.
Heightmaps are an efficient way of representing the shape of a hilly landscape. Picture a heightmap as a float array containing height values between 0f and 255f. Here is a very simple example of a heightmap with 25 height values.
Important things to note:
Low values (e.g. 0 or 50) are valeys.
High values (e.g. 200, 255) are hills.
We only specified a few points, and the engine interpolates the rest. Interpolation is more efficient than creating a model with several millions of vertices.
Now when looking at Java data types to hold an array of floats between 0 and 255, the Image class comes to mind. Storing a terrain's height values as a grayscale image has one big advantage: The outcome is a very userfriendly, almost topographical, representation of a landscape:
Low values (e.g. 0 or 50) are dark gray – these are valleys.
High values (e.g. 200, 255) are light grays – these are hills.
Look at the next screenshot: In the top left you see the 128x128 grayscale image (heightmap) that was used as a base to generate the depicted terrain. To make the hilly shape better visible, the mountain tops are colored white, valleys brown, and the areas inbetween green:
}
In a real game, you will want to use more complex and smoother terrains than the simple heightmaps shown here. Heightmaps typically have square sizes of 512x512 or 1024x1024, and contain hundred thousands to 1 million height values. No matter which size, the concept is the same as described here.
The first step is always to create the heightmap. You can create it yourself in any standard graphic application. Make sure it has the following properties:
The size must be square and a power of two
Examples: 128x128, 256x256, 512x512, 1024x1024
Color mode: 255 grayscales.
If you supply a color image, it will be converted to grayscale (with possibly weird results).
Save it as a normal .jpg or .png file
The file mountains512.png that you see here is a typical example of a heightmap.
Here is how you create the heightmap object in your jME code:
Create a Texture object
Load your prepared heightmap texture into the texture object
Create an AbstractHeightmap object from an ImageBasedHeightMap. ImageBasedHeightMap expects the following parameters:
An ImageToAwt.convert()ed image file
A boolean whether you are using 16 bit – here false.
A boolean whether you are using an alphamap – here true.
Load the heightmap.
final Texture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/mountains512.png");
final AbstractHeightMap heightmap =
new ImageBasedHeightMap(
ImageToAwt.convert(
heightMapImage.getImage(), false, true, 0));
- heightmap.load();
-
-Texture splatting allows you create a custom textured material and “paint” on it. This is very useful for terrains: As you see in the example here, you can paint a grass texture into the valleys, a dirt texture onto the mountains, and free-form roads inbetween.
-
-
-
-How is it done? We have three texture layers to paint on, m_Tex1, m_Tex2 and m_Tex3 (these names are found by opening the Terrain.j3md file, under the Material Parameters section; they may be changed) . before we start we have to make a few decisions:
-
-
-
-
You choose three textures. For example grass.jpg, dirt.jpg, and road.jpg.
-
-
You will “paint” three texture layers with three colors: Red, blue and, green. We arbitrarily chose that…
-
-
… everything red will be grass – this goes into layer m_Tex1
-
-
… everything green will be dirt – this goes into layer m_Tex2
-
-
… everything blue will be roads – this goes into layer m_Tex3
-
-
-
-
-
-
-
-Now we start painting the texture:
-
-
-
-
Make a copy of your terrains heightmap, mountains512.png, so you know the shape of the landscape.
-
-
Name the copy alphamap.png.
-
-
Open alphamap.png in a graphic editor and switch the image mode to color image.
-
-
Paint the black valleys in the image red – this will be the grass.
-
-
Paint the white hills in shades of green – this will be the dirt of the mountains.
-
-
Paint blue lines where you want roads to cross the landscape.
-
-
-
-
The end result should look similar to this:
-
-
-
-
-
- ⇒
-
-
-
-Note: In the future, the jMonkeyPlatform will take over some of these steps so you don't have to worry about the details.
-
-Three other textures are the layers that we have previously decided to paint: grass, dirt, and road. We create texture objects and load the three textures as usual. Note how we assign them to their respective texture layers (m_Tex1, m_Tex2, and m_Tex3) inside the Material!
-
-
/** 1.2) Add GRASS texture into the red layer (m_Tex1). */
+ heightmap.load();
Texture splatting allows you create a custom textured material and "paint" on it. This is very useful for terrains: As you see in the example here, you can paint a grass texture into the valleys, a dirt texture onto the mountains, and free-form roads inbetween.
How is it done? We have three texture layers to paint on, m_Tex1, m_Tex2 and m_Tex3 (these names are found by opening the Terrain.j3md file, under the Material Parameters section; they may be changed) . before we start we have to make a few decisions:
You choose three textures. For example grass.jpg, dirt.jpg, and road.jpg.
You will "paint" three texture layers with three colors: Red, blue and, green. We arbitrarily chose that…
… everything red will be grass – this goes into layer m_Tex1
… everything green will be dirt – this goes into layer m_Tex2
… everything blue will be roads – this goes into layer m_Tex3
Now we start painting the texture:
Make a copy of your terrains heightmap, mountains512.png, so you know the shape of the landscape.
Name the copy alphamap.png.
Open alphamap.png in a graphic editor and switch the image mode to color image.
Paint the black valleys in the image red – this will be the grass.
Paint the white hills in shades of green – this will be the dirt of the mountains.
Paint blue lines where you want roads to cross the landscape.
The end result should look similar to this:
⇒
Note: In the future, the jMonkeyPlatform will take over some of these steps so you don't have to worry about the details.
Three other textures are the layers that we have previously decided to paint: grass, dirt, and road. We create texture objects and load the three textures as usual. Note how we assign them to their respective texture layers (m_Tex1, m_Tex2, and m_Tex3) inside the Material!
/** 1.2) Add GRASS texture into the red layer (m_Tex1). */
Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg");
grass.setWrap(WrapMode.Repeat);
mat_terrain.setTexture("m_Tex1", grass);
@@ -324,200 +197,77 @@ Three other textures are the layers that we have previously decided to paint: gr
Texture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg");
rock.setWrap(WrapMode.Repeat);
mat_terrain.setTexture("m_Tex3", rock);
- mat_terrain.setFloat("m_Tex3Scale", 128f);
-
-The individual texture scales (e.g. mat_terrain.setFloat(“m_Tex3Scale”, 128f);) depend on the size of the textures you use. You can tell you picked a too small scale if, for example, your road tiles appear like tiny grains of sand, or to big if the blades of grass look like twigs.
-
-
-
-We use setWrap(WrapMode.Repeat) to make the small texture fill the wide area. If the repetition is too visible, try adjusting the Tex*Scale value.
-
-
-
-Later, after we have created the actual terrain object, we must not forgot to set the material on it:
-
-
-Internally, the generated terrain mesh is broken down into tiles and blocks. This is an optimization for culling. You do not need to worry about tiles and blocks too much, just use recommended values for now.
-
-
-
-Let's assume we want to generate a small 512×512 terrain. We already have created the heightmap object. Here are the steps that we perform everytime we create a new terrain.
-
-
-
-We create a TerrainQuad with the following arguments:
-
-
-
Name: E.g. my terrain.
-
-
Tile size: We want to create terrain tiles of size 64×64, so we supply 64+1 = 65.
-
-
In general, 64 is a good value for terrain tiles.
-
-
-
-
Block size: Since we prepared a heightmap of size 512×512, we supply 512+1 = 513.
-
-
If the the block size is double the heightmap size (1024+1=1025), you get a stretched out, wider, flatter terrain.
-
-
If the the block size is half the heightmap size (256+1=257), you get a smaller, more detailed terrain.
-
-
-
-
Finally, we supply the 512×512 heightmap object that we have previously created.
-
-
-
-
-
-Here's the code:
-
-
-
terrain = new TerrainQuad(
+ mat_terrain.setFloat("m_Tex3Scale", 128f);
The individual texture scales (e.g. mat_terrain.setFloat("m_Tex3Scale", 128f);) depend on the size of the textures you use. You can tell you picked a too small scale if, for example, your road tiles appear like tiny grains of sand, or to big if the blades of grass look like twigs.
We use setWrap(WrapMode.Repeat) to make the small texture fill the wide area. If the repetition is too visible, try adjusting the Tex*Scale value.
Later, after we have created the actual terrain object, we must not forgot to set the material on it:
Internally, the generated terrain mesh is broken down into tiles and blocks. This is an optimization for culling. You do not need to worry about tiles and blocks too much, just use recommended values for now.
Let's assume we want to generate a small 512x512 terrain. We already have created the heightmap object. Here are the steps that we perform everytime we create a new terrain.
We create a TerrainQuad with the following arguments:
Name: E.g. my terrain.
Tile size: We want to create terrain tiles of size 64x64, so we supply 64+1 = 65.
In general, 64 is a good value for terrain tiles.
Block size: Since we prepared a heightmap of size 512x512, we supply 512+1 = 513.
If the the block size is double the heightmap size (1024+1=1025), you get a stretched out, wider, flatter terrain.
If the the block size is half the heightmap size (256+1=257), you get a smaller, more detailed terrain.
Finally, we supply the 512x512 heightmap object that we have previously created.
Here's the code:
terrain = new TerrainQuad(
"my terrain", // name
65, // tile size
513, // block size
- heightmap.getHeightMap()); // heightmap
-
-
-
-Don't forget to attach the terrain to the rootNode. You can scale and translate the terrain just like any other Spatial.
-
jME3 includes an optimization that adjusts the level of detail of the rendered terrain depending on how close or far the camera is.
List<Camera> cameras = new ArrayList<Camera>();
cameras.add(getCamera());
TerrainLodControl control = new TerrainLodControl(terrain, cameras);
- terrain.addControl(control);
-
-Close parts of the terrain are rendered in full detail. Terrain parts that are further away are not clearly visible anyway, and jME improves performance by rendering them less detailed. This way you can afford to load huge terrains with no penalty caused by invisible details.
-
-
-What happens if you swap two layers, for example m_Tex1 and m_Tex2?
-
-
-
...
+ terrain.addControl(control);
Close parts of the terrain are rendered in full detail. Terrain parts that are further away are not clearly visible anyway, and jME improves performance by rendering them less detailed. This way you can afford to load huge terrains with no penalty caused by invisible details.
Change one value at a time and the run the sample again. Note the differences. Can you find out which of the values has which effect on the generated terrain?
-
-
Which value controls the size?
-
-
What happens if the size is not a square number +1 ?
-
-
-
-
Which value controls the number of hills generated?
-
-
Which values control the minimum and maximum radius of the hills?
-
-
What happens if the minimum is bigger than the maximum?
-
-
-
-
Which value controls the flattening of the hills?
-
-
What happens if this value is 1 ?
-
-
-
-
-
-
-
-
-
-Tip: You can keep using the splatted texture from the sample code above. Just don't be surprised that the textures do not automatically adjust to the randomized landscape.
-
Change one value at a time and the run the sample again. Note the differences. Can you find out which of the values has which effect on the generated terrain?
Which value controls the size?
What happens if the size is not a square number +1 ?
Which value controls the number of hills generated?
Which values control the minimum and maximum radius of the hills?
What happens if the minimum is bigger than the maximum?
Which value controls the flattening of the hills?
What happens if this value is 1 ?
Tip: You can keep using the splatted texture from the sample code above. Just don't be surprised that the textures do not automatically adjust to the randomized landscape.
\ No newline at end of file
diff --git a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/build_jme3_sources_with_netbeans.html b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/build_jme3_sources_with_netbeans.html
index a7c636f40..b7fb43f1c 100644
--- a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/build_jme3_sources_with_netbeans.html
+++ b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/build_jme3_sources_with_netbeans.html
@@ -1,187 +1,85 @@
-
-
-
-You are welcome to try out the new jME3, and contribute patches and features! This document shows how to download, set up, build, and run the latest development version from the sources. (As of Spring 2010, we are in alpha.) These instructions work in NetBeans IDE 6 or better.
-
-
-
-Note: In the following, always replace ”~” with the path to your home directory.
-
-
-Check out the sources from the repository. (The following NetBeans instructions are equivalent to executing cd ~/NetBeansProjects; svn checkout jme3 on the commandline.)
-
-
-
-
In NetBeans go to Team > Subversion > Checkout
-
-
Repository URL:
-
-
You can leave user/pw blank for anonymous access.
-
-
-
-
Click Next
-
-
Repository Folders: trunk/engine
-
-
Enable the checkbox to Skip “engine” and only checkout its contents.
-
-
Local Folder: ~/NetBeansProjects/jme3
-
-
-
-
Click Finish and wait.
-
-
-
-
-
-The jme3 project opens in the Project window. It already includes a working ANT build script for building and running.
-
-
-
-Look into the Libraries node and confirm that the project depends on the following libraries in the classpath:
-
You are welcome to try out the new jME3, and contribute patches and features! This document shows how to download, set up, build, and run the latest development version from the sources. (As of Spring 2010, we are in alpha.) These instructions work in NetBeans IDE 6 or better.
Note: In the following, always replace "~" with the path to your home directory.
Check out the sources from the repository. (The following NetBeans instructions are equivalent to executing cd ~/NetBeansProjects; svn checkout http://jmonkeyengine.googlecode.com/svn/trunk/engine jme3 on the commandline.)
-A jme3 application can either be deployed to the desktop (as Java Swing application) and web browser (as JNLP/WebStart or Applet), or to an Android phone. While the former is the default, switching to Android deployment can be done in a few steps.
-
-
In the Projects window, right-click the jme3 project and choose Generate Javadoc. Wait.
-
-
Confirm in the Files window that the javadoc has been created in ~/NetBeansProjects/jme3/dist/javadoc
-
-
In the editor, place the caret in a jme class and press ctrl-space to view javadoc.
-
-
-
-
-
-If you are working on a game project that depends on jme3:
-
-
-
First follow the previous tip. (In the future, we may offer jme javadoc as download instead.)
-
-
In your game project, right-click the Libraries node and choose “Properties”.
-
-
In the Library properties, select jme3.jar and click the Edit button.
-
-
For the Javadoc field, browse to ~/NetBeansProjects/jme3/dist/javadoc. Check “as relative path” and click select.
-
-
For the Sources field, browse to ~/NetBeansProjects/jme3/src. Check “as relative path” and click select.
-
-
Click OK.
-
-
-
-
In the editor, place the caret in a jme class and press ctrl-space to view javadoc. Ctrl-click any jme3 method to jump to its definition in the sources.
-
-
-
-
-
-This tip works for any third-party JAR library that you use. (You may have to download the javadoc/sources from their home page separately).
-
A jme3 application can either be deployed to the desktop (as Java Swing application) and web browser (as JNLP/WebStart or Applet), or to an Android phone. While the former is the default, switching to Android deployment can be done in a few steps.
In the Projects window, right-click the jme3 project and choose Generate Javadoc. Wait.
Confirm in the Files window that the javadoc has been created in ~/NetBeansProjects/jme3/dist/javadoc
In the editor, place the caret in a jme class and press ctrl-space to view javadoc.
If you are working on a game project that depends on jme3:
First follow the previous tip. (In the future, we may offer jme javadoc as download instead.)
In your game project, right-click the Libraries node and choose "Properties".
In the Library properties, select jme3.jar and click the Edit button.
For the Javadoc field, browse to ~/NetBeansProjects/jme3/dist/javadoc. Check "as relative path" and click select.
For the Sources field, browse to ~/NetBeansProjects/jme3/src. Check "as relative path" and click select.
Click OK.
In the editor, place the caret in a jme class and press ctrl-space to view javadoc. Ctrl-click any jme3 method to jump to its definition in the sources.
This tip works for any third-party JAR library that you use. (You may have to download the javadoc/sources from their home page separately).
\ No newline at end of file
diff --git a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/bullet_multithreading.html b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/bullet_multithreading.html
index b753088f3..b8a3d5851 100644
--- a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/bullet_multithreading.html
+++ b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/bullet_multithreading.html
@@ -1,41 +1,10 @@
-
-
-Since bullet is not (yet) multithreaded or GPU accelerated the jME3 implementation allows to run each physics space on a separate thread that is executed in parallel to rendering.
-
Since bullet is not (yet) multithreaded or GPU accelerated the jME3 implementation allows to run each physics space on a separate thread that is executed in parallel to rendering.
A SimpleApplication with a BulletAppState allows setting the threading type via
setThreadingType(ThreadingType type);
where ThreadingType can be either SEQUENTIAL or PARALLEL.
In the simpleInitApp() method:
bulletAppState = new BulletAppState();
bulletAppState.setThreadingType(BulletAppState.ThreadingType.PARALLEL);
-stateManager.attach(bulletAppState);
-
-The physics update happens in parallel to rendering, after the users changes have been made in the update() call. This way the loop logic is still maintained: the user can set and change values in physics and scenegraph objects before render() and physicsUpdate() are called in parallel.
-
-
-
-
+stateManager.attach(bulletAppState);
The physics update happens in parallel to rendering, after the users changes have been made in the update() call. This way the loop logic is still maintained: the user can set and change values in physics and scenegraph objects before render() and physicsUpdate() are called in parallel.
\ No newline at end of file
diff --git a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/intermediate/api_feature_mapping.html b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/intermediate/api_feature_mapping.html
index 44cf3e401..1be0e20be 100644
--- a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/intermediate/api_feature_mapping.html
+++ b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/intermediate/api_feature_mapping.html
@@ -1,277 +1,334 @@
-
-
-
-This page provides a quick answer to the questions “I want my game to do X, where do I find that in jME 3 ??”
-
-
-
-Knowing exactly what you are looking for allows you to search more efficiently, find documentation more quickly, and ask clearer questions on the . This intermediate page assumes that you already went through the beginner tutorials. Feel free to add APIs, tutorials and javadoc links that helped you understand and use a feature!
-
Attach nodes and geometries to the rootNode: rootNode.attachChild(geo);
- com.jme3.scene.Node, com.jme3.scene.Geometry
- node.setCullHint(CullHint.Never);
Import asset as Ogre XML mesh.
- jMonkeyPlatform: Converting Ogre to j3o binary format speeds up model loading.
- AssetManager, com.jme3.scene.plugins.ogre.*, com.jme3.scene.Geometry
Change the geo's translation in the update phase of the main loop. Or remote-control the motion using cinematics.
- com.jme3.scene.Geometry, setLocalTranslation(), setWalkDirection() for physical objects.
com.jme3.material.RenderState.FaceCullMode: Back, Front, FrontAndBack, Off
- e.g. material.getAdditionalRenderState(). setFaceCullMode(FaceCullMode.FrontAndBack);
Use Controls to define behaviours of types of Spatials. Use Application States to implement global behaviours. Use the simpleUpdate() loop for the remaining tests and interactions. Use Cinematics to remote-control objects in scenes.
This page provides a quick answer to the questions "I want my game to do X, where do I find that in jME 3 ??"
Knowing exactly what you are looking for allows you to search more efficiently, find documentation more quickly, and ask clearer questions on the support forum. This intermediate page assumes that you already went through the beginner tutorials. Feel free to add APIs, tutorials and javadoc links that helped you understand and use a feature!
Import asset as Ogre XML mesh. jMonkeyPlatform: Converting Ogre to j3o binary format speeds up model loading. AssetManager, com.jme3.scene.plugins.ogre.*, com.jme3.scene.Geometry
Change the geo's translation in the update phase of the main loop. Or remote-control the motion using cinematics. com.jme3.scene.Geometry, setLocalTranslation(), setWalkDirection() for physical objects.
com.jme3.material.RenderState.FaceCullMode: Back, Front, FrontAndBack, Off e.g. material.getAdditionalRenderState(). setFaceCullMode(FaceCullMode.FrontAndBack);
Use Controls to define behaviours of types of Spatials. Use Application States to implement global behaviours. Use the simpleUpdate() loop for the remaining tests and interactions. Use Cinematics to remote-control objects in scenes.
\ No newline at end of file
diff --git a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/intermediate/appsettings.html b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/intermediate/appsettings.html
index 741a78d35..4e726fe62 100644
--- a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/intermediate/appsettings.html
+++ b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/intermediate/appsettings.html
@@ -1,106 +1,77 @@
-
-
-
-Every class that extends jme3.app.Application (or jme3.app.SimpleApplication) has properties that can be configured by customizing a com.jme3.system.AppSettings object. Configure the settings before you call app.start() on the application object. If you change display settings during runtime, call app.restart() to make them take effect.
-
Every class that extends jme3.app.Application (or jme3.app.SimpleApplication) has properties that can be configured by customizing a com.jme3.system.AppSettings object. Configure the settings before you call app.start() on the application object. If you change display settings during runtime, call app.restart() to make them take effect.
AppSettings settings = new AppSettings(true);
settings.setRenderer(AppSettings.LWJGL_OPENGL3);
Application app = new Application();
app.setSettings(settings);
-app.start();
-
-Set the boolean in the AppSettings contructor to true if you want to keep the default settings for everything that you do not specify. Set this parameter to false if you want to specify each property yourself (you'll get an exception if you missed one).
-
-
-
-Use app.setShowSettings(false); to disable the default settings-window at startup.
-
Set color depth.
- 1 = black and white, 2 bit = gray,
- 4 = 16 colors, 8 = 256 colors, 24 or 32 = “truecolor”.
24
-
-
-
setFrequency(60)
The screen frequency (refresh rate of the graphics card), usually 60 or 75 fps.
60 fps
-
-
-
setFramerate(60)
How often per second the engine should try to refresh the frame. For the release, usually 60 fps. Can be lower (59-30) for FX-intensive games. Do not set to a higher value than the screen frequency.
-1 (auto)
-
-
-
setFullscreen(true)
Set this to true to make the display fill the whole screen; you need to provide a key that calls app.stop() to exit the fullscreen view gracefully (default: escape).
- Set it to false to play the game in a normal window of its own.
Two equivalent ways of setting the display resolution.
640×480 pixels
-
-
-
setSamples(4)
Set multisampling to 0 to switch antialiasing off (harder edges, faster.)
- Set multisampling to 2 or 4 to activate antialising (softer edges, may be slower.)
- Depending on your graphic card, you may be able to go set multisampling to 8, 16, or 32 samples.
0
-
-
-
setVSync(true)
Set vertical syncing to true to time the frame buffer to coincide with the refresh interval of the screen: Prevents page tearing, but slower; recommened for release.
- Set to false to deactivate vertical syncing (faster, but possible page tearing artifacts); can be deactivated during development.
false
-
-
-
useInput(false)
Respond to user input by mouse and keyboard. Can be deactivated for use cases where you only display a 3D scene on the canvas without any interaction.
true
-
-
-
useJoysticks(true)
Activate optional joystick support
false
-
-
-
setSettingsDialogImage(”/path/in/assets.png”)
A custom image to display when the settings dialog is shown.
”/com/jme3/app/Monkey.png”
-
-
-
setTitle(“My Game”)
This string will be visible in the titlebar, unless the window is fullscreen.
-
-An AppSettings object also supports the following methods:
-
-
-
Use settings.save(outstream) and settings.load(instream) to save and load your settings via standard java.io serialization.
-
-
Use newSettings.copyFrom(oldSettings) to copy a settings object.
-
-
-
-
+app.start();
Set the boolean in the AppSettings contructor to true if you want to keep the default settings for everything that you do not specify. Set this parameter to false if you want to specify each property yourself (you'll get an exception if you missed one).
Use app.setShowSettings(false); to disable the default settings-window at startup.
Set color depth. 1 = black and white, 2 bit = gray, 4 = 16 colors, 8 = 256 colors, 24 or 32 = "truecolor".
24
setFrequency(60)
The screen frequency (refresh rate of the graphics card), usually 60 or 75 fps.
60 fps
setFramerate(60)
How often per second the engine should try to refresh the frame. For the release, usually 60 fps. Can be lower (59-30) for FX-intensive games. Do not set to a higher value than the screen frequency.
-1 (auto)
setFullscreen(true)
Set this to true to make the display fill the whole screen; you need to provide a key that calls app.stop() to exit the fullscreen view gracefully (default: escape). Set it to false to play the game in a normal window of its own.
Two equivalent ways of setting the display resolution.
640x480 pixels
setSamples(4)
Set multisampling to 0 to switch antialiasing off (harder edges, faster.) Set multisampling to 2 or 4 to activate antialising (softer edges, may be slower.) Depending on your graphic card, you may be able to go set multisampling to 8, 16, or 32 samples.
0
setVSync(true)
Set vertical syncing to true to time the frame buffer to coincide with the refresh interval of the screen: Prevents page tearing, but slower; recommened for release. Set to false to deactivate vertical syncing (faster, but possible page tearing artifacts); can be deactivated during development.
false
useInput(false)
Respond to user input by mouse and keyboard. Can be deactivated for use cases where you only display a 3D scene on the canvas without any interaction.
true
useJoysticks(true)
Activate optional joystick support
false
setSettingsDialogImage("/path/in/assets.png")
A custom image to display when the settings dialog is shown.
"/com/jme3/app/Monkey.png"
setTitle("My Game")
This string will be visible in the titlebar, unless the window is fullscreen.
\ No newline at end of file
diff --git a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/intermediate/best_practices.html b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/intermediate/best_practices.html
index d99e6b46e..92577857a 100644
--- a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/intermediate/best_practices.html
+++ b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/intermediate/best_practices.html
@@ -1,508 +1,271 @@
-
-
-
-As a quick overview, answer yourself the following questions:
-
-
-
-
Motivation
-
-
Sum up your game idea in one sentence. If you can't, it's too complicated.
-
-
Who's the target group? Why would they choose your game over the million others that exist?
-
-
-
-
Game type
-
-
Point of view (camera)? What character(s) does the player control (if any)?
-
-
Time- or turn-based?
-
-
Genre, setting, background story? (If applicable)
-
-
-
-
Gameplay
-
-
What is the start state, what is the end state?
-
-
What resources does the player manage? How are resources gained, transformed, spent? E.g. speed, gold, health, “points”.
-
-
How does the player interact? I.e. rules, challenges, game mechanics.
-
-
What state is considered winning, and what losing?
-
-
-
-
Media assets
-
-
Which media will you need? How will you get this content?
- models, terrains; materials, textures; audio, sound, music; video; spoken/written dialog; levels, quests, stories; AI scripts
-
-
-
-
Interface
-
-
Can you achieve a high degree of input control? Even minor navigation and interaction glitches make the game unsolvable.
-
-
Clearly reflect current status, and changes in game states. E.g. health/damage.
-
-
Clearly reward good moves and discourage bad ones.
Lay out the overall application flow using mock-ups or stock art. E.g. switching between intro screen / options screen / game screen.
-
-
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.
-
-
-
-
Alpha
-
-
Run internal tests, debug, optimize (issue tracker).
-
-
Replace all mock-ups with first drafts of real media and levels.
-
-
Feature Freeze: Avoid a bottomless pit of side effects causing new issues.
-
-
-
-
Beta
-
-
Have external people review and “beta test” it (issue tracker).
-
-
Even out the kinks in the code – don't add any more new features.
-
-
Fill in all final content.
-
-
-
-
Gamma, Delta = Release Candidates
-
-
Last chance to find a horrible bug.
-
-
-
-
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:
-
-
-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?
-
-
-
-
Start with implementing the most complex game feature first – the one that imposes most constraints on the structure of your project (for instance, networking.)
-
-
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.
-
-
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.
-
-
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.
-
-
-
Example: 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”.
-
-Typically, developers extend a custom class off of jME3's com.jme3.app.SimpleApplication (or even com.jme3.app.Application). For a racing game you would create a different base game class than for a space game or a shooter.
-
-
-
-
Create a generic game class for your custom game:
-
-
Create a jME3-based project with all necessary JARs on the classpath.
-
-
Create a class in this package that extends SimpleApplication, name it something like my.company.MyBaseGame.java.
-
-
Implement all generic features that the game type needs in the MyBaseGame class. For example methods for loading and saving scenes, physics, networking and multi-player logon screen, switching to settings screen, etc.
-
-
Include generic assets (company logo, reusable GUI elements in your company style, etc) in the MyBaseGame's assets directory.
-
-
-
-
Create your actual game, e.g. a shooter:
-
-
Create another jME3-based project, and a new package for the game itself, e.g. my.company.zombieshooter.MyGame.java.
-
-
Add MyBaseGame.jar to the classpath of MyGame.java.
-
-
Make MyGame.java's main class extend MyBaseGame.
-
-
The specific assets (scenes, models) of this game go into MyGame's own assets folder.
-
-
Now implement this 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.
-
-As your jME3-based application grows more advanced, you may find yourself putting more and more tests in the simpleUpdate() loop, and passing around lots of object references. Don't implement game behaviour by copying and pasting boilerplate code! It is a best practice to move game behaviour into classes of their own. In jME3 these classes are Controls and AppStates.
-
-
-
-
Use Controls to implement the behaviour of types of game entities. A character control that defines how this type of Spatials moves, an animation control that plays animations in this type of Spatial's model, etc.
-
-
Use AppStates to implement global game behaviour: A physics manager, a custom artificial intelligence manager, etc.
-
-
Use the simpleUpdate() loop for the remaining “one-off” tests and interactions.
-
-
-
-
-
-Both classes automatically hook into the main update loop. Instead of remote controlling game entities via simpleUpdate(), you define the desired behaviour in the update methods of custom Controls and AppStates. You then add Controls to Spatials, and AppStates to the application, and jME3 will automatically trigger the update methods. This cleans up your simpleUpdate() loop code considerably.
-
As a quick overview, answer yourself the following questions:
Motivation
Sum up your game idea in one sentence. If you can't, it's too complicated.
Who's the target group? Why would they choose your game over the million others that exist?
Game type
Point of view (camera)? What character(s) does the player control (if any)?
Time- or turn-based?
Genre, setting, background story? (If applicable)
Gameplay
What is the start state, what is the end state?
What resources does the player manage? How are resources gained, transformed, spent? E.g. speed, gold, health, "points".
How does the player interact? I.e. rules, challenges, game mechanics.
What state is considered winning, and what losing?
Media assets
Which media will you need? How will you get this content? models, terrains; materials, textures; audio, sound, music; video; spoken/written dialog; levels, quests, stories; AI scripts
Interface
Can you achieve a high degree of input control? Even minor navigation and interaction glitches make the game unsolvable.
Clearly reflect current status, and changes in game states. E.g. health/damage.
Clearly reward good moves and discourage bad ones.
Lay out the overall application flow using mock-ups or stock art. E.g. switching between intro screen / options screen / game screen.
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.
Alpha
Run internal tests, debug, optimize (issue tracker).
Replace all mock-ups with first drafts of real media and levels.
Feature Freeze: Avoid a bottomless pit of side effects causing new issues.
Beta
Have external people review and "beta test" it (issue tracker).
Even out the kinks in the code – don't add any more new features.
Fill in all final content.
Gamma, Delta = Release Candidates
Last chance to find a horrible bug.
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:
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?
Start with implementing the most complex game feature first – the one that imposes most constraints on the structure of your project (for instance, networking.)
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.
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.
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.
Example: 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".
Typically, developers extend a custom class off of jME3's com.jme3.app.SimpleApplication (or even com.jme3.app.Application). For a racing game you would create a different base game class than for a space game or a shooter.
Create a generic game class for your custom game:
Create a jME3-based project with all necessary JARs on the classpath.
Create a class in this package that extends SimpleApplication, name it something like my.company.MyBaseGame.java.
Implement all generic features that the game type needs in the MyBaseGame class. For example methods for loading and saving scenes, physics, networking and multi-player logon screen, switching to settings screen, etc.
Include generic assets (company logo, reusable GUI elements in your company style, etc) in the MyBaseGame's assets directory.
Create your actual game, e.g. a shooter:
Create another jME3-based project, and a new package for the game itself, e.g. my.company.zombieshooter.MyGame.java.
Add MyBaseGame.jar to the classpath of MyGame.java.
Make MyGame.java's main class extend MyBaseGame.
The specific assets (scenes, models) of this game go into MyGame's own assets folder.
Now implement this 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.
As your jME3-based application grows more advanced, you may find yourself putting more and more tests in the simpleUpdate() loop, and passing around lots of object references. Don't implement game behaviour by copying and pasting boilerplate code! It is a best practice to move game behaviour into classes of their own. In jME3 these classes are Controls and AppStates.
Use Controls to implement the behaviour of types of game entities. A character control that defines how this type of Spatials moves, an animation control that plays animations in this type of Spatial's model, etc.
Use AppStates to implement global game behaviour: A physics manager, a custom artificial intelligence manager, etc.
Use the simpleUpdate() loop for the remaining "one-off" tests and interactions.
Both classes automatically hook into the main update loop. Instead of remote controlling game entities via simpleUpdate(), you define the desired behaviour in the update methods of custom Controls and AppStates. You then add Controls to Spatials, and AppStates to the application, and jME3 will automatically trigger the update methods. This cleans up your simpleUpdate() loop code considerably.
Put your assets into subfolders of your project's assets directory. This is the default path where the assetManager looks for files.
jMonkeyProjects/Pong/assets/ # Store assets here
jMonkeyProjects/Pong/build/ # jMP generates built classes here *
jMonkeyProjects/Pong/build.xml # Customize Ant build script here
jMonkeyProjects/Pong/nbproject/ # jMP stores default build.xml and meta data *
jMonkeyProjects/Pong/dist/ # jMP generates executables here *
jMonkeyProjects/Pong/src/ # Store Java sources here
jMonkeyProjects/Pong/test/ # Store test classes here (optional)
-(*) managed by jMonkeyPlatform, don't edit
-
-
-
Agree on a file and directory naming scheme with the designers.
-
-
Are there assets (models, sound files, …) that will be used interchangeably? Then name or number them in a way so that the developer can swap the assets by swapping part of the path string.
-
-
Decide on naming standards for naming interactive parts of models (e.g. arms/legs in an animation).
-
-
-
-
Structure the subfolders of assets in any way that suits the project – but stick with one system.
-
-
Either keep all Textures together with their Ogre meshes in the Model directory.
-
-
Or keep the Ogre meshes with their Textures in the Textures directory. (Recommended.)
-
-
-
-
Place reusable Textures and Materials (the ones that you set programmatically) into the Textures and Materials directory, respectively.
-
-
If different types of assets (materials, textures, models) belong together, create a parallel subdirectory structure for them: Textures/vehicles/car/, Materials/vehicles/car/, Models/vehicles/car/
-
-
-
-
-
-Here is an example of a commonly used directory structure:
-
Agree on a file and directory naming scheme with the designers.
Are there assets (models, sound files, …) that will be used interchangeably? Then name or number them in a way so that the developer can swap the assets by swapping part of the path string.
Decide on naming standards for naming interactive parts of models (e.g. arms/legs in an animation).
Structure the subfolders of assets in any way that suits the project – but stick with one system.
Either keep all Textures together with their Ogre meshes in the Model directory.
Or keep the Ogre meshes with their Textures in the Textures directory. (Recommended.)
Place reusable Textures and Materials (the ones that you set programmatically) into the Textures and Materials directory, respectively.
If different types of assets (materials, textures, models) belong together, create a parallel subdirectory structure for them: Textures/vehicles/car/, Materials/vehicles/car/, Models/vehicles/car/
Here is an example of a commonly used directory structure:
-
-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.
-
-
-
-
Do not call updateGeometricState() on anything but the root node!
-
-
Do not override or mess with updateGeometricState() at all.
-
-
Do not use getLocalTranslation().set() to move a spatial, always use setLocalTranslation().
-
-It's unlikely you will be willing to fully document every class you write. You should at minimum javadoc all crucial methods/parameters in a meaningful way.
-
-
-
-
Answer three questions for every crucial method/parameter:
-
-
What is this?
-
-
How does it solve its task? (e.g. algorithm used)
-
-
In which situation do I want to use this?
-
-
-
-
Write down limits (e.g. min/max values) and defaults while you still remember.
-
-
Is this optional or required? What are the alternatives?
-
-
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.
-
-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 that code that you or someone deleted and now is needed.
-
-
-
Treat commit messages as messages to your future self. “Made some changes” is not a commit message.
-
-
The jMonkeyPlatform supports Subversion, Mercurial, and CVS.
-
-
If you don't know which to choose, Subversion is a good choice for starters.
-
-
You can get free project hosting space from various open-source dev portals like , , or . support private projects.
-
-From the beta on, convert all Ogre mesh models and scenes to the binary .j3o format. Use the jMonkeyPlatform for the conversion, and save the .j3o files into the Models directory.
-
-
-
-
.j3o is an optimized format to store part of a jME3 scenegraph.
- It can contain an individual model or a whole scene. Optionally (using the jMonkeyEngine SceneComposer) you can include the model's physical properties, materials, lights, particle emitters, and audio nodes.
-
-
If you kept the Ogre mesh together with the textures in the Textures directory during the conversion, the paths are recorded in a way so that you can move the .j3o to another directory, and it will still find its textures.
-
-
The default Ant build script copies .j3o / .j3m files and other assets into the distributable JAR automatically.
-
-
Important: Other model files however (.mesh.xml, .material, .obj, .mat) are not bundled automatically. You will get a runtime error that a resource was not found if you try to run the JAR with code referring to these files.
-
-Unit Tests (Java Assertions) 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 separate game features such as loaders, content generators, effects. Run them 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. There can be bugs in software, but 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 list again, on every supported operating system, and systematically look for regressions or 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, e.g. why they gave up. Evaluate whether these problems are exceptions or must be fixed for the game to be playable.
-
-
-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().
-
-
-A Java Profiler can be added 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.
-
Prepare promotional art: Cool screenshots (in thumbnail, square, vertical, horizontal, and fullscreen formats) and video clips. Include name, contact info, slogan, etc so customers can find you.
-
-
Prepare a web page, start getting advertisment slots, etc
-
-
Prepare a readme.txt file, or installation guide, or handbook – if applicable.
-
-
Get a certificate if it is required for your distribution method (see below).
-
-
Specify a classification rating.
-
-
…
-
-
-
-
-
-Distributable Executable
-
-
-
-The SDK can help you with deployment. Do you release your game as WebStart, Desktop JAR, or Applet? Each has its pros and cons.
-
-
-
-
-
Distribution
Pros
Cons
-
-
-
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.)
-
-
-
-
-
-Which ever method you choose, a Java-Application works on the three main operating systems: Windows, Mac OS, Linux.
-
-
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.
Do not call updateGeometricState() on anything but the root node!
Do not override or mess with updateGeometricState() at all.
Do not use getLocalTranslation().set() to move a spatial, always use setLocalTranslation().
It's unlikely you will be willing to fully document every class you write. You should at minimum javadoc all crucial methods/parameters in a meaningful way.
Answer three questions for every crucial method/parameter:
What is this?
How does it solve its task? (e.g. algorithm used)
In which situation do I want to use this?
Write down limits (e.g. min/max values) and defaults while you still remember.
Is this optional or required? What are the alternatives?
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.
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 that code that you or someone deleted and now is needed.
Treat commit messages as messages to your future self. "Made some changes" is not a commit message.
The jMonkeyPlatform supports Subversion, Mercurial, and CVS.
If you don't know which to choose, Subversion is a good choice for starters.
From the beta on, convert all Ogre mesh models and scenes to the binary .j3o format. Use the jMonkeyPlatform for the conversion, and save the .j3o files into the Models directory.
.j3o is an optimized format to store part of a jME3 scenegraph. It can contain an individual model or a whole scene. Optionally (using the jMonkeyEngine SceneComposer) you can include the model's physical properties, materials, lights, particle emitters, and audio nodes.
If you kept the Ogre mesh together with the textures in the Textures directory during the conversion, the paths are recorded in a way so that you can move the .j3o to another directory, and it will still find its textures.
The default Ant build script copies .j3o / .j3m files and other assets into the distributable JAR automatically.
Important: Other model files however (.mesh.xml, .material, .obj, .mat) are not bundled automatically. You will get a runtime error that a resource was not found if you try to run the JAR with code referring to these files.
Unit Tests (Java Assertions) 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 separate game features such as loaders, content generators, effects. Run them 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. There can be bugs in software, but 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 list again, on every supported operating system, and systematically look for regressions or 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, e.g. why they gave up. Evaluate whether these problems are exceptions or must be fixed for the game to be playable.
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().
A Java Profiler can be added 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.
Prepare promotional art: Cool screenshots (in thumbnail, square, vertical, horizontal, and fullscreen formats) and video clips. Include name, contact info, slogan, etc so customers can find you.
Prepare a web page, start getting advertisment slots, etc
Prepare a readme.txt file, or installation guide, or handbook – if applicable.
Get a certificate if it is required for your distribution method (see below).
Specify a classification rating.
…
Distributable Executable
The SDK can help you with deployment. Do you release your game as WebStart, Desktop JAR, or Applet? Each has its pros and cons.
Distribution
Pros
Cons
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.)
Which ever method you choose, a Java-Application works on the three main operating systems: Windows, Mac OS, Linux.
\ No newline at end of file
diff --git a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/intermediate/file_types.html b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/intermediate/file_types.html
index 6a05dff11..e540e6329 100644
--- a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/intermediate/file_types.html
+++ b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/intermediate/file_types.html
@@ -1,56 +1,60 @@
-
-
Binary 3D model or scene. From the Beta release of your game on, you should convert all models to .j3o format. During alpha and earlier development phases (when models still change a lot) you can alternatively load OgreXML/OBJ models directly.
Binary 3D model or scene. From the Beta release of your game on, you should convert all models to .j3o format. During alpha and earlier development phases (when models still change a lot) you can alternatively load OgreXML/OBJ models directly.
\ No newline at end of file
diff --git a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/intermediate/headlessserver.html b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/intermediate/headlessserver.html
index 23cb09dab..1e4853183 100644
--- a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/intermediate/headlessserver.html
+++ b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/intermediate/headlessserver.html
@@ -1,78 +1,37 @@
-
-
-
-When adding multiplayer to your game, you may find that your server needs to know about game state (e.g. where are players, objects? Was that a direct hit? etc.) You can code all this up yourself, but there's an easier way.
-
-
-
-It's very easy to change your current (client) game to function as a server as well.
-
When adding multiplayer to your game, you may find that your server needs to know about game state (e.g. where are players, objects? Was that a direct hit? etc.) You can code all this up yourself, but there's an easier way.
It's very easy to change your current (client) game to function as a server as well.
-
-Now, with a simple change you can start your game in Headless mode. This means that all input and audio/visual output will be ignored. That's a good thing for a server.
-
Now, with a simple change you can start your game in Headless mode. This means that all input and audio/visual output will be ignored. That's a good thing for a server.
import com.jme3.system.JmeContext;
import com.jme3.system.JmeContext.Type;
public static void main(String[] args) {
Application app = new Main();
app.start(JmeContext.Type.Headless);
-}
-
-
Although all input/output is ignored, the server does keep game state and does call the simpleUpdate() as expected.
-
\ No newline at end of file
diff --git a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/intermediate/my_first_game.html b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/intermediate/my_first_game.html
index 19ef426eb..b663a5e8b 100644
--- a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/intermediate/my_first_game.html
+++ b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/intermediate/my_first_game.html
@@ -1,51 +1,63 @@
jMonkeyEngine.org |