-
-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 jMonkeyEngine SDK to convert models to .j3o format. You don't need this step as long you still develop and test the aplication within the jMonkeyEngine SDK.
-
-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 jMonkeyEngine SDK to convert models to .j3o format. You don't need this step as long you still develop and test the aplication within the jMonkeyEngine SDK.
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/.
\ 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 1928b05cb..53498fc03 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,286 +1,9 @@
-
-
-
-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");
@@ -296,81 +19,18 @@ 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 event 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 event 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/asset_manager.html b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/asset_manager.html
index b61327a42..b5d5cadad 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
@@ -174,7 +174,7 @@ If you use the default build script created by the jMonkeyEngine SDK's context menu action to convert OgreXML models to .j3o format.
-
Open the kME3 Project in the jMonkeyEngine SDK.
+
Open the jME3 Project in the jMonkeyEngine SDK.
Browse the assets directory in the Projects window.
-
-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.
-
-
-
-
Buffered: By default, a new audio node is buffered. This means jME3 loads the whole file into memory before playing. You create a buffered sound by setting the boolean to false, or using no boolean at all:
AudioNode boom = new AudioNode(assetManager, "Sound/boom.wav");
-
-
-
Streamed: If it is a long file, you stream the audio, that means, you load and play in parallel until the sound is done. You create a streamed sound by setting the boolean to true:
AudioNode music = new AudioNode(assetManager, "Sound/music.wav", true);
Sets the volume gain. 1 is the default volume, 2 is twice as loud, etc. 0 is silent/mute.
-
-
-
setPitch(1)
Makes the sound play in a higher or lower pitch. Default is 1. 2 is twice as high, .5f is half as low.
-
-
-
-
-
AudioNode Method
Usage
-
-
-
setLooping(false)
Configures the sound so that, if it is played, it plays once and stops. This is the default.
-
-
-
setLooping(true)
Configures the sound so that, if it is played, it plays repeats from the beginning, until stop() or pause() are called. Good for ambient background noises.
-Does not work for streamed sounds!
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.
Buffered: By default, a new audio node is buffered. This means jME3 loads the whole file into memory before playing. You create a buffered sound by setting the boolean to false, or using no boolean at all:
AudioNode boom = new AudioNode(assetManager, "Sound/boom.wav");
Streamed: If it is a long file, you stream the audio, that means, you load and play in parallel until the sound is done. You create a streamed sound by setting the boolean to true:
AudioNode music = new AudioNode(assetManager, "Sound/music.wav", true);
Sets the volume gain. 1 is the default volume, 2 is twice as loud, etc. 0 is silent/mute.
setPitch(1)
Makes the sound play in a higher or lower pitch. Default is 1. 2 is twice as high, .5f is half as low.
AudioNode Method
Usage
setLooping(false)
Configures the sound so that, if it is played, it plays once and stops. This is the default.
setLooping(true)
Configures the sound so that, if it is played, it plays repeats from the beginning, until stop() or pause() are called. Good for ambient background noises. Does not work for streamed sounds!
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.
-
-Use these presets together with Audio Nodes to create different "moods" for sounds. Environment effects make your audio sound as if the listener were in various places that have different types of echoes.
-
Use these presets together with Audio Nodes to create different "moods" for sounds. Environment effects make your audio sound as if the listener were in various places that have different types of echoes.
\ 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 927b1897b..d9fea212a 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,7 @@
-
-
-
-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,132 +13,17 @@ The tank material looks like that :
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);
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 {
....
@@ -235,13 +31,7 @@ In your material definition you need to add those lines in the MaterialParameter
Texture2D GlowMap
// The glow color of the object
Color GlowColor
- }
-
-
-Then add the following technique :
-
-
-
Technique Glow {
+ }
Then add the following technique :
Technique Glow {
LightMode SinglePass
@@ -256,29 +46,5 @@ Then add the following technique :
HAS_GLOWMAP : GlowMap
HAS_GLOWCOLOR : GlowColor
}
- }
-
-
-Then you can use this material with the BloomFilter
-
\ No newline at end of file
diff --git a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/bullet_multithreading.html b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/bullet_multithreading.html
index 816718000..dd6f4c52f 100644
--- a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/bullet_multithreading.html
+++ b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/bullet_multithreading.html
@@ -1,47 +1,4 @@
-
-
-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. More physics spaces can simply be added by using multiple bulletAppStates.
-
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. More physics spaces can simply be added by using multiple bulletAppStates.
\ 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 02252cbff..dc5d35081 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,386 +1,12 @@
-
-
-
-JME3 cinematics (com.jme.cinematic) allow you to remote control nodes and cameras in a 3D game: You can script and and play cinematic scenes. Combined with screen recording software, you use cinematics to create and movies/trailers of your game. Internally, Cinematics are implemented as AppStates.
-
-
-
-Short overview of the cinematic process:
-
-
-
Plan the script of your movie.
-Write down a timeline (e.g. on paper) of which character should be at which spot at which time.
-
-
Attach the scene objects that you want to remote-control to one Node.
-This Node can be the rootNode, or a Node that is attached to the rootNode.
-
-
Create a Cinematic object for this movie scene. The Cinematic will contain and manage the movie script.
-
-
For each line in your script (for each frame in your timeline), add a CinematicEvent to the Cinematic.
JME3 cinematics (com.jme.cinematic) allow you to remote control nodes and cameras in a 3D game: You can script and and play cinematic scenes. Combined with screen recording software, you use cinematics to create and movies/trailers of your game. Internally, Cinematics are implemented as AppStates.
Short overview of the cinematic process:
Plan the script of your movie. Write down a timeline (e.g. on paper) of which character should be at which spot at which time.
Attach the scene objects that you want to remote-control to one Node. This Node can be the rootNode, or a Node that is attached to the rootNode.
Create a Cinematic object for this movie scene. The Cinematic will contain and manage the movie script.
For each line in your script (for each frame in your timeline), add a CinematicEvent to the Cinematic.
sceneNode is the node containing the scene (can be the rootNode).
-
-
duration is the duration of the whole scene in seconds.
-
-
Each Cinematic is a set of CinematicEvents, that are triggered at a given moment on the timeline.
-
-
-
-
Create one CinematicEvent for each line of your movie script.
-
-
track is one motion of a moving object. You can add several tracks. More details below.
-
-
starttime is the time when this particular cinematic event starts on the timeline. Specify the start time in seconds since the beginning of the cinematic.
-
-
-
-
Attach the Cinematic to the SimpleApplication's stateManager.
-
-
Play, stop and pause the Cinematic from your code.
-
-
-
-
-
Method
Usage
-
-
-
cinematic.play()
Starts playing the cinematic from the start, or from where it was paused.
-
-Just like a movie script consists of lines with instructions to the actors, each Cinematic consists of a series of tracks.
-
-
-
-Here is the list of available CinematicEvents that you use as tracks. Each track remote-controls scene objects in a different way:
-
-
-
-
-
Tracks (CinematicEvents)
Description
-
-
-
MotionTrack
Use a MotionTrack to move a Spatial non-linearly over time. A MotionTrack is based on a list of waypoints in a MotionPath. The curve goes through each waypoint, and you can adjust the tension of the curve to modify the roundedness of the path. This is the motion interpolation you are going to use in most cases.
-
-
-
PositionTrack
Use a PositionTrack to move a Spatial linearly over time. This linear interpolation results in straight motion segments between the way points. Use this to make the remote-controlled objects zig-zag from one way point to the other in a straight line.
-
-
-
RotationTrack
Use a RotationTrack to change the rotation of a Spatial over time. It spins the Spatial to the given angle in the given amount of time by linearly interpolating the rotation.
-
-
-
ScaleTrack
Use a ScaleTrack to change the size of a Spatial over time. It resizes the Spatial in the given amount of time by linearly interpolating the scale.
-
-
-
SoundTrack
Use a SoundTrack 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)
-
-
-
-
-
-The jMonkey team can add more types of tracks, just ask in the forum.
-
Sets the direction behavior type of the controled node. Direction.None deactivates this feature. You can choose from the following options: LookAt, Path, PathAndRotation, Rotation.
The spatial always faces towards this location. Use together with MotionTrack.Direction.LookAt.
-
-
-
track.setRotation(quaternion)
Sets the rotation. Use together with MotionTrack.Direction.Rotation or MotionTrack.Direction.PathAndRotation.
-
-
-
-
-
-Tip: Most likely you remote-control more than one object in your scene. Give the tracks and paths useful names such as dragon_track, dragon_path, hero_track, hero_path, etc.
-
-
-You can extend individual CinematicEvents. The shows how to extend a GuiTrack to script subtitles. See how the subtitles are used in the .
+stateManager.attach(cinematic);
Create one Cinematic per scripted scene.
sceneNode is the node containing the scene (can be the rootNode).
duration is the duration of the whole scene in seconds.
Each Cinematic is a set of CinematicEvents, that are triggered at a given moment on the timeline.
Create one CinematicEvent for each line of your movie script.
track is one motion of a moving object. You can add several tracks. More details below.
starttime is the time when this particular cinematic event starts on the timeline. Specify the start time in seconds since the beginning of the cinematic.
Attach the Cinematic to the SimpleApplication's stateManager.
Play, stop and pause the Cinematic from your code.
Method
Usage
cinematic.play()
Starts playing the cinematic from the start, or from where it was paused.
Just like a movie script consists of lines with instructions to the actors, each Cinematic consists of a series of tracks.
Here is the list of available CinematicEvents that you use as tracks. Each track remote-controls scene objects in a different way:
Tracks (CinematicEvents)
Description
MotionTrack
Use a MotionTrack to move a Spatial non-linearly over time. A MotionTrack is based on a list of waypoints in a MotionPath. The curve goes through each waypoint, and you can adjust the tension of the curve to modify the roundedness of the path. This is the motion interpolation you are going to use in most cases.
PositionTrack
Use a PositionTrack to move a Spatial linearly over time. This linear interpolation results in straight motion segments between the way points. Use this to make the remote-controlled objects zig-zag from one way point to the other in a straight line.
RotationTrack
Use a RotationTrack to change the rotation of a Spatial over time. It spins the Spatial to the given angle in the given amount of time by linearly interpolating the rotation.
ScaleTrack
Use a ScaleTrack to change the size of a Spatial over time. It resizes the Spatial in the given amount of time by linearly interpolating the scale.
SoundTrack
Use a SoundTrack 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)
The jMonkey team can add more types of tracks, just ask in the forum.
Sets the direction behavior type of the controled node. Direction.None deactivates this feature. You can choose from the following options: LookAt, Path, PathAndRotation, Rotation.
The spatial always faces towards this location. Use together with MotionTrack.Direction.LookAt.
track.setRotation(quaternion)
Sets the rotation. Use together with MotionTrack.Direction.Rotation or MotionTrack.Direction.PathAndRotation.
Tip: Most likely you remote-control more than one object in your scene. Give the tracks and paths useful names such as dragon_track, dragon_path, hero_track, hero_path, etc.
-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.
-
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.
-
-jME3 supports two types of effects, post-rendering filters and particle emitters. This list contains screenshots and links to sample code that demonstrates how to add the effect to a scene.
-
-
-
-For example, post-processor filter effects are typically activated after the following pattern:
-
jME3 supports two types of effects, post-rendering filters and particle emitters. This list contains screenshots and links to sample code that demonstrates how to add the effect to a scene.
For example, post-processor filter effects are typically activated after the following pattern:
public class MyGame extends SimpleApplication {
private FilterPostProcessor fpp;
private SomeFilter sf;
@@ -21,193 +9,7 @@ For example, post-processor filter effects are typically activated after the fol
fpp.addFilter(sf);
viewPort.addProcessor(fpp);
...
- }
-
-The jMonkeyEngine3 has built-in support for via the com.jme3.bullet package.
-
-
-
-Game Physics are not only employed to calculate collisions, but they can also simulate hinges and joints. Think of pulley chains, shaky rope bridges, swinging pendulums, or (trap)door and chest hinges. Physics are a great addition to e.g. an action or puzzle game.
-
-
-
-In this example, we will create a pendulum. The joint is the (invisible) connection between the pendulum body and the hook. You will see that you can use what you learn from the simple pendulum and apply it to other joint/hinge objects (rope bridges, etc).
-
The jMonkeyEngine3 has built-in support for via the com.jme3.bullet package.
Game Physics are not only employed to calculate collisions, but they can also simulate hinges and joints. Think of pulley chains, shaky rope bridges, swinging pendulums, or (trap)door and chest hinges. Physics are a great addition to e.g. an action or puzzle game.
In this example, we will create a pendulum. The joint is the (invisible) connection between the pendulum body and the hook. You will see that you can use what you learn from the simple pendulum and apply it to other joint/hinge objects (rope bridges, etc).
-
-A PhysicsHingeJoint is an invisible connection between two nodes – here between the pendulum body and the hook. Why are hinges and joints represented by the same class? Hinges and joints have something in common: They constrain the mechanical degree of freedom (DOF) of another object.
+getPhysicsSpace().add(pendulumNode);
For a rope bridge, each set of planks would be one dynamic node.
A PhysicsHingeJoint is an invisible connection between two nodes – here between the pendulum body and the hook. Why are hinges and joints represented by the same class? Hinges and joints have something in common: They constrain the mechanical degree of freedom (DOF) of another object.
@@ -125,7 +35,7 @@ Now consider some examples of objects with joints:
-You'll understand that, when creating any type of joint, it is important to correctly specify the DOFs that the joint restricts, and the DOFs that the joint allows. For the typical DOF of a ragDoll character's limbs, jME even offers a special joint, PhysicsConeJoint.
+You'll understand that, when creating any type of joint, it is important to correctly specify the DOFs that the joint restricts, and the DOFs that the joint allows. For the typical DOF of a ragDoll character's limbs, jME even offers a special joint, ConeJoint.
@@ -135,7 +45,7 @@ You'll understand that, when creating any type of joint, it is important to
-You create the PhysicsHingeJoint after you have created the nodes that are to be chained together. In the code snippet you see that the PhysicsHingeJoint constructor requires the two node objects. You also have to specify axes and pivots – they are the degrees of freedom that you just heard about.
+You create the HingeJoint after you have created the nodes that are to be chained together. In the code snippet you see that the HingeJoint constructor requires the two node objects. You also have to specify axes and pivots – they are the degrees of freedom that you just heard about.
-
-In the Material Definitions article you learned how to configure Materials programmatically in Java code. If you have certain commonly used Materials that never change, you can clean up the amount of Java code that clutters your init method, by moving material settings into .j3m files. Then later in your code, you only need to call one setter instead of several to apply the material.
-
In the Material Definitions article you learned how to configure Materials programmatically in Java code. If you have certain commonly used Materials that never change, you can clean up the amount of Java code that clutters your init method, by moving material settings into .j3m files. Then later in your code, you only need to call one setter instead of several to apply the material.
For every Material, create a file and give it a name that describes it: e.g. SimpleBump.j3m
Place the file in your project's assets/Materials/ directory, e.g. MyGame/src/assets/Materials/SimpleBump.j3m
Edit the file and add content using the following Syntax, e.g.:
Material shiny bumpy rock : Common/MatDefs/Light/Lighting.j3md {
MaterialParameters {
Shininess: 8.0
NormalMap: Textures/bump_rock_normal.png
@@ -25,21 +7,7 @@ In the
-
-
-
-
-
-
-How to this file is structured:
-
-
-
Header
-
-
Material is a fixed keyword, keep it.
-
-
shiny bumpy rock is a descriptive string that you can make up. Choose a name to help you remember for what you intend to use this material.
+}
How to this file is structured:
Header
Material is a fixed keyword, keep it.
shiny bumpy rock is a descriptive string that you can make up. Choose a name to help you remember for what you intend to use this material.
After the colon, specify on which Material definition you base this Material.
-
-There is a good tutorial about creating a nifty progress bar here:
-
-
-
-
-This example will use the existing hello terrain as an example.
-It will require these 2 images inside Assets/Interface/ (save them as border.png and inner.png respectively)
-
There is a good tutorial about creating a nifty progress bar here:
This example will use the existing hello terrain as an example. It will require these 2 images inside Assets/Interface/ (save them as border.png and inner.png respectively)
This screen simply displays a button in the middle of the screen, which could be seen as a simple main menu UI.
<screen id="start" controller = "jme3test.TestLoadingScreen"><layer id="layer" childLayout="center"><panel id = "panel2" height="30%" width="50%" align="center" valign="center" childLayout="vertical" visibleToMouse="true">
@@ -101,13 +50,7 @@ This screen simply displays a button in the middle of the screen, which could be
</control></panel></layer>
- </screen>
-
-
-This screen displays our custom progress bar control with a text control
-
-
-There are 3 main ways to update a progress bar. To understand why these methods are necessary, an understanding of the graphics pipeline is needed.
+ </screen>
There are 3 main ways to update a progress bar. To understand why these methods are necessary, an understanding of the graphics pipeline is needed.
@@ -223,7 +158,7 @@ public class TestLoadingScreen extends SimpleApplication implements ScreenContro
@Override
public void simpleUpdate(float tpf) {
- if (load == true) { //loading is done over many frames
+ if (load) { //loading is done over many frames
if (frameCount == 1) {
Element element = nifty.getScreen("loadlevel").findElementByName("loadingtext");
textRenderer = element.getRenderer(TextRenderer.class);
diff --git a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/localization.html b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/localization.html
index f1ef4c946..fa9baa621 100644
--- a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/localization.html
+++ b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/localization.html
@@ -1,132 +1,8 @@
-
-
-
-Localizing an application can mean several things:
-
-
-
-
At minimum you translate all messages and dialogs in the user interface to your target languages.
-
-
You should also translate the "read me", help, and other documentation.
-
-
Also translating web content related to the application makes sure international users find out about your localized game.
-
-
If you go the whole way of internationalization, you also "translate" metaphors in icons or symbols used.
-E.g. For localizations to right-to-left languages, you must also adjust the whole flow of the UI (order of menus and buttons).
-
-
-
-
-
-There are tools that assist you with localizing Java Swing GUIs. jME3 applications do not typically have a Swing GUI, so those tools are not of much help. Just stick to the normal Java rules about using Bundle Properties:
-
Create one file named Bundle.properties in each directory where there are Java file that contain messages.
-
-
For every hard-coded message, you add one line to the Bundle.properties file: First specify a unique key that identifies this string; then an equal sign; and the literal string itself.
-
greeting=Hello World!
-score.display=Score:
-
-
-
In the source code, replace every occurence of a hard-coded message with the appropriate Resource Bundle call to its unique key:
-
-Each additional language comes in a set of files that is marked with a (usually) two-letter suffix. Common locales are de for German, en for English, fr for French, ja for Japanese, pt for Portuguese, etc.
-
-
-
-To translate the messages to another language, for example, German:
-
-
-
-
Make a copy of the Bundle.properties files.
-
-
Name the copy Bundle_de.properties for German. Note the added suffix _de.
-
-
Translate all strings (text on the right side of the equal sign) in the Bundle_de.properties to German.
greeting=Hallo Welt!
-score.display=Spielstand:
-
-
- Important: Do not modify any of the keys (text to the left of the equal sign)!
-
-
-
-
To test the German localization, start the application from the command line with -Duser.language=de. Note the parameter de.
-
-
-
-
-
-Tip: In the jMonkeyEngine SDK, you set this VM Option in the Project properties under Run. Here you can also save individual run configuraions for each language you want to test.
-
-
-
-To get the full list of language suffixes use
-
-
-
-Important: In the Bundle.properties file, do not include any strings that are asset paths, node or geometry names, input mappings, or material layers.
-
Localizing an application can mean several things:
At minimum you translate all messages and dialogs in the user interface to your target languages.
You should also translate the "read me", help, and other documentation.
Also translating web content related to the application makes sure international users find out about your localized game.
If you go the whole way of internationalization, you also "translate" metaphors in icons or symbols used. E.g. For localizations to right-to-left languages, you must also adjust the whole flow of the UI (order of menus and buttons).
There are tools that assist you with localizing Java Swing GUIs. jME3 applications do not typically have a Swing GUI, so those tools are not of much help. Just stick to the normal Java rules about using Bundle Properties:
Create one file named Bundle.properties in each directory where there are Java file that contain messages.
For every hard-coded message, you add one line to the Bundle.properties file: First specify a unique key that identifies this string; then an equal sign; and the literal string itself.
greeting=Hello World!
+score.display=Score:
In the source code, replace every occurence of a hard-coded message with the appropriate Resource Bundle call to its unique key:
ResourceBundle.getBundle("Bundle").getString("greeting"));
+UiText.setText(Translating the Messages
Each additional language comes in a set of files that is marked with a (usually) two-letter suffix. Common locales are de for German, en for English, fr for French, ja for Japanese, pt for Portuguese, etc.
To translate the messages to another language, for example, German:
Make a copy of the Bundle.properties files.
Name the copy Bundle_de.properties for German. Note the added suffix _de.
Translate all strings (text on the right side of the equal sign) in the Bundle_de.properties to German.
greeting=Hallo Welt!
+score.display=Spielstand:
Important: Do not modify any of the keys (text to the left of the equal sign)!
To test the German localization, start the application from the command line with -Duser.language=de. Note the parameter de.
Tip: In the jMonkeyEngine SDK, you set this VM Option in the Project properties under Run. Here you can also save individual run configuraions for each language you want to test.
To get the full list of language suffixes use
Which Strings Not to Translate
Important: In the Bundle.properties file, do not include any strings that are asset paths, node or geometry names, input mappings, or material layers.
-
-Many developers just use System.out.println() to print diagnostic strings to the terminal. The problem with that is that before the release, you'd have to go through all your code and make certain you removed all these println() calls. You do not want your users to see them and worry about ominous strings babbling about old development diagnostics.
-
-
-Instead of println(), you use the standard Java logger from java.util.logging. It has many advantages for professional game development:
-
-
-
You "tag" each message with a log level: Severe error, informative warning, etc.
-
-
You can switch off printing of all messages up to certain log level with just one line of code.
-
-
During development, you would set the log level to fine, because you want all warnings printed.
-
-
For the release, you set the log level to only report severe errors, and no informative diagnostics.
-
-
-
-
The logger string is localizable, since it contains variables. You may want to localize all errors.
-
-
-
-
-
-So to print comments like a pro, you use the following logger syntax. The variables a, b, c, can be any printable Java object, e.g. Vector3f a = cam.getLocation(). They are numbered {0},{1},{2},etc for use in the string, in the order you put them in the Object array.
-
-
private static final Logger logger = Logger.getLogger(HelloWorld.class.getName());
-
-
-
-Replace HelloWorld by the name of the class where you are using this line.
-
-
-
logger.log(Level.WARNING, "ok seriously wtf somebody check why {0} is {1} again?!",
- new Object[]{a , b});
-
-
-
-or
-
-
-
logger.log(Level.SEVERE, "Game error: {0} must not be {1} after {2}! Please check your flux generator.",
- new Object[]{a , b , c});
-
-
-As you see in the example, you should phrase potentially "customer facing" errors in a neutral way and offer a reason and a solution. If you use WARNINGs as replacement for casual printlns, make sure you deactivate them for the release.
+
Many developers just use System.out.println() to print diagnostic strings to the terminal. The problem with that is that before the release, you'd have to go through all your code and make certain you removed all these println() calls. You do not want your users to see them and worry about ominous strings babbling about old development diagnostics.
Instead of println(), you use the standard Java logger from java.util.logging. It has many advantages for professional game development:
You "tag" each message with a log level: Severe error, informative warning, etc.
You can switch off printing of all messages up to certain log level with just one line of code.
During development, you would set the log level to fine, because you want all warnings printed.
For the release, you set the log level to only report severe errors, and no informative diagnostics.
The logger string is localizable, since it contains variables. You may want to localize all errors.
So to print comments like a pro, you use the following logger syntax. The variables a, b, c, can be any printable Java object, e.g. Vector3f a = cam.getLocation(). They are numbered {0},{1},{2},etc for use in the string, in the order you put them in the Object array.
private static final Logger logger = Logger.getLogger(HelloWorld.class.getName());
Replace HelloWorld by the name of the class where you are using this line.
logger.log(Level.WARNING, "ok seriously wtf somebody check why {0} is {1} again?!",
+ new Object[]{a , b});
or
logger.log(Level.SEVERE, "Game error: {0} must not be {1} after {2}! Please check your flux generator.",
+ new Object[]{a , b , c});
As you see in the example, you should phrase potentially "customer facing" errors in a neutral way and offer a reason and a solution. If you use WARNINGs as replacement for casual printlns, make sure you deactivate them for the release.
-
-When players steer a game character with 1st-person view, they directly steer the camera (flyCam.setEnabled(true);), and they never see the walking character itself. In a game with 3rd-person view, however, the players see the character walk, and you (the game developer) want to make the camera follow the character around when it walks.
-
-
-
-There are two ways how the camera can do that:
-
-
-
Registering a chase camera to the player and the input manager.
-
-
Attaching the camera to the character using a camera node.
-
-
-
-
-
-Important: Using third-person view requires you to deactivate the default flyCam (first-person view). This means that you have to configure your own navigation (key inputs and analogListener) that make your player character walk. For moving a physical player character, use player.setWalkDirection(), for a non-pysical character you can use player.move().
-
-To make the camera follow a target node, add this camera node code to your init method (e.g. simpleInitApp()). The target spatial is typically the player node.
-
When players steer a game character with 1st-person view, they directly steer the camera (flyCam.setEnabled(true);), and they never see the walking character itself. In a game with 3rd-person view, however, the players see the character walk, and you (the game developer) want to make the camera follow the character around when it walks.
There are two ways how the camera can do that:
Registering a chase camera to the player and the input manager.
Attaching the camera to the character using a camera node.
Important: Using third-person view requires you to deactivate the default flyCam (first-person view). This means that you have to configure your own navigation (key inputs and analogListener) that make your player character walk. For moving a physical player character, use player.setWalkDirection(), for a non-pysical character you can use player.move().
To make the camera follow a target node, add this camera node code to your init method (e.g. simpleInitApp()). The target spatial is typically the player node.
// Disable the default flyby cam
flyCam.setEnabled(false);
//create the camera Node
camNode = new CameraNode("Camera Node", cam);
@@ -56,33 +9,7 @@ camNode.setLocalTranslation(new Vector3f(0, 5, -5));
//Rotate the camNode to look at the target:
camNode.lookAt(target.getLocalTranslation(), Vector3f.UNIT_Y);
//Attach the camNode to the target:
-target.attachChild(camNode);
-
-
-Important: Where the example says camNode.setLocalTranslation(new Vector3f(0, 5, -5));, you have to supply your own start position for the camera. This depends on the size of your target (the player character) and its position in your particular scene. Optimally, you set this to a spot a bit behind and above the target.
-
-
-
-
-
Methods
Description
-
-
-
setControlDir(ControlDirection.SpatialToCamera)
User input steers the target spatial, and the camera follows the spatial.
-The spatial's transformation is copied over the camera's transformation.
-Example: Use with CharacterControlled spatial.
-
-
-
setControlDir(ControlDirection.CameraToSpatial)
User input steers the camera, and the target spatial follows the camera.
-The camera's transformation is copied over the spatial's transformation.
-
-
-
-
-
-Code sample:
-
-
-
– Press the WASD or arrow keys to move. Drag with the left mouse button to rotate.
+target.attachChild(camNode);
Important: Where the example says camNode.setLocalTranslation(new Vector3f(0, 5, -5));, you have to supply your own start position for the camera. This depends on the size of your target (the player character) and its position in your particular scene. Optimally, you set this to a spot a bit behind and above the target.
Methods
Description
setControlDir(ControlDirection.SpatialToCamera)
User input steers the target spatial, and the camera follows the spatial. The spatial's transformation is copied over the camera's transformation. Example: Use with CharacterControlled spatial.
setControlDir(ControlDirection.CameraToSpatial)
User input steers the camera, and the target spatial follows the camera. The camera's transformation is copied over the spatial's transformation.
Code sample:
– Press the WASD or arrow keys to move. Drag with the left mouse button to rotate.
-
-A Geometry (mesh) is just the shape of the object. jMonkeyEngine cannot render a shape without knowing anything about its surface properties. You need to apply a color or texture to the surface of your Geometries to make them visible. In jMonkeyEngine, colors and textures are represented as Material objects.
-
-
-
-All Geometries have Materials: You either use the setters described here to specifiy the Material's properties in your Java code, or you load a custom .j3m file that lists the properties. To improve performance, reuse Materials for similar models, don't create a new Material object for every Geometry. (E.g. use one bark Material for many tree models.)
-
-Each Material is based on one of the default material definitions (.j3md files) that are included in the engine. The Materials table shows you the material definitions that jMonkeyEngine supports by default. You want to make the most of your models by setting good looking material parameters: The developers should be in contact with the graphic designer regarding which of the available jMonkeyEngine features (listed here) are intended to be used in individual Models' Materials. You must have an understanding what texture maps are to be able to use textured materials.
-
A Geometry (mesh) is just the shape of the object. jMonkeyEngine cannot render a shape without knowing anything about its surface properties. You need to apply a color or texture to the surface of your Geometries to make them visible. In jMonkeyEngine, colors and textures are represented as Material objects.
All Geometries have Materials: You either use the setters described here to specifiy the Material's properties in your Java code, or you load a custom .j3m file that lists the properties. To improve performance, reuse Materials for similar models, don't create a new Material object for every Geometry. (E.g. use one bark Material for many tree models.)
Each Material is based on one of the default material definitions (.j3md files) that are included in the engine. The Materials table shows you the material definitions that jMonkeyEngine supports by default. You want to make the most of your models by setting good looking material parameters: The developers should be in contact with the graphic designer regarding which of the available jMonkeyEngine features (listed here) are intended to be used in individual Models' Materials. You must have an understanding what texture maps are to be able to use textured materials.
The following samples assume that you loaded a Geometry, e.g. Spatial myGeometry = assetManager.loadModel("Models/Teapot/Teapot.j3o");
Material mat = new Material(assetManager, // Create new material and
"Common/MatDefs/Misc/Unshaded.j3md"); // specify .j3md file path.
mat.setColor("Color", ColorRGBA.Blue); // Set one or more parameters.
-myGeometry.setMaterial(mat); // Use material on Geometry.
-Most Material parameters are not mandatory. For example, it is normal to specify solely the DiffuseMap and NormalMap when using Lighting.j3md, and leave the rest empty. You are only using a subset of the advanced features, but that's acceptable if it results in the material looking the way you want. You can always add more texture maps later.
-
-
-
-
1) Looks confusing? Start with Unshaded.j3md, then look into Lighting.j3md.
-2) The jMonkeyEngine SDK offers a visual editor where you can set properties and preview the outcome. The SDK Palette contains code snippets to load materials.
-3) If you don't know what an obscure parameter means, you're likely not using it.
-
-
-
-
-jMonkeyEngine supports illuminated and unshaded Material Definitions.
-
-
-
Phong Illuminated materials look more naturalistic.
-
-"Unshaded" materials look somewhat abstract because they ignore lighting and shading. Unshaded Materials work even if the scene does not include a light source. These Materials can be single-colored or textured. For example, they are used for cards and tiles, for the sky, billboards and UI elements, for toon-style games, or for testing.
-
-
-
-
-
Basic Material Definition
Usage
Parameter
-
-
-
Common/MatDefs/Misc/Unshaded.j3md
Standard, non-illuminated Materials.
-Use this for simple coloring and texturing, glow, and transparency.
-See also: Hello Material
A multi-layered texture for terrains.
-Specify four textures and a Vector3f describing the region in which each texture should appear:
-X = start height,
-Y = end height,
-Z = texture scale.
-Texture regions can overlap.
-For example: Specify a seafloor texture for the lowest areas,
-a sandy texture for the beaches,
-a grassy texure for inland areas,
-and a rocky texture for mountain tops.
setFloat("terrainSize",512f);
-setTexture("region1ColorMap", assetManager.loadTexture(""));
-setTexture("region2ColorMap", assetManager.loadTexture(""));
-setTexture("region3ColorMap", assetManager.loadTexture(""));
-setTexture("region4ColorMap", assetManager.loadTexture(""));
-setVector3("region1", new Vector3f(0,0,0));
- setVector3("region2", new Vector3f(0,0,0));
- setVector3("region3", new Vector3f(0,0,0));
- setVector3("region4", new Vector3f(0,0,0));
-Settings for steep areas:
-setTexture("slopeColorMap", assetManager.loadTexture(""));
- setFloat("slopeTileFactor",1f);
-
-
-
Common/MatDefs/Misc/Particle.j3md
Used with texture masks for particle effects, or for point sprites.
-The Quadratic value scales the particle for perspective view ().
-Does support an optional colored glow effect.
-See also: Hello Effects
-
-Illuminated materials require a light source added to at least one of their parent nodes! (e.g. rootNode.) Illuminated materials are darker on the sides facing away from light sources. They use Phong illumination model (default), or the Ward isotropic gaussian specular shader (WardIso) which looks more like plastic. They do not cast drop shadows unless you use a FilterPostProcessor.
-
-
-
-
-
Illuminated Material Definition
Usage
Setter, Parameter, Type
-
-
-
Common/MatDefs/Light/Lighting.j3md
Commonly used Material with Phong illumination.
-Use this material together with DiffuseMap, SpecularMap, BumpMap (NormalMaps, ParalaxMap) textures.
-Supports shininess, transparency, and plain material colors (Diffuse, Ambient, Specular colors).
-See also: Hello Material
Same kind of multi-layered splat texture as Terrain.j3md, but with illumination and shading.
-Typically used for terrains, but works on any mesh.
-For every 3 splat textures, you need one alpha map.
-You can use a total of 11 texture maps in the terrain's splat texture:
-Note that diffuse and normal maps all count against that.
-For example, you can use a maximum of 9 diffuse textures, two of which can have normal maps;
-or, five textures with both diffuse and normal maps.
A color gradient calculated from the model's surface normals. You can use this built-in material to debug the generation of normals in meshes, to preview models that have no material, or as fall-back default material. This built-in material has no parameters.
-
-A NormalMap (alos called BumpMap) describes the fine bumpy details of the Material surface that are not part of the mesh itself. E.g. cracks, pores, creases, notches.
-
-
-
Generate normals for the Mesh (not for the Geometry!)
Specify the Shininess intensity.
-A float value between 1 (rough surface with blurry shininess) and 128 (very smooth surface with focused shininess)
-
-
Specify a Color as Specular value.
-The ColorRGBA value of the light source, e.g. often RGBA.White.
-
-
(Optionally for some Materials) Specify a SpecularMap texture.
-This grayscale texture outlines in detail where the DiffuseMap texture should be shiny (white) and were not (black), instead of rendering the whole material evenly shiny.
-
-
-
-
-
-To deactivate shininess
-
-
-
Set the Specular color to ColorRGBA.Black. Do not just set Shininess to 0.
Specify a Color as Glow value.
-A ColorRGBA value of your choice, e.g. choose a warm or cold color for different effects.
-
-
(Optionally for some Materials) Specify a GlowMap texture.
-This texture outlines in detail where the DiffuseMap texture glows, instead of making the whole material glow everwhere evenly.
-
-Most Material Definitions support an alpha channel for opaqueness and transparency in textures. In an RGBA color, the last float is the alpha channel: 0.0f is transparent and 1.0f is opaque. For example, mat.setColor("Color", new ColorRGBA(1,0,0,0.5f)); is a half-opaque red.
-
-
-
-Additionally, you must specify a blendmode:
+myGeometry.setMaterial(mat); // Use material on Geometry.
Most Material parameters are not mandatory. For example, it is normal to specify solely the DiffuseMap and NormalMap when using Lighting.j3md, and leave the rest empty. You are only using a subset of the advanced features, but that's acceptable if it results in the material looking the way you want. You can always add more texture maps later.
1) Looks confusing? Start with Unshaded.j3md, then look into Lighting.j3md. 2) The jMonkeyEngine SDK offers a visual editor where you can set properties and preview the outcome. The SDK Palette contains code snippets to load materials. 3) If you don't know what an obscure parameter means, you're likely not using it.
jMonkeyEngine supports illuminated and unshaded Material Definitions.
Phong Illuminated materials look more naturalistic.
"Unshaded" materials look somewhat abstract because they ignore lighting and shading. Unshaded Materials work even if the scene does not include a light source. These Materials can be single-colored or textured. For example, they are used for cards and tiles, for the sky, billboards and UI elements, for toon-style games, or for testing.
Basic Material Definition
Usage
Parameter
Common/MatDefs/Misc/Unshaded.j3md
Standard, non-illuminated Materials. Use this for simple coloring and texturing, glow, and transparency. See also: Hello Material
A multi-layered texture for terrains. Specify four textures and a Vector3f describing the region in which each texture should appear: X = start height, Y = end height, Z = texture scale. Texture regions can overlap. For example: Specify a seafloor texture for the lowest areas, a sandy texture for the beaches, a grassy texure for inland areas, and a rocky texture for mountain tops.
setFloat("terrainSize",512f); setTexture("region1ColorMap", assetManager.loadTexture("")); setTexture("region2ColorMap", assetManager.loadTexture("")); setTexture("region3ColorMap", assetManager.loadTexture("")); setTexture("region4ColorMap", assetManager.loadTexture("")); setVector3("region1", new Vector3f(0,0,0)); setVector3("region2", new Vector3f(0,0,0)); setVector3("region3", new Vector3f(0,0,0)); setVector3("region4", new Vector3f(0,0,0)); Settings for steep areas: setTexture("slopeColorMap", assetManager.loadTexture("")); setFloat("slopeTileFactor",1f);
Common/MatDefs/Misc/Particle.j3md
Used with texture masks for particle effects, or for point sprites. The Quadratic value scales the particle for perspective view (). Does support an optional colored glow effect. See also: Hello Effects
Illuminated materials require a light source added to at least one of their parent nodes! (e.g. rootNode.) Illuminated materials are darker on the sides facing away from light sources. They use Phong illumination model (default), or the Ward isotropic gaussian specular shader (WardIso) which looks more like plastic. They do not cast drop shadows unless you use a FilterPostProcessor.
Illuminated Material Definition
Usage
Setter, Parameter, Type
Common/MatDefs/Light/Lighting.j3md
Commonly used Material with Phong illumination. Use this material together with DiffuseMap, SpecularMap, BumpMap (NormalMaps, ParalaxMap) textures. Supports shininess, transparency, and plain material colors (Diffuse, Ambient, Specular colors). See also: Hello Material
Same kind of multi-layered splat texture as Terrain.j3md, but with illumination and shading. Typically used for terrains, but works on any mesh. For every 3 splat textures, you need one alpha map. You can use a total of 11 texture maps in the terrain's splat texture: Note that diffuse and normal maps all count against that. For example, you can use a maximum of 9 diffuse textures, two of which can have normal maps; or, five textures with both diffuse and normal maps.
A color gradient calculated from the model's surface normals. You can use this built-in material to debug the generation of normals in meshes, to preview models that have no material, or as fall-back default material. This built-in material has no parameters.
A NormalMap (alos called BumpMap) describes the fine bumpy details of the Material surface that are not part of the mesh itself. E.g. cracks, pores, creases, notches.
Generate normals for the Mesh (not for the Geometry!)
Specify the Shininess intensity. A float value between 1 (rough surface with blurry shininess) and 128 (very smooth surface with focused shininess)
Specify a Color as Specular value. The ColorRGBA value of the light source, e.g. often RGBA.White.
(Optionally for some Materials) Specify a SpecularMap texture. This grayscale texture outlines in detail where the DiffuseMap texture should be shiny (white) and were not (black), instead of rendering the whole material evenly shiny.
To deactivate shininess
Set the Specular color to ColorRGBA.Black. Do not just set Shininess to 0.
Specify a Color as Glow value. A ColorRGBA value of your choice, e.g. choose a warm or cold color for different effects.
(Optionally for some Materials) Specify a GlowMap texture. This texture outlines in detail where the DiffuseMap texture glows, instead of making the whole material glow everwhere evenly.
Most Material Definitions support an alpha channel for opaqueness and transparency in textures. In an RGBA color, the last float is the alpha channel: 0.0f is transparent and 1.0f is opaque. For example, mat.setColor("Color", new ColorRGBA(1,0,0,0.5f)); is a half-opaque red.
-
-A MotionPath describes the motion of a spatial between waypoints. The path can be linear or rounded. You use MotionPaths to remote-control a spatial, or the camera.
-
-
-
-Tip: If you want to remote-control a whole cutscene with several spatials moving at various times, then we recommened you use MotionPaths together with Cinematics.
-
-
-When shooting a movie scene, the director tells actors where to walk, for example, by drawing a series of small crosses on the floor. Cameramen often mount the camera on rails (so called dolly track) so they can follow along complex scenes more easily.
-
-
-
-In JME3, you use MotionPaths to specify a series of positions for a character or the camera. The MotionPath automatically updates the transformation of the spatial in each frame to make it move from one point to the next.
-
-
-
A way point is one positions on a path.
-
-
A MotionPath contains a list of all way points of one path.
-
-
-
-
-The final shape of the path is computed using a linear interpolation or a spline interpolation on the way points.
-
A MotionPath describes the motion of a spatial between waypoints. The path can be linear or rounded. You use MotionPaths to remote-control a spatial, or the camera.
Tip: If you want to remote-control a whole cutscene with several spatials moving at various times, then we recommened you use MotionPaths together with Cinematics.
When shooting a movie scene, the director tells actors where to walk, for example, by drawing a series of small crosses on the floor. Cameramen often mount the camera on rails (so called dolly track) so they can follow along complex scenes more easily.
In JME3, you use MotionPaths to specify a series of positions for a character or the camera. The MotionPath automatically updates the transformation of the spatial in each frame to make it move from one point to the next.
A way point is one positions on a path.
A MotionPath contains a list of all way points of one path.
The final shape of the path is computed using a linear interpolation or a spline interpolation on the way points.
-
-You can hook interactions into a playing MotionPath. Register a MotionPathListener to the MotionPath to track whether way points have been reached, and then trigger a custom action. The onWayPointReach() method of the interface gives you access to the MotionTrack object control, and an integer value representing the current wayPointIndex.
-
-
-
-In this example, you just print the status at every way point. In a game you could trigger actions here: Transformations, animations, sounds, game actions (attack, open door, etc).
-
-
path.addListener( new MotionPathListener() {
+...
You can configure the path as follows.
MotionPath Method
Usage
path.setCycle(true)
Sets whether the motion along this path should be closed (true) or open-ended (false).
path.addWayPoint(vector)
Adds individual waypoints to this path. The order is relevant.
path.removeWayPoint(vector) removeWayPoint(index)
Removes a way point from this path. You can specify the point that you want to remove as vector or as integer index.
path.setCurveTension(0.83f)
Sets the tension of the curve (Catmull-Rom Spline). A value of 0.0f results in a straight linear line, 1.0 a very round curve.
path.getNbWayPoints()
Returns the number of waypoints in this path.
path.enableDebugShape(assetManager,rootNode)
Shows a line that visualizes the path. Use this during development and for debugging so you see what you are doing.
path.disableDebugShape()
Hides the line that visualizes the path. Use this for the release build.
You can hook interactions into a playing MotionPath. Register a MotionPathListener to the MotionPath to track whether way points have been reached, and then trigger a custom action. The onWayPointReach() method of the interface gives you access to the MotionTrack object control, and an integer value representing the current wayPointIndex.
In this example, you just print the status at every way point. In a game you could trigger actions here: Transformations, animations, sounds, game actions (attack, open door, etc).
path.addListener( new MotionPathListener() {
public void onWayPointReach(MotionTrack control, int wayPointIndex) {
if (path.getNbWayPoints() == wayPointIndex + 1) {
println(control.getSpatial().getName() + " has finished moving. ");
@@ -114,7 +9,5 @@ In this example, you just print the status at every way point. In a game you cou
println(control.getSpatial().getName() + " has reached way point " + wayPointIndex);
}
}
-});
\ No newline at end of file
diff --git a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/mouse_picking.html b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/mouse_picking.html
index 819786851..8bbea0499 100644
--- a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/mouse_picking.html
+++ b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/mouse_picking.html
@@ -1,45 +1,4 @@
-
-
-
-Mouse picking means that the user clicks an object in the scene to select it, or to interact with it otherwise. Games use picking to implement aiming and shooting, casting spells, picking up objects, selecting targets, dragging and moving objects, etc. Mouse picking can be done using fixed crosshairs, or using the mouse pointer.
-
-
-
-
-
-
-
-See Input Handling for details on how to define the necessary input triggers, input mappings, and input listeners.
-
-
-The following pick target input mapping implements an action that determines what a user clicked. It assumes that the mouse pointer is invisible and there are crosshairs painted in the center of the screen. It assumes that the user aims the crosshairs at an object in the scene and clicks. You use Ray Casting to identify the geometry that was picked by the user. Use use this method together with a first-person flyCam.
-
-
-
-
Activate the first-person camera: flyCam.setEnabled(true);
-
-
Keep mouse pointer invisible using inputManager.setCursorVisible(false).
-
-
Map the pick target action to a MouseButtonTrigger.
-
-
Implement the action in the Listener.
-
-
-
-
-The following example rotates Spatials named "Red Box" or "Blue Box" when they are clicked. Modify this code to do whatever your game needs to do with the identified target (shoot it, take it, move it, etc).
-
-
private AnalogListener analogListener = new AnalogListener() {
+
Mouse picking means that the user clicks an object in the scene to select it, or to interact with it otherwise. Games use picking to implement aiming and shooting, casting spells, picking up objects, selecting targets, dragging and moving objects, etc. Mouse picking can be done using fixed crosshairs, or using the mouse pointer.
See Input Handling for details on how to define the necessary input triggers, input mappings, and input listeners.
The following pick target input mapping implements an action that determines what a user clicked. It assumes that the mouse pointer is invisible and there are crosshairs painted in the center of the screen. It assumes that the user aims the crosshairs at an object in the scene and clicks. You use Ray Casting to identify the geometry that was picked by the user. Use use this method together with a first-person flyCam.
Activate the first-person camera: flyCam.setEnabled(true);
Keep mouse pointer invisible using inputManager.setCursorVisible(false).
Map the pick target action to a MouseButtonTrigger.
Implement the action in the Listener.
The following example rotates Spatials named "Red Box" or "Blue Box" when they are clicked. Modify this code to do whatever your game needs to do with the identified target (shoot it, take it, move it, etc).
-
-The default viewPort is as big as the window. If you have several, the must be of different sizes, either overlapping or adjacent to one another. How do you tell jME which of the ViewPorts should appear where on the screen, and how big it should be?
-
-
-
-Imagine the window as a 1.0f x 1.0f rectangle. The default cam's viewPort is set to
-
-
-
cam.setViewPort(0f, 1f, 0f, 1f);
-
-
-
-This setting makes the ViewPort take up the whole rectangle.
-
-
-
-The four values are read in the following order:
-
The default viewPort is as big as the window. If you have several, the must be of different sizes, either overlapping or adjacent to one another. How do you tell jME which of the ViewPorts should appear where on the screen, and how big it should be?
Imagine the window as a 1.0f x 1.0f rectangle. The default cam's viewPort is set to
cam.setViewPort(0f, 1f, 0f, 1f);
This setting makes the ViewPort take up the whole rectangle.
These viewport parameters are, (in this order) the left-right extend, and the bottom-top extend of a views's rectangle on the screen.
0.0 , 1.0 1.0 , 1.0
+-----+-----+
|cam1 |
| |
@@ -62,79 +7,8 @@ These viewport parameters are, (in this order) the left-right extend, and the bo
| | |
| |cam2 |
+-----+-----+
-0.0 , 0.0 1.0 , 0.0
-
-
-Example: Cam2's rectangle is int he bottom right: It extends from mid (x1=0.5f) bottom (y1=0.0f), to right (x2=1.0f) mid (y2=0.5f)
-
-
-
-
If you scale the views in a way so that the aspect ratio of a ViewPort is different than the window's aspect ratio, then the ViewPort appears distorted. In these cases, you must recreate (not clone) the ViewPort's cam object with the right aspect ratio. For example: Camera cam5 = new Camera(100,100);
-
-
-Here is the outline for how you create the three other cams and viewPorts (.) In the code snippet, cam_n stand for cam_2 - cam_4, respectively, same for view_n.
-
-
-
-
Clone the first cam to reuse its settings
-
-
Resize and position the cam's viewPort with setViewPort().
-
-
(Optionally) Move the cameras in the scene and rotate them so they face what you want to see.
-
-
Create a ViewPort for each camera
-
-
Reset the camera's enabled statuses
-
-
Attach the Node to be displayed to this ViewPort.
-The camera doesn't have to look at the rootNode, but that is the most common use case.
-
-
-
-
-
-Here is the abstract code sample for camera n:
-
-
-
Camera cam_n = cam.clone();
+0.0 , 0.0 1.0 , 0.0
Example: Cam2's rectangle is int he bottom right: It extends from mid (x1=0.5f) bottom (y1=0.0f), to right (x2=1.0f) mid (y2=0.5f)
If you scale the views in a way so that the aspect ratio of a ViewPort is different than the window's aspect ratio, then the ViewPort appears distorted. In these cases, you must recreate (not clone) the ViewPort's cam object with the right aspect ratio. For example: Camera cam5 = new Camera(100,100);
Here is the outline for how you create the three other cams and viewPorts (.) In the code snippet, cam_n stand for cam_2 - cam_4, respectively, same for view_n.
Clone the first cam to reuse its settings
Resize and position the cam's viewPort with setViewPort().
(Optionally) Move the cameras in the scene and rotate them so they face what you want to see.
Create a ViewPort for each camera
Reset the camera's enabled statuses
Attach the Node to be displayed to this ViewPort. The camera doesn't have to look at the rootNode, but that is the most common use case.
Here is the abstract code sample for camera n:
Camera cam_n = cam.clone();
cam_n.setViewPort(...); // resize the viewPort
cam_n.setLocation(new Vector3f(...));
cam_n.setRotation(new Quaternion(...));
@@ -142,12 +16,7 @@ cam_n.setRotation(new Quaternion(...));
ViewPort view_n = renderManager.createMainView("View of camera #n", cam_n);
view_n.setClearEnabled(true);
view_n.attachScene(rootNode);
-view_n.setBackgroundColor(ColorRGBA.Black);
-
-
-To visualize what you do, use the following drawing of the viewport positions:
-
-
-You can customize the camera and the viewPort of each view individually. For example, each view can have a different background color:
+viewPort2.attachScene(rootNode);
-More complex games may feature complex mathematical operations or artificially intelligent calculations (such as path finding for several NPCs). If you make many time-intensive calls on the same thread (in the update loop), they will block one another, and thus slow down the game to a degree that makes it unplayable. If your game requires long running tasks, you should run them concurrently on separate threads, which speeds up the application considerably.
-
-
-
-Often multithreading means having separate detached logical loops going on in parallel, which communicate about their state. (For example, one thread for AI, one Sound, one Graphics). However we recommend to use a global update loop for game logic, and do multithreading within that loop when it is appropriate. This approach scales way better to multiple cores and does not break up your code logic.
-
-
-
-Effectively, each for-loop in the main update loop might be a chance for multithreading, if you can break it up into self-contained tasks.
-
-
-The java.util.concurrent package provides a good foundation for multithreading and dividing work into tasks that can be executed concurrently (hence the name). The three basic components are the Executor, Callable Objects (the tasks), and Future Objects. You can , I will give just a short introduction.
-
-
-
-
A Callable is a class with a method call() that gets executed on a thread in the Executor. It represents one task (e.g, path finding).
-
-
The Executor is one central object that manages the threads that are running to execute the Callables. Every time a Callable is added to the Executor, the Executor returns a Future object for it.
-
-
A Future is an object that you use to check the status of an individual Callable's execution. It also gives you the return value in case one is created.
-
-So how do we implement multithreading in jME3?
-
-
-
-Let's take the example of a Control that controls an NPC Spatial. The NPC Control has to compute a lengthy pathfinding operation for each NPC. If we would execute the operations directly in the simpleUpdate() loop, it would block the game each time a NPC wants to move from A to B. Even if we move this behaviour into the update() method of a dedicated NPC Control, we would still get annoying freeze frames, because it still runs on the same update loop thread.
-
-
-
-To avoid slowdown, we decide to keep the pathfinding operations in the NPC Control, but execute it on another thread.
-
-
-You create the executor object in a global AppState (or the initSimpleApp() method), in any case in a high-level place where multiple controls can access it.
-
-
/* This constructor creates a new executor with a core pool size of 4. */
-ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(4);
-
-
-Pool size means the executor will keep four threads alive at any time. Having more threads in the pool means that more tasks can run concurrently. But a bigger pool only results in a speed gain if the PC can handle it! Allocating a pool that is uselessly large just wastes memory, so you need to find a good compromise: About the same to double the size of the number of cores in the computer makes sense.
-
-
-In the NPC Control, we create the individual objects that the thread manipulates. In our example case (the pathfinding control), the task is about locations and path arrays, so we need the following variables:
-
More complex games may feature complex mathematical operations or artificially intelligent calculations (such as path finding for several NPCs). If you make many time-intensive calls on the same thread (in the update loop), they will block one another, and thus slow down the game to a degree that makes it unplayable. If your game requires long running tasks, you should run them concurrently on separate threads, which speeds up the application considerably.
Often multithreading means having separate detached logical loops going on in parallel, which communicate about their state. (For example, one thread for AI, one Sound, one Graphics). However we recommend to use a global update loop for game logic, and do multithreading within that loop when it is appropriate. This approach scales way better to multiple cores and does not break up your code logic.
Effectively, each for-loop in the main update loop might be a chance for multithreading, if you can break it up into self-contained tasks.
The java.util.concurrent package provides a good foundation for multithreading and dividing work into tasks that can be executed concurrently (hence the name). The three basic components are the Executor (supervises threads), Callable Objects (the tasks), and Future Objects (the result). You can , I will give just a short introduction.
A Callable is one of the classes that gets executed on a thread in the Executor. The object represents one of several concurrent tasks (e.g, one NPC's path finding task). Each Callable is started from the updateloop by calling a method named call().
The Executor is one central object that manages all your Callables. Every time you schedule a Callable in the Executor, the Executor returns a Future object for it.
A Future is an object that you use to check the status of an individual Callable task. The Future also gives you the return value in case one is returned.
Let's take the example of a Control that controls an NPC Spatial. The NPC Control has to compute a lengthy pathfinding operation for each NPC. If we would execute the operations directly in the simpleUpdate() loop, it would block the game each time a NPC wants to move from A to B. Even if we move this behaviour into the update() method of a dedicated NPC Control, we would still get annoying freeze frames, because it still runs on the same update loop thread.
To avoid slowdown, we decide to keep the pathfinding operations in the NPC Control, but execute it on another thread.
You create the executor object in a global AppState (or the initSimpleApp() method), in any case in a high-level place where multiple controls can access it.
/* This constructor creates a new executor with a core pool size of 4. */
+ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(4);
Pool size means the executor will keep four threads alive at any time. Having more threads in the pool means that more tasks can run concurrently. But a bigger pool only results in a speed gain if the PC can handle it! Allocating a pool that is uselessly large just wastes memory, so you need to find a good compromise: About the same to double the size of the number of cores in the computer makes sense.
In the NPC Control, we create the individual objects that the thread manipulates. In our example case (the pathfinding control), the task is about locations and path arrays, so we need the following variables:
//The vector to store the desired location in:
Vector3f desiredLocation = new Vector3f();
//The MyWayList object that contains the result waylist:
MyWayList wayList = null;
//The future that is used to check the execution status:
-Future future = null;
-
-
-Here we also created the Future variable to track the state of this task.
-
-
-Next let's look at the update() call of the Control where the time-intensive task starts. In our example, the task is the findWay Callable (which contains the pathfinding process). So instead of spelling out the pathfinding process in the Control's update() loop, we start the process via future = executor.submit(findWay);.
-
-
public void update(float tpf) {
+Future future = null;
Here we also created the Future variable to track the state of this task.
Next let's look at the update() call of the Control where the time-intensive task starts. In our example, the task is the findWay Callable (which contains the pathfinding process). So instead of spelling out the pathfinding process in the Control's update() loop, we start the process via future = executor.submit(findWay);.
public void update(float tpf) {
try{
//If we have no waylist and not started a callable yet, do so!
if(wayList == null && future == null){
@@ -130,48 +33,7 @@ Next let's look at the update() call of the Control where the time-intensiv
if(wayList != null){
//.... Success! Let's process the wayList and move the NPC...
}
-}
-
-
-Note how this logic makes its decision based on the Future object.
-
-
-
-Remember not to mess with the class fields after starting the thread, because they are being accessed and modified on the new thread. In more obvious terms: You cannot change the "desired location" of the NPC while the path finder is calculating a different path. You have to cancel the current Future first.
-
-
-The next code sample shows the Callable that is dedicated to performing the long-running task (here, wayfinding). This is the task that used to block the rest of the application, and is now executed on a thread of its own. You implement the task in the Callable always in an inner method named call().
-
-
-
-The task code in the Callable should be self-contained! It should not write or read any data of objects that are managed by the scene graph or OpenGL thread directly. Even reading locations of Spatials can be problematic! So ideally all data that is needed for the wayfinding process should be available to the new thread when it starts already, possibly in a cloned version so no concurrent access to the data happens.
-
-
-
-In reality, you might need access to the game state. If you must read or write a current state from the scene graph, you must have a clone of the data in your thread. There are only two ways:
-
-
-
-
Use the execution queue application.enqueue() to create a sub-thread that clones the info. Only disadvantage is, it may be slower.
-The example below gets the Vector3f location from the scene object mySpatial using this way.
-
-
Create a separate World class that allows safe access to its data via synchronized methods to access the scene graph. Alternatively it can also internally use application.enqueue().
-The following example gets the object Data data = myWorld.getData(); using this way.
-
-
-
-
-
-These two ways are thread-safe, they don't mess up the game logic, and keep the Callable code readable.
-
-
// A self-contained time-intensive task:
+}
Note how this logic makes its decision based on the Future object.
Remember not to mess with the class fields after starting the thread, because they are being accessed and modified on the new thread. In more obvious terms: You cannot change the "desired location" of the NPC while the path finder is calculating a different path. You have to cancel the current Future first.
The next code sample shows the Callable that is dedicated to performing the long-running task (here, wayfinding). This is the task that used to block the rest of the application, and is now executed on a thread of its own. You implement the task in the Callable always in an inner method named call().
The task code in the Callable should be self-contained! It should not write or read any data of objects that are managed by the scene graph or OpenGL thread directly. Even reading locations of Spatials can be problematic! So ideally all data that is needed for the wayfinding process should be available to the new thread when it starts already, possibly in a cloned version so no concurrent access to the data happens.
In reality, you might need access to the game state. If you must read or write a current state from the scene graph, you must have a clone of the data in your thread. There are only two ways:
Use the execution queue application.enqueue() to create a sub-thread that clones the info. Only disadvantage is, it may be slower. The example below gets the Vector3f location from the scene object mySpatial using this way.
Create a separate World class that allows safe access to its data via synchronized methods to access the scene graph. Alternatively it can also internally use application.enqueue(). The following example gets the object Data data = myWorld.getData(); using this way.
These two ways are thread-safe, they don't mess up the game logic, and keep the Callable code readable.
// A self-contained time-intensive task:
private Callable<MyWayList> findWay = new Callable<MyWayList>(){
public MyWayList call() throws Exception {
diff --git a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/networking.html b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/networking.html
index cae36cdb6..e71691c27 100644
--- a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/networking.html
+++ b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/networking.html
@@ -1,106 +1,38 @@
-
-
-
-This document introduces you to the SpiderMonkey networking API. A multi-player game is made up of clients and a server.
-
-
-
One central server (a headless SimpleApplication) coordinates the game in the background.
-
-
Each player runs a game client (a standard SimpleApplications) and connects to the central server.
-
-
-
-
-
-Each Client informs the Server about its player's moves and actions. The Server centrally collects the game state and broadcasts the state info back to all connected clients. This way all clients share the same game world and can display it to their players from their perspective.
-
-
-The SpiderMonkey API is a set of interfaces and helper classes in the 'com.jme3.network' package. For most users, this package and the 'message' package is all they need to worry about. (The 'base' and 'kernel' packages only come into play when implementing custom network transports or alternate client/server protocols, which is now possible).
-
-
-
-The SpiderMonkey API assists you in creating a Server, Clients, and Messages. Once a Server instance is created and started, the Server accepts remote connections from Clients, and you can send and receive Messages. Client objects represent the client-side of the client-server connection. Within the Server, these Client objects are referred to as HostedConnections. HostedConnections can hold application-defined client-specific session attributes that the server-side listeners and services can use to track player information, etc.
-
-
-
-
-
Seen from the Client
Seen from the Server
-
-
-
com.jme3.network.Client
==
com.jme3.network.HostedConnection
-
-
-
-
-
-You can register several types of listeners to be notified of changes.
-
-
-
MessageListeners on both the Client and the Server are notified when new messages arrive. You can use MessageListeners to be notified about only specific types of messages.
-
-
ClientStateListeners inform the Client of changes in its connection state, e.g. when the client gets kicked from the server.
-
-
ConnectionListeners inform the Server about HostedConnection arrivals and removals, e.g. if a client joins or quits.
-
-A com.jme3.network.Server is a headless com.jme3.app.SimpleApplication. Headless means that the update loop runs, but the application does not open a window and does not listen to direct user input.
+
This document introduces you to the SpiderMonkey networking API. You use this API when you develop games where several players compete with one another in real time. A multi-player game is made up of several clients connecting to a server:
The central server (one headless SimpleApplication) coordinates the game in the background.
Each player runs a game client (a standard SimpleApplications) and connects to the central server.
Each Client keeps the the Server informed about its player's moves and actions. The Server centrally maintains the game state and broadcasts the state info back to all connected clients. This network synchronization allows all clients share the same game world. Each client then displays the game state to one player from this player's perspective.
The SpiderMonkey API is a set of interfaces and helper classes in the 'com.jme3.network' package. For most users, this package and the 'message' package is all they need to worry about. (The 'base' and 'kernel' packages only come into play when implementing custom network transports or alternate client/server protocols, which is now possible).
The SpiderMonkey API assists you in creating a Server, Clients, and Messages. Once a Server instance is created and started, the Server accepts remote connections from Clients, and you can send and receive Messages. Client objects represent the client-side of the client-server connection. Within the Server, these Client objects are referred to as HostedConnections. HostedConnections can hold application-defined client-specific session attributes that the server-side listeners and services can use to track player information, etc.
Seen from the Client
Seen from the Server
com.jme3.network.Client
==
com.jme3.network.HostedConnection
You can register several types of listeners to be notified of changes.
MessageListeners on both the Client and the Server are notified when new messages arrive. You can use MessageListeners to be notified about only specific types of messages.
ClientStateListeners inform the Client of changes in its connection state, e.g. when the client gets kicked from the server.
ConnectionListeners inform the Server about HostedConnection arrivals and removals, e.g. if a client joins or quits.
The game server is a "headless" com.jme3.app.SimpleApplication:
public class MyGameServer extends SimpleApplication {
+ public static void main(String[] args) {
+ ServerMain app = new ServerMain();
+ app.start(JmeContext.Type.Headless); // headless type for servers!
+ }
+}
A Headless SimpleApplication executes the simpleInitApp() method and runs the update loop normally. But the application does not open a window, and it does not listen to user input. This is the typical behavior for a server application.
Create a com.jme3.network.Server in the simpleInitApp() method and specify a communication port, for example 6143.
public void simpleInitApp() {
+ ...
+ Server myServer = Network.createServer(6143);
+ myServer.start();
+ ...
+ }
When you run this app on a host, the server is ready to accept clients. Let's create a client next.
A game client is a standard com.jme3.app.SimpleApplication.
public class MyGameClient extends SimpleApplication {
+ public static void main(String[] args) {
+ ClientMain app = new ClientMain();
+ app.start(JmeContext.Type.Display); // standard display type
+ }
+}
A standard SimpleApplication in Display mode executes the simpleInitApp() method, runs the update loop, opens a window for the rendered video output, and listens to user input. This is the typical behavior for a client application.
+
-
ServerMain app = new ServerMain();
-app.start(JmeContext.Type.Headless);
-Create a Server in the simpleInitApp() method and specify a communication port, for example 6143.
-
-
Server myServer = Network.createServer(6143);
-myServer.start();
-
-The server is ready to accept clients. Let's create one.
+Create a com.jme3.network.Client in the simpleInitApp() method and specify the servers IP address, and the same communication port as for the server, here 6143.
-
-A com.jme3.network.Client is a standard com.jme3.app.SimpleApplication.
+The server address can be in the format "localhost" or "127.0.0.1" (for local testing), or an IP address of a remote host in the format “123.456.78.9”. In this example, we assume the server is running on the localhost.
-
ClientMain app = new ClientMain();
-app.start(JmeContext.Type.Display); // standard type
-Create a Client in the simpleInitApp() method and specify the servers IP address, and the same communication port as for the server, here 6143.
-
-The server address can be in the format "localhost", "127.0.0.1" (for local testing) or “123.456.78.9” (the IP address of a real server).
+When you run this client, it connects to the server.
@@ -110,7 +42,7 @@ The server address can be in the format "localhost", "127.0.0.1&q
-The server refers to a connected client as com.jme3.network.HostedConnection. The server can get info about clients as follows:
+The server refers to a connected client as com.jme3.network.HostedConnection objects. The server can get info about clients as follows:
@@ -118,19 +50,19 @@ The server refers to a connected client as com.jme3.network.HostedConnection. Th
Accessor
Purpose
-
myServer.getConnection(0)
Server gets the first etc connected HostedConnection object.
+
myServer.getConnections()
Server gets a collection of all connected HostedConnection objects (all connected clients).
-
myServer.getConnections()
Server gets a collection of all connected HostedConnection objects.
+
myServer.getConnections().size()
Server gets the number of all connected HostedConnection objects (number of clients).
-
myServer.getConnections().size()
Server gets the number of all connected HostedConnection objects.
+
myServer.getConnection(0)
Server gets the first (0), second (1), etc, connected HostedConnection object (one client).
-
+
-Your game can define its own player ID based on whatever user criteria you want. If the server needs to look up player/client-specific information, it can store this information directly on the HostedConnection object:
+Your game can define its own game data based on whatever criteria you want, typically these include player ID and state. If the server needs to look up player/client-specific information, you can store this information directly on the HostedConnection object. The following examples read and write a custom Java object MyState in the HostedConnection object conn:
@@ -144,7 +76,7 @@ Your game can define its own player ID based on whatever user criteria you want.
MyState state = conn.getAttribute("MyState")
Server can read an attribute of the HostedConnection.
@@ -157,28 +89,28 @@ Your game can define its own player ID based on whatever user criteria you want.
-Each message represents data you want to transmit, for instance transformation updates or game actions. For each message type, create a message class that extends com.jme3.network.AbstractMessage. Use the @Serializable annotation from com.jme3.network.serializing.Serializable and create an empty default constructor. Custom constructors, fields, and methods are up to you and depend on the message data that you want to transmit.
+Each message represents data that you want to transmit between client and server. Common message examples include transformation updates or game actions. For each message type, create a message class that extends com.jme3.network.AbstractMessage. Use the @Serializable annotation from com.jme3.network.serializing.Serializable and create an empty default constructor. Custom constructors, fields, and methods are up to you and depend on the message data that you want to transmit.
@Serializable
public class HelloMessage extends AbstractMessage {
- private String hello; // message data
+ private String hello; // custom message data
public HelloMessage() {} // empty constructor
public HelloMessage(String s) { hello = s; } // custom constructor
}
-Register each message type to the com.jme3.network.serializing.Serializer, in both server and client.
+You must register each message type to the com.jme3.network.serializing.Serializer, in both server and client!
-After a message was received, a listener responds to it. The listener can access fields of the message, and send messages back. Implement responses in the two Listeners’ messageReceived() methods for each message type.
+After a Message was received, a Listener responds to it. The listener can access fields of the message, and send messages back, start new threads, etc. There are two listeners, one on the server, one on the client. For each message type, you implement the responses in either Listeners’ messageReceived() method.
@@ -235,22 +167,35 @@ For each message type, register a server listener to the server:
-A client can send a message to the server:
+Let's create a new message of type HelloMessage:
+
+
Message message = new HelloMessage("Hello World!");
+
+
+Now the client can send this message to the server:
-
Message message = new HelloMessage("Hello World!");
-myClient.send(message);
+
myClient.send(message);
-The server can broadcast a message to all HostedConnection (clients):
+Or the server can broadcast this message to all HostedConnection (clients):
Message message = new HelloMessage("Welcome!");
myServer.broadcast(message);
-Using com.jme3.network.Filters, the server can send a message to specific HostedConnection (conn1, conn2, conn3), or to all but a few HostedConnections (not to conn4).
+Or the server can send the message to a specific subset of clients (e.g. to HostedConnection conn1, conn2, and conn3):
+
+The last two broadcasting methods use com.jme3.network.Filters to select a subset of recipients. If you know the exact list of recipients, always send the messages directly to them using the Filters; avoid floodig the network with unnessary broadcasts to all.
@@ -264,7 +209,7 @@ The ID of the Client and HostedConnection are the same at both ends of a connect
... myClient.getId() ...
-A server has a game version and game name. Each client expects to communicate with a server with a certain game name and version. Test first whether the game name matches, and then whether game version matches, before sending any messages! If they do not match, you should refuse to connect, because the client and server will not be able to communicate.
+A server has a game version and game name property. Each client expects to communicate with a server with a certain game name and version. Test first whether the game name matches, and then whether game version matches, before sending any messages! If they do not match, you should refuse to connect, because unmatched clients and servers will likely miscommunicate.
@@ -272,22 +217,23 @@ A server has a game version and game name. Each client expects to communicate wi
Accessor
Purpose
-
myServer.setName()
Specify the game name (free-form String)
+
myServer.setName()
Specify the game name of the Server (a free-form String)
-
myServer.setVersion()
Specify the game version (int)
+
myServer.setVersion()
Specify the game version of the Server (an integer number)
-
myClient.getGameName()
Client gets the name of the server it is connected to.
+
myClient.getGameName()
Client queries the name of the server it is connected to.
-
myClient.getVersion()
Client gets the version of the server it is connected to.
+
myClient.getVersion()
Client queries the version of the server it is connected to.
-
+
-Tip: Your game defines its own attributs, such as player ID, based on whatever criteria you want. If you want to look up player/client-specific information, you can set this information directly on the Client/HostedConnection (see Getting Info About a Client).
+
Typically, your networked game defines its own attributes (such as player ID) based on whatever criteria you want. If you want to look up player/client-specific information beyond the game version, you can set this information directly on the Client/HostedConnection object (see Getting Info About a Client).
+
@@ -306,6 +252,7 @@ You must override the client's destroy() method to close the connection cle
@@ -332,7 +280,7 @@ You must override the server's destroy() method to close the connection whe
-The server can kick a HostedConnection to make it disconnect. You should provide a String with further info (an explanation to the user what happened) for the server to send along. This info message can be used (displayed to the user) by a ClientStateListener. (See below)
+The server can kick a HostedConnection to make it disconnect. You should provide a String with further info (an explanation to the user what happened, e.g. "Shutting down for maintenance") for the server to send along. This info message can be used (displayed to the user) by a ClientStateListener. (See below)
conn.close("We kick cheaters.");
@@ -352,24 +300,25 @@ The server and clients are notified about connection changes.
+
The com.jme3.network.ClientStateListener notifies the Client when the Client has fully connected to the server (including any internal handshaking), and when the Client is kicked (disconnected) from the server.
-
ClientStateListener interface
Purpose
+
ClientStateListener interface method
Purpose
-
clientConnected(Client c)
Implement here what happens as soon as this clients has fully connected to the server.
+
public void clientConnected(Client c){}
Implement here what happens as soon as this clients has fully connected to the server.
-
clientDisconnected(Client c, DisconnectInfo info)
Implement here what happens after the server kicks this client. For example, display the DisconnectInfo to the user.
+
public void clientDisconnected(Client c, DisconnectInfo info){}
Implement here what happens after the server kicks this client. For example, display the DisconnectInfo to the user.
-
+
-Implement the ClientStateListener interface in the Client, and then register it:
+First implement the ClientStateListener interface in the Client class. Then register it to myClient in MyGameClient's simeplInitApp() method:
myClient.addClientStateListener(this);
@@ -385,19 +334,20 @@ The com.jme3.network.ConnectionListener notifies the Server whenever new HostedC
-
ConnectionListener interface
Purpose
+
ConnectionListener interface method
Purpose
-
connectionAdded(Server s, HostedConnection c)
Implemenent here what happens after a new HostedConnection has joined the Server.
+
public void connectionAdded(Server s, HostedConnection c){}
Implemenent here what happens after a new HostedConnection has joined the Server.
-
connectionRemoved(Server s, HostedConnection c)
Implement here what happens after a HostedConnection has left. E.g. a player has quit the game and the server removes his character.
+
public void connectionRemoved(Server s, HostedConnection c){}
Implement here what happens after a HostedConnection has left. E.g. a player has quit the game and the server removes his character.
-
+
-Implement the ConnectionListener in the Server, and register it.
+First implement the ConnectionListener interface in the Server class. Then register it to myServer in MyGameServer's simpleInitApp() method.
+
-You cannot modify the scenegraph in the NetworkThread. You have to create a Callable, enqueue the Callable in the OpenGLThread, and the callable makes the modification in the correct moment. A Callable is a Java class representing a (possibly time-intensive), self-contained task.
+
You cannot modify the scenegraph directly from the network thread. A common example for such a modification is when you synchronize the player's position in the scene. You have to use Java Multithreading.
+
+
+
+
+Multithreading means that you create a Callable. A Callable is a Java class representing any (possibly time-intensive) self-contained task that has an impact on the scene graph (such as positioning the player). You enqueue the Callable in the Executor of the client's OpenGL thread. The Callable ensures to executes the modification in sync with the update loop.
-You may want your players to press a button to save a game, you want a scrolling text field for highscores, a text label to display the score, drop-downs to select keymap preferences, or checkboxes to specify multi-media options. Usually you solve these tasks by using Swing controls. Although it is possible to embed a jME3 canvas in a Swing GUI, a 3D game typically runs full-screen, or in a window of its own.
-
-
-
-This document introduces you to , a Java library for building interactive graphical user interfaces (GUIs) for games or similar applications. Nifty GUI (the de.lessvoid.nifty package) is well integrated with jME3 through the com.jme3.niftygui package. You define the base GUI layout in XML, and control it dynamically from your Java code. The necessary JAR libraries are included in your jME3 download, you do not need to install anything extra. (Just make sure they are on the classpath.)
-
-
You may want your players to press a button to save a game, you want a scrolling text field for highscores, a text label to display the score, drop-downs to select keymap preferences, or checkboxes to specify multi-media options. Usually you solve these tasks by using Swing controls. Although it is possible to embed a jME3 canvas in a Swing GUI, a 3D game typically runs full-screen, or in a window of its own.
This document introduces you to , a Java library for building interactive graphical user interfaces (GUIs) for games or similar applications. Nifty GUI (the de.lessvoid.nifty package) is well integrated with jME3 through the com.jme3.niftygui package. You define the base GUI layout in XML, and control it dynamically from your Java code. The necessary JAR libraries are included in your jME3 download, you do not need to install anything extra. (Just make sure they are on the classpath.)
-
-In the previous parts of the tutorial, you created a two-screen user interface. But it is still static, and when you click the buttons, nothing happens yet. The purpose of the GUI is to communicate with your Java classes: Your game needs to know what the users clicked, which settings they chose, which values they entered into a field, etc. Similarly, the user needs to know what the currently game state is (score, health, etc).
-
-
-To let a Nifty screen communicate with the Java application, you register a ScreenController to every NiftyGUI screen. You create a ScreenController by creating a Java class that implements the de.lessvoid.nifty.screen.ScreenController interface and its abtract methods.
-
-
-
-Pro Tip: Since you are writing a jME3 application, you can additionally make the ScreenController class extend the AbstractAppState class! This gives the ScreenController access to the application object and to the update loop!
-
In the previous parts of the tutorial, you created a two-screen user interface. But it is still static, and when you click the buttons, nothing happens yet. The purpose of the GUI is to communicate with your Java classes: Your game needs to know what the users clicked, which settings they chose, which values they entered into a field, etc. Similarly, the user needs to know what the currently game state is (score, health, etc).
To let a Nifty screen communicate with the Java application, you register a ScreenController to every NiftyGUI screen. You create a ScreenController by creating a Java class that implements the de.lessvoid.nifty.screen.ScreenController interface and its abtract methods.
Pro Tip: Since you are writing a jME3 application, you can additionally make the ScreenController class extend the AbstractAppState class! This gives the ScreenController access to the application object and to the update loop!
-The name and package of your custom ScreenController class (here tutorial.MyStartScreen) goes into the controller parameter of the respective XML screen it belongs to. For example:
-
-
<nifty>
+}
The name and package of your custom ScreenController class (here tutorial.MyStartScreen) goes into the controller parameter of the respective XML screen it belongs to. For example:
-
-In most cases, you will want to pass game data in and out of the ScreenController. Note that you can pass any custom arguments from your Java class into your ScreenController constructor (public MyStartScreen(GameData data) {}).
-
-
-
-Use any combination of the three following approaches to make Java classes interact with the GUI.
-
In most cases, you will want to pass game data in and out of the ScreenController. Note that you can pass any custom arguments from your Java class into your ScreenController constructor (public MyStartScreen(GameData data) {}).
Use any combination of the three following approaches to make Java classes interact with the GUI.
-Typically, you define a key (for example escape) that switches the GUI on and off. The GUI can be a StartScreen, OptionsScreen, CharacterCreationScreen, etc. While the GUI is up, you pause the running game, and then overlay the GUI. You also must switch to a different set of user inputs while the game is paused, so the player can use the mouse pointer and keyboard to interact with the GUI.
-
-
-
-You can also project the GUI as a texture onto a mesh texture (but then you cannot click to select).
-On this page, we look at the overlay variant, which is more commonly used in games.
-
Typically, you define a key (for example escape) that switches the GUI on and off. The GUI can be a StartScreen, OptionsScreen, CharacterCreationScreen, etc. While the GUI is up, you pause the running game, and then overlay the GUI. You also must switch to a different set of user inputs while the game is paused, so the player can use the mouse pointer and keyboard to interact with the GUI.
You can also project the GUI as a texture onto a mesh texture (but then you cannot click to select). On this page, we look at the overlay variant, which is more commonly used in games.
-Typically you define a key (for example escape) to switch the GUI on and off. Then you overlay the running game with the GUI (you will most likely pause the game then).
-
-
-
-Alternatively, you can also project the GUI as a texture onto a mesh textures inside the game. Allthough this looks cool and "immersive", this approach is rarely used since it is difficult to record clicks this way. You can only interact with this projected GUI by keyboard, or programmatically. You can select input fields using the arrow keys, and trigger actions using the return key.
-
-
-
-This GUI projection variant is less commonly used than the GUI overlay variant. Usecases for GUI projection are, for example, a player avatar using an in-game computer screen.
-
Typically you define a key (for example escape) to switch the GUI on and off. Then you overlay the running game with the GUI (you will most likely pause the game then).
Alternatively, you can also project the GUI as a texture onto a mesh textures inside the game. Allthough this looks cool and "immersive", this approach is rarely used since it is difficult to record clicks this way. You can only interact with this projected GUI by keyboard, or programmatically. You can select input fields using the arrow keys, and trigger actions using the return key.
This GUI projection variant is less commonly used than the GUI overlay variant. Usecases for GUI projection are, for example, a player avatar using an in-game computer screen.
You can project the Nifty GUI onto a texture, load the texture into a material, and assign it to a Geometry (Quads or Boxes are best).
/** Create a special viewport for the Nifty GUI */
ViewPort niftyView = renderManager.createPreView("NiftyView", new Camera(1024, 768));
niftyView.setClearEnabled(true);
/** Create a new NiftyJmeDisplay for the integration */
@@ -73,36 +24,5 @@ Geometry geom = new Geometry("Box", b);
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat.setTexture("m_ColorMap", niftytex); /** Here comes the texture! */
geom.setMaterial(mat);
-rootNode.attachChild(geom);
-
-
-The MySettingsScreen class is a custom de.lessvoid.nifty.screen.ScreenController in which you implement your GUI behaviour. The variable data contains an object that you use to exchange state info with the game. See Nifty GUI Java Interaction for details on how to create this class.
-
-
-
-Run the code sample. You select buttons on this GUI with the arrow keys and then press return. Note that clicking on the texture will not work!
-
The MySettingsScreen class is a custom de.lessvoid.nifty.screen.ScreenController in which you implement your GUI behaviour. The variable data contains an object that you use to exchange state info with the game. See Nifty GUI Java Interaction for details on how to create this class.
Run the code sample. You select buttons on this GUI with the arrow keys and then press return. Note that clicking on the texture will not work!
\ No newline at end of file
diff --git a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_xml_layout.html b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_xml_layout.html
index 43a5c5780..7d180fc91 100644
--- a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_xml_layout.html
+++ b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_xml_layout.html
@@ -1,101 +1,4 @@
-
-
-In this tutorial, you want to create two game screens: An out-of-game StartScreen that the players see before the game starts; and an in-game that displays info during the game. Before writing code, you plan the GUI layout, either on paper or in a graphic application.
-
-
-
-The StartScreen contains:
-
-
-
The background layer has a centered layout and contains an image.
-
-
The top layer has a vertical layout, containing 3 panels:
-
-
The top panel contains a label with the game title,
-
-
The middle panel contains a text field with the game description.
-
-
The bottom panel has a horizontal layout and contains two more panels:
-
-
The left panel contains a Start button.
-
-
The right panel contains a Quit button.
-
-
-
-
-
-
-
-
-
-The HUD contains:
-
-
-
The background layer has a centered layout, and contains a the partially transparent HUD image.
-
-
The top layer has a horizontal layout, containing 2 panels:
-
-
The left panel as transparent spacer.
-
-
The right panel has a vertical layout containing 2 panels, a label and an image.
-Create an empty screen.xml file in the assets/Interfaces/ directory of your project. One XML file can contain several, or even all screens. As a reminder: Nifty displays one screen at a time; a screen contains several layers on top of one another; each layer contains panels that are embedded into another; the panels contain the actual content (text, images, or controls).
-
In this tutorial, you want to create two game screens: An out-of-game StartScreen that the players see before the game starts; and an in-game that displays info during the game. Before writing code, you plan the GUI layout, either on paper or in a graphic application.
The StartScreen contains:
The background layer has a centered layout and contains an image.
The top layer has a vertical layout, containing 3 panels:
The top panel contains a label with the game title,
The middle panel contains a text field with the game description.
The bottom panel has a horizontal layout and contains two more panels:
The left panel contains a Start button.
The right panel contains a Quit button.
The HUD contains:
The background layer has a centered layout, and contains a the partially transparent HUD image.
The top layer has a horizontal layout, containing 2 panels:
The left panel as transparent spacer.
The right panel has a vertical layout containing 2 panels, a label and an image.
Create an empty screen.xml file in the assets/Interfaces/ directory of your project. One XML file can contain several, or even all screens. As a reminder: Nifty displays one screen at a time; a screen contains several layers on top of one another; each layer contains panels that are embedded into another; the panels contain the actual content (text, images, or controls).
The following minimal XML file shows how we added layers to the start screen and HUD screen:
<nifty><screen id="start"><layer id="background" backgroundColor="#000f">
<!-- ... -->
@@ -140,22 +24,7 @@ The following minimal XML
<!-- ... -->
</layer></screen>
-</nifty>
-
-
-In a layer, you can now add panels and arrange them. Panels are containers that mark the areas where you want to display text, images, or controls (buttons etc) later.
-
-
-A panel is the inner-most container (that will contain the actual content: text, images, or controls). You place panels inside layers. The following panels go into in the start screen's foreground layer:
-
In a layer, you can now add panels and arrange them. Panels are containers that mark the areas where you want to display text, images, or controls (buttons etc) later.
A panel is the inner-most container (that will contain the actual content: text, images, or controls). You place panels inside layers. The following panels go into in the start screen's foreground layer:
<panel id="panel_top" height="25%" width="75%" align="center" childLayout="center" backgroundColor="#f008"></panel><panel id="panel_mid" height="50%" width="75%" align="center" childLayout="center"
@@ -169,12 +38,7 @@ A panel is the inner-most container (that will contain the actual content: text,
<panel id="panel_bottom_right" height="50%" width="50%" valign="center" childLayout="center" backgroundColor="#88f8"></panel>
- </panel>
-
-
-The following panels go into in the hud screen's foreground layer:
-
For longer pieces of static text, such as an introduction, you can use wrap="true". Add the following text element to the Start screen:
<panel id="panel_mid" height="50%" width="75%" align="center" childLayout="center"><text text="Here goes some text describing the game and the rules and stuff. Incidentally,
the text is quite long and needs to wrap at the end of lines. ..." font="Interface/Fonts/Default.fnt" width="100%" height="100%" wrap="true" />
- </panel>
-
-
-The font used is jME3's default font "Interface/Fonts/Default.fnt" which is included in the jMonkeyEngine.JAR. You can add your own fonts to your own assets/Interface directory.
-
-
-Use label controls for text that you want to edit dynamically from Java. One example for this is the score display.
-In the hud screen's foreground layer, add the following text element:
-
The font used is jME3's default font "Interface/Fonts/Default.fnt" which is included in the jMonkeyEngine.JAR. You can add your own fonts to your own assets/Interface directory.
Use label controls for text that you want to edit dynamically from Java. One example for this is the score display. In the hud screen's foreground layer, add the following text element:
-Note that the width and height do not scale the bitmap font, but the make indirectly certain it is centered. If you want a different size for the font, you need to provide an extra bitmap font (they come with fixes sizes and don't scale well).
-
-
-Our GUI plan asks for two buttons on the start screen. You add the Start and Quit buttons to the bottom panel of the start screen using the <control> element:
-
Note that the width and height do not scale the bitmap font, but the make indirectly certain it is centered. If you want a different size for the font, you need to provide an extra bitmap font (they come with fixes sizes and don't scale well).
Our GUI plan asks for two buttons on the start screen. You add the Start and Quit buttons to the bottom panel of the start screen using the <control> element:
-The Open Game Finder (OGF) by Mark Schrijver can be plugged into any Java game. OGF enables you to find other people playing the same multiplayer game, and join them.
-
-
-
Homepage:
-
-
Documentation:
-
-
-
-
-Both on the client and the server side of OGF is written purely in Java. OGF has a pluggable architecture and comes with a full set of plugins to get the job done. You can add your own plugins, or replace existing plugins to make them more in line with your game. OGF uses NiftyGUI as the main GUI plugin.
-
-
-The OGF server uses an embedded Apache Derby database. You have to install the database, this means creating the data files and adding the tables. You can do this straight from the command line by running a script file.
-
-
-
On Windows, use installServer.bat to create a new database from scratch. On Mac OS or Linux, run java -jar lib/Server-0.1.jar install in the Terminal.
-
-
On Windows, use updateServer.bat to update the difference between the current state of the database and the way it should be. On Mac OS and Linux, run java -jar lib/Server-0.1.jar update in the Terminal.
-This new feature is currently untested.
-Change into the OGF-Server directory and run the server:
-
-
-
On Windows: Run startServer.bat
-
-
On Linux and MacOS X: Run java -jar lib/Server-1.0.jar in the Terminal.
-
-
-
-
-The server is now running and ready to accept connections.
-
-Note: In the alpha release, the server runs on localhost. In the final release, you will be able to configure the host!
-
-
Change into the OGF-Client directory and run the client:
-
-
On Windows: Run startClient.bat
-
-
On Linux and MacOS X: Run java -jar lib/Client-1.0.jar in the Terminal.
-
-
-
-
If a Display Settings window appears, you can keep the defaults and click OK.
-
-
-
-
-A client is now running, connects to the server, and displays a registration/login window.
-
-Note: You can run several clients on localhost for testing.
-
-
-The chat window shows a list of all users logged in to the server. Logged-in users can send public messages, and can receive public messages from others.
-
-
-Q: I want to gather players using the OGF client to connect to the game server. How do I start my multiplayer game?
-
-A: The following sample code demos the typical use case:
-
-
-In a JME3 Application's init method:
-
-
-
Create a com.ractoc.opengamefinder.client.GUIContainer object.
-
-
Create a game instance using the GUIContainer (via a ClientFactory).
-
-
Check the com.ractoc.pffj.api.BasePluginMessageResult for success or failure.
-
-
-
-
-After this, continue writing your JME3 init method.
-
-
The Open Game Finder (OGF) by Mark Schrijver can be plugged into any Java game. OGF enables you to find other people playing the same multiplayer game, and join them.
Homepage:
Documentation:
Both on the client and the server side of OGF is written purely in Java. OGF has a pluggable architecture and comes with a full set of plugins to get the job done. You can add your own plugins, or replace existing plugins to make them more in line with your game. OGF uses NiftyGUI as the main GUI plugin.
The OGF server uses an embedded Apache Derby database. You have to install the database, this means creating the data files and adding the tables. You can do this straight from the command line by running a script file.
On Windows, use installServer.bat to create a new database from scratch. On Mac OS or Linux, run java -jar lib/Server-0.1.jar install in the Terminal.
On Windows, use updateServer.bat to update the difference between the current state of the database and the way it should be. On Mac OS and Linux, run java -jar lib/Server-0.1.jar update in the Terminal. This new feature is currently untested.
Change into the OGF-Server directory and run the server:
On Windows: Run startServer.bat
On Linux and MacOS X: Run java -jar lib/Server-1.0.jar in the Terminal.
The server is now running and ready to accept connections. Note: In the alpha release, the server runs on localhost. In the final release, you will be able to configure the host!
The chat window shows a list of all users logged in to the server. Logged-in users can send public messages, and can receive public messages from others.
Q: I want to gather players using the OGF client to connect to the game server. How do I start my multiplayer game? A: The following sample code demos the typical use case: In a JME3 Application's init method:
Create a com.ractoc.opengamefinder.client.GUIContainer object.
Create a game instance using the GUIContainer (via a ClientFactory).
Check the com.ractoc.pffj.api.BasePluginMessageResult for success or failure.
After this, continue writing your JME3 init method.
\ No newline at end of file
diff --git a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/particle_emitters.html b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/particle_emitters.html
index 6d57fab56..dce934499 100644
--- a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/particle_emitters.html
+++ b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/particle_emitters.html
@@ -1,82 +1,6 @@
-
-
-
-You cannot create a 3D model for delicate things like fire, smoke, or explosions. Particle Emitters are quite an efficient solution to create these kinds of effects: The emitter renders a series of flat orthogonal images and manipulates them in a way that creates the illusion of a anything from a delicate smoke cloud to individual flames, etc.
-Creating an effect involves some trial and error to get the settings just right, and it's worth exploring the expressiveness of the options described below.
-
-Not all of these parameters are required for all kinds of effects. If you don't specify one of them, a default value will be used.
-
-
-
-
Parameter
Method
Default
Description
-
-
-
number
setNumParticles()
The maximum number of particles visible at the same time. Specified by user in constructor.
-
-
-
emission rate
setParticlesPerSec()
20
Density of the effect, how many new particles are emitted per second.
-Set to zero to control the start/end of the effect.
-Set to a number for a constantly running effect.
-
-
-
size
setStartSize(), setEndSize()
0.2f, 2f
The radius of the scaled sprite image. Set both to same value for constant size effect.
-Set to different values for shrink/grow effect.
-
-
-
color
setStartColor(), setEndColor()
gray
Controls how the opaque (non-black) parts of the texture are colorized.
-Set both to the same color for single-colored effects (e.g. fog, debris).
-Set both to different colors for a gradient effect (e.g. fire).
You cannot create a 3D model for delicate things like fire, smoke, or explosions. Particle Emitters are quite an efficient solution to create these kinds of effects: The emitter renders a series of flat orthogonal images and manipulates them in a way that creates the illusion of a anything from a delicate smoke cloud to individual flames, etc. Creating an effect involves some trial and error to get the settings just right, and it's worth exploring the expressiveness of the options described below.
Not all of these parameters are required for all kinds of effects. If you don't specify one of them, a default value will be used.
Parameter
Method
Default
Description
number
setNumParticles()
The maximum number of particles visible at the same time. Specified by user in constructor.
emission rate
setParticlesPerSec()
20
Density of the effect, how many new particles are emitted per second. Set to zero to control the start/end of the effect. Set to a number for a constantly running effect.
size
setStartSize(), setEndSize()
0.2f, 2f
The radius of the scaled sprite image. Set both to same value for constant size effect. Set to different values for shrink/grow effect.
color
setStartColor(), setEndColor()
gray
Controls how the opaque (non-black) parts of the texture are colorized. Set both to the same color for single-colored effects (e.g. fog, debris). Set both to different colors for a gradient effect (e.g. fire).
A vector specifying the initial direction and speed of particles. The longer the vector, the faster.
@@ -195,7 +119,7 @@ The following effect textures are available by default from test-data.jar<
Effects/Smoke/Smoke.png
1*15
-
+
Tip: Use the setStartColor()/setEndColor() settings described above to colorize the white and gray parts of textures.
diff --git a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/physics.html b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/physics.html
index bf25ee040..9753eaf51 100644
--- a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/physics.html
+++ b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/physics.html
@@ -1,166 +1,7 @@
-
-
-
-Bullet physics runs internally at 60fps by default. This rate is not dependent on the actual framerate and it does not lock the framerate at 60fps. Instead, when the actual fps is higher than the physics framerate the system will display interpolated positions for the physics entities. When the framerate is lower than the physics framerate the physics space will be stepped multiple times per frame to make up for the missing calculations.
-
-
-
-A bullet physics space can be created with a BulletAppState. The updating and syncing of the actual physics entities happens in the following way:
-
-
-
-A "normal" update loop with physics looks like this:
-
-
-
collision callbacks (BulletAppState.update())
-
-
user update (simpleUpdate / update)
-
-
physics to scenegraph syncing/applying (updateLogicalState())
-
-
stepping physics (before / in parallel to Application.render())
-
-
-
-
-When you use physics, 1 unit (1.0f) equals 1 meter, weight is expressed in kilograms, most torque and rotation values are expressed in radians.
-
Bullet physics runs internally at 60fps by default. This rate is not dependent on the actual framerate and it does not lock the framerate at 60fps. Instead, when the actual fps is higher than the physics framerate the system will display interpolated positions for the physics entities. When the framerate is lower than the physics framerate the physics space will be stepped multiple times per frame to make up for the missing calculations.
A bullet physics space can be created with a BulletAppState. The updating and syncing of the actual physics entities happens in the following way:
A "normal" update loop with physics looks like this:
collision callbacks (BulletAppState.update())
user update (simpleUpdate / update)
physics to scenegraph syncing/applying (updateLogicalState())
stepping physics (before / in parallel to Application.render())
When you use physics, 1 unit (1.0f) equals 1 meter, weight is expressed in kilograms, most torque and rotation values are expressed in radians.
-
-A Collision Shape is a simplified shape for which physics are easier to calculate than for the true shape of the model. This simplication approach speeds up the simulation greatly.
-
-
-
-Before you can create a Physics Control, you must create a Collision Shape from the com.jme3.bullet.collision.shapes package. (Read the tip under "PhysicsControls Code Samples" to learn how to use default CollisionShapes for Boxes and Spheres.)
-
-
-
-
-
Shape
Usage
Examples
-
-
-
BoxCollisionShape
Box shaped entities Does not roll.
Bricks, crates, simple oblong entities.
-
-
-
SphereCollisionShape
Spherical entities. Can roll.
Balls, simple compact entities.
-
-
-
CylinderCollisionShape
Tube-shaped and disc-shaped entities. Can roll on one side.
Pillars, wheels.
-
-
-
CapsuleCollisionShape
A compound of a cylinder plus two spheres at the top and bottom. Is locked to stay upright, does not roll.
Optimized for CharacterControls: A cylinder-shaped body does not get stuck at corners and vertical obstacles; the rounded top and bottom do not get stuck on stair steps and ground obstacles.
-
-
-
CompoundCollisionShape
A CompoundCollisionShape allows custom combinations of box/sphere/cylinder shapes to form another more complex shape.
Complex shapes.
-
-
-
MeshCollisionShape
A free-form mesh-accurate shape that wraps itself around a static entity.
-Limitations: Only non-mesh collision shapes (sphere, box, cylinder, compound) can collide with mesh-accurate collision shapes. Only works for static obstacles.
A whole static game level model.
-
-
-
GImpactCollisionShape
This free-form Mesh Collision Shape that wraps itself around dynamically moving entities. Uses .
+ ...
You can also access the BulletAppState via the state manager:
stateManager.getState(BulletAppState.class)
For each Spatial that you want to be physical:
Create a CollisionShape.
Create a PhysicsControl by supplying the CollisionShape and mass.
E.g. com.jme3.bullet.control.RigidBodyControl
Add the PhysicsControl to the Spatial.
Add the PhysicsControl to the physicsSpace object.
Attach the Spatial to the rootNode, as usual.
(Optional) Implement the PhysicsCollisionListener interface to respond to PhysicsCollisionEvents if desired.
A Collision Shape is a simplified shape for which physics are easier to calculate than for the true shape of the model. This simplication approach speeds up the simulation greatly.
Before you can create a Physics Control, you must create a Collision Shape from the com.jme3.bullet.collision.shapes package. (Read the tip under "PhysicsControls Code Samples" to learn how to use default CollisionShapes for Boxes and Spheres.)
Shape
Usage
Examples
BoxCollisionShape
Box shaped entities Does not roll.
Bricks, crates, simple oblong entities.
SphereCollisionShape
Spherical entities. Can roll.
Balls, simple compact entities.
CylinderCollisionShape
Tube-shaped and disc-shaped entities. Can roll on one side.
Pillars, wheels.
CapsuleCollisionShape
A compound of a cylinder plus two spheres at the top and bottom. Is locked to stay upright, does not roll.
Optimized for CharacterControls: A cylinder-shaped body does not get stuck at corners and vertical obstacles; the rounded top and bottom do not get stuck on stair steps and ground obstacles.
CompoundCollisionShape
A CompoundCollisionShape allows custom combinations of box/sphere/cylinder shapes to form another more complex shape.
Complex shapes.
MeshCollisionShape
A free-form mesh-accurate shape that wraps itself around a static entity. Limitations: Only non-mesh collision shapes (sphere, box, cylinder, compound) can collide with mesh-accurate collision shapes. Only works for static obstacles.
A whole static game level model.
GImpactCollisionShape
This free-form Mesh Collision Shape that wraps itself around dynamically moving entities. Uses . Limitations: CPU intensive, use sparingly! We recommend using HullCollisionShapes or CompoundShapes made of simple shapes if you need improved performance.
-You can control physical objects by triggering forces. Or maybe you want to respond to collisions, e.g. by substracting health points, or by playing a sound. To specify how the game responds to such physics events, you use Physics Listeners.
-
-
-The jBullet Physics implementation is stepped at a constant 60 physics ticks per second frame rate.
-Applying forces or checking for overlaps only has an effect right at a physics update cycle, which is not every frame. If you do physics interactions at arbitrary spots in the simpleUpdate() loop, calls will be dropped at irregular intervals, because they happen out of cycle.
-
-
-When you write game mechanics that apply forces, you must implement a tick listener (com.jme3.bullet.PhysicsTickListener) for it. The tick listener makes certain the forces are not dropped, but applied in time for the next physics tick.
-Also, when you check for overlaps of physical objects with a PhysicsGhostObject, you cannot just go physicsSpace.add(ghost); ghost.getOverLappingObjects() somewhere. You have to make certain 1 physics tick has passed before the overlapping objects list is filled with data. Again, the PhysicsTickListener does that for you.
-When your game mechanics however just poll the current state (e.g. location) of physical objects, or if you only use the Ghost control like a sphere trigger, then you don't need a PhysicsTickListener.
-
-
You can control physical objects by triggering forces. Or maybe you want to respond to collisions, e.g. by substracting health points, or by playing a sound. To specify how the game responds to such physics events, you use Physics Listeners.
The jBullet Physics implementation is stepped at a constant 60 physics ticks per second frame rate. Applying forces or checking for overlaps only has an effect right at a physics update cycle, which is not every frame. If you do physics interactions at arbitrary spots in the simpleUpdate() loop, calls will be dropped at irregular intervals, because they happen out of cycle.
When you write game mechanics that apply forces, you must implement a tick listener (com.jme3.bullet.PhysicsTickListener) for it. The tick listener makes certain the forces are not dropped, but applied in time for the next physics tick. Also, when you check for overlaps of physical objects with a PhysicsGhostObject, you cannot just go physicsSpace.add(ghost); ghost.getOverLappingObjects() somewhere. You have to make certain 1 physics tick has passed before the overlapping objects list is filled with data. Again, the PhysicsTickListener does that for you. When your game mechanics however just poll the current state (e.g. location) of physical objects, or if you only use the Ghost control like a sphere trigger, then you don't need a PhysicsTickListener.
-If you do not implement the Collision Listener interface (com.jme3.bullet.collision.PhysicsCollisionListener), a collisions will just mean that physical forces are applied automatically. If you just want "Balls rolling, bricks falling" you do not need a listener.
-If however you want to respond to a collision event (com.jme3.bullet.collision.PhysicsCollisionEvent) with a custom action, then you need to implement the PhysicsCollisionListener interface. Typical actions triggered by collisions include:
+}
If you do not implement the Collision Listener interface (com.jme3.bullet.collision.PhysicsCollisionListener), a collisions will just mean that physical forces are applied automatically. If you just want "Balls rolling, bricks falling" you do not need a listener. If however you want to respond to a collision event (com.jme3.bullet.collision.PhysicsCollisionEvent) with a custom action, then you need to implement the PhysicsCollisionListener interface. Typical actions triggered by collisions include:
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 "topView", 6 seconds after the start of the cinematic, you'd write
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 "topView", 6 seconds after the start of the cinematic, you'd write
\ No newline at end of file
diff --git a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/save_and_load.html b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/save_and_load.html
index 064f4a3a7..602684fa9 100644
--- a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/save_and_load.html
+++ b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/save_and_load.html
@@ -1,26 +1,4 @@
-
-
-
-You can save and load scenes and individual Nodes using com.jme3.export.binary.BinaryExporter and com.jme3.export.binary.BinaryImporter. Use standard Java serialization to load game data or use the Savable interface. The jMonkeyEngine binary file format is .j3o. You can open, view, and edit .j3o files in the jMonkeyEngine SDK.
-
You can save and load scenes and individual Nodes using com.jme3.export.binary.BinaryExporter and com.jme3.export.binary.BinaryImporter. Use standard Java serialization to load game data or use the Savable interface. The jMonkeyEngine binary file format is .j3o. You can open, view, and edit .j3o files in the jMonkeyEngine SDK.
@Override
public void destroy() {
System.getProperty("user.home");
BinaryExporter exporter = BinaryExporter.getInstance();
@@ -31,13 +9,7 @@ You can save and load scenes and individual Nodes using com.jme3.export.binary.B
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, "Failed to save node!", ex);
}
super.destroy();
- }
@Override
public void simpleInitApp() {
System.getProperty("user.home");
BinaryImporter importer = BinaryImporter.getInstance();
@@ -51,18 +23,7 @@ You can save and load scenes and individual Nodes using com.jme3.export.binary.B
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, "No saved node loaded.", ex);
}
...
-
-Here is an example for how you add a static horizon (a background landscape and a sky) to a scene.
-Having a discernable horizon with a suitable landscape (or space, or ocean, or whatever) in the background makes scenes look more realistic than just a single-colored "sky" background.
-
Set the boolean to true if you are using a sphere map texture. For a cube map, use false.
-Tip: Cube map is the default. You would know if you had created a sphere map.
-
-
-
-
-
-Internally, the SkyFactory calls the following methods:
-
-
-
sky.setQueueBucket(Bucket.Sky); makes certain the sky is rendered in the right order, behind everything else.
-
-
sky.setCullHint(Spatial.CullHint.Never); makes certain that the sky is never culled.
-
-
The SkyFactory uses the internal jME3 material definition Sky.j3md. This Material definition works with sphere and cube maps.
-
-As the sky texture we use the sample BrightSky.dds file from jme3test-test-data.
-
-
-
-How to create a sky textures?
-
-
-
-
There are many tools out there that generate cube and sphere maps.
-Examples for landscape texture generators are Terragen or Bryce.
-
-
The actual texture size does not matter, as long as you add the Sky Geometry to the Sky bucket: Everything in the sky bucket will always be infinitely far away behind everything else, and never intersect with your scene.
-Of course the higher the resolution, the better it will look. On the other hand, if the graphic is too big, it will slow the game down.
-
-
A box or sphere map is the simplest solution. But you can use any Node as sky, even complex sets of geometries and quads with animated clouds, blinking stars, city skylines, etc.
-
-
JME3 supports cube maps in PNG, JPG, or (compressed) DDS format.
-
-
-
-
-
-Box or Sphere?
-
-
-
If you have access to cube map textures, then use a SkyBox
-
-
-
-
-
-
If you have access to sphere map textures – specially projected sky images that fit inside a sphere – then you use a SkySphere or SkyDome.
Here is an example for how you add a static horizon (a background landscape and a sky) to a scene. Having a discernable horizon with a suitable landscape (or space, or ocean, or whatever) in the background makes scenes look more realistic than just a single-colored "sky" background.
Set the boolean to true if you are using a sphere map texture. For a cube map, use false. Tip: Cube map is the default. You would know if you had created a sphere map.
Internally, the SkyFactory calls the following methods:
sky.setQueueBucket(Bucket.Sky); makes certain the sky is rendered in the right order, behind everything else.
sky.setCullHint(Spatial.CullHint.Never); makes certain that the sky is never culled.
The SkyFactory uses the internal jME3 material definition Sky.j3md. This Material definition works with sphere and cube maps.
As the sky texture we use the sample BrightSky.dds file from jme3test-test-data.
How to create a sky textures?
There are many tools out there that generate cube and sphere maps. Examples for landscape texture generators are Terragen or Bryce.
The actual texture size does not matter, as long as you add the Sky Geometry to the Sky bucket: Everything in the sky bucket will always be infinitely far away behind everything else, and never intersect with your scene. Of course the higher the resolution, the better it will look. On the other hand, if the graphic is too big, it will slow the game down.
A box or sphere map is the simplest solution. But you can use any Node as sky, even complex sets of geometries and quads with animated clouds, blinking stars, city skylines, etc.
JME3 supports cube maps in PNG, JPG, or (compressed) DDS format.
Box or Sphere?
If you have access to cube map textures, then use a SkyBox
If you have access to sphere map textures – specially projected sky images that fit inside a sphere – then you use a SkySphere or SkyDome.
-
-This is an introduction to the concept of Spatials, the elements of the 3D scene graph. The scene graph is a data structure that manages all objects in your 3D world. For example, the scene graph keeps track of the 3D models that you load and position. When you extend a Java class from com.jme3.app.SimpleApplication, you automatically inherit the scene graph and its rootNode.
-
-
-
-The rootNode is the central element of the scene graph. Even if the scenegraph is empty, it always has at least its rootNode. All other Spatials are attached to the rootNode in a parent-child relationship. If you think you need to understand the scene graph concept better, please read Scenegraph for dummies first.
-
-
-In your Java code, a Spatial is either a com.jme3.scene.Node or a com.jme3.scene.Geometry. You use the two for different purposes:
-
-
-
-
-
-
-
-
-
com.jme3.scene.Spatial
-
-
-
Purpose:
A Spatial is an abstract data structure that stores transformations (translation, rotation, scale) of elements of the scene graph. Spatials can be saved and loaded using the AssetManager.
This is an introduction to the concept of Spatials, the elements of the 3D scene graph. The scene graph is a data structure that manages all objects in your 3D world. For example, the scene graph keeps track of the 3D models that you load and position. When you extend a Java class from com.jme3.app.SimpleApplication, you automatically inherit the scene graph and its rootNode.
The rootNode is the central element of the scene graph. Even if the scenegraph is empty, it always has at least its rootNode. All other Spatials are attached to the rootNode in a parent-child relationship. If you think you need to understand the scene graph concept better, please read Scenegraph for dummies first.
In your Java code, a Spatial is either a com.jme3.scene.Node or a com.jme3.scene.Geometry. You use the two for different purposes:
com.jme3.scene.Spatial
Purpose:
A Spatial is an abstract data structure that stores transformations (translation, rotation, scale) of elements of the scene graph. Spatials can be saved and loaded using the AssetManager.
com.jme3.scene.Geometry
com.jme3.scene.Node
Visibility:
A Geometry represents a visible 3-D object in the scene graph.
A Node is an invisible "handle" for a group of objects in the scene graph.
-
-The goal of TerraMonkey is to provide a base implementation that will be usable for 80% of people's goals, while providing tools and a good foundation for the other 20% to build off of. Check out the videos in the following announcements:
-
-
-TerraMonkey is a GeoMipMapping quad tree of terrain tiles that supports real time editing and texture splatting. That's a mouth full! Lets look at each part:
-
-
-
GeoMipMapping: a method of changing the level of detail (LOD) of geometry tiles based on how far away they are from the camera. Between the edges of two tiles, it will seam those edges together so you don't get gaps or holes. For an in-depth read on how it works, here is a pdf .
-
-
Quad Tree: The entire terrain structure is made up of TerrainPatches (these hold the actual meshes) as leaves in a quad tree (TerrainQuad). TerrainQuads are subdivided by 4 until they reach minimum size, then a TerrainPatch is created, and that is where the actual geometry mesh lives. This allows for fast culling of the terrain that you can't see.
-
-
Splatting: The ability to paint multiple textures onto your terrain. What differs here from JME2 is that this is all done in a shader, no more render passes. So it performs much faster.
-
-
Real-time editing: TerraMonkey terrains are editable in jMonkeyEngine SDK, and you are able to modify them in real time: raising and lowering terrain.
-
-You have seen GeoMipMapping implemented in games before. This is where the farther away terrain has fewer polygons, and as you move closer, more polygons fill in. The whole terrain is divided into a grid of patches, and each one has its own level of detail (LOD). The GeoMipMapping algorithm looks at each patch, and its neighbours, to determine how to render the geometry. It will seam the edges between two patches with different LOD.
-
-
-
-GeoMipMapping often leads to "popping" where you see the terrain switch from one LOD to another. TerraMonkey has been designed so you can swap out different LOD calculation algorithms based on what will look best for your game. You can do this with the LodCalculator interface.
-
-
-
-GeoMipMapping in TerraMonkey has been split into several parts: the terrain quad tree, and the LODGeomap. The geomap deals with the actual LOD and seaming algorithm. So if you want a different data structure for your terrain system, you can re-use this piece of code. The quad tree (TerrainQuad and TerrainPatch) provide a means to organize the LODGeomaps, notify them of their neighbour's LOD change, and to update the geometry when the LOD does change. To change the LOD it does this by changing the index buffer of the triangle strip, so the whole geometry doesn't have to be re-loaded onto the video card. If you are eager, you can read up more detail how GeoMipMapping works here:
-
-
-TerraMonkey is a quad tree. Each node is a TerrainQuad, and each leaf is a TerrainPatch. A TerrainQuad has either 4 child TerrainQuads, or 4 child TerrainPatches. The TerrainPatch holds the actual mesh geometry. This structure is almost exactly the same as JME2's TerrainPage system. Except now each leaf has a reference to its neighbours, so it doesn't ever have to traverse the tree to get them.
-
The goal of TerraMonkey is to provide a base implementation that will be usable for 80% of people's goals, while providing tools and a good foundation for the other 20% to build off of. Check out the videos in the following announcements:
TerraMonkey is a GeoMipMapping quad tree of terrain tiles that supports real time editing and texture splatting. That's a mouth full! Lets look at each part:
GeoMipMapping: a method of changing the level of detail (LOD) of geometry tiles based on how far away they are from the camera. Between the edges of two tiles, it will seam those edges together so you don't get gaps or holes. For an in-depth read on how it works, here is a pdf .
Quad Tree: The entire terrain structure is made up of TerrainPatches (these hold the actual meshes) as leaves in a quad tree (TerrainQuad). TerrainQuads are subdivided by 4 until they reach minimum size, then a TerrainPatch is created, and that is where the actual geometry mesh lives. This allows for fast culling of the terrain that you can't see.
Splatting: The ability to paint multiple textures onto your terrain. What differs here from JME2 is that this is all done in a shader, no more render passes. So it performs much faster.
Real-time editing: TerraMonkey terrains are editable in jMonkeyEngine SDK, and you are able to modify them in real time: raising and lowering terrain.
You have seen GeoMipMapping implemented in games before. This is where the farther away terrain has fewer polygons, and as you move closer, more polygons fill in. The whole terrain is divided into a grid of patches, and each one has its own level of detail (LOD). The GeoMipMapping algorithm looks at each patch, and its neighbours, to determine how to render the geometry. It will seam the edges between two patches with different LOD.
GeoMipMapping often leads to "popping" where you see the terrain switch from one LOD to another. TerraMonkey has been designed so you can swap out different LOD calculation algorithms based on what will look best for your game. You can do this with the LodCalculator interface.
GeoMipMapping in TerraMonkey has been split into several parts: the terrain quad tree, and the LODGeomap. The geomap deals with the actual LOD and seaming algorithm. So if you want a different data structure for your terrain system, you can re-use this piece of code. The quad tree (TerrainQuad and TerrainPatch) provide a means to organize the LODGeomaps, notify them of their neighbour's LOD change, and to update the geometry when the LOD does change. To change the LOD it does this by changing the index buffer of the triangle strip, so the whole geometry doesn't have to be re-loaded onto the video card. If you are eager, you can read up more detail how GeoMipMapping works here:
TerraMonkey is a quad tree. Each node is a TerrainQuad, and each leaf is a TerrainPatch. A TerrainQuad has either 4 child TerrainQuads, or 4 child TerrainPatches. The TerrainPatch holds the actual mesh geometry. This structure is almost exactly the same as JME2's TerrainPage system. Except now each leaf has a reference to its neighbours, so it doesn't ever have to traverse the tree to get them.
-
-This tutorial expands the HelloTerrain tutorial and makes the terrain solid. You combine what you learned in Hello Terrain and Hello Collision and add a CollisionShape to the terrain. The terrain's CollisionShape lets the first-person player (who is also a CollisionShape) collide with the terrain, i.e. walk on it and stand on it.
-
This tutorial expands the HelloTerrain tutorial and makes the terrain solid. You combine what you learned in Hello Terrain and Hello Collision and add a CollisionShape to the terrain. The terrain's CollisionShape lets the first-person player (who is also a CollisionShape) collide with the terrain, i.e. walk on it and stand on it.
-
-For physical vehicles, jME's uses the jBullet ray-cast vehicle. In this vehicle implementation, the physical chassis 'floats' along on four non-physical vertical rays.
-
-
-
-Internally, each wheel casts a ray down, and using the ray's intersection point, jBullet calculates the suspension length, and the suspension force. The suspension force is applied to the chassis, keeping it from hitting the ground. The friction force is calculated for each wheel where the ray intersects with the ground. Friction is applied as a sideways and forwards force. 1)
-
-
-
-This article shows how you use this vehicle implementation in a jME3 application.
-
-
-The vehicle that we create here in the example is just a "box on wheels", a basic vehicle shape that you can replace with a fancy car model, as demonstrated in .
-
-
-
-Every physical object must have a collision shape, that we prepare first. For the vehicle, we choose a compound collision shape that is made up of a box-shaped body of the right size for the vehicle. We will add the wheels later.
-
-
CompoundCollisionShape compoundShape = new CompoundCollisionShape();
-BoxCollisionShape box = new BoxCollisionShape(new Vector3f(1.2f, 0.5f, 2.4f));
-
-
-Best Practice: We attach the BoxCollisionShape (the vehicle body) to the CompoundCollisionShape at a Vector of (0,1,0): This shifts the effective center of mass of the BoxCollisionShape downwards to 0,-1,0 and makes a moving vehicle more stable!
-
-
compoundShape.addChildShape(box, new Vector3f(0, 1, 0));
For physical vehicles, jME's uses the jBullet ray-cast vehicle. In this vehicle implementation, the physical chassis 'floats' along on four non-physical vertical rays.
Internally, each wheel casts a ray down, and using the ray's intersection point, jBullet calculates the suspension length, and the suspension force. The suspension force is applied to the chassis, keeping it from hitting the ground. The friction force is calculated for each wheel where the ray intersects with the ground. Friction is applied as a sideways and forwards force. 1)
This article shows how you use this vehicle implementation in a jME3 application.
The vehicle that we create here in the example is just a "box on wheels", a basic vehicle shape that you can replace with a fancy car model, as demonstrated in .
Every physical object must have a collision shape, that we prepare first. For the vehicle, we choose a compound collision shape that is made up of a box-shaped body of the right size for the vehicle. We will add the wheels later.
CompoundCollisionShape compoundShape = new CompoundCollisionShape();
+BoxCollisionShape box = new BoxCollisionShape(new Vector3f(1.2f, 0.5f, 2.4f));
Best Practice: We attach the BoxCollisionShape (the vehicle body) to the CompoundCollisionShape at a Vector of (0,1,0): This shifts the effective center of mass of the BoxCollisionShape downwards to 0,-1,0 and makes a moving vehicle more stable!
compoundShape.addChildShape(box, new Vector3f(0, 1, 0));
Any kind of geometry can make up the visible part of the vehicle, here we use a wireframe box. We create a node that we use to group the geometry.
diff --git a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/walking_character.html b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/walking_character.html
index d3aa4b54b..b581d59aa 100644
--- a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/walking_character.html
+++ b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/walking_character.html
@@ -1,56 +1,4 @@
-
-
-In the Hello Collision tutorial and the code sample you have seen how to create collidable landscapes and walk around in a first-person perspective. The first-person camera is enclosed by a collision shape and is steered by a CharacterControl.
-
-
-
-Other games however require a third-person perspective of the character: In these cases you use a CharacterControl on a Spatial. This example also shows how to set up custom navigation constrols, so you can press WASD to make the third-person character walk, and drag the mouse to rotate.
-
-
-When you load a character model with a RigidBodyControl, and use forces to push it around, you do not get the desired effect: RigidBodyControl'ed objects can tip over when pushed, and that is not what you expect of a walking character. jMonkeyEngine offers a special CharacterControl with a special walking methods to implement characters that walk upright.
-
-
In the Hello Collision tutorial and the code sample you have seen how to create collidable landscapes and walk around in a first-person perspective. The first-person camera is enclosed by a collision shape and is steered by a CharacterControl.
Other games however require a third-person perspective of the character: In these cases you use a CharacterControl on a Spatial. This example also shows how to set up custom navigation constrols, so you can press WASD to make the third-person character walk, and drag the mouse to rotate.
When you load a character model with a RigidBodyControl, and use forces to push it around, you do not get the desired effect: RigidBodyControl'ed objects can tip over when pushed, and that is not what you expect of a walking character. jMonkeyEngine offers a special CharacterControl with a special walking methods to implement characters that walk upright.
public class WalkingCharacterDemo extends SimpleApplication
implements ActionListener, AnimEventListener {
public static void main(String[] args) {
WalkingCharacterDemo app = new WalkingCharacterDemo();
@@ -60,67 +8,18 @@ The code in this tutorial is a combination of these samples.
public void simpleUpdate(float tpf) { }
public void onAction(String name, boolean isPressed, float tpf) { }
public void onAnimCycleDone(AnimControl control, AnimChannel channel, String animName) { }
- public void onAnimChange(AnimControl control, AnimChannel channel, String animName) { }
-In the simpleInitApp() method you initialize the scene and give it a MeshCollisionShape. The sample in the jme3 sources uses a custom helper class that simply creates a flat floor and drops some cubes and spheres on it:
-
-
In the simpleInitApp() method you initialize the scene and give it a MeshCollisionShape. The sample in the jme3 sources uses a custom helper class that simply creates a flat floor and drops some cubes and spheres on it:
public void simpleInitApp() {
...
PhysicsTestHelper.createPhysicsTestWorld(rootNode,
assetManager, bulletAppState.getPhysicsSpace());
- ...
-
-
-
-In a real game, you would load a scene model here instead of a test world. You can load a model from a local or remote zip file, and scale and position it:
-
-
-
private Node gameLevel;
+ ...
In a real game, you would load a scene model here instead of a test world. You can load a model from a local or remote zip file, and scale and position it:
-
-
-
-Did you know? A CapsuleCollisionShape is a cylinder with rounded top and bottom. A capsule rotated upright is a good collision shape for a humanoid character since its roundedness reduces the risk of getting stuck on obstacles.
-
-
-Create several AnimChannels, one for each animation that can happen simultaneously. In this example, you create one channel for walking and one for attacking. (Because the character can attack with its arms and walk with the rest of the body at the same time.)
-
-
-
private AnimChannel animationChannel;
+ ...
Did you know? A CapsuleCollisionShape is a cylinder with rounded top and bottom. A capsule rotated upright is a good collision shape for a humanoid character since its roundedness reduces the risk of getting stuck on obstacles.
Create several AnimChannels, one for each animation that can happen simultaneously. In this example, you create one channel for walking and one for attacking. (Because the character can attack with its arms and walk with the rest of the body at the same time.)
Configure custom key bindings for WASD keys that you will use to make the character walk.
private boolean left = false, right = false, up = false, down = false;
...
public void simpleInitApp() {
...
@@ -256,14 +82,7 @@ public void simpleInitApp() {
inputManager.addListener(this, "CharForward", "CharBackward");
inputManager.addListener(this, "CharJump", "CharAttack");
...
-}
-
-
-
-Respond to the key bindings by setting variables that track in which direction you will go. (No actual walking happens here yet)
-
-
-
@Override
+}
Respond to the key bindings by setting variables that track in which direction you will go. (No actual walking happens here yet)
@Override
public void onAction(String binding, boolean value, float tpf) {
if (binding.equals("CharLeft")) {
if (value) left = true;
@@ -281,24 +100,10 @@ public void onAction(String binding, boolean value, float tpf) {
character.jump();
if (binding.equals("CharAttack"))
attack();
-}
-
-
-
-The player can attack and walk at the same time. Attack() is a custom method that triggers an attack animation in the arms. Here you should also add custom code to play an effect and sound, and to determine whether the hit was successful.
-
-
-
private void attack() {
+}
The player can attack and walk at the same time. Attack() is a custom method that triggers an attack animation in the arms. Here you should also add custom code to play an effect and sound, and to determine whether the hit was successful.
-
-The update loop looks at the directional variables and moves the character accordingly. Since it's a physical character, we use setWalkDirection(). The variable airTime tracks how long the character is off the ground (e.g. when jumping or falling) and adjusts the walk and stand animations acccordingly.
-
-
-
private Vector3f walkDirection = new Vector3f(0,0,0);
+}
The update loop looks at the directional variables and moves the character accordingly. Since it's a physical character, we use setWalkDirection(). The variable airTime tracks how long the character is off the ground (e.g. when jumping or falling) and adjusts the walk and stand animations acccordingly.
\ No newline at end of file
diff --git a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/water.html b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/water.html
index 884076eda..dd2891973 100644
--- a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/water.html
+++ b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/advanced/water.html
@@ -1,37 +1,4 @@
-
-
-
-A JME3 scene with water can use a com.jme3.water.SimpleWaterProcessor (which implements the SceneProcessor interface).
-
-
-
-To achieve a water effect, JME3 uses shaders and a special material, Common/MatDefs/Water/SimpleWater.j3md. The water surface is a quad, and we use normal map and dU/dV map texturing to simulate the waves.
+
A JME3 scene with water can use a com.jme3.water.SimpleWaterProcessor (which implements the SceneProcessor interface).
To achieve a water effect, JME3 uses shaders and a special material, Common/MatDefs/Water/SimpleWater.j3md. The water surface is a quad, and we use normal map and dU/dV map texturing to simulate the waves.
-
-You create animated models with a tool such as Blender. Take some time and learn how to create your own models in these . For now, download and use a free model, such as the one included here as an example (, and ).
-
-
-
-Loading an animated model is pretty straight-forward, just as you have learned in the previous chapters. Animated Ogre models come as a set of files: The model is in Oto.mesh.xml, and the animation details are in Oto.skeleton.xml, plus the usual files for materials and textures. Check that all files of the model are together in the same Model subdirectory.
-
You create animated models with a tool such as Blender. Take some time and learn how to create your own models in these . For now, download and use a free model, such as the one included here as an example (, and ).
Loading an animated model is pretty straight-forward, just as you have learned in the previous chapters. Animated Ogre models come as a set of files: The model is in Oto.mesh.xml, and the animation details are in Oto.skeleton.xml, plus the usual files for materials and textures. Check that all files of the model are together in the same Model subdirectory.
public void simpleInitApp() {
/* Displaying the model requires a light source */
DirectionalLight dl = new DirectionalLight();
dl.setDirection(new Vector3f(-0.1f, -1f, -1).normalizeLocal());
@@ -114,30 +78,7 @@ Loading an animated model is pretty straight-forward, just as you have learned i
player.setLocalScale(0.5f); // resize
rootNode.attachChild(player);
...
- }
-
-
-Don't forget to add a light source to make the material visible.
-
After you load the animated model, you register it to the Animation Controller.
The controller object gives you access to the available animation sequences.
The controller can have several channels, each channel can run one animation sequence at a time.
To run several sequences, you create several channels, and set them each to their animation.
private AnimChannel channel;
private AnimControl control;
public void simpleInitApp() {
@@ -148,18 +89,7 @@ After you load the animated model, you register it to the Animation Controller.
control.addListener(this);
channel = control.createChannel();
channel.setAnim("stand");
- ...
-
-Add implements AnimEventListener to the class declaration. This interface gives you access to events that notify you when a sequence is done, or when you change from one sequence to another, so you can respond to it. In this example, you reset the character to a standing position after a Walk cycle is done.
-
-
public class HelloAnimation extends SimpleApplication
+ ...
Add implements AnimEventListener to the class declaration. This interface gives you access to events that notify you when a sequence is done, or when you change from one sequence to another, so you can respond to it. In this example, you reset the character to a standing position after a Walk cycle is done.
public class HelloAnimation extends SimpleApplication
implements AnimEventListener {
...
@@ -173,54 +103,10 @@ Add implements AnimEventListener to the class declaration. This int
}
public void onAnimChange(AnimControl control, AnimChannel channel, String animName) {
// unused
- }
-
-There are ambient animations like animals or trees that you may want to trigger in the main event loop. In other cases, animations are triggered by user interaction, such as key input. You want to play the Walk animation when the player presses a certain key (here the spacebar), at the same time as the avatar performs the walk action and changes its location.
-
-
-
Initialize a new input controller (in simpleInitApp()).
-
-
Write the initKey() convenience method and call it from simpleInitApp().
-
-
-
-
Add a key mapping with the name as the action you want to trigger.
-
-
Here for example, you map Walk to the Spacebar key.
There are ambient animations like animals or trees that you may want to trigger in the main event loop. In other cases, animations are triggered by user interaction, such as key input. You want to play the Walk animation when the player presses a certain key (here the spacebar), at the same time as the avatar performs the walk action and changes its location.
Initialize a new input controller (in simpleInitApp()).
Write the initKey() convenience method and call it from simpleInitApp().
Add a key mapping with the name as the action you want to trigger.
Here for example, you map Walk to the Spacebar key.
-To use the input controller, you need to implement the actionLister:
-Test for each action by name, and set the channel to the corresponding animation to run.
-
-
-
-
The second parameter of setAnim() is the blendTime (how long the current animation should overlap with the last one).
-
-
LoopMode can be Loop (repeat), Cycle (forward then backward), and DontLoop (only once).
-
-
If needed, use channel.setSpeed() to set the speed of this animation.
-
-
Optionally, use channel.setTime() to Fast-forward or rewind to a certain moment in time of this animation.
-
-
-
private ActionListener() {
+ }
To use the input controller, you need to implement the actionLister: Test for each action by name, and set the channel to the corresponding animation to run.
The second parameter of setAnim() is the blendTime (how long the current animation should overlap with the last one).
LoopMode can be Loop (repeat), Cycle (forward then backward), and DontLoop (only once).
If needed, use channel.setSpeed() to set the speed of this animation.
Optionally, use channel.setTime() to Fast-forward or rewind to a certain moment in time of this animation.
private ActionListener() {
public void onAction(String name, boolean keyPressed, float tpf) {
if (name.equals("Walk") && !keyPressed) {
if (!channel.getAnimationName().equals("Walk")){
@@ -229,40 +115,7 @@ Test for each action by name, and set the channel to the corresponding animation
}
}
}
- };
-
-Open the skeleton.xml file in a text editor of your choice. You don't have to be able to read or write these xml files (Blender does that for you) – but it is good to know how skeletons work. "There's no magic to it!"
+ };
Make a mouse click trigger another animation sequence!
Create a second channel in the controller
Create a new key trigger mapping and action (see: Hello Input)
Tip: Do you want to find out what animation sequences are available in the model? Use:
for (Exercise 2: Revealing the Skeleton (1)
Open the skeleton.xml file in a text editor of your choice. You don't have to be able to read or write these xml files (Blender does that for you) – but it is good to know how skeletons work. "There's no magic to it!"
Note how the bones are numbered and named. All names of animated models follow a naming scheme.
-In this tutorial we will learn to load 3-D models and text into the scene graph, using the jME asset manager. You also learn how to arrive at the correct paths, and which file formats to use.
-
-
-
-
-
-
-
-
To use the example assets in a new jMonkeyEngine SDK project, right-click your project, select "Properties", go to "Libraries", press "Add Library" and add the "jme3-test-data" library.
-
In this tutorial we will learn to load 3-D models and text into the scene graph, using the jME asset manager. You also learn how to arrive at the correct paths, and which file formats to use.
To use the example assets in a new jMonkeyEngine SDK project, right-click your project, select "Properties", go to "Libraries", press "Add Library" and add the "jme3-test-data" library.
package jme3test.helloworld;
import com.jme3.app.SimpleApplication;
import com.jme3.font.BitmapText;
@@ -86,36 +59,7 @@ public class HelloAssets extends SimpleApplication {
rootNode.addLight(sun);
}
-}
-
-
-Build and run the code sample. You should see a green Ninja with a colorful teapot standing behind a wall. The text on the screen should say "Hello World".
-
-
-JME3 comes with a handy asset manager that helps you keep your assets organized. Project assets are media files such as models, materials, textures, scenes, shaders, sounds, and fonts.
-The Asset manager can load files from:
-
-
-
the current classpath (the top level of your project directory),
-
-
the assets directory of your project, and
-
-
optionally, custom paths.
-
-
-
-
-
-This is our recommended directory structure for storing assets:
-
-
MyGame/assets/Interface/
+}
Build and run the code sample. You should see a green Ninja with a colorful teapot standing behind a wall. The text on the screen should say "Hello World".
JME3 comes with a handy asset manager that helps you keep your assets organized. Project assets are media files such as models, materials, textures, scenes, shaders, sounds, and fonts. The Asset manager can load files from:
the current classpath (the top level of your project directory),
the assets directory of your project, and
optionally, custom paths.
This is our recommended directory structure for storing assets:
-
-Place your textures in a subdirectory of assets/Textures/. Load the texture into the material before you set the Material. The following code sample is from the simpleInitApp() method and loads a simple wall model:
-
-
// Create a wall with a simple texture from test_data
+MyGame/...
This is just a suggested best practice, you can name the directories in the assets directory what ever you like.
Place your textures in a subdirectory of assets/Textures/. Load the texture into the material before you set the Material. The following code sample is from the simpleInitApp() method and loads a simple wall model:
// Create a wall with a simple texture from test_data
Box(Vector3f.ZERO, 2.5f,2.5f,1.0f);
Spatial wall = new Geometry("Box", box );
Material mat_brick = new Material(
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 567727aeb..4972c5a84 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,20 +1,4 @@
-
-
-This tutorial explains how to add 3D sound to a game, and how make sounds play together with events, such as clicking. You learn how to use an Audio Listener and Audio Nodes. You 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.
-
This tutorial explains how to add 3D sound to a game, and how make sounds play together with events, such as clicking. You learn how to use an Audio Listener and Audio Nodes. You 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.
-This tutorial demonstrates how you load a scene model and give it solid walls and floors for a character to walk around.
-You use a RigidBodyControl for the static collidable scene, and a CharacterControl for the mobile first-person character. You also learn how to set up the default first-person camera to work with physics-controlled navigation.
-You can use the solution shown here for first-person shooters, mazes, and similar games.
-
This tutorial demonstrates how you load a scene model and give it solid walls and floors for a character to walk around. You use a RigidBodyControl for the static collidable scene, and a CharacterControl for the mobile first-person character. You also learn how to set up the default first-person camera to work with physics-controlled navigation. You can use the solution shown here 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. Here is the code:
-
-
package jme3test.helloworld;
+src/
Place town.zip in the root directory of your JME3 project. Here is the code:
package jme3test.helloworld;
import com.jme3.app.SimpleApplication;
import com.jme3.asset.plugins.ZipLocator;
@@ -180,70 +147,16 @@ 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 with a first-person perspective. 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!
-
public class HelloCollision extends SimpleApplication
- implements ActionListener { ... }
-
-
-You already know that SimpleApplication is the base class for all jME3 games. You make this class implement the ActionListener interface because you 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 with a first-person perspective. 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!
public class HelloCollision extends SimpleApplication
+ implements ActionListener { ... }
You already know that SimpleApplication is the base class for all jME3 games. You make this class implement the ActionListener interface because you 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;
-
-
-You 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 for loading an OgreXML model of a town.
-
-
You need a RigidBodyControl to make the town model solid.
-
-
The (invisible) first-person player is represented by a CharacterControl object.
-
-
The fields walkDirection and the four Booleans are used for physics-controlled navigation.
-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 scene elements cannot be modeled by meshes. In very simple terms:
-
-
-
The difference between an explosion and a dust cloud is the speed of the particle effect.
-
-
The difference between flames and a waterfall is the direction and the color of the particle 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 you learn how to make 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 scene elements cannot be modeled by meshes. In very simple terms:
The difference between an explosion and a dust cloud is the speed of the particle effect.
The difference between flames and a waterfall is the direction and the color of the particle 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 you learn how to make 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 you base the material on the Particle.j3md material definition. Let's have a closer look at the material for the Debris effect.
-
-
ParticleEmitter debris =
+}
You should see an explosion that sends debris flying, and a fire.
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 you base the material on the Particle.j3md material definition. Let's have a closer look at the material for the Debris effect.
ParticleEmitter debris =
new ParticleEmitter("Debris", ParticleMesh.Type.Triangle, 10);
Material debris_mat = new Material(assetManager,
"Common/MatDefs/Misc/Particle.j3md");
@@ -142,73 +66,7 @@ Setting emitter textures works just as you have already learned in previous chap
debris.setImagesX(3);
debris.setImagesY(3); // 3x3 texture animation
debris.setSelectRandomImage(true);
- ...
-
-
Create a material and load the texture.
-
-
Tell the Emitter into how many animation steps (x*y) the texture is divided.
-The debris texture has 3x3 frames.
-
-
Optionally, tell the Emitter whether the animation steps are to be at random, or in order.
-For the debris, the frames play at random.
-
-
-
-
-
-As you see in the debris example, texture animations improve effects because each "flame" or "piece of debris" now 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.
-
-
-
-The fire material is created the same way, just using "Effects/Explosion/flame.png" texture, which has with 2x2 ordered animation steps.
-
-
-For your game, you will likely create custom particle textures. Look at the fire example again.
-
-
ParticleEmitter fire =
+ ...
Create a material and load the texture.
Tell the Emitter into how many animation steps (x*y) the texture is divided. The debris texture has 3x3 frames.
Optionally, tell the Emitter whether the animation steps are to be at random, or in order. For the debris, the frames play at random.
As you see in the debris example, texture animations improve effects because each "flame" or "piece of debris" now 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.
The fire material is created the same way, just using "Effects/Explosion/flame.png" texture, which has with 2x2 ordered animation steps.
For your game, you will likely create custom particle 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");
@@ -219,10 +77,7 @@ For your game, you will likely create custom particle textures. Look at the fire
fire.setImagesY(2); // 2x2 texture animation
fire.setEndColor( new ColorRGBA(1f, 0f, 0f, 1f)); // red
fire.setStartColor(new ColorRGBA(1f, 1f, 0f, 0.5f)); // yellow
-
-
-
-
+
@@ -318,7 +173,7 @@ Vector3f.NAN
gravity
setGravity()
0,1,0
Whether particles fall down (positive) or fly up (negative). Set to 0f for a zero-g effect where particles keep flying.
-
+
You can find details about effect parameters here.
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 94e30e87c..a423b18ff 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,4 @@
-
-
-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:
-
-
-
An input trigger can be a key press or mouse action.
-For example a mouse movement, a mouse click, or pressing the letter "P".
-
-
The mapping name is a string that you can choose.
-The name should describe the action (e.g. "Rotate"), and not the trigger. Because the trigger can change.
-
-
One named mapping can have several triggers.
-For example, 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 key trigger.
-new KeyTrigger(KeyInput.KEY_SPACE)).
-
-
In the same line, you also register "Rotate" to an alternative mouse click trigger.
-new MouseButtonTrigger(MouseInput.BUTTON_LEFT)
-
-
You map the Pause, Left, Right mappings to the P, J, K keys, respectively.
-
-
-
// You can map one or several inputs to one named action
+}
Build and run the example.
Press the Spacebar or click to rotate the cube.
Press the J and K keys to move the cube.
Press P to pause and unpause the game. While paused, the game should not respond to any input, other than P.
First you register each mapping name with its trigger(s). Remember the following:
An input trigger can be a key press or mouse action. For example a mouse movement, a mouse click, or pressing the letter "P".
The mapping name is a string that you can choose. The name should describe the action (e.g. "Rotate"), and not the trigger. Because the trigger can change.
One named mapping can have several triggers. For example, 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 key trigger. new KeyTrigger(KeyInput.KEY_SPACE)).
In the same line, you also register "Rotate" to an alternative mouse click trigger. new MouseButtonTrigger(MouseInput.BUTTON_LEFT)
You map the Pause, Left, Right mappings to the P, J, K keys, respectively.
// You can map one or several inputs to one named action
inputManager.addMapping("Pause", new KeyTrigger(KeyInput.KEY_P));
inputManager.addMapping("Left", new KeyTrigger(KeyInput.KEY_J));
inputManager.addMapping("Right", new KeyTrigger(KeyInput.KEY_K));
inputManager.addMapping("Rotate", new KeyTrigger(KeyInput.KEY_SPACE),
- new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
-
-
-
-Now you need to register your trigger mappings.
-
-
-
You register the pause action to the ActionListener, because it is an "on/off" action.
-
-
You register the movement actions to the AnalogListener, because they are gradual actions.
-
-
-
// Add the names to the action listener.
+ new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
Now you need to register your trigger mappings.
You register the pause action to the ActionListener, because it is an "on/off" action.
You register the movement actions to the AnalogListener, because they are gradual actions.
// Add the names to the action listener.
inputManager.addListener(actionListener, new String[]{"Pause"});
inputManager.addListener(analogListener, new String[]{"Left", "Right", "Rotate"});
-Now that you know how to load assets, such as 3D models, you want to implement some gameplay that uses these assets. 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 3D models, you want to implement some gameplay that uses these assets. In this tutorial we look at the update loop. The update loop of your game is where the action happens.
-The term Material includes everything that influences what the surface of a 3D model looks like: The color, texture, shininess, and opacity/transparency. Plain coloring is covered in Hello Node. Loading models that come with materials is covered in Hello Asset. In this tutorial you learn to create and use custom JME3 Material Definitions.
-
-
The term Material includes everything that influences what the surface of a 3D model looks like: The color, texture, shininess, and opacity/transparency. Plain coloring is covered in Hello Node. Loading models that come with materials is covered in Hello Asset. In this tutorial you learn to create and use custom JME3 Material Definitions.
For a game, you create custom Materials based on these existing MaterialDefintions – as you have just seen in the example with the shiny rock's material.
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 25c2abb49..76b59675f 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,46 +1,4 @@
-
-
You create some scene objects like players, buildings, etc.
-
-
You add the objects to the scene.
-
-
You move, resize, rotate, color, and animate them.
-
-
-
-
-
-You will learn that the scene graph represents the 3D world, and why the rootNode is important. You will learn how to create simple objects, how to let them carry custom data (such as health points), and how to "transform" them by moving, scaling, and rotating. You will understand the difference between the two types of "Spatials" in the scene graph: Nodes and Geometries.
-
You create some scene objects like players, buildings, etc.
You add the objects to the scene.
You move, resize, rotate, color, and animate them.
You will learn that the scene graph represents the 3D world, and why the rootNode is important. You will learn how to create simple objects, how to let them carry custom data (such as health points), and how to "transform" them by moving, scaling, and rotating. You will understand the difference between the two types of "Spatials" in the scene graph: Nodes and Geometries.
-
-In this tutorial, you learn some new terms:
-
-
-
-
-
What you want to do
How you say it in JME3 terminology
-
-
-
Lay out the 3D scene
Populate the scene graph
-
-
-
Create scene objects
Create Spatials (e.g. create Geometries)
-
-
-
Make an object appear in the scene
Attach a Spatial to the rootNode
-
-
-
Make an object disappear from the scene
Detach the Spatial from the rootNode
-
-
-
Position/move, turn, or resize an object
Translate, rotate, scale an object. Transform an object.
-
-
-
-
-
-Every JME3 application has a rootNode: Your game automatically inherits the rootNode object from SimpleApplication. Everything attached to the rootNode is part of the scene graph. The elements of the scene graph are Spatials.
-
-
-
A Spatial contains the location, rotation, and scale of an object.
-
-
A Spatial can be loaded, transformed, and saved.
+}
Build and run the code sample. You should see two colored boxes tilted at the same angle.
Translate, rotate, scale an object. Transform an object.
Every JME3 application has a rootNode: Your game automatically inherits the rootNode object from SimpleApplication. Everything attached to the rootNode is part of the scene graph. The elements of the scene graph are Spatials.
A Spatial contains the location, rotation, and scale of an object.
A Spatial can be loaded, transformed, and saved.
There are two types of Spatials: Nodes and Geometries.
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 e153f41de..825eade41 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
@@ -83,8 +83,7 @@ public class HelloTerrain extends SimpleApplication {
AbstractHeightMap heightmap = null;
Texture heightMapImage = assetManager.loadTexture(
"Textures/Terrain/splat/mountains512.png");
- heightmap = new ImageBasedHeightMap(
- ImageToAwt.convert(heightMapImage.getImage(), false, true, 0));
+ heightmap = new ImageBasedHeightMap(heightMapImage.getImage());
heightmap.load();
/** 3. We have prepared material and heightmap.
@@ -105,9 +104,7 @@ public class HelloTerrain extends SimpleApplication {
rootNode.attachChild(terrain);
/** 5. The LOD (level of detail) depends on were the camera is: */
- List<Camera> cameras = new ArrayList<Camera>();
- cameras.add(getCamera());
- TerrainLodControl control = new TerrainLodControl(terrain, cameras);
+ TerrainLodControl control = new TerrainLodControl(terrain, getCamera());
terrain.addControl(control);
}
}
@@ -214,15 +211,7 @@ Here is how you create the heightmap object in your jME code:
Load your prepared heightmap image 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, this image is 8-bit.
-
-
A boolean whether you are using an alphamap – here: true, you will use one.
-
-
+It requires an image from a JME Texture.
Load the heightmap.
@@ -230,8 +219,7 @@ ImageBasedHeightMap expects the following parameters:
@@ -440,9 +428,7 @@ You have created the terrain object.
JME3 includes an optimization that adjusts the level of detail (LOD) 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);
+
TerrainLodControl control = new TerrainLodControl(terrain, getCamera());
terrain.addControl(control);
-
-We recommend downloading the - but of course you can also build the jMonkeyEngine yourself from the sources. In this case, you need the file version system installed (svn).
-
-
We recommend downloading the - but of course you can also build the jMonkeyEngine yourself from the sources. In this case, you need the file version system installed (svn).
\ No newline at end of file
diff --git a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/faq.html b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/faq.html
index ba440061d..95222bd42 100644
--- a/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/faq.html
+++ b/sdk/jme3-core/javahelp/com/jme3/gde/core/docs/jme3/faq.html
@@ -1,456 +1,9 @@
-
-
-You create 3-D models in a 3-D mesh editor, for example Blender, and export it in Ogre Mesh XML or Wavefront OBJ format.
-
-Learn more:3D Models, , , .
-
-Use the jMonkeyEngine SDK to convert models from Ogre XML or Wavefront OBJ formats to .j3o binary format. Load the .j3o file using the AssetManager.
-
-
-
// To load .../jMonkeyProjects/MyGame/assets/Models/Ninja/Ninja.mesh.xml
-Spatial ninja = assetManager.loadModel("Models/Ninja/Ninja.mesh.xml");
-To move or turn or resize a spatial you use transformations. You can concatenate transformations (e.g. perform rotations around several axes in one step using a Quaternion with slerp() or a com.jme3.math.Transform with interpolateTransforms().
-
-
-Change the geometry's translation (position) live in the update loop using setLocalTranslation() for non-physical and setWalkDirection() for physical objects. You can also define and remote-control a spatial's motion using Cinematics, e.g. to record cut scenes.
-
-Learn more:Hello Loop, Update Loop, Custom Controls, Cinematics
-
-Code sample: ,
-
-
-You can set the boolean value in the constructor of TextureKey to flipped or not flipped. Toggle the boolean to see if it fixes your UV wrapping/texture problem:
-
-
-You cannot scale a texture, but you scale the texture coordinates of the mesh the texture is applied to:
-
-
-
mesh.scaleTextureCoordinates(new Vector2f(2,2));
-
-
-
-You can choose among various com.jme3.texture.Texture.WrapModes for individual texture maps of a material: BorderClamp, EdgeClamp, Clamp; MirrorBorderClamp, MirrorEdgeClamp, MirrorClamp; Repeat, MirroredRepeat.
-
-
-Create Textures as image files. Use the AssetManager to load a Material and set the material's texture maps.
-
-Learn more:Hello Material, Materials Overview, Asset Manager, ,
-
-Code sample:
-
-If you use a lit material (based on Lighting.j3md) then you must attach a light source to the rootNode, otherwise you see nothing. If you use lit material colors, make sure you have specified an Ambient color (can be the same as the Diffuse color) if you use an AmbientLight. If you see objects, but they are gray or too dark, set the light color to white, or make it brighter (you can multiply the color value with a scalar), or add a global light source (AmbientLight). Similarly, if everything is white, tune down the lights. If materials flicker under a directional light, change the light direction vector. Change the background color (which is independent of light sources) to get a better contrast while debugging a light problem.
-
-Use com.jme3.shadow.BasicShadowRenderer together with com.jme3.light.DirectionalLight, and setShadowMode().
-
-Learn more:Light and Shadow
-
-Code sample: ,
-
-Assign a texture with an alpha channel to a Material and set the Material's blend mode to alpha. Use this to create transparent or translucent materials such as glass, window panes, water, tree leaves, etc.
-
-
-You can switch the com.jme3.material.RenderState.FaceCullMode to Back, Front, FrontAndBack, or Off. This influences whether the front or backside of an object is being drawn. By default, backsides are culled (not drawn) because they are usually not visible anyway.
-
-
-Use Controls to define the behaviour of types of Spatials. Use Application States to implement global behaviour. Use the simpleUpdate() loop for the remaining tests and interactions. Use Cinematics to remote-control objects in scenes.
-
-Learn more:Hello Loop, Update Loop, Custom Controls, Application States, Cinematics
-
-Players use the mouse to pick up objects, to open doors, to shoot a weapon, etc. Use an Input Listener to respond to mouse clicks, then cast a ray from the player; if it intersect with the bounding volume of a spatial, this is the selected target. The links below contain code samples for both "fixed crosshair" picking and "free mouse pointer" picking.
-
-Learn more:Hello Picking, Mouse Picking, Collision and Intersection, Input Handling, com.jme3.bounding.*, com.jme3.math.Ray, com.jme3.collision.CollisionResults.
-
-Code sample:
-
-Create an animated OgreMesh model with bones in a 3-D mesh editor (e.g. Blender).
-
-Learn more: com.jme3.animation.*, Hello Animation, Animation,
-
-Code sample:
-
-Use collision detection. The most common solution is to use jme's physics integration.
-
-Learn more:Hello Collision, Physics, com.jme3.bullet.*, CapsuleCollisionShape versus CompoundCollisionShape, CharacterControl versus RigidBodyControl.
-
-Add physics controls to Spatials and give them spherical or cylindrical bounding volumes.
-
-Learn more:Hello Physics, Physics, com.jme3.bounding.*, com.jme3.bullet.collisions, com.jme3.bullet.controls.RigidBodyControl,
+this.assetManager.registerLocator("town.zip", ZipLocator.class.getName());
To move or turn or resize a spatial you use transformations. You can concatenate transformations (e.g. perform rotations around several axes in one step using a Quaternion with slerp() or a com.jme3.math.Transform with interpolateTransforms().
Change the geometry's translation (position) live in the update loop using setLocalTranslation() for non-physical and setWalkDirection() for physical objects. You can also define and remote-control a spatial's motion using Cinematics, e.g. to record cut scenes. Learn more:Hello Loop, Update Loop, Custom Controls, Cinematics Code sample: ,
You can set the boolean value in the constructor of TextureKey to flipped or not flipped. Toggle the boolean to see if it fixes your UV wrapping/texture problem:
You cannot scale a texture, but you scale the texture coordinates of the mesh the texture is applied to:
mesh.scaleTextureCoordinates(new Vector2f(2,2));
You can choose among various com.jme3.texture.Texture.WrapModes for individual texture maps of a material: BorderClamp, EdgeClamp, Clamp; MirrorBorderClamp, MirrorEdgeClamp, MirrorClamp; Repeat, MirroredRepeat.
Create Textures as image files. Use the AssetManager to load a Material and set the material's texture maps. Learn more:Hello Material, Materials Overview, Asset Manager, , Code sample:
If you use a lit material (based on Lighting.j3md) then you must attach a light source to the rootNode, otherwise you see nothing. If you use lit material colors, make sure you have specified an Ambient color (can be the same as the Diffuse color) if you use an AmbientLight. If you see objects, but they are gray or too dark, set the light color to white, or make it brighter (you can multiply the color value with a scalar), or add a global light source (AmbientLight). Similarly, if everything is white, tune down the lights. If materials flicker under a directional light, change the light direction vector. Change the background color (which is independent of light sources) to get a better contrast while debugging a light problem.
Assign a texture with an alpha channel to a Material and set the Material's blend mode to alpha. Use this to create transparent or translucent materials such as glass, window panes, water, tree leaves, etc.
You can switch the com.jme3.material.RenderState.FaceCullMode to Back, Front, FrontAndBack, or Off. This influences whether the front or backside of an object is being drawn. By default, backsides are culled (not drawn) because they are usually not visible anyway.
Use Controls to define the behaviour of types of Spatials. Use Application States to implement global behaviour. Use the simpleUpdate() loop for the remaining tests and interactions. Use Cinematics to remote-control objects in scenes. Learn more:Hello Loop, Update Loop, Custom Controls, Application States, Cinematics
Players use the mouse to pick up objects, to open doors, to shoot a weapon, etc. Use an Input Listener to respond to mouse clicks, then cast a ray from the player; if it intersect with the bounding volume of a spatial, this is the selected target. The links below contain code samples for both "fixed crosshair" picking and "free mouse pointer" picking. Learn more:Hello Picking, Mouse Picking, Collision and Intersection, Input Handling, com.jme3.bounding.*, com.jme3.math.Ray, com.jme3.collision.CollisionResults. Code sample:
Create an animated OgreMesh model with bones in a 3-D mesh editor (e.g. Blender). Learn more: com.jme3.animation.*, Hello Animation, Animation, Code sample:
Use collision detection. The most common solution is to use jme's physics integration. Learn more:Hello Collision, Physics, com.jme3.bullet.*, CapsuleCollisionShape versus CompoundCollisionShape, CharacterControl versus RigidBodyControl.
Add physics controls to Spatials and give them spherical or cylindrical bounding volumes. Learn more:Hello Physics, Physics, com.jme3.bounding.*, com.jme3.bullet.collisions, com.jme3.bullet.controls.RigidBodyControl,
Code sample: ,
The following shortened example shows the capabilities of an older graphic card. In this case you decide whether to branch to a low-quality rendering of the unsupported features (if you still want to support this card), or print an error message explaining the user what capabilities the card is missing to play the game.
+
+
+
+Here is an example of the capabilities of an older graphic card:
-
INFO: Running on jMonkey Engine 3 Alpha 0.6
+
INFO: Running on jMonkey Engine 3
INFO: Using LWJGL 2.7.1
INFO: Selected display mode: 1024 x 768 x 0 @0Hz
INFO: Adapter: null
@@ -719,8 +276,30 @@ INFO: Renderer: ATI Radeon X1600 OpenGL Engine
INFO: GLSL Ver: 1.20
INFO: Timer resolution: 1.000 ticks per second
INFO: Capabilities: [FrameBuffer, FrameBufferMRT, FrameBufferMultisample,
-OpenGL20, ARBprogram, GLSL100, GLSL110, GLSL120, VertexTextureFetch,
-FloatTexture, TextureCompressionLATC, NonPowerOfTwoTextures]
-
-Every class that extends 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.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.
public static void main(String[] args) {
AppSettings settings = new AppSettings(true);
settings.setResolution(640,480);
... // other properties see below
@@ -23,86 +6,7 @@ Every class that extends jme3.app.SimpleApplication has properties that can be c
MyGame app = new MyGame(); // or Main or whatever you called your SimpleApplication
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 change some of the settings, but otherwise want the application to load user settings from previous launches.
-
-
-
-
Use app.setShowSettings(true); to present the user with a splashscreen and display settings dialog when starting the game, or app.setShowSettings(false); to hide the custom splashscreen. Set this boolean before calling app.start() on the SimpleApplication.
-
Switch Video Renderer to OpenGL 1.1, OpenGL 2, or OpenGL 3.3. If your graphic card does not support all OpenGL2 features (UnsupportedOperationException: GLSL and OpenGL2 is required for the LWJGL renderer), then you can force your SimpleApplication to use OpenGL1 compatibility. (Then you still can't use special OpenGL2 features, but at least the error goes away and you can continue with the rest.)
OpenGL 2
-
-
-
setBitsPerPixel(32)
Set the color depth.
-1 bpp = black and white, 2 bpp = gray,
-4 bpp = 16 colors, 8 bpp = 256 colors, 24 or 32 bpp = "truecolor".
24
-
-
-
setFramerate(60)
How often per second the engine should try to refresh the frame. For the release, usually 60 fps. Can be lower (30) if you need to free up the CPU for other applications. No use setting it to a higher value than the screen frequency! If the framerate goes below 30 fps, viewers start to notice choppiness or flickering.
-1 (unlimited)
-
-
-
setFullscreen(true)
Set this to true to make the game window fill the whole screen; you need to provide a key that calls app.stop() to exit the fullscreen view gracefully (default: escape).
-Set this 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 set multisampling to higher values such as 8, 16, or 32 samples.
0
-
-
-
setVSync(true)
-setFrequency(60)
Set vertical syncing to true to time the frame buffer to coincide with the refresh frequency of the screen. VSync prevents ugly page tearing artefacts, but is a bit slower; recommened for release build.
-Set VSync to false to deactivate vertical syncing (faster, but possible page tearing artifacts); can remain deactivated during development or for slower PCs.
false
-60 fps
-
-
-
-
-
Settings Property (Input)
Description
Default
-
-
-
setUseInput(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
-
-
-
setUseJoysticks(true)
Activate optional joystick support
false
-
-
-
-
-
Settings Property (Audio)
Description
Default
-
-
-
setAudioRenderer(AppSettings.LWJGL_OPENAL)
Switch Audio Renderer. Currently there is only one option.
OpenAL
-
-
-
setStereo3D(true)
Enable 3D stereo. This feature requires hardware support from the GPU driver. See . Currently, your everday user's hardware does not support this, so you can ignore it for now.
false
-
-
-
-
-
Settings Property (Branding)
Description
Default
-
-
-
setTitle("My Game")
This string will be visible in the titlebar, unless the window is fullscreen.
"jMonkey Engine 3.0"
+}
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 change some of the settings, but otherwise want the application to load user settings from previous launches.
Use app.setShowSettings(true); to present the user with a splashscreen and display settings dialog when starting the game, or app.setShowSettings(false); to hide the custom splashscreen. Set this boolean before calling app.start() on the SimpleApplication.
Switch Video Renderer to OpenGL 1.1, OpenGL 2, or OpenGL 3.3. If your graphic card does not support all OpenGL2 features (UnsupportedOperationException: GLSL and OpenGL2 is required for the LWJGL renderer), then you can force your SimpleApplication to use OpenGL1 compatibility. (Then you still can't use special OpenGL2 features, but at least the error goes away and you can continue with the rest.)
OpenGL 2
setBitsPerPixel(32)
Set the color depth. 1 bpp = black and white, 2 bpp = gray, 4 bpp = 16 colors, 8 bpp = 256 colors, 24 or 32 bpp = "truecolor".
24
setFramerate(60)
How often per second the engine should try to refresh the frame. For the release, usually 60 fps. Can be lower (30) if you need to free up the CPU for other applications. No use setting it to a higher value than the screen frequency! If the framerate goes below 30 fps, viewers start to notice choppiness or flickering.
-1 (unlimited)
setFullscreen(true)
Set this to true to make the game window fill the whole screen; you need to provide a key that calls app.stop() to exit the fullscreen view gracefully (default: escape). Set this 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 set multisampling to higher values such as 8, 16, or 32 samples.
0
setVSync(true) setFrequency(60)
Set vertical syncing to true to time the frame buffer to coincide with the refresh frequency of the screen. VSync prevents ugly page tearing artefacts, but is a bit slower; recommened for release build. Set VSync to false to deactivate vertical syncing (faster, but possible page tearing artifacts); can remain deactivated during development or for slower PCs.
false 60 fps
Settings Property (Input)
Description
Default
setUseInput(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
setUseJoysticks(true)
Activate optional joystick support
false
Settings Property (Audio)
Description
Default
setAudioRenderer(AppSettings.LWJGL_OPENAL)
Switch Audio Renderer. Currently there is only one option.
OpenAL
setStereo3D(true)
Enable 3D stereo. This feature requires hardware support from the GPU driver. See . Currently, your everday user's hardware does not support this, so you can ignore it for now.
false
Settings Property (Branding)
Description
Default
setTitle("My Game")
This string will be visible in the titlebar, unless the window is fullscreen.
-
-A collection of recommendations and expert tips. Feel free to add your own!
-If you are a beginner, you should first game development. We cannot cover all general tips here.
-
Binary 3D model or scene. At the latest 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.
A Material definition. These are pre-defined templates for shader-based Materials.
-Each custom .j3m Material is based on a material definition. Advanced users can create their own material definitions.
Binary 3D model or scene. At the latest 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.
A Material definition. These are pre-defined templates for shader-based Materials. Each custom .j3m Material is based on a material definition. Advanced users can create their own material definitions.