- remove documentation from core plugin git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@10185 75d07b2b-3a1a-0410-a2c5-0572b91ccdca3.0
@ -1,88 +0,0 @@ |
||||
<!-- |
||||
Copyright (c) 2009-2010 jMonkeyEngine |
||||
All rights reserved. |
||||
|
||||
Redistribution and use in source and binary forms, with or without |
||||
modification, are permitted provided that the following conditions are |
||||
met: |
||||
|
||||
* Redistributions of source code must retain the above copyright |
||||
notice, this list of conditions and the following disclaimer. |
||||
|
||||
* Redistributions in binary form must reproduce the above copyright |
||||
notice, this list of conditions and the following disclaimer in the |
||||
documentation and/or other materials provided with the distribution. |
||||
|
||||
* Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||
may be used to endorse or promote products derived from this software |
||||
without specific prior written permission. |
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
--> |
||||
<html> |
||||
<head> |
||||
<title>About jMonkeyEngine SDK</title> |
||||
<link rel="stylesheet" href="nbdocs:/org/netbeans/modules/usersguide/ide.css" type="text/css"> |
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> |
||||
</head> |
||||
<body> |
||||
<h2>About jMonkeyEngine SDK</h2> |
||||
<p> |
||||
The jMonkeyEngine SDK (or "jMonkeyPlatform") is a game development environment for jMonkeyEngine 3. |
||||
</p> |
||||
<p> |
||||
The jMonkeyEngine SDK is based on the NetBeans Platform so you automatically have access to all of the |
||||
developer tools of the NetBeans IDE to create, compile and deploy Java applications. |
||||
On top of that, the jMonkeyEngine SDK provides you with specialized plugins for creating jMonkeyEngine 3 game content. |
||||
</p> |
||||
<h2>Documentation</h2> |
||||
<p> |
||||
This help contains info about most of the functions of the jMonkeyEngine SDK, take a look at the |
||||
"Introduction" section of the help to get started with <a href="/com/jme3/gde/core/docs/sdk/project_creation.html">creating projects</a>. The sections |
||||
on <a href="/com/jme3/gde/core/docs/sdk/model_loader_and_viewer.html">model</a> and <a href="/com/jme3/gde/core/docs/sdk/material_editing.html">material</a> handling will give you information on how you can manage and edit |
||||
your game assets. Finally theres information about how jMonkeyPlatform helps you |
||||
<a href="/com/jme3/gde/core/docs/sdk/code_editor.html">edit your code</a> and <a href="/com/jme3/gde/core/docs/sdk/application_deployment.html">deploy your application</a> to multiple platforms. |
||||
</p> |
||||
<h2>Getting started</h2> |
||||
<p> |
||||
If you are completely new to jMonkeyEngine we suggest you go through the <a href="/com/jme3/gde/core/docs/jme3/beginner/hello_simpleapplication.html">jMonkeyEngine3 tutorials</a> |
||||
first, they will give you an idea on how jMonkeyEngine works and contain lots of little |
||||
good-to-knows that will help you getting your Application up and running in no time. |
||||
</p> |
||||
<p> |
||||
To see some code examples of jMonkeyEngine3 functions, press the "New Project" button and |
||||
create a new "JME3Tests" project. To start coding, create a new "BasicGame" project. |
||||
</p> |
||||
<p> |
||||
Have fun coding!<br/> |
||||
<object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"> |
||||
<param name="content" value="http://jmonkeyengine.org/introduction/team/"> |
||||
<param name="text" value="<html><u>The jMonkeyEngine Team</u></html>"> |
||||
<param name="textFontSize" value="medium"> |
||||
<param name="textColor" value="blue"> |
||||
</object> |
||||
</p> |
||||
</body> |
||||
</html> |
||||
<!-- |
||||
Tip: to create a link which will open in an external web browser, try: |
||||
<object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"> |
||||
<param name="content" value="http://www.netbeans.org/"> |
||||
<param name="text" value="<html><u>http://www.netbeans.org/</u></html>"> |
||||
<param name="textFontSize" value="medium"> |
||||
<param name="textColor" value="blue"> |
||||
</object> |
||||
To create a link to a help set from another module, you need to know the code name base and path, e.g.: |
||||
<a href="nbdocs://org.netbeans.modules.usersguide/org/netbeans/modules/usersguide/configure/configure_options.html">Using the Options Window</a> |
||||
(This link will behave sanely if that module is disabled or missing.) |
||||
--> |
@ -1,53 +0,0 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<!-- |
||||
Copyright (c) 2009-2010 jMonkeyEngine |
||||
All rights reserved. |
||||
|
||||
Redistribution and use in source and binary forms, with or without |
||||
modification, are permitted provided that the following conditions are |
||||
met: |
||||
|
||||
* Redistributions of source code must retain the above copyright |
||||
notice, this list of conditions and the following disclaimer. |
||||
|
||||
* Redistributions in binary form must reproduce the above copyright |
||||
notice, this list of conditions and the following disclaimer in the |
||||
documentation and/or other materials provided with the distribution. |
||||
|
||||
* Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||
may be used to endorse or promote products derived from this software |
||||
without specific prior written permission. |
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
--> |
||||
<!DOCTYPE helpset PUBLIC "-//Sun Microsystems Inc.//DTD JavaHelp HelpSet Version 2.0//EN" "http://java.sun.com/products/javahelp/helpset_2_0.dtd"> |
||||
<helpset version="2.0"> |
||||
<title>jMonkeyEngine SDK Core Help</title> |
||||
<maps> |
||||
<homeID>com.jme3.gde.core.about</homeID> |
||||
<mapref location="core-map.xml"/> |
||||
<mapref location="wiki-map.xml"/> |
||||
</maps> |
||||
<view mergetype="javax.help.AppendMerge"> |
||||
<name>TOC</name> |
||||
<label>Table of Contents</label> |
||||
<type>javax.help.TOCView</type> |
||||
<data>core-toc.xml</data> |
||||
</view> |
||||
<view> |
||||
<name>Search</name> |
||||
<label>Search</label> |
||||
<type>javax.help.SearchView</type> |
||||
<data engine="com.sun.java.help.search.DefaultSearchEngine">JavaHelpSearch</data> |
||||
</view> |
||||
</helpset> |
@ -1,40 +0,0 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<!-- |
||||
Copyright (c) 2009-2010 jMonkeyEngine |
||||
All rights reserved. |
||||
|
||||
Redistribution and use in source and binary forms, with or without |
||||
modification, are permitted provided that the following conditions are |
||||
met: |
||||
|
||||
* Redistributions of source code must retain the above copyright |
||||
notice, this list of conditions and the following disclaimer. |
||||
|
||||
* Redistributions in binary form must reproduce the above copyright |
||||
notice, this list of conditions and the following disclaimer in the |
||||
documentation and/or other materials provided with the distribution. |
||||
|
||||
* Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||
may be used to endorse or promote products derived from this software |
||||
without specific prior written permission. |
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
--> |
||||
<!DOCTYPE map PUBLIC "-//Sun Microsystems Inc.//DTD JavaHelp Map Version 2.0//EN" "http://java.sun.com/products/javahelp/map_2_0.dtd"> |
||||
<map version="2.0"> |
||||
<!--TODO: move spidermonkey page, remove this--> |
||||
<mapID target="spidermonkey" url="spidermonkey.html"/> |
||||
<mapID target="com.jme3.gde.core.about" url="core-about.html"/> |
||||
<mapID target="com.jme3.gde.core.sceneviewer" url="core-sceneviewer.html"/> |
||||
<mapID target="com.jme3.gde.core.updating" url="core-updating.html"/> |
||||
</map> |
@ -1,54 +0,0 @@ |
||||
<!-- |
||||
Copyright (c) 2009-2010 jMonkeyEngine |
||||
All rights reserved. |
||||
|
||||
Redistribution and use in source and binary forms, with or without |
||||
modification, are permitted provided that the following conditions are |
||||
met: |
||||
|
||||
* Redistributions of source code must retain the above copyright |
||||
notice, this list of conditions and the following disclaimer. |
||||
|
||||
* Redistributions in binary form must reproduce the above copyright |
||||
notice, this list of conditions and the following disclaimer in the |
||||
documentation and/or other materials provided with the distribution. |
||||
|
||||
* Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||
may be used to endorse or promote products derived from this software |
||||
without specific prior written permission. |
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
--> |
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> |
||||
<html> |
||||
<head> |
||||
<title></title> |
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> |
||||
</head> |
||||
<body> |
||||
<h2>The OpenGL Window</h2> |
||||
<div class="level2"> |
||||
|
||||
<p> |
||||
The OpenGL window and the SceneExplorer window are shared among plugins to save system resources. This means that you will have to keep an eye on what plugin is using the scene right now and what you are actually modifying in these windows. |
||||
</p> |
||||
|
||||
<p> |
||||
Most plugins will deliver their own UI elements to modify the scene so the SceneExplorer is more of a global tool. The simple SceneComposer however heavily relies on its functions as other plugins might too in the future. |
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
<!-- SECTION "About the SceneViewer and SceneExplorer window" [2258-] --> |
||||
</body> |
||||
</html> |
@ -1,196 +0,0 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<!-- |
||||
Copyright (c) 2009-2010 jMonkeyEngine |
||||
All rights reserved. |
||||
|
||||
Redistribution and use in source and binary forms, with or without |
||||
modification, are permitted provided that the following conditions are |
||||
met: |
||||
|
||||
* Redistributions of source code must retain the above copyright |
||||
notice, this list of conditions and the following disclaimer. |
||||
|
||||
* Redistributions in binary form must reproduce the above copyright |
||||
notice, this list of conditions and the following disclaimer in the |
||||
documentation and/or other materials provided with the distribution. |
||||
|
||||
* Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||
may be used to endorse or promote products derived from this software |
||||
without specific prior written permission. |
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
--> |
||||
<!DOCTYPE toc PUBLIC "-//Sun Microsystems Inc.//DTD JavaHelp TOC Version 2.0//EN" "http://java.sun.com/products/javahelp/toc_2_0.dtd"> |
||||
<toc version="2.0"> |
||||
<tocitem text="jMonkeyEngine SDK" mergetype="javax.help.UniteAppendMerge"> |
||||
<tocitem text="About jMonkeyEngine SDK" target="com.jme3.gde.core.about"/> |
||||
<tocitem text="Introduction"> |
||||
<tocitem text="Creating a Project" target="sdk.project_creation"/> |
||||
<tocitem text="The OpenGL Window" target="com.jme3.gde.core.sceneviewer"/> |
||||
<tocitem text="The SceneExplorer" target="sdk.scene_explorer"/> |
||||
</tocitem> |
||||
<tocitem text="Working with Models and Scenes"> |
||||
<tocitem text="Importing Models" target="sdk.model_loader_and_viewer"/> |
||||
<tocitem text="SceneComposer" target="sdk.scene_composer"/> |
||||
<tocitem text="Terrain Editor" target="sdk.terrain_editor"/> |
||||
<tocitem text="AssetPacks" target="sdk.asset_packs"/> |
||||
<tocitem text="Filters" target="sdk.filters"/> |
||||
<tocitem text="Blender File Support" target="sdk.blender"/> |
||||
<tocitem text="Creating compatible models in Blender" target="jme3.external.blender"/> |
||||
<tocitem text="Creating compatible models in 3DS Max" target="jme3.external.3dsmax"/> |
||||
<tocitem text="Vehicle Creator" target="sdk.vehicle_creator"/> |
||||
</tocitem> |
||||
<tocitem text="Working with Materials"> |
||||
<tocitem text="Using the Material Editor" target="sdk.material_editing"/> |
||||
<tocitem text="Materials Overview" target="jme3.advanced.materials_overview"/> |
||||
<tocitem text="Shaders and Materials in jME3" target="jme3.advanced.jme3_shaders"/> |
||||
</tocitem> |
||||
<tocitem text="Working with Code"> |
||||
<tocitem text="Code Editor" target="sdk.code_editor"/> |
||||
<tocitem text="Version Control" target="sdk.version_control"/> |
||||
<tocitem text="Debugging, Testing" target="sdk.debugging_profiling_testing"/> |
||||
<tocitem text="Using a custom version of jME3" target="sdk.use_own_jme"/> |
||||
</tocitem> |
||||
<tocitem text="Application Deployment"> |
||||
<tocitem text="General" target="sdk.application_deployment"/> |
||||
<tocitem text="Android" target="jme3.android"/> |
||||
</tocitem> |
||||
<tocitem text="jMP Plugin Development" expand="false"> |
||||
<tocitem text="About jMP Plugin Development" target="sdk.development"/> |
||||
<tocitem text="Creating a plugin" target="sdk.development.setup"/> |
||||
<tocitem text="Creating components" target="sdk.development.general"/> |
||||
<tocitem text="Projects and Assets" target="sdk.development.projects_assets"/> |
||||
<tocitem text="Accessing the Scene" target="sdk.development.scene"/> |
||||
<tocitem text="Extending the SceneExplorer" target="sdk.development.sceneexplorer"/> |
||||
<tocitem text="jMP Log Files" target="sdk.log_files"/> |
||||
<!-- <tocitem text="Recipes" expand="false">--> |
||||
<tocitem text="Creating a library plugin from a jar file" target="sdk.development.extension_library"/> |
||||
<tocitem text="Integrate a new model filetype and loader" target="sdk.development.model_loader"/> |
||||
<!-- </tocitem>--> |
||||
</tocitem> |
||||
<tocitem text="Updating the SDK and Engine" target="com.jme3.gde.core.updating"/> |
||||
<tocitem text="Troubleshooting the SDK" target="sdk.troubleshooting"/> |
||||
</tocitem> |
||||
<tocitem text="jMonkeyEngine3 Engine" expand="true"> |
||||
<tocitem text="Beginner Tutorials" expand="false"> |
||||
<tocitem text="Hello SimpleApplication" target="jme3.beginner.hello_simpleapplication"/> |
||||
<tocitem text="Hello Node" target="jme3.beginner.hello_node"/> |
||||
<tocitem text="Hello Assets" target="jme3.beginner.hello_asset"/> |
||||
<tocitem text="Hello Event Loop" target="jme3.beginner.hello_main_event_loop"/> |
||||
<tocitem text="Hello Input System" target="jme3.beginner.hello_input_system"/> |
||||
<tocitem text="Hello Material" target="jme3.beginner.hello_material"/> |
||||
<tocitem text="Hello Animation" target="jme3.beginner.hello_animation"/> |
||||
<tocitem text="Hello Picking" target="jme3.beginner.hello_picking"/> |
||||
<tocitem text="Hello Collision" target="jme3.beginner.hello_collision"/> |
||||
<tocitem text="Hello Terrain" target="jme3.beginner.hello_terrain"/> |
||||
<tocitem text="Hello Audio" target="jme3.beginner.hello_audio"/> |
||||
<tocitem text="Hello Effects" target="jme3.beginner.hello_effects"/> |
||||
<tocitem text="Hello Physics" target="jme3.beginner.hello_physics"/> |
||||
</tocitem> |
||||
<tocitem text="Best Practices" expand="false"> |
||||
<tocitem text="Best Practices" target="jme3.intermediate.best_practices"/> |
||||
<tocitem text="FAQ" target="jme3.faq"/> |
||||
<tocitem text="SimpleApplication" target="jme3.intermediate.simpleapplication"/> |
||||
<tocitem text="How to Use Materials" target="jme3.intermediate.how_to_use_materials"/> |
||||
<tocitem text="Application Settings" target="jme3.intermediate.appsettings"/> |
||||
<tocitem text="File Types" target="jme3.intermediate.file_types"/> |
||||
<tocitem text="Math in jME3" target="jme3.math"/> |
||||
<tocitem text="Math Formulas" target="jme3.intermediate.math"/> |
||||
<tocitem text="Multi-Media Assets Pipeline" target="jme3.intermediate.multi-media_asset_pipeline"/> |
||||
<tocitem text="Optimization" target="jme3.intermediate.optimization"/> |
||||
</tocitem> |
||||
<!-- <tocitem text="Advanced" expand="false">--> |
||||
<tocitem text="Controlling Game Logic" expand="false"> |
||||
<tocitem text="Update Loop" target="jme3.advanced.update_loop"/> |
||||
<tocitem text="Application States" target="jme3.advanced.application_states"/> |
||||
<tocitem text="Custom Controls" target="jme3.advanced.custom_controls"/> |
||||
<tocitem text="Multithreading" target="jme3.advanced.multithreading"/> |
||||
</tocitem> |
||||
<tocitem text="Managing and Moving Objects" expand="false"> |
||||
<tocitem text="Spatial: Node vs Geometry" target="jme3.advanced.spatial"/> |
||||
<tocitem text="Meshes" target="jme3.advanced.mesh"/> |
||||
<tocitem text="Shape" target="jme3.advanced.shape"/> |
||||
<tocitem text="3D Models" target="jme3.advanced.3d_models"/> |
||||
<tocitem text="Custom Meshes" target="jme3.advanced.custom_meshes"/> |
||||
<tocitem text="Asset Manager" target="jme3.advanced.asset_manager"/> |
||||
<tocitem text="Save and Load" target="jme3.advanced.save_and_load"/> |
||||
<tocitem text="Collision and Intersection" target="jme3.advanced.collision_and_intersection"/> |
||||
<tocitem text="Mouse Picking" target="jme3.advanced.mouse_picking"/> |
||||
<tocitem text="Animation" target="jme3.advanced.animation"/> |
||||
<tocitem text="Cinematics" target="jme3.advanced.cinematics"/> |
||||
<tocitem text="MotionPath" target="jme3.advanced.motionpath"/> |
||||
</tocitem> |
||||
<tocitem text="Materials, Light and Shadow" expand="false"> |
||||
<tocitem text="jME3 and Shaders" target="jme3.advanced.jme3_shaders"/> |
||||
<tocitem text="Materials Overview" target="jme3.advanced.materials_overview"/> |
||||
<tocitem text="J3MD Material Definitions" target="jme3.advanced.material_definitions"/> |
||||
<tocitem text="J3M Material Files" target="jme3.advanced.j3m_material_files"/> |
||||
<tocitem text="Light and Shadow" target="jme3.advanced.light_and_shadow"/> |
||||
</tocitem> |
||||
<tocitem text="Physics Integration" expand="false"> |
||||
<tocitem text="Physics Overview" target="jme3.advanced.physics"/> |
||||
<tocitem text="Multithreading" target="jme3.advanced.bullet_multithreading"/> |
||||
<tocitem text="Hinges and Joints" target="jme3.advanced.hinges_and_joints"/> |
||||
<tocitem text="Walking Character Example" target="jme3.advanced.walking_character"/> |
||||
<tocitem text="Ragdoll Example" target="jme3.advanced.ragdoll"/> |
||||
<tocitem text="Vehicle Example" target="jme3.advanced.vehicles"/> |
||||
</tocitem> |
||||
<tocitem text="Audio" expand="false"> |
||||
<tocitem text="Audio" target="jme3.advanced.audio"/> |
||||
<tocitem text="Audio Environment Presets" target="jme3.advanced.audio_environment_presets"/> |
||||
<!--tocitem text="Video" target="jme3.advanced.video"/--> |
||||
</tocitem> |
||||
<tocitem text="Effects" expand="false"> |
||||
<tocitem text="Effects Overview" target="jme3.advanced.effects_overview"/> |
||||
<tocitem text="Bloom and Glow" target="jme3.advanced.bloom_and_glow"/> |
||||
<tocitem text="Particle Emitters" target="jme3.advanced.particle_emitters"/> |
||||
</tocitem> |
||||
<tocitem text="Landscapes" expand="false"> |
||||
<tocitem text="Sky" target="jme3.advanced.sky"/> |
||||
<tocitem text="Terrain" target="jme3.advanced.terrain"/> |
||||
<tocitem text="Terrain Collision" target="jme3.advanced.terrain_collision"/> |
||||
<tocitem text="Grid Terrain" target="jme3.advanced.endless_terraingrid"/> |
||||
<tocitem text="Simple Water" target="jme3.advanced.water"/> |
||||
<tocitem text="Post-Processor Water" target="jme3.advanced.post-processor_water"/> |
||||
</tocitem> |
||||
<tocitem text="Networking" expand="false"> |
||||
<tocitem text="Networking" target="jme3.advanced.networking"/> |
||||
<tocitem text="Headless Server" target="jme3.advanced.headless_server"/> |
||||
<tocitem text="Open Game Finder" target="jme3.advanced.open_game_finder"/> |
||||
<tocitem text="MonkeyZone demo" target="jme3.advanced.monkey_zone"/> |
||||
</tocitem> |
||||
<tocitem text="Camera" expand="false"> |
||||
<tocitem text="Camera" target="jme3.advanced.camera"/> |
||||
<tocitem text="Multiple Cameras" target="jme3.advanced.multiple_camera_views"/> |
||||
<tocitem text="Camera Follows Character" target="jme3.advanced.making_the_camera_follow_a_character"/> |
||||
<tocitem text="Remote-Control Camera" target="jme3.advanced.remote-controlling_the_camera"/> |
||||
<tocitem text="Screen Capture" target="jme3.advanced.capture_audio_video_to_a_file"/> |
||||
<tocitem text="Screen Shots" target="jme3.advanced.screenshots"/> |
||||
</tocitem> |
||||
<tocitem text="User Interaction" expand="false"> |
||||
<tocitem text="Input Handling" target="jme3.advanced.input_handling"/> |
||||
<tocitem text="Combo Moves" target="jme3.advanced.combo_moves"/> |
||||
<tocitem text="NiftyGUI" target="jme3.advanced.nifty_gui"/> |
||||
<tocitem text="Head-Up Display (HUD)" target="jme3.advanced.hud"/> |
||||
<tocitem text="Loading Screen" target="jme3.advanced.loading_screen"/> |
||||
<tocitem text="Swing Canvas" target="jme3.advanced.swing_canvas"/> |
||||
<tocitem text="Game Localization" target="jme3.advanced.localization"/> |
||||
</tocitem> |
||||
<tocitem text="Debugging / Logging" expand="false"> |
||||
<tocitem text="Logging" target="jme3.advanced.logging"/> |
||||
<tocitem text="Debugging" target="jme3.advanced.debugging"/> |
||||
<tocitem text="Graphic Card Capabilities" target="jme3.advanced.read_graphic_card_capabilites"/> |
||||
</tocitem> |
||||
<!-- </tocitem>--> |
||||
</tocitem> |
||||
</toc> |
@ -1,66 +0,0 @@ |
||||
<!-- |
||||
Copyright (c) 2009-2010 jMonkeyEngine |
||||
All rights reserved. |
||||
|
||||
Redistribution and use in source and binary forms, with or without |
||||
modification, are permitted provided that the following conditions are |
||||
met: |
||||
|
||||
* Redistributions of source code must retain the above copyright |
||||
notice, this list of conditions and the following disclaimer. |
||||
|
||||
* Redistributions in binary form must reproduce the above copyright |
||||
notice, this list of conditions and the following disclaimer in the |
||||
documentation and/or other materials provided with the distribution. |
||||
|
||||
* Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||
may be used to endorse or promote products derived from this software |
||||
without specific prior written permission. |
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
--> |
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> |
||||
<html> |
||||
<head> |
||||
<title></title> |
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> |
||||
</head> |
||||
<body> |
||||
<h2><a>Automatically Updating jMonkeyEngine SDK</a></h2><div></div><h3><a>Getting stable updates</a></h3><div> |
||||
<p> The jMonkeyPlatform software includes an automatic web update feature. To run an update, simply go to Help→Check for Updates and you will get the most current stable update of the <acronym |
||||
title="Software Development Kit">SDK</acronym> and the engine. By default the IDE will check every week for new update and inform you about them with a symbol in the lower right.</p></div><h3><a |
||||
name="testing_the_nightly_version" id="testing_the_nightly_version">Testing the nightly version</a></h3><div |
||||
class="level3"><p> You can test the nightly version with all the latest untested features to give feedback to the developers. Be warned however, the changes in the nightly versions might break your current game project if heavy changes have been committed.</p><p> To make sure that you do not break your current development environment it is recommended to use a separate application and settings directory for the nightly version.</p><ul><li |
||||
class="level1"><div |
||||
class="li"> Copy the whole application (folder) to a new name like jmonkeyplatform_nightly.</div></li><li |
||||
class="level1"><div |
||||
class="li"> Edit the file jmonkeyplatform.conf in the etc directory of the folder. Mac users have to right-click the application and select "Show package contents" and then navigate to Contents/Resources/jmonkeyplatform.</div></li><li |
||||
class="level1"><div |
||||
class="li"> Change the default_userdir or default_mac_userdir from "${HOME}/.${APPNAME}/version" to something like "${HOME}/.${APPNAME}/nightly".</div></li></ul><p> Then start the new application and have your <acronym |
||||
title="Software Development Kit">SDK</acronym> being updated to the most current nightly version:</p><ul><li |
||||
class="level1"><div |
||||
class="li"> Go to Tools→Plugins</div></li><li |
||||
class="level1"><div |
||||
class="li"> Select the "Settings" tab</div></li><li |
||||
class="level1"><div |
||||
class="li"> Select the checkbox for "jMonkeyPlatform nightly svn"</div></li><li |
||||
class="level1"><div |
||||
class="li"> Make sure the "force install to shared directories" checkbox is selected</div></li><li |
||||
class="level1"><div |
||||
class="li"> Select the "Updates" tab</div></li><li |
||||
class="level1"><div |
||||
class="li"> Press "Reload Catalog"</div></li><li |
||||
class="level1"><div |
||||
class="li"> Press "Update"</div></li></ul></div> |
||||
</body> |
||||
</html> |
Before Width: | Height: | Size: 191 KiB |
Before Width: | Height: | Size: 73 KiB |
Before Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 32 KiB |
@ -1,91 +0,0 @@ |
||||
|
||||
<h1><a>Models and Scenes</a></h1> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Like <a href="/com/jme3/gde/core/docs/jme3/advanced/shape.html">Shape</a>s, 3D models are also made up of <a href="/com/jme3/gde/core/docs/jme3/advanced/mesh.html">Mesh</a>es, but models are more complex than Shapes. While Shapes are built into jME3, you typically create models in external 3D Mesh Editors. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT1 SECTION "Models and Scenes" [1-226] --> |
||||
<h2><a>Using Models and Scenes with jME3</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
To use 3D models in a jME3 application: |
||||
</p> |
||||
<ol> |
||||
<li><div> Export the 3D model in Ogre <acronym title="Extensible Markup Language">XML</acronym> or Wavefront OBJ format. Export Scenes as Ogre DotScene format.</div> |
||||
</li> |
||||
<li><div> Save the files into a subdirectory of your jME3 project's <code>assets</code> directory.</div> |
||||
</li> |
||||
<li><div> In your code, you use the <a href="/com/jme3/gde/core/docs/jme3/advanced/asset_manager.html">Asset Manager</a> to load models as <a href="/com/jme3/gde/core/docs/jme3/advanced/spatial.html">Spatial</a>s into a jME application. <pre>Spatial model = assetManager.loadModel( |
||||
"Models/MonkeyHead/MonkeyHead.mesh.xml" );</pre> |
||||
</div> |
||||
</li> |
||||
<li><div> (For the release build:) Use the jMonkeyEngine <acronym title="Software Development Kit">SDK</acronym> to convert models to .j3o format. You don't need this step as long you still develop and test the aplication within the jMonkeyEngine <acronym title="Software Development Kit">SDK</acronym>.</div> |
||||
</li> |
||||
</ol> |
||||
|
||||
</div> |
||||
<!-- EDIT2 SECTION "Using Models and Scenes with jME3" [227-901] --> |
||||
<h2><a>Creating Models and Scenes</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
To create 3D models and scenes, you need a 3D Mesh Editor such as <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://www.blender.org/"><param name="text" value="<html><u>Blender</u></html>"><param name="textColor" value="blue"></object>, with an OgreXML Exporter plugin. |
||||
</p> |
||||
|
||||
<p> |
||||
<strong>Tip:</strong> Learn how to create <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://en.wikibooks.org/wiki/Blender_3D:_Noob_to_Pro/UV_Map_Basics"><param name="text" value="<html><u>UV textures</u></html>"><param name="textColor" value="blue"></object> for more complex models, it looks more professional. |
||||
</p> |
||||
|
||||
<p> |
||||
3D model editors are third-party products, so please consult their documentation for instructions how to use them. Here is an example workflow for Blender users: |
||||
|
||||
</p> |
||||
<ul> |
||||
<li><div> <a href="/com/jme3/gde/core/docs/jme3/external/blender.html">Creating jME3 compatible 3D models in Blender</a></div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
|
||||
To export your models as Ogre <acronym title="Extensible Markup Language">XML</acronym> meshes with materials: |
||||
</p> |
||||
<ol> |
||||
<li><div> Open the menu File > Export > OgreXML Exporter to open the exporter dialog.</div> |
||||
</li> |
||||
<li><div> In the Export Materials field: Give the material the same name as the model. For example, the model <code>something.mesh.xml</code> goes with <code>something.material</code>, plus (optionally) <code>something.skeleton.xml</code>, and some <acronym title="Joint Photographics Experts Group">JPG</acronym> files.</div> |
||||
</li> |
||||
<li><div> In the Export Meshes field: Select a target subdirectory of your <code>assets/Models/</code> directory. E.g. <code>assets/Models/something/</code>.</div> |
||||
</li> |
||||
<li><div> Activate the following exporter settings: </div> |
||||
<ul> |
||||
<li><div> Copy Textures: YES</div> |
||||
</li> |
||||
<li><div> Rendering Materials: YES</div> |
||||
</li> |
||||
<li><div> Flip Axis: YES</div> |
||||
</li> |
||||
<li><div> Require Materials: YES</div> |
||||
</li> |
||||
<li><div> Skeleton name follows mesh: YES</div> |
||||
</li> |
||||
</ul> |
||||
</li> |
||||
<li><div> Click export.</div> |
||||
</li> |
||||
</ol> |
||||
|
||||
<p> |
||||
|
||||
You can now use the <a href="/com/jme3/gde/core/docs/sdk.html">jMonkeyEngine SDK</a> to <a href="/com/jme3/gde/core/docs/sdk/model_loader_and_viewer.html">load and view models</a>. You can <a href="/com/jme3/gde/core/docs/sdk/scene_composer.html">create scenes</a> from them and write cde that loads them into your application. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT3 SECTION "Creating Models and Scenes" [902-] --> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:3d_models?do=export_xhtmlbody">view online version</a></em></p> |
Before Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 24 KiB |
@ -1,402 +0,0 @@ |
||||
|
||||
<h1><a>Animation in jME3</a></h1> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
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. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT1 SECTION "Animation in jME3" [1-167] --> |
||||
<h2><a>Requirements</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
JME3 only loads and plays animated models, it does not create them. |
||||
</p> |
||||
|
||||
<p> |
||||
What is required for an animated model? (<a href="/com/jme3/gde/core/docs/jme3/terminology#animation.html">See also: Animation terminology</a>) |
||||
</p> |
||||
<ol> |
||||
<li><div> For each model, you have to segment the model into a skeleton (bone rigging). </div> |
||||
</li> |
||||
<li><div> For each motion, you have to specify how the animation distorts parts of the model (skinning). </div> |
||||
</li> |
||||
<li><div> For each animation, you have to specify a series of snapshots of how the bones are positioned (keyframes).</div> |
||||
</li> |
||||
<li><div> One model can contain several animations. You give every animation a name when you save it in the mesh editor.</div> |
||||
</li> |
||||
</ol> |
||||
|
||||
<p> |
||||
|
||||
Unless you download free models, or buy them from a 3D artist, you must create your animated models in an <strong>external mesh editor</strong> (for example, Blender) yourself. |
||||
</p> |
||||
<ul> |
||||
<li><div> <a href="/com/jme3/gde/core/docs/sdk/blender.html">Converting Blender Models to JME3 (.J3o files)</a></div> |
||||
</li> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://www.youtube.com/user/aramakara"><param name="text" value="<html><u>Video Series: Creating models in Blender, OgreMax, 3dsMax</u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://www.youtube.com/watch?v=NdjC9sCRV0s"><param name="text" value="<html><u>Video: Creating and Exporting OgreXML Animations from Blender 2.61 to JME3 </u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="https://docs.google.com/fileview?id=0B9hhZie2D-fENDBlZDU5MzgtNzlkYi00YmQzLTliNTQtNzZhYTJhYjEzNWNk&hl=en"><param name="text" value="<html><u>Scene Workflow: Exporting OgreXML scenes from Blender to JME3</u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="https://docs.google.com/leaf?id=0B9hhZie2D-fEYmRkMTYwN2YtMzQ0My00NTM4LThhOTYtZTk1MTRlYTNjYTc3&hl=en"><param name="text" value="<html><u>Animation Workflow: Create Animated UV-Mapped OgreXML Models in Blender, and use them in JME3</u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://www.youtube.com/watch?v=IDHMWsu_PqA"><param name="text" value="<html><u>Video: Creating Worlds with Instances in Blender</u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
|
||||
What is required in your JME3-based Java class? |
||||
</p> |
||||
<ul> |
||||
<li><div> One Animation Control per animated model</div> |
||||
</li> |
||||
<li><div> As many Animation Channels per Control as you need to play your animations. In simple cases one channel is enough, sometimes you need two or more Channels per model to play gestures and motions in parallel.</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT2 SECTION "Requirements" [168-2025] --> |
||||
<h2><a>Code Samples</a></h2> |
||||
<div> |
||||
<ul> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/model/anim/TestSpatialAnim.java"><param name="text" value="<html><u>TestSpatialAnim.java</u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/model/anim/TestBlenderAnim.java"><param name="text" value="<html><u>TestBlenderAnim.java</u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/model/anim/TestBlenderObjectAnim.java"><param name="text" value="<html><u>TestBlenderObjectAnim.java</u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/model/anim/TestOgreAnim.java"><param name="text" value="<html><u>TestOgreAnim.java</u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/model/anim/TestOgreComplexAnim.java"><param name="text" value="<html><u>TestOgreComplexAnim.java</u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/model/anim/TestCustomAnim.java"><param name="text" value="<html><u>TestCustomAnim.java</u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT3 SECTION "Code Samples" [2026-2934] --> |
||||
<h2><a>Controlling Animations</a></h2> |
||||
<div> |
||||
|
||||
</div> |
||||
<!-- EDIT4 SECTION "Controlling Animations" [2935-2970] --> |
||||
<h3><a>The Animation Control</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Create one <code>com.jme3.animation.AnimControl</code> 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 Controls. The control object gives you access to the available animation sequences in the model. |
||||
</p> |
||||
<pre> AnimControl playerControl; // you need one Control 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</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT5 SECTION "The Animation Control" [2971-3610] --> |
||||
<h3><a>Animation Channels</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
An Animation Control has several Animation Channels (<code>com.jme3.animation.AnimChannel</code>). Each channel can play one animation sequence at a time. |
||||
</p> |
||||
|
||||
<p> |
||||
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. |
||||
</p> |
||||
<pre> AnimChannel channel_walk = playerControl.createChannel(); |
||||
AnimChannel channel_jump = playerControl.createChannel(); |
||||
...</pre> |
||||
|
||||
<p> |
||||
To reset a Control, call <code>control.clearChannels();</code> |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT6 SECTION "Animation Channels" [3611-4244] --> |
||||
<h2><a>Animation Control Properties</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
The following information is available for an AnimControl. |
||||
|
||||
</p> |
||||
<div><table> |
||||
<tr> |
||||
<th>AnimControl Property</th><th>Usage</th> |
||||
</tr> |
||||
<tr> |
||||
<td>createChannel()</td><td>Returns a new channel, controlling all bones by default.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>getNumChannels()</td><td>The number of channels registered to this Control.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>getChannel(0)</td><td>Gets individual channels by index number. At most <code>getNumChannels()</code>.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>clearChannels()</td><td>Clear all channels in this control.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>addListener(animEventListener) <br/> |
||||
removeListener(animEventListener) <br/> |
||||
clearListeners() </td><td>Adds or removes listeners to receive animation related events.</td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT8 TABLE [4347-4816] --><div><table> |
||||
<tr> |
||||
<th>AnimControl Property</th><th>Usage</th> |
||||
</tr> |
||||
<tr> |
||||
<td>setAnimations(aniHashMap)</td><td>Sets the animations that this AnimControl is capable of playing. The animations must be compatible with the skeleton given in the constructor.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>addAnim(boneAnim) <br/> |
||||
removeAnim(boneAnim)</td><td>Adds or removes an animation from this Control.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>getAnimationNames()</td><td>A String Collection of names of all animations that this Control can play for this model.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>getAnim("anim")</td><td>Retrieve an animation from the list of animations.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>getAnimationLength("anim")</td><td>Returns the length of the given named animation in seconds</td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT9 TABLE [4818-5378] --><div><table> |
||||
<tr> |
||||
<th>AnimControl Property</th><th>Usage</th> |
||||
</tr> |
||||
<tr> |
||||
<td>getSkeleton()</td><td>The Skeleton object controlled by this Control.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>getTargets()</td><td>The Skin objects controlled by this Control, as Mesh array.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>getAttachmentsNode("bone")</td><td>Returns the attachment node of a bone. Attach models and effects to this node to make them follow this bone's motions.</td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT10 TABLE [5380-5695] --> |
||||
</div> |
||||
<!-- EDIT7 SECTION "Animation Control Properties" [4245-5697] --> |
||||
<h2><a>Animation Channel Properties</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
The following properties are set per AnimChannel. |
||||
|
||||
</p> |
||||
<div><table> |
||||
<tr> |
||||
<th>AnimChannel Property</th><th>Usage</th> |
||||
</tr> |
||||
<tr> |
||||
<td>setLoopMode(LoopMode.Loop); </td><td> From now on, the animation on this channel will repeat from the beginning when it ends. </td> |
||||
</tr> |
||||
<tr> |
||||
<td>setLoopMode(LoopMode.DontLoop); </td><td> From now on, the animation on this channel will play once, and the freeze at the last keyframe. </td> |
||||
</tr> |
||||
<tr> |
||||
<td>setLoopMode(LoopMode.Cycle); </td><td> From now on, the animation on this channel will play forward, then backward, then again forward, and so on. </td> |
||||
</tr> |
||||
<tr> |
||||
<td>setSpeed(1f); </td><td> From now on, play this animation slower (<1f) or faster (>1f), or with default speed (1f). </td> |
||||
</tr> |
||||
<tr> |
||||
<td>setTime(1.3f); </td><td> Fast-forward or rewind to a certain moment in time of this animation. </td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT12 TABLE [5791-6415] --> |
||||
<p> |
||||
|
||||
The following information is available for a channel. |
||||
|
||||
</p> |
||||
<div><table> |
||||
<tr> |
||||
<th>AnimChannel Property</th><th>Usage</th> |
||||
</tr> |
||||
<tr> |
||||
<td>getAnimationName()</td><td>The name of the animation playing on this channel. Returns <code>null</code> when no animation is playing.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>getLoopMode()</td><td>The current loop mode on this channel. The returned com.jme3.animation enum can be LoopMode.Loop, LoopMode.DontLoop, or LoopMode.Cycle.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>getAnimMaxTime()</td><td>The total length of the animation on this channel. Or <code>0f</code> if nothing is playing.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>getTime()</td><td>How long the animation on this channel has been playing. It returns <code>0f</code> if the channel has not started playing yet, or a value up to getAnimMaxTime().</td> |
||||
</tr> |
||||
<tr> |
||||
<td>getControl()</td><td>The AnimControl that belongs to this AnimChannel.</td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT13 TABLE [6472-7105] --> |
||||
<p> |
||||
|
||||
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). |
||||
|
||||
</p> |
||||
<div><table> |
||||
<tr> |
||||
<th>AnimChannel Methods</th><th>Usage</th> |
||||
</tr> |
||||
<tr> |
||||
<td>addAllBones()</td><td>Add all the bones of the model's skeleton to be influenced by this animation channel. (default)</td> |
||||
</tr> |
||||
<tr> |
||||
<td>addBone("bone1") <br/> |
||||
addBone(bone1)</td><td>Add a single bone to be influenced by this animation channel.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>addToRootBone("bone1") <br/> |
||||
addToRootBone(bone1) </td><td>Add a series of bones to be influenced by this animation channel: Add all bones, starting from the given bone, to the root bone.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>addFromRootBone("bone1") <br/> |
||||
addFromRootBone(bone1) </td><td>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.</td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT14 TABLE [7345-7966] --> |
||||
</div> |
||||
<!-- EDIT11 SECTION "Animation Channel Properties" [5698-7968] --> |
||||
<h2><a>Playing Animations</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Animations are played by channel. <strong>Note:</strong> Whether the animation channel plays continuously or only once, depends on the Loop properties you have set. |
||||
|
||||
</p> |
||||
<div><table> |
||||
<tr> |
||||
<th>Channel Method</th><th>Usage</th> |
||||
</tr> |
||||
<tr> |
||||
<td>channel_walk.setAnim("Walk",0.50f); </td><td> Start the animation named "Walk" on channel channel_walk. <br/> |
||||
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.</td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT16 TABLE [8154-8480] --> |
||||
<p> |
||||
|
||||
<strong>Tip:</strong> Use the AnimEventLister below to react at the end or start of an animation cycle. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT15 SECTION "Playing Animations" [7969-8573] --> |
||||
<h3><a>Usage Example</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
In this short example, we define the space key to trigger playing the "Walk" animation on channel2. |
||||
</p> |
||||
<pre> public void simpleInitApp() { |
||||
... |
||||
inputManager.addMapping("Walk", new KeyTrigger(KeyInput.KEY_SPACE)); |
||||
inputManager.addListener(actionListener, "Walk"); |
||||
... |
||||
} |
||||
|
||||
private ActionListener actionListener = new ActionListener() { |
||||
public void onAction(String name, boolean keyPressed, float tpf) { |
||||
if (name.equals("Walk") && !keyPressed) { |
||||
if (!channel2.getAnimationName().equals("Walk")) { |
||||
channel2.setLoopMode(LoopMode.Loop); |
||||
channel2.setAnim("Walk", 0.50f); |
||||
} |
||||
} |
||||
} |
||||
};</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT17 SECTION "Usage Example" [8574-9263] --> |
||||
<h2><a>Animation Event Listener</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
A jME3 application that contains animations can implement the <code>com.jme3.animation.AnimEventListener</code> interface. |
||||
</p> |
||||
<pre>public class HelloAnimation extends SimpleApplication |
||||
implements AnimEventListener { ... }</pre> |
||||
|
||||
<p> |
||||
This optional Listener enables you to respond to animation start and end events, onAnimChange() and onAnimCycleDone(). |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT18 SECTION "Animation Event Listener" [9264-9667] --> |
||||
<h3><a>Responding to Animation End</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
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. |
||||
</p> |
||||
|
||||
<p> |
||||
You have access to the following objects: |
||||
</p> |
||||
<ul> |
||||
<li><div> The Control to which the listener is assigned.</div> |
||||
</li> |
||||
<li><div> The animation channel being played.</div> |
||||
</li> |
||||
<li><div> The name of the animation that has just finished playing.</div> |
||||
</li> |
||||
</ul> |
||||
<pre> 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); |
||||
} |
||||
}</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT19 SECTION "Responding to Animation End" [9668-10458] --> |
||||
<h3><a>Responding to Animation Start</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
The onAnimChange() event is invoked every time before an animation is set by the user to be played on a given channel (<code>channel.setAnim()</code>). |
||||
</p> |
||||
|
||||
<p> |
||||
You have access to the following objects |
||||
</p> |
||||
<ul> |
||||
<li><div> The Control to which the listener is assigned.</div> |
||||
</li> |
||||
<li><div> The animation channel being played.</div> |
||||
</li> |
||||
<li><div> The name of the animation that will start playing.</div> |
||||
</li> |
||||
</ul> |
||||
<pre> 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); |
||||
} |
||||
}</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT20 SECTION "Responding to Animation Start" [10459-] --> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:animation?do=export_xhtmlbody">view online version</a></em></p> |
@ -1,353 +0,0 @@ |
||||
|
||||
<h1><a>Application States</a></h1> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
The <code>com.jme3.app.state.AppState</code> class is a customizable jME3 interface that allows you to control the global game logic ??? the overall game mechanics. (To control the behaviour of a Spatial, see <a href="/com/jme3/gde/core/docs/jme3/advanced/custom_controls.html">Custom Controls</a> instead. Controls and AppStates can be used together.) |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT1 SECTION "Application States" [1-324] --> |
||||
<h2><a>Overview</a></h2> |
||||
<div> |
||||
|
||||
</div> |
||||
<!-- EDIT2 SECTION "Overview" [325-346] --> |
||||
<h3><a>Use Case Examples</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
There are situations during your game development where you think: |
||||
</p> |
||||
<ul> |
||||
<li><div> Mouse and key inputs are handled differently in-game versus in the main menu. Can I group a set of input handler settings, and activate and deactivate them all in one step? </div> |
||||
</li> |
||||
<li><div> I have the in-game scene, and a character editor, and a Captain's Quarters screen. Can I group a set of nodes and behaviours, and swap them in and out in one step?</div> |
||||
</li> |
||||
<li><div> When I pause the game, I want the character's "idle" animation to continue, but all other loops and game events should stop. How do I define what happens when the game is paused/unpaused? </div> |
||||
</li> |
||||
<li><div> I have a conditional block that takes up a lot of space in my simpleUpdate() loop. Can I wrap up this block of code, and switch it on and off in one step?</div> |
||||
</li> |
||||
<li><div> Can I package everything that belongs in-game, and everything that belongs to the menu screen, and switch between these two "big states" in one step? </div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
|
||||
You can! This is what AppStates are there for. An AppState class is subset of (or an extension to) your application. Every AppState class has access to all fields in your main application (AssetManager, ViewPort, StateManager, InputManager, RootNode, GuiNode, etc) and hooks into the main update loop. An AppState can contain: |
||||
</p> |
||||
<ul> |
||||
<li><div> a subset of class fields, functions, methods (game state data and accessors), </div> |
||||
</li> |
||||
<li><div> a subset of <acronym title="Graphical User Interface">GUI</acronym> elements and their listeners, </div> |
||||
</li> |
||||
<li><div> a subset of input handlers and mappings, </div> |
||||
</li> |
||||
<li><div> a subset of nodes that you load and attach to the rootNode, </div> |
||||
</li> |
||||
<li><div> a subset of conditional actions that you branch to in the simpleUpdate() loop, </div> |
||||
</li> |
||||
<li><div> a subset of other AppStates and Controls</div> |
||||
</li> |
||||
<li><div> ??? or combinations thereof. </div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT3 SECTION "Use Case Examples" [347-2034] --> |
||||
<h3><a>Supported Features</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Each AppState lets you define what happens in the following situations: |
||||
</p> |
||||
<ul> |
||||
<li><div> <strong>The AppState is initialized:</strong> You load and initialize game data, InputHandlers, AppStates and Controls and attach nodes. <br/> |
||||
The AppState has its own simpleInitApp() method, so to speak.</div> |
||||
</li> |
||||
<li><div> <strong>The AppState has been enabled (unpaused):</strong> This toggles a boolean isEnabled() to true. Here you attach nodes and listeners that should become active while it's running. </div> |
||||
</li> |
||||
<li><div> <strong>While the AppState is running/paused:</strong> You can poll isEnabled() to define paused and unpaused game behaviour in the update() loop that. Polls and modify the game state, modify the scene graph, and triggers events. If !isEnabled(), write code that skips the running sections of this AppState's <code>update()</code> loop. <br/> |
||||
Each AppState has its own update loop, which hooks into the main simpleUpdate() loop (callback). </div> |
||||
</li> |
||||
<li><div> <strong>The AppState has been disabled (paused):</strong> This toggles a boolean isEnabled() to false. Switch to your specific "paused" state. </div> |
||||
</li> |
||||
<li><div> <strong>The AppState is cleaned up:</strong> Here you decide whether to save this AppState's game state, unregister Controls and InputHandlers, detach related AppStates, and detach nodes from the rootNode.</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
|
||||
<p><div>Tip: AppStates are extremely handy to swap out, or pause/unpause whole sets of other AppStates. For example, an InGameState (loads in-game <acronym title="Graphical User Interface">GUI</acronym>, activates click-to-shoot input mappings, inits game content, starts game loop) versus MainScreenState (stops game loop, saves and detaches game content, switches to menu screen <acronym title="Graphical User Interface">GUI</acronym>, switches to click-to-select input mappings). |
||||
</div></p> |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT4 SECTION "Supported Features" [2035-3649] --> |
||||
<h3><a>Usage</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
To implement game logic: |
||||
</p> |
||||
<ol> |
||||
<li><div> Create one AbstractAppState instance for each set of game mechanics. </div> |
||||
</li> |
||||
<li><div> Implement game behaviour in the AppState's update() method.</div> |
||||
<ul> |
||||
<li><div> You can pass custom data as arguments in the constructor.</div> |
||||
</li> |
||||
<li><div> The AppState has access to everything inside the app's scope via the Application <code>app</code> object.</div> |
||||
</li> |
||||
</ul> |
||||
</li> |
||||
<li><div> Attach the AppState to the AppStateManager (<code>stateManager.attach(myAppState);</code>).</div> |
||||
</li> |
||||
<li><div> Activate and deactivate (unpause and pause) the AppStates that you need.</div> |
||||
</li> |
||||
</ol> |
||||
|
||||
<p> |
||||
|
||||
When you add several AppStates to one Application and activate them, their initialize() methods and update() loops are executed in the order in which the AppStates were added to the AppStateManager. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT5 SECTION "Usage" [3650-4363] --> |
||||
<h3><a>Code Samples</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
JME3 comes with a BulletAppState that implements Physical behaviour (using the jBullet library). You, for example, could write an Artificial Intelligence AppState to control all your enemy units. Existing examples in the code base include: |
||||
</p> |
||||
<ul> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/bullet-common/com/jme3/bullet/BulletAppState.java"><param name="text" value="<html><u>BulletAppState</u></html>"><param name="textColor" value="blue"></object> controls physical behaviour in PhysicsControl'ed Spatials.</div> |
||||
</li> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/app/state/TestAppStates.java"><param name="text" value="<html><u>TestAppStates.java</u></html>"><param name="textColor" value="blue"></object> an example of a custom AppState</div> |
||||
<ul> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/app/state/RootNodeState.java"><param name="text" value="<html><u>RootNodeState.java</u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
</ul> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT6 SECTION "Code Samples" [4364-5144] --> |
||||
<h2><a>AppState</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
The AppState interface lets you initialize sets of objects, and hook a set of continously executing code into the main loop. |
||||
|
||||
</p> |
||||
<div><table> |
||||
<tr> |
||||
<th>AppState Method</th><th>Usage</th> |
||||
</tr> |
||||
<tr> |
||||
<td>initialize(asm,app)</td><td>When this AppState is added to the game, the RenderThread initializes the AppState and then calls this method. You can modify the scene graph from here (e.g. attach nodes). To get access to the main app, call: <pre>super.initialize(stateManager, app); |
||||
this.app = (SimpleApplication) app;</pre> |
||||
</td> |
||||
</tr> |
||||
<tr> |
||||
<td>cleanup()</td><td>This method is executed after you remove the AppState from the game. Here you implement clean-up code for when this state is detached. You can modify the scene graph from here (e.g. detach nodes).</td> |
||||
</tr> |
||||
<tr> |
||||
<td>update(float tpf)</td><td>Here you implement the behaviour that you want to hook into the simpleUpdate() loop while this state is attached to the game. You can modify the scene graph from here.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>isInitialized()</td><td>Your implementations of this interface should return the correct respective boolean value. (See AbstractAppState)</td> |
||||
</tr> |
||||
<tr> |
||||
<td>setActive(true) <br/> |
||||
setActive(false)</td><td>Temporarily enables or disables an AppState. (See AbstractAppState) </td> |
||||
</tr> |
||||
<tr> |
||||
<td>isActive()</td><td>Test whether AppState is enabled or disabled. Your implementation should consider the boolean. (See AbstractAppState)</td> |
||||
</tr> |
||||
<tr> |
||||
<td>stateAttached(asm) <br/> |
||||
stateDetached(asm)</td><td>The AppState knows when it is attached to, or detached from, the AppStateManager, and triggers these two methods. Don't modify the scene graph from here! (Typically not used.) </td> |
||||
</tr> |
||||
<tr> |
||||
<td>render(RenderManager rm)</td><td>Renders the state, plus your optional customizations. (Typically not used.)</td> |
||||
</tr> |
||||
<tr> |
||||
<td>postRender()</td><td>Called after all rendering commands are flushed, including your optional customizations. (Typically not used.)</td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT8 TABLE [5293-6855] --> |
||||
</div> |
||||
<!-- EDIT7 SECTION "AppState" [5145-6856] --> |
||||
<h2><a>AbstractAppState</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
The AbstractAppState class already implements some common methods (<code>isInitialized(), setActive(), isActive()</code>) and makes creation of custom AppStates a bit easier. We recommend you extend AbstractAppState and override the remaining AppState methods: <code>initialize(), setEnabled(), cleanup()</code>. |
||||
</p> |
||||
|
||||
<p> |
||||
Definition: |
||||
|
||||
</p> |
||||
<pre>public class MyAppState extends AbstractAppState { |
||||
|
||||
private SimpleApplication app; |
||||
|
||||
private Node x = new Node("x"); // some custom class fields... |
||||
public Node getX(){ return x; } // some custom methods... |
||||
|
||||
@Override |
||||
public void initialize(AppStateManager stateManager, Application app) { |
||||
super.initialize(stateManager, app); |
||||
this.app = (SimpleApplication)app; // cast to a more specific class |
||||
|
||||
// init stuff that is independent of whether state is PAUSED or RUNNING |
||||
this.app.getRootNode().attachChild(getX()); // modify scene graph... |
||||
this.app.doSomething(); // call custom methods... |
||||
} |
||||
|
||||
@Override |
||||
public void cleanup() { |
||||
super.cleanup(); |
||||
// unregister all my listeners, detach all my nodes, etc... |
||||
this.app.getRootNode().detachChild(getX()); // modify scene graph... |
||||
this.app.doSomethingElse(); // call custom methods... |
||||
} |
||||
|
||||
@Override |
||||
public void setEnabled(boolean enabled) { |
||||
// Pause and unpause |
||||
super.setEnabled(enabled); |
||||
if(enabled){ |
||||
// init stuff that is in use while this state is RUNNING |
||||
this.app.getRootNode().attachChild(getX()); // modify scene graph... |
||||
this.app.doSomethingElse(); // call custom methods... |
||||
} else { |
||||
// take away everything not needed while this state is PAUSED |
||||
... |
||||
} |
||||
} |
||||
|
||||
// Note that update is only called while the state is both attached and enabled. |
||||
@Override |
||||
public void update(float tpf) { |
||||
// do the following while game is RUNNING |
||||
this.app.getRootNode().getChild("blah").scale(tpf); // modify scene graph... |
||||
x.setUserData(...); // call some methods... |
||||
} |
||||
|
||||
}</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT9 SECTION "AbstractAppState" [6857-9029] --> |
||||
<h2><a>Pausing and Unpausing</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
You define what an AppState does when Paused or Unpaused, in the <code>setEnabled()</code> and <code>update()</code> methods. Call <code>myState.setEnabled(false)</code> on all states that you want to pause. Call <code>myState.setEnabled(true)</code> on all states that you want to unpause. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT10 SECTION "Pausing and Unpausing" [9030-9320] --> |
||||
<h2><a>AppStateManager</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
The com.jme3.app.state.AppStateManager holds the list of AppStates for an application. AppStateManager ensures that active AppStates can modify the scene graph, and that the update() loops of active AppStates is executed. There is one AppStateManager per application. You typically attach several AppStates to one AppStateManager, but the same state can only be attached once. |
||||
|
||||
</p> |
||||
<div><table> |
||||
<tr> |
||||
<th>AppStateManager Method</th><th>Usage</th> |
||||
</tr> |
||||
<tr> |
||||
<td>hasState(myState)</td><td>Is AppState object 'myState' attached?</td> |
||||
</tr> |
||||
<tr> |
||||
<td>getState(MyAppState.class)</td><td>Returns the first attached state that is an instance of a subclass of <code>MyAppState.class</code>.</td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT12 TABLE [9728-9938] --> |
||||
<p> |
||||
|
||||
The AppStateManager's <code>render(), postRender(), cleanup()</code> methods are internal, ignore them, users never call them directly. |
||||
|
||||
</p> |
||||
<ul> |
||||
<li><div> If a detached AppState is attached then initialize() will be called on the following render pass.</div> |
||||
</li> |
||||
<li><div> If an attached AppState is detached then cleanup() will be called on the following render pass.</div> |
||||
</li> |
||||
<li><div> If you attach an already-attached AppState then the second attach is a no-op and will return false.</div> |
||||
</li> |
||||
<li><div> If you both attach and detach an AppState within one frame then neither initialize() or cleanup() will be called, although if either is called both will be.</div> |
||||
</li> |
||||
<li><div> If you both detach and then re-attach an AppState within one frame then on the next update pass its cleanup() and initialize() methods will be called in that order.</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT11 SECTION "AppStateManager" [9321-10704] --> |
||||
<h2><a>Best Practices</a></h2> |
||||
<div> |
||||
|
||||
</div> |
||||
<!-- EDIT13 SECTION "Best Practices" [10705-10732] --> |
||||
<h3><a>Communication Among AppStates</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
You can only access other AppStates (read from and write to them) from certain places: From a Control's update() method, from an AppState's update() method, and from the SimpleApplication's simpleUpdate() loop. Don't mess with the AppState from other places, because from other methods you have no control over the order of modifications; the game can go out of sync because you can't know when (during which half-finished step of another state change) your modification will be performed. |
||||
</p> |
||||
|
||||
<p> |
||||
You can use custom accessors to get data from AppStates, to set data in AppStates, or to trigger methods in AppStates. |
||||
|
||||
</p> |
||||
<pre>this.app.getStateManager().getState(MyAppState.class).doSomeCustomStuffInThisState();</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT14 SECTION "Communication Among AppStates" [10733-11488] --> |
||||
<h3><a>Initialize Familiar Class Fields</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
To access class fields of the SimpleApplication the way you are used to, initialize them to local variables, as shown in the following AppState template: |
||||
</p> |
||||
<pre>private SimpleApplication app; |
||||
private Node rootNode; |
||||
private AssetManager assetManager; |
||||
private AppStateManager stateManager; |
||||
private InputManager inputManager; |
||||
private ViewPort viewPort; |
||||
private BulletAppState physics; |
||||
|
||||
public class MyAppState extends AbstractAppState { |
||||
@Override |
||||
public void initialize(AppStateManager stateManager, Application app) { |
||||
super.initialize(stateManager, app); |
||||
this.app = (SimpleApplication) app; // can cast Application to something more specific |
||||
this.rootNode = this.app.getRootNode(); |
||||
this.assetManager = this.app.getAssetManager(); |
||||
this.stateManager = this.app.getStateManager(); |
||||
this.inputManager = this.app.getInputManager(); |
||||
this.viewPort = this.app.getViewPort(); |
||||
this.physics = this.stateManager.getState(BulletAppState.class); |
||||
} |
||||
}</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT15 SECTION "Initialize Familiar Class Fields" [11489-] --> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:application_states?do=export_xhtmlbody">view online version</a></em></p> |
@ -1,382 +0,0 @@ |
||||
|
||||
<h1><a>Simple AppStates Demo</a></h1> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
This demo is a simple example of how you use AppStates to toggle between a StartScreen and a SettingsScreen (press RETURN) while the game is paused, and start the game by switching to a GameRunning state (press BACKSPACE). |
||||
</p> |
||||
|
||||
<p> |
||||
There are four files, Main.java, GameRunningState.java, StartScreenState.java, SettingsScreenState.java. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT1 SECTION "Simple AppStates Demo" [1-369] --> |
||||
<h2><a>Main.java</a></h2> |
||||
<div> |
||||
<pre>package chapter04.appstatedemo; |
||||
|
||||
import com.jme3.app.SimpleApplication; |
||||
import com.jme3.input.KeyInput; |
||||
import com.jme3.input.controls.ActionListener; |
||||
import com.jme3.input.controls.KeyTrigger; |
||||
import com.jme3.input.controls.Trigger; |
||||
|
||||
<span>/** |
||||
* This demo shows a simple "game" with three AppStates. Instead of game content, |
||||
* it just displays three cubes on different backgrounds. |
||||
* <ul> |
||||
* <li>StartScreenState: This state is enabled |
||||
* when the user starts the application, or the the game is paused. |
||||
* Press BACKSPACE to return to the game, press RETURN to go to Settings.</li> |
||||
* <li>GameRunningState: This state shows the game content and is enabled while the game is running. |
||||
* Press BACKSPACE to pause and return to the start screen.</li> |
||||
* <li>SettingsScreenState: This Settings screen state can be reached from the start screen |
||||
* Press RETURN to toggle it on and off.</li> |
||||
* </ul> |
||||
*/</span> |
||||
public class Main extends SimpleApplication { |
||||
|
||||
private Trigger pause_trigger = new KeyTrigger(KeyInput.KEY_BACK); |
||||
private Trigger save_trigger = new KeyTrigger(KeyInput.KEY_RETURN); |
||||
private boolean isRunning = false; // starts at startscreen |
||||
private GameRunningState gameRunningState; |
||||
private StartScreenState startScreenState; |
||||
private SettingsScreenState settingsScreenState; |
||||
|
||||
|
||||
/** Start the jMonkeyEngine application */ |
||||
public static void main(String[] args) { |
||||
Main app = new Main(); |
||||
app.start(); |
||||
} |
||||
|
||||
<span>/** |
||||
* initialize the scene here |
||||
*/</span> |
||||
@Override |
||||
public void simpleInitApp() { |
||||
setDisplayFps(false); |
||||
setDisplayStatView(false); |
||||
|
||||
gameRunningState = new GameRunningState(this); |
||||
startScreenState = new StartScreenState(this); |
||||
settingsScreenState = new SettingsScreenState(this); |
||||
|
||||
stateManager.attach(startScreenState); |
||||
|
||||
inputManager.addMapping("Game Pause Unpause", pause_trigger); |
||||
inputManager.addListener(actionListener, new String[]{"Game Pause Unpause"}); |
||||
inputManager.addMapping("Toggle Settings", save_trigger); |
||||
inputManager.addListener(actionListener, new String[]{"Toggle Settings"}); |
||||
} |
||||
|
||||
private ActionListener actionListener = new ActionListener() { |
||||
public void onAction(String name, boolean isPressed, float tpf) { |
||||
System.out.println("key" + name); |
||||
if (name.equals("Game Pause Unpause") && !isPressed) { |
||||
if (isRunning) { |
||||
stateManager.detach(gameRunningState); |
||||
stateManager.attach(startScreenState); |
||||
System.out.println("switching to startscreen..."); |
||||
|
||||
} else { |
||||
stateManager.detach(startScreenState); |
||||
stateManager.attach(gameRunningState); |
||||
System.out.println("switching to game..."); |
||||
} |
||||
isRunning = !isRunning; |
||||
} else if (name.equals("Toggle Settings") && !isPressed && !isRunning) { |
||||
if (!isRunning && stateManager.hasState(startScreenState)) { |
||||
stateManager.detach(startScreenState); |
||||
stateManager.attach(settingsScreenState); |
||||
System.out.println("switching to settings..."); |
||||
} else if (!isRunning && stateManager.hasState(settingsScreenState)) { |
||||
stateManager.detach(settingsScreenState); |
||||
stateManager.attach(startScreenState); |
||||
System.out.println("switching to startscreen..."); |
||||
} |
||||
} |
||||
} |
||||
}; |
||||
|
||||
@Override |
||||
public void simpleUpdate(float tpf) {} |
||||
|
||||
} |
||||
</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT2 SECTION "Main.java" [370-3778] --> |
||||
<h2><a>GameRunningState.java</a></h2> |
||||
<div> |
||||
<pre>package chapter04.appstatedemo; |
||||
|
||||
import com.jme3.app.Application; |
||||
import com.jme3.app.SimpleApplication; |
||||
import com.jme3.app.state.AbstractAppState; |
||||
import com.jme3.app.state.AppStateManager; |
||||
import com.jme3.asset.AssetManager; |
||||
import com.jme3.font.BitmapFont; |
||||
import com.jme3.font.BitmapText; |
||||
import com.jme3.material.Material; |
||||
import com.jme3.math.ColorRGBA; |
||||
import com.jme3.math.Vector3f; |
||||
import com.jme3.renderer.ViewPort; |
||||
import com.jme3.scene.Geometry; |
||||
import com.jme3.scene.Node; |
||||
import com.jme3.scene.shape.Box; |
||||
|
||||
<span>/** |
||||
* A template how to create an Application State. This example state simply |
||||
* changes the background color depending on the camera position. |
||||
*/</span> |
||||
public class GameRunningState extends AbstractAppState { |
||||
|
||||
private ViewPort viewPort; |
||||
private Node rootNode; |
||||
private Node guiNode; |
||||
private AssetManager assetManager; |
||||
private Node localRootNode = new Node("Game Screen RootNode"); |
||||
private Node localGuiNode = new Node("Game Screen GuiNode"); |
||||
private final ColorRGBA backgroundColor = ColorRGBA.Blue; |
||||
|
||||
public GameRunningState(SimpleApplication app){ |
||||
this.rootNode = app.getRootNode(); |
||||
this.viewPort = app.getViewPort(); |
||||
this.guiNode = app.getGuiNode(); |
||||
this.assetManager = app.getAssetManager(); |
||||
} |
||||
|
||||
@Override |
||||
public void initialize(AppStateManager stateManager, Application app) { |
||||
super.initialize(stateManager, app); |
||||
|
||||
/** Load this scene */ |
||||
viewPort.setBackgroundColor(backgroundColor); |
||||
|
||||
Box mesh = new Box(Vector3f.ZERO, 1, 1, 1); |
||||
Geometry geom = new Geometry("Box", mesh); |
||||
Material mat = new Material(assetManager, |
||||
"Common/MatDefs/Misc/Unshaded.j3md"); |
||||
mat.setColor("Color", ColorRGBA.Green); |
||||
geom.setMaterial(mat); |
||||
geom.setLocalTranslation(1, 0, 0); |
||||
localRootNode.attachChild(geom); |
||||
|
||||
/** Load the HUD*/ |
||||
BitmapFont guiFont = assetManager.loadFont( |
||||
"Interface/Fonts/Default.fnt"); |
||||
BitmapText displaytext = new BitmapText(guiFont); |
||||
displaytext.setSize(guiFont.getCharSet().getRenderedSize()); |
||||
displaytext.move(10, displaytext.getLineHeight() + 20, 0); |
||||
displaytext.setText("Game running. Press BACKSPACE to pause and return to the start screen."); |
||||
localGuiNode.attachChild(displaytext); |
||||
} |
||||
|
||||
@Override |
||||
public void update(float tpf) { |
||||
/** the action happens here */ |
||||
Vector3f v = viewPort.getCamera().getLocation(); |
||||
viewPort.setBackgroundColor(new ColorRGBA(v.getX() / 10, v.getY() / 10, v.getZ() / 10, 1)); |
||||
rootNode.getChild("Box").rotate(tpf, tpf, tpf); |
||||
} |
||||
|
||||
@Override |
||||
public void stateAttached(AppStateManager stateManager) { |
||||
rootNode.attachChild(localRootNode); |
||||
guiNode.attachChild(localGuiNode); |
||||
viewPort.setBackgroundColor(backgroundColor); |
||||
} |
||||
|
||||
@Override |
||||
public void stateDetached(AppStateManager stateManager) { |
||||
rootNode.detachChild(localRootNode); |
||||
guiNode.detachChild(localGuiNode); |
||||
|
||||
} |
||||
|
||||
}</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT3 SECTION "GameRunningState.java" [3779-6746] --> |
||||
<h2><a>SettingsScreenState.java</a></h2> |
||||
<div> |
||||
<pre>package chapter04.appstatedemo; |
||||
|
||||
import com.jme3.app.Application; |
||||
import com.jme3.app.SimpleApplication; |
||||
import com.jme3.app.state.AbstractAppState; |
||||
import com.jme3.app.state.AppStateManager; |
||||
import com.jme3.asset.AssetManager; |
||||
import com.jme3.font.BitmapFont; |
||||
import com.jme3.font.BitmapText; |
||||
import com.jme3.material.Material; |
||||
import com.jme3.math.ColorRGBA; |
||||
import com.jme3.math.Vector3f; |
||||
import com.jme3.renderer.ViewPort; |
||||
import com.jme3.scene.Geometry; |
||||
import com.jme3.scene.Node; |
||||
import com.jme3.scene.shape.Box; |
||||
|
||||
<span>/** |
||||
* A template how to create an Application State. This example state simply |
||||
* changes the background color depending on the camera position. |
||||
*/</span> |
||||
public class SettingsScreenState extends AbstractAppState { |
||||
|
||||
private ViewPort viewPort; |
||||
private Node rootNode; |
||||
private Node guiNode; |
||||
private AssetManager assetManager; |
||||
private Node localRootNode = new Node("Settings Screen RootNode"); |
||||
private Node localGuiNode = new Node("Settings Screen GuiNode"); |
||||
private final ColorRGBA backgroundColor = ColorRGBA.DarkGray; |
||||
|
||||
public SettingsScreenState(SimpleApplication app) { |
||||
this.rootNode = app.getRootNode(); |
||||
this.viewPort = app.getViewPort(); |
||||
this.guiNode = app.getGuiNode(); |
||||
this.assetManager = app.getAssetManager(); |
||||
} |
||||
|
||||
@Override |
||||
public void initialize(AppStateManager stateManager, Application app) { |
||||
super.initialize(stateManager, app); |
||||
|
||||
/** Load this scene */ |
||||
viewPort.setBackgroundColor(backgroundColor); |
||||
|
||||
Box mesh = new Box(new Vector3f(-1, -1, 0), .5f, .5f, .5f); |
||||
Geometry geom = new Geometry("Box", mesh); |
||||
Material mat = new Material(assetManager, |
||||
"Common/MatDefs/Misc/Unshaded.j3md"); |
||||
mat.setColor("Color", ColorRGBA.Red); |
||||
geom.setMaterial(mat); |
||||
geom.setLocalTranslation(1, 0, 0); |
||||
localRootNode.attachChild(geom); |
||||
|
||||
/** Load the HUD */ |
||||
BitmapFont guiFont = assetManager.loadFont( |
||||
"Interface/Fonts/Default.fnt"); |
||||
BitmapText displaytext = new BitmapText(guiFont); |
||||
displaytext.setSize(guiFont.getCharSet().getRenderedSize()); |
||||
displaytext.move(10, displaytext.getLineHeight() + 20, 0); |
||||
displaytext.setText("Settings screen. Press RETURN to save " |
||||
+ "and return to start screen."); |
||||
localGuiNode.attachChild(displaytext); |
||||
} |
||||
|
||||
@Override |
||||
public void update(float tpf) { |
||||
/** the action happens here */ |
||||
} |
||||
|
||||
@Override |
||||
public void stateAttached(AppStateManager stateManager) { |
||||
rootNode.attachChild(localRootNode); |
||||
guiNode.attachChild(localGuiNode); |
||||
viewPort.setBackgroundColor(backgroundColor); |
||||
} |
||||
|
||||
@Override |
||||
public void stateDetached(AppStateManager stateManager) { |
||||
rootNode.detachChild(localRootNode); |
||||
guiNode.detachChild(localGuiNode); |
||||
} |
||||
|
||||
}</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT4 SECTION "SettingsScreenState.java" [6747-9561] --> |
||||
<h2><a>StartScreenState.java</a></h2> |
||||
<div> |
||||
<pre>package chapter04.appstatedemo; |
||||
|
||||
import com.jme3.app.Application; |
||||
import com.jme3.app.SimpleApplication; |
||||
import com.jme3.app.state.AbstractAppState; |
||||
import com.jme3.app.state.AppStateManager; |
||||
import com.jme3.asset.AssetManager; |
||||
import com.jme3.font.BitmapFont; |
||||
import com.jme3.font.BitmapText; |
||||
import com.jme3.material.Material; |
||||
import com.jme3.math.ColorRGBA; |
||||
import com.jme3.math.Vector3f; |
||||
import com.jme3.renderer.ViewPort; |
||||
import com.jme3.scene.Geometry; |
||||
import com.jme3.scene.Node; |
||||
import com.jme3.scene.shape.Box; |
||||
|
||||
<span>/** |
||||
* A template how to create an Application State. This example state simply |
||||
* changes the background color depending on the camera position. |
||||
*/</span> |
||||
public class StartScreenState extends AbstractAppState { |
||||
|
||||
private ViewPort viewPort; |
||||
private Node rootNode; |
||||
private Node guiNode; |
||||
private AssetManager assetManager; |
||||
private Node localRootNode = new Node("Start Screen RootNode"); |
||||
private Node localGuiNode = new Node("Start Screen GuiNode"); |
||||
private final ColorRGBA backgroundColor = ColorRGBA.Gray; |
||||
|
||||
public StartScreenState(SimpleApplication app){ |
||||
this.rootNode = app.getRootNode(); |
||||
this.viewPort = app.getViewPort(); |
||||
this.guiNode = app.getGuiNode(); |
||||
this.assetManager = app.getAssetManager(); |
||||
} |
||||
|
||||
@Override |
||||
public void initialize(AppStateManager stateManager, Application app) { |
||||
super.initialize(stateManager, app); |
||||
|
||||
/** Init this scene */ |
||||
viewPort.setBackgroundColor(backgroundColor); |
||||
|
||||
Box mesh = new Box(new Vector3f(-1,1,0), .5f,.5f,.5f); |
||||
Geometry geom = new Geometry("Box", mesh); |
||||
Material mat = new Material(assetManager, |
||||
"Common/MatDefs/Misc/Unshaded.j3md"); |
||||
mat.setColor("Color", ColorRGBA.Yellow); |
||||
geom.setMaterial(mat); |
||||
geom.setLocalTranslation(1, 0, 0); |
||||
localRootNode.attachChild(geom); |
||||
|
||||
/** Load a HUD */ |
||||
BitmapFont guiFont = assetManager.loadFont( |
||||
"Interface/Fonts/Default.fnt"); |
||||
BitmapText displaytext = new BitmapText(guiFont); |
||||
displaytext.setSize(guiFont.getCharSet().getRenderedSize()); |
||||
displaytext.move( 10, displaytext.getLineHeight() + 20, 0); |
||||
displaytext.setText("Start screen. Press BACKSPACE to resume the game, " |
||||
+ "press RETURN to edit Settings."); |
||||
localGuiNode.attachChild(displaytext); |
||||
} |
||||
|
||||
@Override |
||||
public void update(float tpf) { |
||||
/** the action happens here */ |
||||
} |
||||
|
||||
@Override |
||||
public void stateAttached(AppStateManager stateManager) { |
||||
rootNode.attachChild(localRootNode); |
||||
guiNode.attachChild(localGuiNode); |
||||
viewPort.setBackgroundColor(backgroundColor); |
||||
} |
||||
|
||||
@Override |
||||
public void stateDetached(AppStateManager stateManager) { |
||||
rootNode.detachChild(localRootNode); |
||||
guiNode.detachChild(localGuiNode); |
||||
} |
||||
|
||||
}</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT5 SECTION "StartScreenState.java" [9562-] --> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:appstatesdemo?do=export_xhtmlbody">view online version</a></em></p> |
@ -1,320 +0,0 @@ |
||||
|
||||
<h1><a>AssetManager</a></h1> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
By assets we mean multi-media files, such as 3D models, materials, textures, scenes, custom shaders, music and sound files, and custom fonts. JME3 has an integrated asset manager that helps you keep your project assets organized. Think of the asset manager as the filesystem of your game, independent of the actual deployment platform. By default, store your assets in the <code>MyGame/assets/ </code> directory of your project. |
||||
</p> |
||||
|
||||
<p> |
||||
Advantages of the AssetManager: |
||||
</p> |
||||
<ul> |
||||
<li><div> The paths stay the same, no matter whether the game runs on Windows, Mac, Linux, etc!</div> |
||||
</li> |
||||
<li><div> The AssetManager automatically optimizes the handling of OpenGL objects. <br/> |
||||
For example, the same textures are not uploaded to the graphics card multiple times when multiple models use them.</div> |
||||
</li> |
||||
<li><div> The <a href="/com/jme3/gde/core/docs/sdk/default_build_script.html">default build script</a> automatically bundles the contents of the <code>assets</code> directory into the executable. </div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
|
||||
Advanced users can write a custom build and packaging script, and can register custom paths to the AssetManager, but this is up to you then. |
||||
</p> |
||||
|
||||
</div> |
||||
|
||||
<h4><a>Context</a></h4> |
||||
<div> |
||||
<pre>jMonkeyProjects/MyGame/assets/ # You store assets in subfolders here! <------ |
||||
jMonkeyProjects/MyGame/build/ # SDK generates built classes here (*) |
||||
jMonkeyProjects/MyGame/build.xml # You customize Ant build script here |
||||
jMonkeyProjects/MyGame/nbproject/ # SDK stores default build.xml and meta data (*) |
||||
jMonkeyProjects/MyGame/dist/ # SDK generates executable distribution here (*) |
||||
jMonkeyProjects/MyGame/src/ # You store Java sources here |
||||
jMonkeyProjects/MyGame/test/ # You store test classes here (optional) |
||||
(*) Managed by jMonkeyEngine SDK -- don't edit!</pre> |
||||
|
||||
<p> |
||||
See also <a href="/com/jme3/gde/core/docs/jme3/intermediate/best_practices.html">Best Practices</a>. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT1 SECTION "AssetManager" [1-1691] --> |
||||
<h2><a>Usage</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
The <code>assetManager</code> object is an com.jme3.asset.AssetManager instance that every com.jme3.app.Application can access. It maintains a root that also includes your project's classpath by default, so you can load any asset that's on the classpath, that is, the top level of your project directory. |
||||
</p> |
||||
|
||||
<p> |
||||
You can use the inherited <code>assetManager</code> object directly, or use the accessor <code>app.getAssetManager()</code>. |
||||
</p> |
||||
|
||||
<p> |
||||
Here is an example how you load assets using the AssetManager. This lines loads a default Material from the built-in <code>Common/</code> directory: |
||||
</p> |
||||
<pre>Material mat = (Material) assetManager.loadAsset( |
||||
new AssetKey("Common/Materials/RedColor.j3m"));</pre> |
||||
|
||||
<p> |
||||
This Material is "somewhere" in the jME3 JAR; the default Asset Manager is configured to handle a <code>Common/???</code> path correctly, so you don't have to specify the whole path when referring to built-in assets (such as default Materials). |
||||
</p> |
||||
|
||||
<p> |
||||
Additionally, you can configure the Asset Manager and add any path to its root. This means, you can load assets from any project directory you specify. The next example shows how you load assets from your project's assets directory. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT2 SECTION "Usage" [1692-2849] --> |
||||
<h2><a>Asset Directory</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
By default, jME3 searches for models in a directory named <code>assets</code>. |
||||
</p> |
||||
|
||||
<p> |
||||
<p><div>In Java projects created with the jMonkeyEngine <acronym title="Software Development Kit">SDK</acronym>, an <code>assets</code> folder is created by default in your project directory. If you are using any other IDE, or the command line, you simply create an <code>assets</code> directory manually (see the Codeless Project tip below). |
||||
</div></p> |
||||
</p> |
||||
|
||||
<p> |
||||
This is our recommended directory structure for storing assets: |
||||
</p> |
||||
<pre>jMonkeyProjects/MyGame/src/... # Packages, .java source code. |
||||
jMonkeyProjects/MyGame/assets/... # The assets directory: |
||||
jMonkeyProjects/MyGame/assets/Interface/ # .font, .jpg, .png, .xml |
||||
jMonkeyProjects/MyGame/assets/MatDefs/ # .j3md |
||||
jMonkeyProjects/MyGame/assets/Materials/ # .j3m |
||||
jMonkeyProjects/MyGame/assets/Models/ # .j3o |
||||
jMonkeyProjects/MyGame/assets/Scenes/ # .j3o |
||||
jMonkeyProjects/MyGame/assets/Shaders/ # .j3f, .vert, .frag |
||||
jMonkeyProjects/MyGame/assets/Sounds/ # .ogg, .wav |
||||
jMonkeyProjects/MyGame/assets/Textures/ # .jpg, .png; also .mesh.xml+.material, .mtl+.obj, .blend (!) </pre> |
||||
|
||||
<p> |
||||
These subdirectories are just the most common examples. |
||||
</p> |
||||
|
||||
<p> |
||||
<p><div>You can rename/delete/add (sub)directories inside the <code>assets</code> directory in any way you like. Note however that there is no automatic refactoring for asset paths in the <acronym title="Software Development Kit">SDK</acronym>, so if you modify them late in the development process, you have to refactor all paths manually. |
||||
</div></p> |
||||
</p> |
||||
|
||||
<p> |
||||
<strong>Examples:</strong> You can rename <code>assets/Sounds</code> to <code>assets/Audio</code>, you can delete <code>assets/MatDefs</code> if you don't use it, you can create <code>assets/AIscripts</code>, etc. You can rename/move the <code>assets/Textures</code> directory or its subdirectories, but then you have to re-export all models, and re-convert them all to .j3o, so plan ahead! |
||||
</p> |
||||
|
||||
<p> |
||||
<p><div>Store textures in <code>assets/Textures/</code> before you work with them in a mesh editor! Export and save 3D model files (.mesh.xml+.material, .mtl+.obj, .blend) into the <code>assets/Textures/</code> (!) before you convert the model to binary format (.j3o)! This ensures that texture paths correctly point to the <code>assets/Textures</code> directory. <br/> |
||||
After the conversion, you move the .j3o file into the <code>assets/Models/</code> or <code>assets/Scenes/</code> directories. This way, you can reuse textures, your binaries consistently link the correct textures, and the <code>assets/Models</code> and <code>assets/Scenes</code> directories don't become cluttered. |
||||
</div></p> |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT3 SECTION "Asset Directory" [2850-5279] --> |
||||
<h2><a>Example Code: Loading Assets</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Creating a material instance with the definition "Unshaded.j3md": |
||||
|
||||
</p> |
||||
<pre>Material mat_brick = new Material( |
||||
assetManager, "Common/MatDefs/Misc/Unshaded.j3md");</pre> |
||||
|
||||
<p> |
||||
Applying a texture to the material: |
||||
|
||||
</p> |
||||
<pre>mat_brick.setTexture("ColorMap", |
||||
assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall.jpg"));</pre> |
||||
|
||||
<p> |
||||
Loading a font: |
||||
|
||||
</p> |
||||
<pre>guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");</pre> |
||||
|
||||
<p> |
||||
Loading a model: |
||||
|
||||
</p> |
||||
<pre>Spatial ninja = assetManager.loadModel("Models/Ninja/Ninja.mesh.xml");</pre> |
||||
|
||||
<p> |
||||
Loading a scene from an Ogre3D dotScene file stored inside a zip: |
||||
|
||||
</p> |
||||
<pre>assetManager.registerLocator("town.zip", ZipLocator.class); |
||||
Spatial scene = assetManager.loadModel("main.scene"); |
||||
rootNode.attachChild(scene);</pre> |
||||
|
||||
<p> |
||||
Alternatively to ZipLocator, there is also a HttpZipLocator that can stream models from a zip file online: |
||||
</p> |
||||
<pre>assetManager.registerLocator("http://jmonkeyengine.googlecode.com/files/wildhouse.zip", |
||||
HttpZipLocator.class); |
||||
Spatial scene = assetManager.loadModel("main.scene"); |
||||
rootNode.attachChild(scene);</pre> |
||||
|
||||
<p> |
||||
jME3 also offers a ClasspathLocator, ZipLocator, FileLocator, HttpZipLocator, and UrlLocator (see <code>com.jme3.asset.plugins</code>). |
||||
</p> |
||||
|
||||
<p> |
||||
<p><div>The custom build script does not automatically include all ZIP files in the executable build. See "Cannot Locate Resource" solution below. |
||||
</div></p> |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT4 SECTION "Example Code: Loading Assets" [5280-6752] --> |
||||
<h2><a>Common AssetManager Tasks</a></h2> |
||||
<div> |
||||
<div><table> |
||||
<tr> |
||||
<th> Task? </th><th> Solution! </th> |
||||
</tr> |
||||
<tr> |
||||
<td> Load a model with materials </td><td> Use the asset manager's <code>loadModel()</code> method and attach the Spatial to the rootNode. <pre>Spatial elephant = assetManager.loadModel("Models/Elephant/Elephant.mesh.xml"); |
||||
rootNode.attachChild(elephant);</pre> |
||||
<pre>Spatial elephant = assetManager.loadModel("Models/Elephant/Elephant.j3o"); |
||||
rootNode.attachChild(elephant);</pre> |
||||
</td> |
||||
</tr> |
||||
<tr> |
||||
<td> Load a model without materials </td><td> If you have a model without materials, you have to add a default material to make it visible. <pre>Spatial teapot = assetManager.loadModel("Models/Teapot/Teapot.obj"); |
||||
Material mat = new Material(assetManager, "Common/MatDefs/Misc/ShowNormals.j3md"); |
||||
teapot.setMaterial(mat); |
||||
rootNode.attachChild(teapot);</pre> |
||||
</td> |
||||
</tr> |
||||
<tr> |
||||
<td> Load a scene </td><td> You load scenes just like you load models: <pre>Spatial scene = assetManager.loadModel("Scenes/house/main.scene"); |
||||
rootNode.attachChild(scene);</pre> |
||||
</td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT6 TABLE [6792-7720] --> |
||||
</div> |
||||
<!-- EDIT5 SECTION "Common AssetManager Tasks" [6753-7721] --> |
||||
<h2><a>NullPointerException: Cannot locate resource?</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
<strong>Problem:</strong> |
||||
</p> |
||||
|
||||
<p> |
||||
My game runs fine when I run it right from the jMonkeyEngine <acronym title="Software Development Kit">SDK</acronym>. But when I run the stand-alone executables (.jar, .jnlp .exe, .app), a DesktopAssetManager error message occurs in the console, and it quits? |
||||
</p> |
||||
<pre>com.jme3.asset.DesktopAssetManager loadAsset |
||||
WARNING: Cannot locate resource: Scenes/town/main.scene |
||||
com.jme3.app.Application handleError |
||||
SEVERE: Uncaught exception thrown in Thread[LWJGL Renderer Thread,5,main] |
||||
java.lang.NullPointerException</pre> |
||||
|
||||
<p> |
||||
<strong>Reason:</strong> |
||||
</p> |
||||
|
||||
<p> |
||||
If you use the default build script, <strong>original models and scenes (.mesh.xml, .obj, .blend, .zip), are excluded</strong> from the distribution automatically. A stand-alone executable includes converted <strong>.j3o files</strong> (models and scenes) only. The default build script makes sure to bundle existing .j3o files in the distribution, but you need to remember to convert the models (from mesh.xml???>.j3o, or .obj???>.j3o, etc) yourself. |
||||
</p> |
||||
|
||||
<p> |
||||
<strong>Solution</strong> |
||||
</p> |
||||
|
||||
<p> |
||||
Before building the executable, you must use the jMonkeyEngine <acronym title="Software Development Kit">SDK</acronym>'s context menu action to <a href="/com/jme3/gde/core/docs/sdk/model_loader_and_viewer.html">convert 3D models to .j3o binary format</a>. |
||||
</p> |
||||
<ol> |
||||
<li><div> Save your original models (.mesh.xml, .scene, .blend, or .obj files, plus textures) into <code>assets/Textures/</code>. (!)</div> |
||||
</li> |
||||
<li><div> Open the jME3 project in the jMonkeyEngine <acronym title="Software Development Kit">SDK</acronym>.</div> |
||||
</li> |
||||
<li><div> Browse to the <code>assets</code> directory in the Projects window. </div> |
||||
</li> |
||||
<li><div> Right-click an original model in <code>assets/Textures/</code>, and choose "Convert to JME3 binary".</div> |
||||
</li> |
||||
<li><div> The converted file appears in the same directory as the original file. It has the same name and a <code>.j3o</code> suffix. </div> |
||||
</li> |
||||
<li><div> Move the .j3o file into the <code>assets/Models/</code> or <code>assets/Scenes/</code> directory.</div> |
||||
</li> |
||||
<li><div> Use the assetManager's <code>load()</code> method to load the <code>.j3o</code> file.</div> |
||||
</li> |
||||
</ol> |
||||
|
||||
<p> |
||||
|
||||
This ensures that the model's Texture paths keep working between your 3D mesh editor and JME3. |
||||
</p> |
||||
|
||||
<p> |
||||
<p><div>If you must load custom assets from a non-.j3o ZIP file, you must manually ammend the <a href="/com/jme3/gde/core/docs/sdk/default_build_script.html">default build script</a> to copy ZIP files into your distribution. ZIPs are skipped by default. |
||||
</div></p> |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT7 SECTION "NullPointerException: Cannot locate resource?" [7722-9798] --> |
||||
<h2><a>Asset Handling For Other IDEs: Codeless Projects</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
<strong>Problem:</strong> |
||||
</p> |
||||
|
||||
<p> |
||||
I use another IDE than jMonkeyEngine <acronym title="Software Development Kit">SDK</acronym> for coding (Eclipse, IntelliJ, text editor). Where is my <code>asset</code> folder and .j3o converter? |
||||
</p> |
||||
|
||||
<p> |
||||
<strong>Solution:</strong> |
||||
</p> |
||||
|
||||
<p> |
||||
You can code in any IDE, but you must create a so-called codeless project in the jMonkeyEngine <acronym title="Software Development Kit">SDK</acronym> to maintain assets. <strong>A code-less jMonkeyEngine project does not meddle with your sources or custom build scripts.</strong> You merely use it to convert models to .j3o binaries. |
||||
|
||||
</p> |
||||
<ol> |
||||
<li><div> Create your (Eclipse or whatever) project as you like.</div> |
||||
</li> |
||||
<li><div> Create a directory in your project folder and name it, for example, <code>assets</code>. <br/> |
||||
Store your assets there as described above.</div> |
||||
</li> |
||||
<li><div> Download and install the jMonkeyEngine <acronym title="Software Development Kit">SDK</acronym>.</div> |
||||
</li> |
||||
<li><div> In the <acronym title="Software Development Kit">SDK</acronym>, go to File ??? Import Projects ??? External Project Assets.</div> |
||||
</li> |
||||
<li><div> Select your (Eclipse or whatever) project and your assets folder in the Import Wizard.</div> |
||||
</li> |
||||
<li><div> You can now open this (Eclipse or whatever) project in the jMonkeyEngine <acronym title="Software Development Kit">SDK</acronym>. <br/> |
||||
Convert assets as described above.</div> |
||||
</li> |
||||
</ol> |
||||
|
||||
<p> |
||||
|
||||
<p><div>If you don't use the <acronym title="Software Development Kit">SDK</acronym> for some reason, you can still convert models to j3o format: Load any model in Ogre3D or Wavefront format with the AssetManager.loadModel() as a spatial. Then save the spatial as j3o file using <a href="/com/jme3/gde/core/docs/jme3/advanced/save_and_load.html">BinaryExporter</a>. |
||||
</div></p> |
||||
</p> |
||||
|
||||
<p> |
||||
<p><div>Use file version control and let team members check out the project. Your developers open the project in Eclipse (etc) as they are used to. Additionally to their graphic tools, ask your graphic designers to install the jMonkeyEngine <acronym title="Software Development Kit">SDK</acronym>, and to check out the codeless project that you just prepared. This makes it easy for non-coding team member to browse and preview game assets, to arrange scenes, and to convert files. At the same time, non-coders don't accidentally mess with code, and developers don't accidentally mess with assets. :) |
||||
</div></p> |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT8 SECTION "Asset Handling For Other IDEs: Codeless Projects" [9799-] --> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:asset_manager?do=export_xhtmlbody">view online version</a></em></p> |
@ -1,270 +0,0 @@ |
||||
|
||||
<h1><a>Audio in jME3</a></h1> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Place audio files in the <code>assets/Sound/</code> directory of your project. jME3 supports Ogg Vorbis audio compression (.ogg) and uncompressed PCM Wave (.wav) formats. You can use for example <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://audacity.sourceforge.net/"><param name="text" value="<html><u>Audacity</u></html>"><param name="textColor" value="blue"></object> to convert from other formats. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT1 SECTION "Audio in jME3" [1-293] --> |
||||
<h2><a>Audio Terminology</a></h2> |
||||
<div> |
||||
<ul> |
||||
<li><div> <strong>Streaming:</strong> There are two ways to load audio data: Short audio files are to be stored entirely in memory (prebuffered), while long audio files, such as music, are streamed from the hard drive as it is played.</div> |
||||
</li> |
||||
<li><div> <strong>Looping:</strong> You can play a sound either once and then stop, or repeatedly (continuously) in a loop. <br/> |
||||
You cannot loop streamed sounds.</div> |
||||
</li> |
||||
<li><div> <strong>Instance:</strong> If you play the same audio twice, the playing is queued up and jME plays one after the other. If you play instances of sounds, several instances of the same sound can play at the same time.</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT2 SECTION "Audio Terminology" [294-891] --> |
||||
<h2><a>Creating Audio Nodes: Streamed or Buffered</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
The main jME audio class to look at is <code>com.jme3.audio.AudioNode</code>. When creating a new audio node you need to declare whether how you want to load this sound: |
||||
|
||||
</p> |
||||
<ul> |
||||
<li><div> <strong>Buffered:</strong> By default, a new audio node is buffered. This means jME3 loads the whole file into memory before playing. Use this for short sounds. You create a buffered sound by setting the boolean to false, or using no boolean at all: <pre>AudioNode boom = new AudioNode(assetManager, "Sound/boom.wav"); |
||||
AudioNode boom = new AudioNode(assetManager, "Sound/boom.wav", false);</pre> |
||||
</div> |
||||
</li> |
||||
<li><div> <strong>Streamed:</strong> If it is a long file such as music or a dialog, you stream the audio. Streaming means, you load and play in parallel until the sound is done. You cannot loop streams. You create a streamed sound by setting the boolean to true:<pre>AudioNode music = new AudioNode(assetManager, "Sound/music.wav", true);</pre> |
||||
</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT3 SECTION "Creating Audio Nodes: Streamed or Buffered" [892-1839] --> |
||||
<h2><a>Getting AudioNode Properties</a></h2> |
||||
<div> |
||||
<div><table> |
||||
<tr> |
||||
<th>AudioNode Method</th><th>Usage</th> |
||||
</tr> |
||||
<tr> |
||||
<td>getStatus()</td><td>Returns either Status.Playing, Status.Stopped, or Status.Paused. </td> |
||||
</tr> |
||||
<tr> |
||||
<td>getVolume()</td><td>Returns the volume. </td> |
||||
</tr> |
||||
<tr> |
||||
<td>getPitch()</td><td>Returns the pitch. </td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT5 TABLE [1882-2054] --> |
||||
<p> |
||||
|
||||
Note: There are other obvious getters to poll the status of all corresponding setters listed here. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT4 SECTION "Getting AudioNode Properties" [1840-2155] --> |
||||
<h2><a>Setting AudioNode Properties</a></h2> |
||||
<div> |
||||
<div><table> |
||||
<tr> |
||||
<th>AudioNode Method</th><th>Usage</th> |
||||
</tr> |
||||
<tr> |
||||
<td>setTimeOffset(0.5f)</td><td>Play the sound starting at a 0.5 second offset from the beginning. Default is 0.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>setPitch(1)</td><td>Makes the sound play in a higher or lower pitch. Default is 1. 2 is twice as high, .5f is half as high. </td> |
||||
</tr> |
||||
<tr> |
||||
<td>setVolume(1)</td><td>Sets the volume gain. 1 is the default volume, 2 is twice as loud, etc. 0 is silent/mute. </td> |
||||
</tr> |
||||
<tr> |
||||
<td>setRefDistance(50f)</td><td>The reference distance controls how far a sound can still be heard at 50% of its original volume (<em>this is assuming an exponential fall-off!</em>). A sound with a high RefDist can be heard loud over wide distances; a sound with a low refDist can only be heard when the listener is close by. Default is 10 world units.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>setMaxDistance(100f)</td><td> The 'maximum attenuation distance' specifies how far from the source the sound stops growing more quiet (sounds in nature don't do that). Set this to a smaller value to keep the sound loud even at a distance; set this to higher value to let the sound fade out quickly. Default is 20 world units.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>setLooping(false)</td><td>Configures the sound so that, if it is played, it plays once and stops. No looping is the default.</td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT7 TABLE [2198-3327] --> |
||||
</div> |
||||
<!-- EDIT6 SECTION "Setting AudioNode Properties" [2156-3328] --> |
||||
<h3><a>Looping & Ambient Sounds</a></h3> |
||||
<div> |
||||
<div><table> |
||||
<tr> |
||||
<th>AudioNode Method</th><th>Usage</th> |
||||
</tr> |
||||
<tr> |
||||
<td>setPositional(false) <br/> |
||||
setDirectional(false)</td><td>All 3D effects switched off. This sound is global and plays in headspace (it appears to come from everywhere). Good for environmental ambient sounds and background music.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>setLooping(true)</td><td>Configures the sound to be a loop: After the sound plays, it repeats from the beginning, until you call stop() or pause(). Good for music and ambient background noises. <br/> |
||||
<strong>Looping does not work on streamed sounds.</strong> </td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT9 TABLE [3365-3846] --> |
||||
</div> |
||||
<!-- EDIT8 SECTION "Looping & Ambient Sounds" [3329-3847] --> |
||||
<h3><a>Positional 3D Sounds</a></h3> |
||||
<div> |
||||
<div><table> |
||||
<tr> |
||||
<th>AudioNode Method</th><th>Usage</th> |
||||
</tr> |
||||
<tr> |
||||
<td>setPositional(true) <br/> |
||||
setLocalTranslation(???)</td><td>Activates 3D audio: The sound appears to come from a certain position, where it is loudest. Position the AudioNode in the 3D scene, or move it with mobile players or NPCs.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>setReverbEnabled(true)</td><td>Reverb is a 3D echo effect that only makes sense with positional AudioNodes. Use Audio Environments to make scenes sound as if they were "outdoors", or "indoors" in a large or small room, etc. The reverb effect is defined by the <code>com.jme3.audio.Environment</code> that the <code>audioRenderer</code> is in. See "Setting Audio Environment Properties" below. </td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT11 TABLE [3880-4496] --> |
||||
<p> |
||||
|
||||
<p><div>Positional 3D sounds require an <code>AudioListener</code> object in the scene (representing the player's ears). |
||||
</div></p> |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT10 SECTION "Positional 3D Sounds" [3848-4625] --> |
||||
<h3><a>Directional 3D Sounds</a></h3> |
||||
<div> |
||||
<div><table> |
||||
<tr> |
||||
<th>AudioNode Method</th><th>Usage</th> |
||||
</tr> |
||||
<tr> |
||||
<td>setDirectional(true) <br/> |
||||
setDirection(???) </td><td>Activates 3D audio: This sound can only be heard from a certain direction. Specify the direction and angle in the 3D scene if you have setDirectional() true. Use this to restrict noises that should not be heard, for example, through a wall.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>setInnerAngle() <br/> |
||||
setOuterAngle()</td><td>Set the angle in degrees for the directional audio. The angle is relative to the direction. Note: By default, both angles are 360?? and the sound can be heard from all directions!</td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT13 TABLE [4659-5186] --> |
||||
<p> |
||||
|
||||
<p><div>Directional 3D sounds require an AudioListener object in the scene (representing the player's ears). |
||||
</div></p> |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT12 SECTION "Directional 3D Sounds" [4626-5313] --> |
||||
<h2><a>Play, Pause, Stop</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
You play, pause, and stop a node called myAudioNode by using the respective of the following three methods: |
||||
</p> |
||||
<pre>myAudioNode.play();</pre> |
||||
<pre>myAudioNode.pause();</pre> |
||||
<pre>myAudioNode.stop();</pre> |
||||
|
||||
<p> |
||||
<strong>Note:</strong> Whether an Audio Node plays continuously or only once, depends on the Loop properties you have set above! |
||||
</p> |
||||
|
||||
<p> |
||||
You can also start playing instances of an AudioNode. Use the <code>playInstance()</code> method if you need to play the same AudioNode multiple times, possibly simulatenously. Note that changes to the parameters of the original AudioNode do not affect the instances that are already playing! |
||||
</p> |
||||
<pre>myAudioNode.playInstance();</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT14 SECTION "Play, Pause, Stop" [5314-6018] --> |
||||
<h2><a>The Audio Listener</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
The default AudioListener object <code>listener</code> in <code>SimpleApplication</code> is the user's ear in the scene. If you use 3D audio (positional or directional sounds), you must move the AudioListener with the player: For example, for a first-person player, you move the listener with the camera. For a third-person player, you move the listener with the player avatar Geometry. |
||||
</p> |
||||
<pre> @Override |
||||
public void simpleUpdate(float tpf) { |
||||
// first-person: keep the audio listener moving with the camera |
||||
listener.setLocation(cam.getLocation()); |
||||
listener.setRotation(cam.getRotation()); |
||||
}</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT15 SECTION "The Audio Listener" [6019-6655] --> |
||||
<h2><a>Setting Audio Environment Properties</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Optionally, You can choose from the following environmental presets from <code>com.jme3.audio.Environment</code>. This presets influence subtle echo effects (reverb) that evoke associations of different environments in your users. That is, it makes you scene sound "indoors" or "outdoors" etc. You use Audio Environments together with <code>setReverbEnabled(true)</code> on positional AudioNodes (see above). |
||||
|
||||
</p> |
||||
<div><table> |
||||
<tr> |
||||
<th>Environment</th><th>density</th><th>diffusion</th><th>gain</th><th>gainHf</th><th>decayTime</th><th>decayHf</th><th>reflGain</th><th>reflDelay</th><th>lateGain</th><th>lateDelay</th> |
||||
</tr> |
||||
<tr> |
||||
<td>Garage </td><td>1.00f</td><td>1.0f</td><td>1.0f</td><td>1.00f</td><td>0.90f</td><td>0.5f</td><td>0.751f</td><td>0.0039f</td><td>0.661f</td><td>0.0137f</td> |
||||
</tr> |
||||
<tr> |
||||
<td>Dungeon </td><td>0.75f</td><td>1.0f</td><td>1.0f</td><td>0.75f</td><td>1.60f</td><td>1.0f</td><td>0.950f</td><td>0.0026f</td><td>0.930f</td><td>0.0103f</td> |
||||
</tr> |
||||
<tr> |
||||
<td>Cavern </td><td>0.50f</td><td>1.0f</td><td>1.0f</td><td>0.50f</td><td>2.25f</td><td>1.0f</td><td>0.908f</td><td>0.0103f</td><td>0.930f</td><td>0.0410f</td> |
||||
</tr> |
||||
<tr> |
||||
<td>AcousticLab </td><td>0.50f</td><td>1.0f</td><td>1.0f</td><td>1.00f</td><td>0.28f</td><td>1.0f</td><td>0.870f</td><td>0.0020f</td><td>0.810f</td><td>0.0080f</td> |
||||
</tr> |
||||
<tr> |
||||
<td>Closet </td><td>1.00f</td><td>1.0f</td><td>1.0f</td><td>1.00f</td><td>0.15f</td><td>1.0f</td><td>0.600f</td><td>0.0025f</td><td>0.500f</td><td>0.0006f</td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT17 TABLE [7098-7587] --><ol> |
||||
<li><div> Activate a Environment preset</div> |
||||
<ul> |
||||
<li><div> Either use a default, e.g. make you scene sounds like a dungeon environment: <pre>audioRenderer.setEnvironment(new Environment(Environment.Dungeon));</pre> |
||||
</div> |
||||
</li> |
||||
<li><div> Or activate <a href="/com/jme3/gde/core/docs/jme3/advanced/audio_environment_presets.html">custom environment settings</a> in the Environment constructor:<pre>audioRenderer.setEnvironment( |
||||
new Environment( density, diffusion, gain, gainHf, decayTime, decayHf, |
||||
reflGain, reflDelay, lateGain, lateDelay ) );</pre> |
||||
</div> |
||||
</li> |
||||
</ul> |
||||
</li> |
||||
<li><div> Activate 3D audio for certain sounds: <pre>footstepsAudio.setPositional(true); |
||||
footstepsAudio.setReverbEnabled(true);</pre> |
||||
</div> |
||||
</li> |
||||
</ol> |
||||
|
||||
<p> |
||||
|
||||
<p><div>A sound engineer can create a custom <code>com.???jme3.???audio.Environment</code> object and specify custom environment values such as density, diffusion, gain, decay, delay??? You can find many <a href="/com/jme3/gde/core/docs/jme3/advanced/audio_environment_presets.html">examples of custom audio environment presets</a> here. |
||||
</div></p> |
||||
</p> |
||||
|
||||
<p> |
||||
Advanced users find more info about OpenAL and its features here: <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://connect.creativelabs.com/openal/Documentation/OpenAL%201.1%20Specification.pdf"><param name="text" value="<html><u>OpenAL 1.1 Specification</u></html>"><param name="textColor" value="blue"></object>. |
||||
</p> |
||||
|
||||
<p> |
||||
<p><div>It depends on the hardware whether audio effects are supported (if not, you get the message <code>OpenAL EFX not available! Audio effects won't work.</code>) |
||||
</div></p> |
||||
</p> |
||||
<div><span> |
||||
<a href="/wiki/doku.php/tag:sound?do=showtag&tag=tag%3Asound">sound</a>, |
||||
<a href="/wiki/doku.php/tag:documentation?do=showtag&tag=tag%3Adocumentation">documentation</a>, |
||||
<a href="/wiki/doku.php/tag:environment?do=showtag&tag=tag%3Aenvironment">environment</a> |
||||
</span></div> |
||||
|
||||
</div> |
||||
<!-- EDIT16 SECTION "Setting Audio Environment Properties" [6656-] --> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:audio?do=export_xhtmlbody">view online version</a></em></p> |
@ -1,213 +0,0 @@ |
||||
|
||||
<h1><a>Audio Environment Presets</a></h1> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Use these presets together with <a href="/com/jme3/gde/core/docs/jme3/advanced/audio.html">Audio</a> 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. |
||||
</p> |
||||
|
||||
<p> |
||||
Usage: |
||||
|
||||
</p> |
||||
<pre>Environment Generic = new Environment( |
||||
new float[]{ 0, 7.5f, 1f, -1000, -100, 0, 1.49f, 0.83f, 1f, -2602, |
||||
0.007f, 0f, 0f, 0f, 200, 0.011f, 0f, 0f, 0f, 0.250f, |
||||
0f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x3f} ); |
||||
audioRenderer.setEnvironment(myEnvironment);</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT1 SECTION "Audio Environment Presets" [1-568] --> |
||||
<h2><a>Castle</a></h2> |
||||
<div> |
||||
<pre>CastleSmallRoom = new Environment ( new float[]{ 26, 8.3f, 0.890f, -1000, -800, -2000, 1.22f, 0.83f, 0.31f, -100, 0.022f, 0f, 0f, 0f, 600, 0.011f, 0f, 0f, 0f, 0.138f, 0.080f, 0.250f, 0f, -5f, 5168.6f, 139.5f, 0f, 0x20} ); |
||||
CastleShortPassage = new Environment ( new float[]{ 26, 8.3f, 0.890f, -1000, -1000, -2000, 2.32f, 0.83f, 0.31f, -100, 0.007f, 0f, 0f, 0f, 200, 0.023f, 0f, 0f, 0f, 0.138f, 0.080f, 0.250f, 0f, -5f, 5168.6f, 139.5f, 0f, 0x20} ); |
||||
CastleMediumroom = new Environment ( new float[]{ 26, 8.3f, 0.930f, -1000, -1100, -2000, 2.04f, 0.83f, 0.46f, -400, 0.022f, 0f, 0f, 0f, 400, 0.011f, 0f, 0f, 0f, 0.155f, 0.030f, 0.250f, 0f, -5f, 5168.6f, 139.5f, 0f, 0x20} ); |
||||
CastleLongpassage = new Environment ( new float[]{ 26, 8.3f, 0.890f, -1000, -800, -2000, 3.42f, 0.83f, 0.31f, -100, 0.007f, 0f, 0f, 0f, 300, 0.023f, 0f, 0f, 0f, 0.138f, 0.080f, 0.250f, 0f, -5f, 5168.6f, 139.5f, 0f, 0x20} ); |
||||
CastleLargeroom = new Environment ( new float[]{ 26, 8.3f, 0.820f, -1000, -1100, -1800, 2.53f, 0.83f, 0.50f, -700, 0.034f, 0f, 0f, 0f, 200, 0.016f, 0f, 0f, 0f, 0.185f, 0.070f, 0.250f, 0f, -5f, 5168.6f, 139.5f, 0f, 0x20} ); |
||||
CastleHall = new Environment ( new float[]{ 26, 8.3f, 0.810f, -1000, -1100, -1500, 3.14f, 0.79f, 0.62f, -1500, 0.056f, 0f, 0f, 0f, 100, 0.024f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 5168.6f, 139.5f, 0f, 0x20} ); |
||||
CastleCupboard = new Environment ( new float[]{ 26, 8.3f, 0.890f, -1000, -1100, -2000, 0.67f, 0.87f, 0.31f, 300, 0.010f, 0f, 0f, 0f, 1100, 0.007f, 0f, 0f, 0f, 0.138f, 0.080f, 0.250f, 0f, -5f, 5168.6f, 139.5f, 0f, 0x20} ); |
||||
CastleCourtyard = new Environment ( new float[]{ 26, 8.3f, 0.420f, -1000, -700, -1400, 2.13f, 0.61f, 0.23f, -1300, 0.160f, 0f, 0f, 0f, -300, 0.036f, 0f, 0f, 0f, 0.250f, 0.370f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x1f} ); |
||||
CastleAlcove = new Environment ( new float[]{ 26, 8.3f, 0.890f, -1000, -600, -2000, 1.64f, 0.87f, 0.31f, 00, 0.007f, 0f, 0f, 0f, 300, 0.034f, 0f, 0f, 0f, 0.138f, 0.080f, 0.250f, 0f, -5f, 5168.6f, 139.5f, 0f, 0x20} );</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT2 SECTION "Castle" [569-2630] --> |
||||
<h2><a>Warehouse, Factory</a></h2> |
||||
<div> |
||||
<pre>FactoryAlcove = new Environment ( new float[]{ 26, 1.8f, 0.590f, -1200, -200, -600, 3.14f, 0.65f, 1.31f, 300, 0.010f, 0f, 0f, 0f, 000, 0.038f, 0f, 0f, 0f, 0.114f, 0.100f, 0.250f, 0f, -5f, 3762.6f, 362.5f, 0f, 0x20} ); |
||||
FactoryShortpassage = new Environment ( new float[]{ 26, 1.8f, 0.640f, -1200, -200, -600, 2.53f, 0.65f, 1.31f, 0, 0.010f, 0f, 0f, 0f, 200, 0.038f, 0f, 0f, 0f, 0.135f, 0.230f, 0.250f, 0f, -5f, 3762.6f, 362.5f, 0f, 0x20} ) ); |
||||
FactoryMediumroom = new Environment ( new float[]{ 26, 1.9f, 0.820f, -1200, -200, -600, 2.76f, 0.65f, 1.31f, -1100, 0.022f, 0f, 0f, 0f, 300, 0.023f, 0f, 0f, 0f, 0.174f, 0.070f, 0.250f, 0f, -5f, 3762.6f, 362.5f, 0f, 0x20} ); |
||||
FactoryLongpassage = new Environment ( new float[]{ 26, 1.8f, 0.640f, -1200, -200, -600, 4.06f, 0.65f, 1.31f, 0, 0.020f, 0f, 0f, 0f, 200, 0.037f, 0f, 0f, 0f, 0.135f, 0.230f, 0.250f, 0f, -5f, 3762.6f, 362.5f, 0f, 0x20} ); |
||||
FactoryLargeroom = new Environment ( new float[]{ 26, 1.9f, 0.750f, -1200, -300, -400, 4.24f, 0.51f, 1.31f, -1500, 0.039f, 0f, 0f, 0f, 100, 0.023f, 0f, 0f, 0f, 0.231f, 0.070f, 0.250f, 0f, -5f, 3762.6f, 362.5f, 0f, 0x20} ); |
||||
FactoryHall = new Environment ( new float[]{ 26, 1.9f, 0.750f, -1000, -300, -400, 7.43f, 0.51f, 1.31f, -2400, 0.073f, 0f, 0f, 0f, -100, 0.027f, 0f, 0f, 0f, 0.250f, 0.070f, 0.250f, 0f, -5f, 3762.6f, 362.5f, 0f, 0x20} ); |
||||
FactoryCupboard = new Environment ( new float[]{ 26, 1.7f, 0.630f, -1200, -200, -600, 0.49f, 0.65f, 1.31f, 200, 0.010f, 0f, 0f, 0f, 600, 0.032f, 0f, 0f, 0f, 0.107f, 0.070f, 0.250f, 0f, -5f, 3762.6f, 362.5f, 0f, 0x20} ); |
||||
FactoryCourtyard = new Environment ( new float[]{ 26, 1.7f, 0.570f, -1000, -1000, -400, 2.32f, 0.29f, 0.56f, -1300, 0.140f, 0f, 0f, 0f, -800, 0.039f, 0f, 0f, 0f, 0.250f, 0.290f, 0.250f, 0f, -5f, 3762.6f, 362.5f, 0f, 0x20} ); |
||||
FactorySmallroom = new Environment ( new float[]{ 26, 1.8f, 0.820f, -1000, -200, -600, 1.72f, 0.65f, 1.31f, -300, 0.010f, 0f, 0f, 0f, 500, 0.024f, 0f, 0f, 0f, 0.119f, 0.070f, 0.250f, 0f, -5f, 3762.6f, 362.5f, 0f, 0x20} );</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT3 SECTION "Warehouse, Factory" [2631-4706] --> |
||||
<h2><a>Ice Palace</a></h2> |
||||
<div> |
||||
<pre>IcepalaceAlcove = new Environment ( new float[]{ 26, 2.7f, 0.840f, -1000, -500, -1100, 2.76f, 1.46f, 0.28f, 100, 0.010f, 0f, 0f, 0f, -100, 0.030f, 0f, 0f, 0f, 0.161f, 0.090f, 0.250f, 0f, -5f, 12428.5f, 99.6f, 0f, 0x20} ); |
||||
IcepalaceShortpassage = new Environment ( new float[]{ 26, 2.7f, 0.750f, -1000, -500, -1100, 1.79f, 1.46f, 0.28f, -600, 0.010f, 0f, 0f, 0f, 100, 0.019f, 0f, 0f, 0f, 0.177f, 0.090f, 0.250f, 0f, -5f, 12428.5f, 99.6f, 0f, 0x20} ) ); |
||||
IcepalaceMediumroom = new Environment ( new float[]{ 26, 2.7f, 0.870f, -1000, -500, -700, 2.22f, 1.53f, 0.32f, -800, 0.039f, 0f, 0f, 0f, 100, 0.027f, 0f, 0f, 0f, 0.186f, 0.120f, 0.250f, 0f, -5f, 12428.5f, 99.6f, 0f, 0x20} ); |
||||
IcepalaceLongpassage = new Environment ( new float[]{ 26, 2.7f, 0.770f, -1000, -500, -800, 3.01f, 1.46f, 0.28f, -200, 0.012f, 0f, 0f, 0f, 200, 0.025f, 0f, 0f, 0f, 0.186f, 0.040f, 0.250f, 0f, -5f, 12428.5f, 99.6f, 0f, 0x20} ); |
||||
IcepalaceLargeroom = new Environment ( new float[]{ 26, 2.9f, 0.810f, -1000, -500, -700, 3.14f, 1.53f, 0.32f, -1200, 0.039f, 0f, 0f, 0f, 000, 0.027f, 0f, 0f, 0f, 0.214f, 0.110f, 0.250f, 0f, -5f, 12428.5f, 99.6f, 0f, 0x20} ); |
||||
IcepalaceHall = new Environment ( new float[]{ 26, 2.9f, 0.760f, -1000, -700, -500, 5.49f, 1.53f, 0.38f, -1900, 0.054f, 0f, 0f, 0f, -400, 0.052f, 0f, 0f, 0f, 0.226f, 0.110f, 0.250f, 0f, -5f, 12428.5f, 99.6f, 0f, 0x20} ); |
||||
IcepalaceCupboard = new Environment ( new float[]{ 26, 2.7f, 0.830f, -1000, -600, -1300, 0.76f, 1.53f, 0.26f, 100, 0.012f, 0f, 0f, 0f, 600, 0.016f, 0f, 0f, 0f, 0.143f, 0.080f, 0.250f, 0f, -5f, 12428.5f, 99.6f, 0f, 0x20} ); |
||||
IcepalaceCourtyard = new Environment ( new float[]{ 26, 2.9f, 0.590f, -1000, -1100, -1000, 2.04f, 1.20f, 0.38f, -1000, 0.173f, 0f, 0f, 0f, -1000, 0.043f, 0f, 0f, 0f, 0.235f, 0.480f, 0.250f, 0f, -5f, 12428.5f, 99.6f, 0f, 0x20} ); |
||||
IcepalaceSmallroom = new Environment ( new float[]{ 26, 2.7f, 0.840f, -1000, -500, -1100, 1.51f, 1.53f, 0.27f, -100, 0.010f, 0f, 0f, 0f, 300, 0.011f, 0f, 0f, 0f, 0.164f, 0.140f, 0.250f, 0f, -5f, 12428.5f, 99.6f, 0f, 0x20} );</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT4 SECTION "Ice Palace" [4707-6805] --> |
||||
<h2><a>Space Station</a></h2> |
||||
<div> |
||||
<pre>SpacestationAlcove = new Environment ( new float[]{ 26, 1.5f, 0.780f, -1000, -300, -100, 1.16f, 0.81f, 0.55f, 300, 0.007f, 0f, 0f, 0f, 000, 0.018f, 0f, 0f, 0f, 0.192f, 0.210f, 0.250f, 0f, -5f, 3316.1f, 458.2f, 0f, 0x20} ); |
||||
SpacestationMediumroom = new Environment ( new float[]{ 26, 1.5f, 0.750f, -1000, -400, -100, 3.01f, 0.50f, 0.55f, -800, 0.034f, 0f, 0f, 0f, 100, 0.035f, 0f, 0f, 0f, 0.209f, 0.310f, 0.250f, 0f, -5f, 3316.1f, 458.2f, 0f, 0x20} ); |
||||
SpacestationShortpassage = new Environment ( new float[]{ 26, 1.5f, 0.870f, -1000, -400, -100, 3.57f, 0.50f, 0.55f, 0, 0.012f, 0f, 0f, 0f, 100, 0.016f, 0f, 0f, 0f, 0.172f, 0.200f, 0.250f, 0f, -5f, 3316.1f, 458.2f, 0f, 0x20} ); |
||||
SpacestationLongpassage = new Environment ( new float[]{ 26, 1.9f, 0.820f, -1000, -400, -100, 4.62f, 0.62f, 0.55f, 0, 0.012f, 0f, 0f, 0f, 200, 0.031f, 0f, 0f, 0f, 0.250f, 0.230f, 0.250f, 0f, -5f, 3316.1f, 458.2f, 0f, 0x20} ); |
||||
SpacestationLargeroom = new Environment ( new float[]{ 26, 1.8f, 0.810f, -1000, -400, -100, 3.89f, 0.38f, 0.61f, -1000, 0.056f, 0f, 0f, 0f, -100, 0.035f, 0f, 0f, 0f, 0.233f, 0.280f, 0.250f, 0f, -5f, 3316.1f, 458.2f, 0f, 0x20} ); |
||||
SpacestationHall = new Environment ( new float[]{ 26, 1.9f, 0.870f, -1000, -400, -100, 7.11f, 0.38f, 0.61f, -1500, 0.100f, 0f, 0f, 0f, -400, 0.047f, 0f, 0f, 0f, 0.250f, 0.250f, 0.250f, 0f, -5f, 3316.1f, 458.2f, 0f, 0x20} ); |
||||
SpacestationCupboard = new Environment ( new float[]{ 26, 1.4f, 0.560f, -1000, -300, -100, 0.79f, 0.81f, 0.55f, 300, 0.007f, 0f, 0f, 0f, 500, 0.018f, 0f, 0f, 0f, 0.181f, 0.310f, 0.250f, 0f, -5f, 3316.1f, 458.2f, 0f, 0x20} ); |
||||
SpacestationSmallroom = new Environment ( new float[]{ 26, 1.5f, 0.700f, -1000, -300, -100, 1.72f, 0.82f, 0.55f, -200, 0.007f, 0f, 0f, 0f, 300, 0.013f, 0f, 0f, 0f, 0.188f, 0.260f, 0.250f, 0f, -5f, 3316.1f, 458.2f, 0f, 0x20} );</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT5 SECTION "Space Station" [6806-8687] --> |
||||
<h2><a>Wooden Hut or Ship</a></h2> |
||||
<div> |
||||
<pre>WoodenAlcove = new Environment ( new float[]{ 26, 7.5f, 1f, -1000, -1800, -1000, 1.22f, 0.62f, 0.91f, 100, 0.012f, 0f, 0f, 0f, -300, 0.024f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 4705f, 99.6f, 0f, 0x3f} ); |
||||
WoodenShortpassage = new Environment ( new float[]{ 26, 7.5f, 1f, -1000, -1800, -1000, 1.75f, 0.50f, 0.87f, -100, 0.012f, 0f, 0f, 0f, -400, 0.024f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 4705f, 99.6f, 0f, 0x3f} ); |
||||
WoodenMediumroom = new Environment ( new float[]{ 26, 7.5f, 1f, -1000, -2000, -1100, 1.47f, 0.42f, 0.82f, -100, 0.049f, 0f, 0f, 0f, -100, 0.029f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 4705f, 99.6f, 0f, 0x3f} ); |
||||
WoodenLongpassage = new Environment ( new float[]{ 26, 7.5f, 1f, -1000, -2000, -1000, 1.99f, 0.40f, 0.79f, 000, 0.020f, 0f, 0f, 0f, -700, 0.036f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 4705f, 99.6f, 0f, 0x3f} ); |
||||
WoodenLargeroom = new Environment ( new float[]{ 26, 7.5f, 1f, -1000, -2100, -1100, 2.65f, 0.33f, 0.82f, -100, 0.066f, 0f, 0f, 0f, -200, 0.049f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 4705f, 99.6f, 0f, 0x3f} ); |
||||
WoodenHall = new Environment ( new float[]{ 26, 7.5f, 1f, -1000, -2200, -1100, 3.45f, 0.30f, 0.82f, -100, 0.088f, 0f, 0f, 0f, -200, 0.063f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 4705f, 99.6f, 0f, 0x3f} ); |
||||
WoodenCupboard = new Environment ( new float[]{ 26, 7.5f, 1f, -1000, -1700, -1000, 0.56f, 0.46f, 0.91f, 100, 0.012f, 0f, 0f, 0f, 100, 0.028f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 4705f, 99.6f, 0f, 0x3f} ); |
||||
WoodenSmallroom = new Environment ( new float[]{ 26, 7.5f, 1f, -1000, -1900, -1000, 0.79f, 0.32f, 0.87f, 00, 0.032f, 0f, 0f, 0f, -100, 0.029f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 4705f, 99.6f, 0f, 0x3f} ); |
||||
WoodenCourtyard = new Environment ( new float[]{ 26, 7.5f, 0.650f, -1000, -2200, -1000, 1.79f, 0.35f, 0.79f, -500, 0.123f, 0f, 0f, 0f, -2000, 0.032f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 4705f, 99.6f, 0f, 0x3f} );</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT6 SECTION "Wooden Hut or Ship" [8688-10715] --> |
||||
<h2><a>Sport</a></h2> |
||||
<div> |
||||
<pre>SportEmptystadium = new Environment ( new float[]{ 26, 7.2f, 1f, -1000, -700, -200, 6.26f, 0.51f, 1.10f, -2400, 0.183f, 0f, 0f, 0f, -800, 0.038f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x20} ); |
||||
SportSquashcourt = new Environment ( new float[]{ 26, 7.5f, 0.750f, -1000, -1000, -200, 2.22f, 0.91f, 1.16f, -700, 0.007f, 0f, 0f, 0f, -200, 0.011f, 0f, 0f, 0f, 0.126f, 0.190f, 0.250f, 0f, -5f, 7176.9f, 211.2f, 0f, 0x20} ); |
||||
SportSmallswimmingpool = new Environment ( new float[]{ 26, 36.2f, 0.700f, -1000, -200, -100, 2.76f, 1.25f, 1.14f, -400, 0.020f, 0f, 0f, 0f, -200, 0.030f, 0f, 0f, 0f, 0.179f, 0.150f, 0.895f, 0.190f, -5f, 5000f, 250f, 0f, 0x0} ); |
||||
SportLargeswimmingpool = new Environment ( new float[]{ 26, 36.2f, 0.820f, -1000, -200, 0, 5.49f, 1.31f, 1.14f, -700, 0.039f, 0f, 0f, 0f, -600, 0.049f, 0f, 0f, 0f, 0.222f, 0.550f, 1.159f, 0.210f, -5f, 5000f, 250f, 0f, 0x0} ); |
||||
SportGymnasium = new Environment ( new float[]{ 26, 7.5f, 0.810f, -1000, -700, -100, 3.14f, 1.06f, 1.35f, -800, 0.029f, 0f, 0f, 0f, -500, 0.045f, 0f, 0f, 0f, 0.146f, 0.140f, 0.250f, 0f, -5f, 7176.9f, 211.2f, 0f, 0x20} ); |
||||
SportFullstadium = new Environment ( new float[]{ 26, 7.2f, 1f, -1000, -2300, -200, 5.25f, 0.17f, 0.80f, -2000, 0.188f, 0f, 0f, 0f, -1100, 0.038f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x20} );</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT7 SECTION "Sport" [10716-12105] --> |
||||
<h2><a>Pipes</a></h2> |
||||
<div> |
||||
<pre>Sewerpipe = new Environment ( new float[]{ 21, 1.7f, 0.800f, -1000, -1000, 0, 2.81f, 0.14f, 1f, 429, 0.014f, 0f, 0f, 0f, 1023, 0.021f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x3f} ); |
||||
PipeSmall = new Environment ( new float[]{ 26, 50.3f, 1f, -1000, -900, -1300, 5.04f, 0.10f, 0.10f, -600, 0.032f, 0f, 0f, 0f, 800, 0.015f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 2854.4f, 20f, 0f, 0x3f} ); |
||||
PipeLongthin = new Environment ( new float[]{ 26, 1.6f, 0.910f, -1000, -700, -1100, 9.21f, 0.18f, 0.10f, -300, 0.010f, 0f, 0f, 0f, -300, 0.022f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 2854.4f, 20f, 0f, 0x0} ); |
||||
PipeLarge = new Environment ( new float[]{ 26, 50.3f, 1f, -1000, -900, -1300, 8.45f, 0.10f, 0.10f, -800, 0.046f, 0f, 0f, 0f, 400, 0.032f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 2854.4f, 20f, 0f, 0x3f} ); |
||||
PipeResonant = new Environment ( new float[]{ 26, 1.3f, 0.910f, -1000, -700, -1100, 6.81f, 0.18f, 0.10f, -300, 0.010f, 0f, 0f, 0f, 00, 0.022f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 2854.4f, 20f, 0f, 0x0} );</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT8 SECTION "Pipes" [12106-13186] --> |
||||
<h2><a>Moods</a></h2> |
||||
<div> |
||||
<pre>Heaven = new Environment ( new float[]{ 26, 19.6f, 0.940f, -1000, -200, -700, 5.04f, 1.12f, 0.56f, -1230, 0.020f, 0f, 0f, 0f, 200, 0.029f, 0f, 0f, 0f, 0.250f, 0.080f, 2.742f, 0.050f, -2f, 5000f, 250f, 0f, 0x3f} ); |
||||
Hell = new Environment ( new float[]{ 26, 100f, 0.570f, -1000, -900, -700, 3.57f, 0.49f, 2f, -10000, 0.020f, 0f, 0f, 0f, 300, 0.030f, 0f, 0f, 0f, 0.110f, 0.040f, 2.109f, 0.520f, -5f, 5000f, 139.5f, 0f, 0x40} ); |
||||
Memory = new Environment ( new float[]{ 26, 8f, 0.850f, -1000, -400, -900, 4.06f, 0.82f, 0.56f, -2800, 0f, 0f, 0f, 0f, 100, 0f, 0f, 0f, 0f, 0.250f, 0f, 0.474f, 0.450f, -10f, 5000f, 250f, 0f, 0x0} ); |
||||
Drugged = new Environment ( new float[]{ 23, 1.9f, 0.500f, -1000, 0, 0, 8.39f, 1.39f, 1f, -115, 0.002f, 0f, 0f, 0f, 985, 0.030f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 1f, -5f, 5000f, 250f, 0f, 0x1f} ); |
||||
Dizzy = new Environment ( new float[]{ 24, 1.8f, 0.600f, -1000, -400, 0, 17.23f, 0.56f, 1f, -1713, 0.020f, 0f, 0f, 0f, -613, 0.030f, 0f, 0f, 0f, 0.250f, 1f, 0.810f, 0.310f, -5f, 5000f, 250f, 0f, 0x1f} ); |
||||
Psychotic = new Environment ( new float[]{ 25, 1f, 0.500f, -1000, -151, 0, 7.56f, 0.91f, 1f, -626, 0.020f, 0f, 0f, 0f, 774, 0.030f, 0f, 0f, 0f, 0.250f, 0f, 4f, 1f, -5f, 5000f, 250f, 0f, 0x1f} );</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT9 SECTION "Moods" [13187-14458] --> |
||||
<h2><a>Car Racing</a></h2> |
||||
<div> |
||||
<pre>DrivingCommentator = new Environment ( new float[]{ 26, 3f, 0f, 1000, -500, -600, 2.42f, 0.88f, 0.68f, -1400, 0.093f, 0f, 0f, 0f, -1200, 0.017f, 0f, 0f, 0f, 0.250f, 1f, 0.250f, 0f, -10f, 5000f, 250f, 0f, 0x20} ); |
||||
DrivingPitgarage = new Environment ( new float[]{ 26, 1.9f, 0.590f, -1000, -300, -500, 1.72f, 0.93f, 0.87f, -500, 0f, 0f, 0f, 0f, 200, 0.016f, 0f, 0f, 0f, 0.250f, 0.110f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x0} ); |
||||
DrivingIncarRacer = new Environment ( new float[]{ 26, 1.1f, 0.800f, -1000, 0, -200, 0.17f, 2f, 0.41f, 500, 0.007f, 0f, 0f, 0f, -300, 0.015f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 10268.2f, 251f, 0f, 0x20} ); |
||||
DrivingIncarSports = new Environment ( new float[]{ 26, 1.1f, 0.800f, -1000, -400, 0, 0.17f, 0.75f, 0.41f, 0, 0.010f, 0f, 0f, 0f, -500, 0f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 10268.2f, 251f, 0f, 0x20} ); |
||||
DrivingIncarLuxury = new Environment ( new float[]{ 26, 1.6f, 1f, -1000, -2000, -600, 0.13f, 0.41f, 0.46f, -200, 0.010f, 0f, 0f, 0f, 400, 0.010f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 10268.2f, 251f, 0f, 0x20} ); |
||||
DrivingFullgrandstand = new Environment ( new float[]{ 26, 8.3f, 1f, -1000, -1100, -400, 3.01f, 1.37f, 1.28f, -900, 0.090f, 0f, 0f, 0f, -1500, 0.049f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 10420.2f, 250f, 0f, 0x1f} ); |
||||
DrivingEmptygrandstand = new Environment ( new float[]{ 26, 8.3f, 1f, -1000, 0, -200, 4.62f, 1.75f, 1.40f, -1363, 0.090f, 0f, 0f, 0f, -1200, 0.049f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 10420.2f, 250f, 0f, 0x1f} ); |
||||
DrivingTunnel = new Environment ( new float[]{ 26, 3.1f, 0.810f, -1000, -800, -100, 3.42f, 0.94f, 1.31f, -300, 0.051f, 0f, 0f, 0f, -300, 0.047f, 0f, 0f, 0f, 0.214f, 0.050f, 0.250f, 0f, -5f, 5000f, 155.3f, 0f, 0x20} );</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT10 SECTION "Car Racing" [14459-16253] --> |
||||
<h2><a>City</a></h2> |
||||
<div> |
||||
<pre>CityIndoors = new Environment ( new float[]{ 16, 7.5f, 0.500f, -1000, -800, 0, 1.49f, 0.67f, 1f, -2273, 0.007f, 0f, 0f, 0f, -1691, 0.011f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x3f} ); |
||||
CityStreets = new Environment ( new float[]{ 26, 3f, 0.780f, -1000, -300, -100, 1.79f, 1.12f, 0.91f, -1100, 0.046f, 0f, 0f, 0f, -1400, 0.028f, 0f, 0f, 0f, 0.250f, 0.200f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x20} ); |
||||
CitySubway = new Environment ( new float[]{ 26, 3f, 0.740f, -1000, -300, -100, 3.01f, 1.23f, 0.91f, -300, 0.046f, 0f, 0f, 0f, 200, 0.028f, 0f, 0f, 0f, 0.125f, 0.210f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x20} ); |
||||
CityMuseum = new Environment ( new float[]{ 26, 80.3f, 0.820f, -1000, -1500, -1500, 3.28f, 1.40f, 0.57f, -1200, 0.039f, 0f, 0f, -0f, -100, 0.034f, 0f, 0f, 0f, 0.130f, 0.170f, 0.250f, 0f, -5f, 2854.4f, 107.5f, 0f, 0x0} ); |
||||
CityLibrary = new Environment ( new float[]{ 26, 80.3f, 0.820f, -1000, -1100, -2100, 2.76f, 0.89f, 0.41f, -900, 0.029f, 0f, 0f, -0f, -100, 0.020f, 0f, 0f, 0f, 0.130f, 0.170f, 0.250f, 0f, -5f, 2854.4f, 107.5f, 0f, 0x0} ); |
||||
CityUnderpass = new Environment ( new float[]{ 26, 3f, 0.820f, -1000, -700, -100, 3.57f, 1.12f, 0.91f, -800, 0.059f, 0f, 0f, 0f, -100, 0.037f, 0f, 0f, 0f, 0.250f, 0.140f, 0.250f, 0f, -7f, 5000f, 250f, 0f, 0x20} ); |
||||
CityAbandoned = new Environment ( new float[]{ 26, 3f, 0.690f, -1000, -200, -100, 3.28f, 1.17f, 0.91f, -700, 0.044f, 0f, 0f, 0f, -1100, 0.024f, 0f, 0f, 0f, 0.250f, 0.200f, 0.250f, 0f, -3f, 5000f, 250f, 0f, 0x20} );</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT11 SECTION "City" [16254-17801] --> |
||||
<h2><a>Small Indoor Rooms</a></h2> |
||||
<div> |
||||
<pre>Room = new Environment ( new float[]{ 2, 1.9f, 1f, -1000, -454, 0, 0.40f, 0.83f, 1f, -1646, 0.002f, 0f, 0f, 0f, 53, 0.003f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x3f} ); |
||||
Bathroom = new Environment ( new float[]{ 3, 1.4f, 1f, -1000, -1200, 0, 1.49f, 0.54f, 1f, -370, 0.007f, 0f, 0f, 0f, 1030, 0.011f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x3f} ); |
||||
Livingroom = new Environment ( new float[]{ 4, 2.5f, 1f, -1000, -6000, 0, 0.50f, 0.10f, 1f, -1376, 0.003f, 0f, 0f, 0f, -1104, 0.004f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x3f} ); |
||||
Paddedcell = new Environment ( new float[]{ 1, 1.4f, 1f, -1000, -6000, 0, 0.17f, 0.10f, 1f, -1204, 0.001f, 0f, 0f, 0f, 207, 0.002f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x3f} ); |
||||
Stoneroom = new Environment ( new float[]{ 5, 11.6f, 1f, -1000, -300, 0, 2.31f, 0.64f, 1f, -711, 0.012f, 0f, 0f, 0f, 83, 0.017f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x3f} );</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT12 SECTION "Small Indoor Rooms" [17802-18853] --> |
||||
<h2><a>Medium-Sized Indoor Rooms</a></h2> |
||||
<div> |
||||
<pre>Workshop = new Environment ( new float[]{ 26, 1.9f, 1f, -1000, -1700, -800, 0.76f, 1f, 1f, 0, 0.012f, 0f, 0f, 0f, 100, 0.012f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x0} ); |
||||
Schoolroom = new Environment ( new float[]{ 26, 1.86f, 0.690f, -1000, -400, -600, 0.98f, 0.45f, 0.18f, 300, 0.017f, 0f, 0f, 0f, 300, 0.015f, 0f, 0f, 0f, 0.095f, 0.140f, 0.250f, 0f, -5f, 7176.9f, 211.2f, 0f, 0x20} ); |
||||
Practiseroom = new Environment ( new float[]{ 26, 1.86f, 0.870f, -1000, -800, -600, 1.12f, 0.56f, 0.18f, 200, 0.010f, 0f, 0f, 0f, 300, 0.011f, 0f, 0f, 0f, 0.095f, 0.140f, 0.250f, 0f, -5f, 7176.9f, 211.2f, 0f, 0x20} ); |
||||
Outhouse = new Environment ( new float[]{ 26, 80.3f, 0.820f, -1000, -1900, -1600, 1.38f, 0.38f, 0.35f, -100, 0.024f, 0f, 0f, -0f, -400, 0.044f, 0f, 0f, 0f, 0.121f, 0.170f, 0.250f, 0f, -5f, 2854.4f, 107.5f, 0f, 0x0} ); |
||||
Caravan = new Environment ( new float[]{ 26, 8.3f, 1f, -1000, -2100, -1800, 0.43f, 1.50f, 1f, 0, 0.012f, 0f, 0f, 0f, 600, 0.012f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x1f} ); |
||||
Dustyroom = new Environment ( new float[]{ 26, 1.8f, 0.560f, -1000, -200, -300, 1.79f, 0.38f, 0.21f, -600, 0.002f, 0f, 0f, 0f, 200, 0.006f, 0f, 0f, 0f, 0.202f, 0.050f, 0.250f, 0f, -10f, 13046f, 163.3f, 0f, 0x20} ); |
||||
Chapel = new Environment ( new float[]{ 26, 19.6f, 0.840f, -1000, -500, 0, 4.62f, 0.64f, 1.23f, -700, 0.032f, 0f, 0f, 0f, -200, 0.049f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0.110f, -5f, 5000f, 250f, 0f, 0x3f} );</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT13 SECTION "Medium-Sized Indoor Rooms" [18854-20400] --> |
||||
<h2><a>Large Indoor Rooms</a></h2> |
||||
<div> |
||||
<pre>Auditorium = new Environment ( new float[]{ 6, 21.6f, 1f, -1000, -476, 0, 4.32f, 0.59f, 1f, -789, 0.020f, 0f, 0f, 0f, -289, 0.030f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x3f} ); |
||||
Concerthall = new Environment ( new float[]{ 7, 19.6f, 1f, -1000, -500, 0, 3.92f, 0.70f, 1f, -1230, 0.020f, 0f, 0f, 0f, -02, 0.029f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x3f} ); |
||||
Cave = new Environment ( new float[]{ 8, 14.6f, 1f, -1000, 0, 0, 2.91f, 1.30f, 1f, -602, 0.015f, 0f, 0f, 0f, -302, 0.022f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x1f} ); |
||||
Arena = new Environment ( new float[]{ 9, 36.2f, 1f, -1000, -698, 0, 7.24f, 0.33f, 1f, -1166, 0.020f, 0f, 0f, 0f, 16, 0.030f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x3f} ); |
||||
Hangar = new Environment ( new float[]{ 10, 50.3f, 1f, -1000, -1000, 0, 10.05f, 0.23f, 1f, -602, 0.020f, 0f, 0f, 0f, 198, 0.030f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x3f} ); |
||||
DomeTomb = new Environment ( new float[]{ 26, 51.8f, 0.790f, -1000, -900, -1300, 4.18f, 0.21f, 0.10f, -825, 0.030f, 0f, 0f, 0f, 450, 0.022f, 0f, 0f, 0f, 0.177f, 0.190f, 0.250f, 0f, -5f, 2854.4f, 20f, 0f, 0x0} ); |
||||
DomeSaintPauls = new Environment ( new float[]{ 26, 50.3f, 0.870f, -1000, -900, -1300, 10.48f, 0.19f, 0.10f, -1500, 0.090f, 0f, 0f, 0f, 200, 0.042f, 0f, 0f, 0f, 0.250f, 0.120f, 0.250f, 0f, -5f, 2854.4f, 20f, 0f, 0x3f} );</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT14 SECTION "Large Indoor Rooms" [20401-21901] --> |
||||
<h2><a>Hallways, Alleys</a></h2> |
||||
<div> |
||||
<pre>Carpettedhallway = new Environment ( new float[]{ 11, 1.9f, 1f, -1000, -4000, 0, 0.30f, 0.10f, 1f, -1831, 0.002f, 0f, 0f, 0f, -1630, 0.030f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x3f} ); |
||||
Hallway = new Environment ( new float[]{ 12, 1.8f, 1f, -1000, -300, 0, 1.49f, 0.59f, 1f, -1219, 0.007f, 0f, 0f, 0f, 441, 0.011f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x3f} ); |
||||
Stonecorridor = new Environment ( new float[]{ 13, 13.5f, 1f, -1000, -237, 0, 2.70f, 0.79f, 1f, -1214, 0.013f, 0f, 0f, 0f, 395, 0.020f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x3f} ); |
||||
Alley = new Environment ( new float[]{ 14, 7.5f, 0.300f, -1000, -270, 0, 1.49f, 0.86f, 1f, -1204, 0.007f, 0f, 0f, 0f, -4, 0.011f, 0f, 0f, 0f, 0.125f, 0.950f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x3f} );</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT15 SECTION "Hallways, Alleys" [21902-22779] --> |
||||
<h2><a>Outdoors</a></h2> |
||||
<div> |
||||
<pre>Backyard = new Environment ( new float[]{ 26, 80.3f, 0.450f, -1000, -1200, -600, 1.12f, 0.34f, 0.46f, -700, 0.069f, 0f, 0f, -0f, -300, 0.023f, 0f, 0f, 0f, 0.218f, 0.340f, 0.250f, 0f, -5f, 4399.1f, 242.9f, 0f, 0x0} ); |
||||
Plain = new Environment ( new float[]{ 19, 42.5f, 0.210f, -1000, -2000, 0, 1.49f, 0.50f, 1f, -2466, 0.179f, 0f, 0f, 0f, -1926, 0.100f, 0f, 0f, 0f, 0.250f, 1f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x3f} ); |
||||
Rollingplains = new Environment ( new float[]{ 26, 80.3f, 0f, -1000, -3900, -400, 2.13f, 0.21f, 0.46f, -1500, 0.300f, 0f, 0f, -0f, -700, 0.019f, 0f, 0f, 0f, 0.250f, 1f, 0.250f, 0f, -5f, 4399.1f, 242.9f, 0f, 0x0} ); |
||||
Deepcanyon = new Environment ( new float[]{ 26, 80.3f, 0.740f, -1000, -1500, -400, 3.89f, 0.21f, 0.46f, -1000, 0.223f, 0f, 0f, -0f, -900, 0.019f, 0f, 0f, 0f, 0.250f, 1f, 0.250f, 0f, -5f, 4399.1f, 242.9f, 0f, 0x0} ); |
||||
Creek = new Environment ( new float[]{ 26, 80.3f, 0.350f, -1000, -1500, -600, 2.13f, 0.21f, 0.46f, -800, 0.115f, 0f, 0f, -0f, -1400, 0.031f, 0f, 0f, 0f, 0.218f, 0.340f, 0.250f, 0f, -5f, 4399.1f, 242.9f, 0f, 0x0} ); |
||||
Valley = new Environment ( new float[]{ 26, 80.3f, 0.280f, -1000, -3100, -1600, 2.88f, 0.26f, 0.35f, -1700, 0.263f, 0f, 0f, -0f, -800, 0.100f, 0f, 0f, 0f, 0.250f, 0.340f, 0.250f, 0f, -5f, 2854.4f, 107.5f, 0f, 0x0} ); |
||||
Forest = new Environment ( new float[]{ 15, 38f, 0.300f, -1000, -3300, 0, 1.49f, 0.54f, 1f, -2560, 0.162f, 0f, 0f, 0f, -229, 0.088f, 0f, 0f, 0f, 0.125f, 1f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x3f} ); |
||||
Mountains = new Environment ( new float[]{ 17, 100f, 0.270f, -1000, -2500, 0, 1.49f, 0.21f, 1f, -2780, 0.300f, 0f, 0f, 0f, -1434, 0.100f, 0f, 0f, 0f, 0.250f, 1f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x1f} ); |
||||
Quarry = new Environment ( new float[]{ 18, 17.5f, 1f, -1000, -1000, 0, 1.49f, 0.83f, 1f, -10000, 0.061f, 0f, 0f, 0f, 500, 0.025f, 0f, 0f, 0f, 0.125f, 0.700f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x3f} ); |
||||
Parkinglot = new Environment ( new float[]{ 20, 8.3f, 1f, -1000, 0, 0, 1.65f, 1.50f, 1f, -1363, 0.008f, 0f, 0f, 0f, -1153, 0.012f, 0f, 0f, 0f, 0.250f, 0f, 0.250f, 0f, -5f, 5000f, 250f, 0f, 0x1f} );</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT16 SECTION "Outdoors" [22780-24957] --> |
||||
<h2><a>Water</a></h2> |
||||
<div> |
||||
<pre>Underwater = new Environment ( new float[]{ 22, 1.8f, 1f, -1000, -4000, 0, 1.49f, 0.10f, 1f, -449, 0.007f, 0f, 0f, 0f, 1700, 0.011f, 0f, 0f, 0f, 0.250f, 0f, 1.180f, 0.348f, -5f, 5000f, 250f, 0f, 0x3f} ); |
||||
Smallwaterroom = new Environment ( new float[]{ 26, 36.2f, 0.700f, -1000, -698, 0, 1.51f, 1.25f, 1.14f, -100, 0.020f, 0f, 0f, 0f, 300, 0.030f, 0f, 0f, 0f, 0.179f, 0.150f, 0.895f, 0.190f, -7f, 5000f, 250f, 0f, 0x0} );</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT17 SECTION "Water" [24958-] --> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:audio_environment_presets?do=export_xhtmlbody">view online version</a></em></p> |
Before Width: | Height: | Size: 124 KiB |
@ -1,290 +0,0 @@ |
||||
|
||||
<h1><a>Bloom and Glow</a></h1> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
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. |
||||
</p> |
||||
|
||||
<p> |
||||
Those images gives an idea of what bloom does. The left image has no bloom effect, the right image does. <br/> |
||||
|
||||
<img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/nobloomsky.png"><img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/blomsky.png"> |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT1 SECTION "Bloom and Glow" [1-484] --> |
||||
<h1><a>Bloom Usage</a></h1> |
||||
<div> |
||||
<ol> |
||||
<li><div> Create a FilterPostProcessor</div> |
||||
</li> |
||||
<li><div> Create a BloomFilter</div> |
||||
</li> |
||||
<li><div> Add the filter to the processor</div> |
||||
</li> |
||||
<li><div> Add the processor to the viewPort</div> |
||||
</li> |
||||
</ol> |
||||
<pre> FilterPostProcessor fpp=new FilterPostProcessor(assetManager); |
||||
BloomFilter bloom=new BloomFilter(); |
||||
fpp.addFilter(bloom); |
||||
viewPort.addProcessor(fpp);</pre> |
||||
|
||||
<p> |
||||
Here are the parameters that you can tweak : |
||||
</p> |
||||
<div><table> |
||||
<tr> |
||||
<th> Parameter </th><th> Method </th><th> Default </th><th> Description </th> |
||||
</tr> |
||||
<tr> |
||||
<td> blur scale </td><td> <code>setBlurScale(float)</code> </td><td>1.5f </td><td> the scale of the bloom effect, but be careful, high values does artifacts </td> |
||||
</tr> |
||||
<tr> |
||||
<td> exposure Power </td><td> <code>setExposurePower(float)</code> </td><td>5.0f </td><td> the glowing channel color is raised to the value power </td> |
||||
</tr> |
||||
<tr> |
||||
<td> exposure cut-off </td><td> <code>setExposureCutOff(float)</code> </td><td>0.0f </td><td> the threshold of color to bloom during extraction </td> |
||||
</tr> |
||||
<tr> |
||||
<td> bloom intensity </td><td> <code>setBloomIntensity(float)</code> </td><td>2.0f </td><td> the resulting bloom value is multiplied by this intensity </td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT3 TABLE [865-1454] --> |
||||
<p> |
||||
|
||||
You'll probably need to adjust those parameters depending on your scene. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT2 SECTION "Bloom Usage" [485-1529] --> |
||||
<h1><a>Bloom with a glow map</a></h1> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Sometimes, you want to have more control over what glows and does not glow. |
||||
The bloom filter supports a glow map or a glow color. |
||||
</p> |
||||
|
||||
</div> |
||||
|
||||
<h5><a>Creating a glow-map</a></h5> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Let's take the hover tank example bundled with JME3 test data.<br/> |
||||
|
||||
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: <br/> |
||||
|
||||
<img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/tank_diffuse_ss.png"> |
||||
<img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/tank_glow_map_ss.png"> |
||||
</p> |
||||
|
||||
<p> |
||||
Glow maps work with Lighting.j3md, Particles.j3md and SolidColor.j3md material definitions. |
||||
The tank material looks like this : |
||||
|
||||
</p> |
||||
<pre>Material My Material : Common/MatDefs/Light/Lighting.j3md { |
||||
MaterialParameters { |
||||
SpecularMap : Models/HoverTank/tank_specular.png |
||||
Shininess : 8 |
||||
NormalMap : Models/HoverTank/tank_normals.png |
||||
DiffuseMap : Models/HoverTank/tank_diffuse.png |
||||
GlowMap : Models/HoverTank/tank_glow_map_highres.png |
||||
UseMaterialColors : true |
||||
Ambient : 0.0 0.0 0.0 1.0 |
||||
Diffuse : 1.0 1.0 1.0 1.0 |
||||
Specular : 1.0 1.0 1.0 1.0 |
||||
} |
||||
}</pre> |
||||
|
||||
<p> |
||||
|
||||
The glow map is defined here : <strong>GlowMap : Models/HoverTank/tank_glow_map_highres.png</strong> |
||||
</p> |
||||
|
||||
</div> |
||||
|
||||
<h5><a>Usage</a></h5> |
||||
<div> |
||||
<ol> |
||||
<li><div> Create a FilterPostProcessor</div> |
||||
</li> |
||||
<li><div> Create a BloomFilter with the GlowMode.Objects parameter</div> |
||||
</li> |
||||
<li><div> Add the filter to the processor</div> |
||||
</li> |
||||
<li><div> Add the processor to the viewPort</div> |
||||
</li> |
||||
</ol> |
||||
<pre> FilterPostProcessor fpp=new FilterPostProcessor(assetManager); |
||||
BloomFilter bf=new BloomFilter(BloomFilter.GlowMode.Objects); |
||||
fpp.addFilter(bf); |
||||
viewPort.addProcessor(fpp);</pre> |
||||
|
||||
<p> |
||||
Here is the result : <br/> |
||||
|
||||
<img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/tanlglow1.png"> |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT4 SECTION "Bloom with a glow map" [1530-3231] --> |
||||
<h1><a>Bloom with a glow color</a></h1> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Sometimes you need an entire object to glow, not just parts of it. |
||||
In this case you'll need to use the glow color parameter. |
||||
</p> |
||||
|
||||
</div> |
||||
|
||||
<h5><a>Usage</a></h5> |
||||
<div> |
||||
<ol> |
||||
<li><div> Create a material for your object and set the GlowColor parameter</div> |
||||
</li> |
||||
<li><div> Create a FilterPostProcessor</div> |
||||
</li> |
||||
<li><div> Create a BloomFilter with the GlowMode.Objects parameter</div> |
||||
</li> |
||||
<li><div> Add the filter to the processor</div> |
||||
</li> |
||||
<li><div> Add the processor to the viewPort</div> |
||||
</li> |
||||
</ol> |
||||
<pre> 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);</pre> |
||||
|
||||
<p> |
||||
Here is the result on Oto's plasma ball (before and after) : <br/> |
||||
|
||||
<img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/otonobloom.png"> |
||||
<img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/otoglow.png"> |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT5 SECTION "Bloom with a glow color" [3232-4239] --> |
||||
<h1><a>Hints and tricks</a></h1> |
||||
<div> |
||||
|
||||
</div> |
||||
|
||||
<h5><a>Increasing the blur range and reducing fps cost</a></h5> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
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 : <br/> |
||||
|
||||
|
||||
</p> |
||||
<pre> BloomFilter bloom=new BloomFilter(); |
||||
bloom.setDownSamplingFactor(2.0f); </pre> |
||||
|
||||
<p> |
||||
|
||||
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. |
||||
</p> |
||||
|
||||
</div> |
||||
|
||||
<h5><a>Using classic bloom combined with a glow map</a></h5> |
||||
<div> |
||||
|
||||
<p> |
||||
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 |
||||
</p> |
||||
<pre>BloomFilter bloom=new BloomFilter(BloomFilter.GlowMode.SceneAndObjects);</pre> |
||||
|
||||
<p> |
||||
However, note that both effects will share the same values of attribute, and sometimes, it won't be what you need. |
||||
</p> |
||||
|
||||
</div> |
||||
|
||||
<h5><a>Making your home brewed material definition support Glow</a></h5> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
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 : |
||||
</p> |
||||
<pre> MaterialParameters { |
||||
|
||||
.... |
||||
|
||||
// Texture of the glowing parts of the material |
||||
Texture2D GlowMap |
||||
// The glow color of the object |
||||
Color GlowColor |
||||
}</pre> |
||||
|
||||
<p> |
||||
Then add the following technique : |
||||
|
||||
</p> |
||||
<pre> Technique Glow { |
||||
|
||||
LightMode SinglePass |
||||
|
||||
VertexShader GLSL100: Common/MatDefs/Misc/SimpleTextured.vert |
||||
FragmentShader GLSL100: Common/MatDefs/Light/Glow.frag |
||||
|
||||
WorldParameters { |
||||
WorldViewProjectionMatrix |
||||
} |
||||
|
||||
Defines { |
||||
HAS_GLOWMAP : GlowMap |
||||
HAS_GLOWCOLOR : GlowColor |
||||
} |
||||
}</pre> |
||||
|
||||
<p> |
||||
Then you can use this material with the BloomFilter |
||||
</p> |
||||
|
||||
</div> |
||||
|
||||
<h5><a>Make a glowing object stop to glow</a></h5> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
If you are using a glow map, remove the texture from the material. |
||||
|
||||
</p> |
||||
<pre>material.clearTextureParam("GlowMap");</pre> |
||||
|
||||
<p> |
||||
If you are using a glow color, set it to black |
||||
|
||||
</p> |
||||
<pre>material.setColor("GlowColor",ColorRGBA.Black);</pre> |
||||
<div><span> |
||||
<a href="/wiki/doku.php/tag:documentation?do=showtag&tag=tag%3Adocumentation">documentation</a>, |
||||
<a href="/wiki/doku.php/tag:effect?do=showtag&tag=tag%3Aeffect">effect</a>, |
||||
<a href="/wiki/doku.php/tag:light?do=showtag&tag=tag%3Alight">light</a> |
||||
</span></div> |
||||
|
||||
</div> |
||||
<!-- EDIT6 SECTION "Hints and tricks" [4240-] --> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:bloom_and_glow?do=export_xhtmlbody">view online version</a></em></p> |
Before Width: | Height: | Size: 283 B |
@ -1,65 +0,0 @@ |
||||
|
||||
<h1><a>Multithreading Bullet Physics in jme3</a></h1> |
||||
<div> |
||||
|
||||
</div> |
||||
<!-- EDIT1 SECTION "Multithreading Bullet Physics in jme3" [1-53] --> |
||||
<h2><a>Introduction</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
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. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT2 SECTION "Introduction" [54-261] --> |
||||
<h2><a>How is it handled in jme3 and bullet?</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
A SimpleApplication with a BulletAppState allows setting the threading type via |
||||
</p> |
||||
<pre>setThreadingType(ThreadingType type);</pre> |
||||
|
||||
<p> |
||||
where ThreadingType can be either SEQUENTIAL or PARALLEL. By default, it's SEQUENTIAL. |
||||
</p> |
||||
|
||||
<p> |
||||
You can activate PARALLEL threading in the simpleInitApp() method: |
||||
</p> |
||||
<pre>bulletAppState = new BulletAppState(); |
||||
bulletAppState.setThreadingType(BulletAppState.ThreadingType.PARALLEL); |
||||
stateManager.attach(bulletAppState);</pre> |
||||
|
||||
<p> |
||||
Now the physics update happens in parallel to render(), that is, after the user's changes in the update() call have been applied. During update() the physics update loop pauses. 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. This allows you to use physics methods in update() as if it was single-threaded. |
||||
</p> |
||||
<div><table> |
||||
<tr> |
||||
<th>PARALLEL</th><th>SEQUENTIAL</th> |
||||
</tr> |
||||
<tr> |
||||
<td>1. update(), 2. render() and physics update().</td><td>1. update(), 2. render(), 3. physics update(). </td> |
||||
</tr> |
||||
<tr> |
||||
<td>Physics Debug View is rendered inaccurately (out of sync)</td><td>Physics Debug View is rendered accurately.</td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT4 TABLE [1202-1424] --> |
||||
<p> |
||||
|
||||
<p><div>You can add more physics spaces by using multiple PARALLEL bulletAppStates. You would do that if you have sets physical objects that never collide (for example, underground bolders and flying cannon balls above ground), so you put those into separate physics spaces, which improves performances (less collisions to check!). |
||||
</div></p> |
||||
</p> |
||||
<div><span> |
||||
<a href="/wiki/doku.php/tag:documentation?do=showtag&tag=tag%3Adocumentation">documentation</a>, |
||||
<a href="/wiki/doku.php/tag:physics?do=showtag&tag=tag%3Aphysics">physics</a>, |
||||
<a href="/wiki/doku.php/tag:threading?do=showtag&tag=tag%3Athreading">threading</a> |
||||
</span></div> |
||||
|
||||
</div> |
||||
<!-- EDIT3 SECTION "How is it handled in jme3 and bullet?" [262-] --> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:bullet_multithreading?do=export_xhtmlbody">view online version</a></em></p> |
Before Width: | Height: | Size: 51 KiB |
Before Width: | Height: | Size: 16 KiB |
@ -1,174 +0,0 @@ |
||||
|
||||
<h1><a>The jME3 Camera</a></h1> |
||||
<div> |
||||
|
||||
</div> |
||||
<!-- EDIT1 SECTION "The jME3 Camera" [1-31] --> |
||||
<h2><a>Default Camera</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
The default com.jme3.renderer.Camera object is <code>cam</code> in com.jme3.app.Application. |
||||
</p> |
||||
|
||||
<p> |
||||
The camera object is created with the following defaults: |
||||
</p> |
||||
<ul> |
||||
<li><div> Width and height are set to the current Application's settings.getWidth() and settings.getHeight() values. </div> |
||||
</li> |
||||
<li><div> Frustum Perspective:</div> |
||||
<ul> |
||||
<li><div> Frame of view angle of 45?? along the Y axis</div> |
||||
</li> |
||||
<li><div> Aspect ratio of width divided by height</div> |
||||
</li> |
||||
<li><div> Near view plane of 1 wu</div> |
||||
</li> |
||||
<li><div> Far view plane of 1000 wu</div> |
||||
</li> |
||||
</ul> |
||||
</li> |
||||
<li><div> Start location at (0f, 0f, 10f).</div> |
||||
</li> |
||||
<li><div> Start direction is looking at the origin.</div> |
||||
</li> |
||||
</ul> |
||||
<div><table> |
||||
<tr> |
||||
<th>Method</th><th>Usage</th> |
||||
</tr> |
||||
<tr> |
||||
<td>cam.getLocation(), setLocation()</td><td>The camera position</td> |
||||
</tr> |
||||
<tr> |
||||
<td>cam.getRotation(), setRotation()</td><td>The camera rotation</td> |
||||
</tr> |
||||
<tr> |
||||
<td>cam.getLeft(), setLeft()</td><td>The left axis of the camera</td> |
||||
</tr> |
||||
<tr> |
||||
<td>cam.getUp(), setUp()</td><td>The up axis of the camera, usually Vector3f(0,1,0)</td> |
||||
</tr> |
||||
<tr> |
||||
<td>cam.getDirection(), setDirection()</td><td>The vector the camera is facing</td> |
||||
</tr> |
||||
<tr> |
||||
<td>cam.getAxes(), setAxes(left,up,dir)</td><td>One accessor for the three properties left/up/direction.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>cam.getFrame(), setFrame(loc,left,up,dir)</td><td>One accessor for the four properties location/left/up/direction.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>cam.resize(width, height, fixAspect)</td><td>Resize an existing camera object while keeping all other settings. Set fixAspect to true to adjust the aspect ratio (?)</td> |
||||
</tr> |
||||
<tr> |
||||
<td>cam.setFrustum( near, far, left, right, top, bottom )</td><td>The frustum is defined by the near/far plane, left/right plane, top/bottom plane (all distances as float values)</td> |
||||
</tr> |
||||
<tr> |
||||
<td>cam.setFrustumPerspective( fovY, aspect ratio, near, far)</td><td>The frustum is defined by view angle along the Y axis (in degrees), aspect ratio, and the near/far plane.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>cam.lookAt(target,up)</td><td>Turn the camera to look at Coordinate target, and rotate it around the up axis.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>cam.setParallelProjection(false)</td><td>Normal perspective</td> |
||||
</tr> |
||||
<tr> |
||||
<td>cam.setParallelProjection(true)</td><td>Parallel projection perspective</td> |
||||
</tr> |
||||
<tr> |
||||
<td>cam.getScreenCoordinates()</td><td>?</td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT3 TABLE [583-1858] --> |
||||
<p> |
||||
<strong>Tip:</strong> After you change view port, frustum, or frame, call <code>cam.update();</code> |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT2 SECTION "Default Camera" [32-1940] --> |
||||
<h2><a>FlyBy Camera</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
The flyby camera is an AppState that extends the default camera in com.jme3.app.SimpleApplication. It is preconfigured to respond to the WASD keys for walking forwards and backwards, and strafing to the sides; move the mouse to rotate the camera ("Mouse Look"), scroll the mouse wheel for zooming in or out. The QZ keys raise or lower the camera vertically. |
||||
|
||||
</p> |
||||
<div><table> |
||||
<tr> |
||||
<th>Method</th><th>Usage</th> |
||||
</tr> |
||||
<tr> |
||||
<td>flyCam.setEnabled(true);</td><td>Activate the flyby cam</td> |
||||
</tr> |
||||
<tr> |
||||
<td>flyCam.setMoveSpeed(10);</td><td>Control the move speed</td> |
||||
</tr> |
||||
<tr> |
||||
<td>flyCam.setRotationSpeed(10);</td><td>Control the rotation speed</td> |
||||
</tr> |
||||
<tr> |
||||
<td>flyCam.setDragToRotate(true)</td><td>Forces the player to keep mouse button pressed to rotate camera, typically used for Applets. If false (default), all mouse movement will be captured and interpreted as rotations.</td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT5 TABLE [2326-2708] --> |
||||
</div> |
||||
<!-- EDIT4 SECTION "FlyBy Camera" [1941-2709] --> |
||||
<h2><a>Chase Camera</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
jME3 also supports a Chase Cam that can follow a moving target Spatial (<code>com.jme3.input.ChaseCamera</code>). Click and hold the mouse button to rotate around the target. |
||||
</p> |
||||
<pre>flyCam.setEnabled(false); |
||||
ChaseCamera chaseCam = new ChaseCamera(cam, target, inputManager);</pre> |
||||
<div><table> |
||||
<tr> |
||||
<th>Method</th><th>Usage</th> |
||||
</tr> |
||||
<tr> |
||||
<td>chaseCam.setSmoothMotion(true);</td><td>Interpolates a smoother acceleration/deceleration when the camera moves.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>chaseCam.setChasingSensitivity(5f)</td><td>The lower the chasing sensitivity, the slower the camera will follow the target when it moves.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>chaseCam.setTrailingSensitivity(0.5f)</td><td>The lower the traling sensitivity, the slower the camera will begin to go after the target when it moves. Default is 0.5;</td> |
||||
</tr> |
||||
<tr> |
||||
<td>chaseCam.setRotationSensitivity(5f)</td><td>The lower the sensitivity, the slower the camera will rotate around the target when the mosue is dragged. Default is 5.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>chaseCam.setTrailingRotationInertia(0.1f)</td><td>This prevents the camera to stop too abruptly when the target stops rotating before the camera has reached the target's trailing position. Default is 0.1f.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>chaseCam.setDefaultDistance(40);</td><td>The default distance to the target at the start of the application.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>chaseCam.setMaxDistance(40);</td><td>The maximum zoom distance. Default is 40f.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>chaseCam.setMinDistance(1);</td><td>The minimum zoom distance. Default is 1f.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>chaseCam.setMinVerticalRotation(-FastMath.PI/2);</td><td>The minimal vertical rotation angle of the camera around the target. Default is 0.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>chaseCam.setDefaultVerticalRotation(-FastMath.PI/2);</td><td>The default vertical rotation angle of the camera around the target at the start of the application.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>chaseCam.setDefaultHorizontalRotation(-FastMath.PI/2);</td><td>The default horizontal rotation angle of the camera around the target at the start of the application.</td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT7 TABLE [3017-4489] --><div><span> |
||||
<a href="/wiki/doku.php/tag:camera?do=showtag&tag=tag%3Acamera">camera</a>, |
||||
<a href="/wiki/doku.php/tag:documentation?do=showtag&tag=tag%3Adocumentation">documentation</a> |
||||
</span></div> |
||||
|
||||
</div> |
||||
<!-- EDIT6 SECTION "Chase Camera" [2710-] --> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:camera?do=export_xhtmlbody">view online version</a></em></p> |
@ -1,653 +0,0 @@ |
||||
|
||||
<h1><a>Capture Audio/Video to a File</a></h1> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
So you've made your cool new JMonkeyEngine3 game and you want to |
||||
create a demo video to show off your hard work. Or maybe you want to |
||||
make a cutscene for your game using the physics and characters in the |
||||
game itself. Screen capturing is the most straightforward way to do |
||||
this, but it can slow down your game and produce low-quality video and |
||||
audio as a result. A better way is to record video and audio directly |
||||
from the game while it is running. |
||||
</p> |
||||
|
||||
<p> |
||||
<p><div>Combine this method with jMonkeyEngine's |
||||
<a href="/com/jme3/gde/core/docs/jme3/advanced/cinematics.html">Cinematics</a> |
||||
feature to record high-quality game trailers! |
||||
</div></p> |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT1 SECTION "Capture Audio/Video to a File" [1-630] --> |
||||
<h2><a>Simple Way</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
First off, if all you need is to record video at 30fps with no sound, then look |
||||
no further than jMonkeyEngine 3's built in <code>VideoRecorderAppState</code> |
||||
class. |
||||
</p> |
||||
|
||||
<p> |
||||
Add the following code to your <code>simpleInitApp()</code> method. |
||||
</p> |
||||
<pre>stateManager.attach(new VideoRecorderAppState()); //start recording</pre> |
||||
|
||||
<p> |
||||
The game will run slow, but the recording will be in high-quality and |
||||
normal speed. The video files will be stored in your user home |
||||
directory, if you want to save to another file, specify it in the |
||||
VideoRecorderAppState constructor. Recording starts when the state is |
||||
attached and ends when the application quits or the state is detached. |
||||
</p> |
||||
|
||||
<p> |
||||
That's all! |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT2 SECTION "Simple Way" [631-1315] --> |
||||
<h2><a>Advanced Way</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
<p><div>This way of A/V recording is still in development. |
||||
It works for all of jMonkeyEngine's test cases. |
||||
If you experience any problems or |
||||
if something isn't clear, please <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://jmonkeyengine.org/members/bortreb/"><param name="text" value="<html><u>let me know</u></html>"><param name="textColor" value="blue"></object>. ??? bortreb |
||||
</div></p> |
||||
</p> |
||||
|
||||
<p> |
||||
If you want to record audio as well, record at different framerates, |
||||
or record from multiple viewpoints at once, then there's a full |
||||
solution for doing this already made for you here: |
||||
</p> |
||||
|
||||
<p> |
||||
<object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://www.aurellem.com/releases/jmeCapture-latest.zip"><param name="text" value="<html><u>http://www.aurellem.com/releases/jmeCapture-latest.zip</u></html>"><param name="textColor" value="blue"></object> |
||||
</p> |
||||
|
||||
<p> |
||||
<object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://www.aurellem.com/releases/jmeCapture-latest.tar.bz2"><param name="text" value="<html><u>http://www.aurellem.com/releases/jmeCapture-latest.tar.bz2</u></html>"><param name="textColor" value="blue"></object> |
||||
</p> |
||||
|
||||
<p> |
||||
Download the archive in your preferred format, extract, |
||||
add the jars to your project, and you are ready to go. |
||||
</p> |
||||
|
||||
<p> |
||||
The javadoc is here: |
||||
<object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://www.aurellem.com/jmeCapture/docs/"><param name="text" value="<html><u>http://www.aurellem.com/jmeCapture/docs/</u></html>"><param name="textColor" value="blue"></object> |
||||
</p> |
||||
|
||||
<p> |
||||
To capture video and audio you use the |
||||
<code>com.aurellem.capture.Capture</code> class, which has two methods, |
||||
<code>captureAudio()</code> and <code>captureVideo()</code>, and the |
||||
<code>com.aurellem.capture.IsoTimer</code> class, which sets the audio and |
||||
video framerate. |
||||
</p> |
||||
|
||||
<p> |
||||
The steps are: |
||||
</p> |
||||
<pre>yourApp.setTimer(new IsoTimer(desiredFramesPerSecond));</pre> |
||||
|
||||
<p> |
||||
This causes jMonkeyEngine to take as much time as it needs to fully |
||||
calculate every frame of the video and audio. You will see your game |
||||
speed up and slow down depending on how computationally demanding your |
||||
game is, but the final recorded audio and video will be perfectly |
||||
sychronized and will run at exactly the fps which you specified. |
||||
</p> |
||||
<pre>captureVideo(yourApp, targetVideoFile); |
||||
captureAudio(yourApp, targetAudioFile);</pre> |
||||
|
||||
<p> |
||||
These will cause the app to record audio and video when it is run. |
||||
Audio and video will stop being recorded when the app stops. Your |
||||
audio will be recorded as a 44,100 Hz linear PCM wav file, while the |
||||
video will be recorded according to the following rules: |
||||
</p> |
||||
|
||||
<p> |
||||
1.) (Preferred) If you supply an empty directory as the file, then |
||||
the video will be saved as a sequence of .png files, one file per |
||||
frame. The files start at 0000000.png and increment from there. |
||||
You can then combine the frames into your preferred |
||||
container/codec. If the directory is not empty, then writing |
||||
video frames to it will fail, and nothing will be written. |
||||
</p> |
||||
|
||||
<p> |
||||
2.) If the filename ends in ".avi" then the frames will be encoded as |
||||
a RAW stream inside an AVI 1.0 container. The resulting file |
||||
will be quite large and you will probably want to re-encode it to |
||||
your preferred container/codec format. Be advised that some |
||||
video payers cannot process AVI with a RAW stream, and that AVI |
||||
1.0 files generated by this method that exceed 2.0GB are invalid |
||||
according to the AVI 1.0 <acronym title="specification">spec</acronym> (but many programs can still deal |
||||
with them.) Thanks to |
||||
<object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://www.randelshofer.ch/blog/2008/08/writing-avi-videos-in-pure-java/"><param name="text" value="<html><u>Werner Randelshofer</u></html>"><param name="textColor" value="blue"></object> |
||||
for his excellent work which made the AVI file writer option possible. |
||||
</p> |
||||
|
||||
<p> |
||||
3.) Any non-directory file ending in anything other than ".avi" will |
||||
be processed through Xuggle. Xuggle provides the option to use |
||||
many codecs/containers, but you will have to install it on your |
||||
system yourself in order to use this option. Please visit |
||||
<object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://www.xuggle.com/"><param name="text" value="<html><u>http://www.xuggle.com/</u></html>"><param name="textColor" value="blue"></object> to learn how to do this. |
||||
</p> |
||||
|
||||
<p> |
||||
Note that you will not hear any sound if you choose to record sound to |
||||
a file. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT3 SECTION "Advanced Way" [1316-4508] --> |
||||
<h3><a>Basic Example</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Here is a complete example showing how to capture both audio and video |
||||
from one of jMonkeyEngine3's advanced demo applications. |
||||
</p> |
||||
<pre>import java.io.File; |
||||
import java.io.IOException; |
||||
|
||||
import jme3test.water.TestPostWater; |
||||
|
||||
import com.aurellem.capture.Capture; |
||||
import com.aurellem.capture.IsoTimer; |
||||
import com.jme3.app.SimpleApplication; |
||||
|
||||
|
||||
<span>/** |
||||
* Demonstrates how to use basic Audio/Video capture with a |
||||
* jMonkeyEngine application. You can use these techniques to make |
||||
* high quality cutscenes or demo videos, even on very slow laptops. |
||||
* |
||||
* @author Robert McIntyre |
||||
*/</span> |
||||
|
||||
public class Basic { |
||||
|
||||
public static void main(String[] ignore) throws IOException{ |
||||
File video = File.createTempFile("JME-water-video", ".avi"); |
||||
File audio = File.createTempFile("JME-water-audio", ".wav"); |
||||
|
||||
SimpleApplication app = new TestPostWater(); |
||||
app.setTimer(new IsoTimer(60)); |
||||
app.setShowSettings(false); |
||||
|
||||
Capture.captureVideo(app, video); |
||||
Capture.captureAudio(app, audio); |
||||
|
||||
app.start(); |
||||
|
||||
System.out.println(video.getCanonicalPath()); |
||||
System.out.println(audio.getCanonicalPath()); |
||||
} |
||||
}</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT4 SECTION "Basic Example" [4509-5641] --> |
||||
<h3><a>How it works</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
A standard JME3 application that extends <code>SimpleApplication</code> or |
||||
<code>Application</code> tries as hard as it can to keep in sync with |
||||
<em>user-time</em>. If a ball is rolling at 1 game-mile per game-hour in the |
||||
game, and you wait for one user-hour as measured by the clock on your |
||||
wall, then the ball should have traveled exactly one game-mile. In |
||||
order to keep sync with the real world, the game throttles its physics |
||||
engine and graphics display. If the computations involved in running |
||||
the game are too intense, then the game will first skip frames, then |
||||
sacrifice physics accuracy. If there are particuraly demanding |
||||
computations, then you may only get 1 fps, and the ball may tunnel |
||||
through the floor or obstacles due to inaccurate physics simulation, |
||||
but after the end of one user-hour, that ball will have traveled one |
||||
game-mile. |
||||
</p> |
||||
|
||||
<p> |
||||
When we're recording video, we don't care if the game-time syncs with |
||||
user-time, but instead whether the time in the recorded video |
||||
(video-time) syncs with user-time. To continue the analogy, if we |
||||
recorded the ball rolling at 1 game-mile per game-hour and watched the |
||||
video later, we would want to see 30 fps video of the ball rolling at |
||||
1 video-mile per <em>user-hour</em>. It doesn't matter how much user-time it |
||||
took to simulate that hour of game-time to make the high-quality |
||||
recording. |
||||
</p> |
||||
|
||||
<p> |
||||
The IsoTimer ignores real-time and always reports that the same amount |
||||
of time has passed every time it is called. That way, one can put code |
||||
to write each video/audio frame to a file without worrying about that |
||||
code itself slowing down the game to the point where the recording |
||||
would be useless. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT5 SECTION "How it works" [5642-7280] --> |
||||
<h3><a>Advanced Example</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
The package from aurellem.com was made for AI research and can do more |
||||
than just record a single stream of audio and video. You can use it |
||||
to: |
||||
</p> |
||||
|
||||
<p> |
||||
1.) Create multiple independent listeners that each hear the world |
||||
from their own perspective. |
||||
</p> |
||||
|
||||
<p> |
||||
2.) Process the sound data in any way you wish. |
||||
</p> |
||||
|
||||
<p> |
||||
3.) Do the same for visual data. |
||||
</p> |
||||
|
||||
<p> |
||||
Here is a more advanced example, which can also be found along with |
||||
other examples in the jmeCapture.jar file included in the |
||||
distribution. |
||||
</p> |
||||
<pre>package com.aurellem.capture.examples; |
||||
|
||||
import java.io.File; |
||||
import java.io.IOException; |
||||
import java.lang.reflect.Field; |
||||
import java.nio.ByteBuffer; |
||||
|
||||
import javax.sound.sampled.AudioFormat; |
||||
|
||||
import org.tritonus.share.sampled.FloatSampleTools; |
||||
|
||||
import com.aurellem.capture.AurellemSystemDelegate; |
||||
import com.aurellem.capture.Capture; |
||||
import com.aurellem.capture.IsoTimer; |
||||
import com.aurellem.capture.audio.CompositeSoundProcessor; |
||||
import com.aurellem.capture.audio.MultiListener; |
||||
import com.aurellem.capture.audio.SoundProcessor; |
||||
import com.aurellem.capture.audio.WaveFileWriter; |
||||
import com.jme3.app.SimpleApplication; |
||||
import com.jme3.audio.AudioNode; |
||||
import com.jme3.audio.Listener; |
||||
import com.jme3.cinematic.MotionPath; |
||||
import com.jme3.cinematic.events.AbstractCinematicEvent; |
||||
import com.jme3.cinematic.events.MotionTrack; |
||||
import com.jme3.material.Material; |
||||
import com.jme3.math.ColorRGBA; |
||||
import com.jme3.math.FastMath; |
||||
import com.jme3.math.Quaternion; |
||||
import com.jme3.math.Vector3f; |
||||
import com.jme3.scene.Geometry; |
||||
import com.jme3.scene.Node; |
||||
import com.jme3.scene.shape.Box; |
||||
import com.jme3.scene.shape.Sphere; |
||||
import com.jme3.system.AppSettings; |
||||
import com.jme3.system.JmeSystem; |
||||
|
||||
<span>/** |
||||
* |
||||
* Demonstrates advanced use of the audio capture and recording |
||||
* features. Multiple perspectives of the same scene are |
||||
* simultaneously rendered to different sound files. |
||||
* |
||||
* A key limitation of the way multiple listeners are implemented is |
||||
* that only 3D positioning effects are realized for listeners other |
||||
* than the main LWJGL listener. This means that audio effects such |
||||
* as environment settings will *not* be heard on any auxiliary |
||||
* listeners, though sound attenuation will work correctly. |
||||
* |
||||
* Multiple listeners as realized here might be used to make AI |
||||
* entities that can each hear the world from their own perspective. |
||||
* |
||||
* @author Robert McIntyre |
||||
*/</span> |
||||
|
||||
public class Advanced extends SimpleApplication { |
||||
|
||||
<span>/** |
||||
* You will see three grey cubes, a blue sphere, and a path which |
||||
* circles each cube. The blue sphere is generating a constant |
||||
* monotone sound as it moves along the track. Each cube is |
||||
* listening for sound; when a cube hears sound whose intensity is |
||||
* greater than a certain threshold, it changes its color from |
||||
* grey to green. |
||||
* |
||||
* Each cube is also saving whatever it hears to a file. The |
||||
* scene from the perspective of the viewer is also saved to a |
||||
* video file. When you listen to each of the sound files |
||||
* alongside the video, the sound will get louder when the sphere |
||||
* approaches the cube that generated that sound file. This |
||||
* shows that each listener is hearing the world from its own |
||||
* perspective. |
||||
* |
||||
*/</span> |
||||
public static void main(String[] args) { |
||||
Advanced app = new Advanced(); |
||||
AppSettings settings = new AppSettings(true); |
||||
settings.setAudioRenderer(AurellemSystemDelegate.SEND); |
||||
JmeSystem.setSystemDelegate(new AurellemSystemDelegate()); |
||||
app.setSettings(settings); |
||||
app.setShowSettings(false); |
||||
app.setPauseOnLostFocus(false); |
||||
|
||||
|
||||
try { |
||||
Capture.captureVideo(app, File.createTempFile("advanced",".avi")); |
||||
Capture.captureAudio(app, File.createTempFile("advanced", ".wav")); |
||||
} |
||||
catch (IOException e) {e.printStackTrace();} |
||||
|
||||
app.start(); |
||||
} |
||||
|
||||
|
||||
private Geometry bell; |
||||
private Geometry ear1; |
||||
private Geometry ear2; |
||||
private Geometry ear3; |
||||
private AudioNode music; |
||||
private MotionTrack motionControl; |
||||
private IsoTimer motionTimer = new IsoTimer(60); |
||||
|
||||
private Geometry makeEar(Node root, Vector3f position){ |
||||
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); |
||||
Geometry ear = new Geometry("ear", new Box(1.0f, 1.0f, 1.0f)); |
||||
ear.setLocalTranslation(position); |
||||
mat.setColor("Color", ColorRGBA.Green); |
||||
ear.setMaterial(mat); |
||||
root.attachChild(ear); |
||||
return ear; |
||||
} |
||||
|
||||
private Vector3f[] path = new Vector3f[]{ |
||||
// loop 1 |
||||
new Vector3f(0, 0, 0), |
||||
new Vector3f(0, 0, -10), |
||||
new Vector3f(-2, 0, -14), |
||||
new Vector3f(-6, 0, -20), |
||||
new Vector3f(0, 0, -26), |
||||
new Vector3f(6, 0, -20), |
||||
new Vector3f(0, 0, -14), |
||||
new Vector3f(-6, 0, -20), |
||||
new Vector3f(0, 0, -26), |
||||
new Vector3f(6, 0, -20), |
||||
// loop 2 |
||||
new Vector3f(5, 0, -5), |
||||
new Vector3f(7, 0, 1.5f), |
||||
new Vector3f(14, 0, 2), |
||||
new Vector3f(20, 0, 6), |
||||
new Vector3f(26, 0, 0), |
||||
new Vector3f(20, 0, -6), |
||||
new Vector3f(14, 0, 0), |
||||
new Vector3f(20, 0, 6), |
||||
new Vector3f(26, 0, 0), |
||||
new Vector3f(20, 0, -6), |
||||
new Vector3f(14, 0, 0), |
||||
// loop 3 |
||||
new Vector3f(8, 0, 7.5f), |
||||
new Vector3f(7, 0, 10.5f), |
||||
new Vector3f(6, 0, 20), |
||||
new Vector3f(0, 0, 26), |
||||
new Vector3f(-6, 0, 20), |
||||
new Vector3f(0, 0, 14), |
||||
new Vector3f(6, 0, 20), |
||||
new Vector3f(0, 0, 26), |
||||
new Vector3f(-6, 0, 20), |
||||
new Vector3f(0, 0, 14), |
||||
// begin ellipse |
||||
new Vector3f(16, 5, 20), |
||||
new Vector3f(0, 0, 26), |
||||
new Vector3f(-16, -10, 20), |
||||
new Vector3f(0, 0, 14), |
||||
new Vector3f(16, 20, 20), |
||||
new Vector3f(0, 0, 26), |
||||
new Vector3f(-10, -25, 10), |
||||
new Vector3f(-10, 0, 0), |
||||
// come at me! |
||||
new Vector3f(-28.00242f, 48.005623f, -34.648228f), |
||||
new Vector3f(0, 0 , -20), |
||||
}; |
||||
|
||||
private void createScene() { |
||||
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); |
||||
bell = new Geometry( "sound-emitter" , new Sphere(15,15,1)); |
||||
mat.setColor("Color", ColorRGBA.Blue); |
||||
bell.setMaterial(mat); |
||||
rootNode.attachChild(bell); |
||||
|
||||
ear1 = makeEar(rootNode, new Vector3f(0, 0 ,-20)); |
||||
ear2 = makeEar(rootNode, new Vector3f(0, 0 ,20)); |
||||
ear3 = makeEar(rootNode, new Vector3f(20, 0 ,0)); |
||||
|
||||
MotionPath track = new MotionPath(); |
||||
|
||||
for (Vector3f v : path){ |
||||
track.addWayPoint(v); |
||||
} |
||||
track.setCurveTension(0.80f); |
||||
|
||||
motionControl = new MotionTrack(bell,track); |
||||
// for now, use reflection to change the timer... |
||||
// motionControl.setTimer(new IsoTimer(60)); |
||||
|
||||
try { |
||||
Field timerField; |
||||
timerField = AbstractCinematicEvent.class.getDeclaredField("timer"); |
||||
timerField.setAccessible(true); |
||||
try {timerField.set(motionControl, motionTimer);} |
||||
catch (IllegalArgumentException e) {e.printStackTrace();} |
||||
catch (IllegalAccessException e) {e.printStackTrace();} |
||||
} |
||||
catch (SecurityException e) {e.printStackTrace();} |
||||
catch (NoSuchFieldException e) {e.printStackTrace();} |
||||
|
||||
|
||||
motionControl.setDirectionType(MotionTrack.Direction.PathAndRotation); |
||||
motionControl.setRotation(new Quaternion().fromAngleNormalAxis(-FastMath.HALF_PI, Vector3f.UNIT_Y)); |
||||
motionControl.setInitialDuration(20f); |
||||
motionControl.setSpeed(1f); |
||||
|
||||
track.enableDebugShape(assetManager, rootNode); |
||||
positionCamera(); |
||||
} |
||||
|
||||
|
||||
private void positionCamera(){ |
||||
this.cam.setLocation(new Vector3f(-28.00242f, 48.005623f, -34.648228f)); |
||||
this.cam.setRotation(new Quaternion(0.3359635f, 0.34280345f, -0.13281013f, 0.8671653f)); |
||||
} |
||||
|
||||
private void initAudio() { |
||||
org.lwjgl.input.Mouse.setGrabbed(false); |
||||
music = new AudioNode(assetManager, "Sound/Effects/Beep.ogg", false); |
||||
|
||||
rootNode.attachChild(music); |
||||
audioRenderer.playSource(music); |
||||
music.setPositional(true); |
||||
music.setVolume(1f); |
||||
music.setReverbEnabled(false); |
||||
music.setDirectional(false); |
||||
music.setMaxDistance(200.0f); |
||||
music.setRefDistance(1f); |
||||
//music.setRolloffFactor(1f); |
||||
music.setLooping(false); |
||||
audioRenderer.pauseSource(music); |
||||
} |
||||
|
||||
public class Dancer implements SoundProcessor { |
||||
Geometry entity; |
||||
float scale = 2; |
||||
public Dancer(Geometry entity){ |
||||
this.entity = entity; |
||||
} |
||||
|
||||
<span>/** |
||||
* this method is irrelevant since there is no state to cleanup. |
||||
*/</span> |
||||
public void cleanup() {} |
||||
|
||||
|
||||
<span>/** |
||||
* Respond to sound! This is the brain of an AI entity that |
||||
* hears its surroundings and reacts to them. |
||||
*/</span> |
||||
public void process(ByteBuffer audioSamples, int numSamples, AudioFormat format) { |
||||
audioSamples.clear(); |
||||
byte[] data = new byte[numSamples]; |
||||
float[] out = new float[numSamples]; |
||||
audioSamples.get(data); |
||||
FloatSampleTools.byte2floatInterleaved(data, 0, out, 0, |
||||
numSamples/format.getFrameSize(), format); |
||||
|
||||
float max = Float.NEGATIVE_INFINITY; |
||||
for (float f : out){if (f > max) max = f;} |
||||
audioSamples.clear(); |
||||
|
||||
if (max > 0.1){entity.getMaterial().setColor("Color", ColorRGBA.Green);} |
||||
else {entity.getMaterial().setColor("Color", ColorRGBA.Gray);} |
||||
} |
||||
} |
||||
|
||||
private void prepareEar(Geometry ear, int n){ |
||||
if (this.audioRenderer instanceof MultiListener){ |
||||
MultiListener rf = (MultiListener)this.audioRenderer; |
||||
|
||||
Listener auxListener = new Listener(); |
||||
auxListener.setLocation(ear.getLocalTranslation()); |
||||
|
||||
rf.addListener(auxListener); |
||||
WaveFileWriter aux = null; |
||||
|
||||
try {aux = new WaveFileWriter(File.createTempFile("advanced-audio-" + n, ".wav"));} |
||||
catch (IOException e) {e.printStackTrace();} |
||||
|
||||
rf.registerSoundProcessor(auxListener, |
||||
new CompositeSoundProcessor(new Dancer(ear), aux)); |
||||
|
||||
} |
||||
} |
||||
|
||||
|
||||
public void simpleInitApp() { |
||||
this.setTimer(new IsoTimer(60)); |
||||
initAudio(); |
||||
|
||||
createScene(); |
||||
|
||||
prepareEar(ear1, 1); |
||||
prepareEar(ear2, 1); |
||||
prepareEar(ear3, 1); |
||||
|
||||
motionControl.play(); |
||||
|
||||
} |
||||
|
||||
public void simpleUpdate(float tpf) { |
||||
motionTimer.update(); |
||||
if (music.getStatus() != AudioNode.Status.Playing){ |
||||
music.play(); |
||||
} |
||||
Vector3f loc = cam.getLocation(); |
||||
Quaternion rot = cam.getRotation(); |
||||
listener.setLocation(loc); |
||||
listener.setRotation(rot); |
||||
music.setLocalTranslation(bell.getLocalTranslation()); |
||||
} |
||||
|
||||
}</pre> |
||||
|
||||
<p> |
||||
|
||||
<!--[if !IE]> --> |
||||
<object> |
||||
<!-- <![endif]--> |
||||
<!--[if IE]> |
||||
<object class="media" width="400" height="350" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" > |
||||
<param name="movie" value="/wiki/lib/exe/fetch.php?hash=568504&media=http%3A%2F%2Fwww.youtube.com%2Fv%2FoCEfK0yhDrY%3F.swf" /> |
||||
<!--><!-- --> |
||||
<param name="quality" value="high"/> |
||||
The <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://www.adobe.com/products/flashplayer/"><param name="text" value="<html><u>Adobe Flash Plugin</u></html>"><param name="textColor" value="blue"></object> is needed to display this content. |
||||
</object> |
||||
<!-- <![endif]--> |
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT6 SECTION "Advanced Example" [7281-17184] --> |
||||
<h3><a>Using Advanced features to Record from more than one perspective at once</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
<!--[if !IE]> --> |
||||
<object> |
||||
<!-- <![endif]--> |
||||
<!--[if IE]> |
||||
<object class="media" width="400" height="350" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" > |
||||
<param name="movie" value="/wiki/lib/exe/fetch.php?hash=6921c2&media=http%3A%2F%2Fwww.youtube.com%2Fv%2FWIJt9aRGusc%3F.swf" /> |
||||
<!--><!-- --> |
||||
<param name="quality" value="high"/> |
||||
The <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://www.adobe.com/products/flashplayer/"><param name="text" value="<html><u>Adobe Flash Plugin</u></html>"><param name="textColor" value="blue"></object> is needed to display this content. |
||||
</object> |
||||
<!-- <![endif]--> |
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT7 SECTION "Using Advanced features to Record from more than one perspective at once" [17185-17326] --> |
||||
<h2><a>More Information</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
This is the old page showing the first version of this idea |
||||
<object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://aurellem.org/cortex/html/capture-video.html"><param name="text" value="<html><u>http://aurellem.org/cortex/html/capture-video.html</u></html>"><param name="textColor" value="blue"></object> |
||||
</p> |
||||
|
||||
<p> |
||||
All source code can be found here: |
||||
</p> |
||||
|
||||
<p> |
||||
<object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://hg.bortreb.com/audio-send"><param name="text" value="<html><u>http://hg.bortreb.com/audio-send</u></html>"><param name="textColor" value="blue"></object> |
||||
</p> |
||||
|
||||
<p> |
||||
<object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://hg.bortreb.com/jmeCapture"><param name="text" value="<html><u>http://hg.bortreb.com/jmeCapture</u></html>"><param name="textColor" value="blue"></object> |
||||
</p> |
||||
|
||||
<p> |
||||
More information on the modifications to OpenAL to support multiple |
||||
listeners can be found here. |
||||
</p> |
||||
|
||||
<p> |
||||
<object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://aurellem.org/audio-send/html/ear.html"><param name="text" value="<html><u>http://aurellem.org/audio-send/html/ear.html</u></html>"><param name="textColor" value="blue"></object> |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT8 SECTION "More Information" [17327-] --> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:capture_audio_video_to_a_file?do=export_xhtmlbody">view online version</a></em></p> |
@ -1,439 +0,0 @@ |
||||
|
||||
<h1><a>JME3 Cinematics</a></h1> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
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 <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://en.wikipedia.org/wiki/Cutscene"><param name="text" value="<html><u>cutscenes</u></html>"><param name="textColor" value="blue"></object> and movies/trailers of your game. Internally, Cinematics are implemented as <a href="/com/jme3/gde/core/docs/jme3/advanced/application_states.html">AppStates</a>. |
||||
</p> |
||||
|
||||
<p> |
||||
Short overview of the cinematic process: |
||||
</p> |
||||
<ol> |
||||
<li><div> Plan the script of your movie. <br/> |
||||
Write down a timeline (e.g. on paper) of which character should be at which spot at which time.</div> |
||||
</li> |
||||
<li><div> Attach the scene objects that you want to remote-control to one Node. <br/> |
||||
This Node can be the rootNode, or a Node that is attached to the rootNode. </div> |
||||
</li> |
||||
<li><div> Create a Cinematic object for this movie scene. The Cinematic will contain and manage the movie script.</div> |
||||
</li> |
||||
<li><div> For each line in your script (for each frame in your timeline), add a CinematicEvent to the Cinematic. </div> |
||||
</li> |
||||
</ol> |
||||
|
||||
</div> |
||||
<!-- EDIT1 SECTION "JME3 Cinematics" [1-956] --> |
||||
<h2><a>Sample Code</a></h2> |
||||
<div> |
||||
<ul> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/animation/TestCinematic.java"><param name="text" value="<html><u>TestCinematic.java</u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT2 SECTION "Sample Code" [957-1123] --> |
||||
<h2><a>How to Use a Cinematic</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
A Cinematic is like a movie script for a node. |
||||
</p> |
||||
<pre>Cinematic cinematic = new Cinematic(sceneNode, duration); |
||||
cinematic.addCinematicEvent(starttime1, track1); |
||||
cinematic.addCinematicEvent(starttime2, track2); |
||||
cinematic.addCinematicEvent(starttime2, track3); |
||||
... |
||||
stateManager.attach(cinematic);</pre> |
||||
<ol> |
||||
<li><div> Create one Cinematic per scripted scene.</div> |
||||
<ul> |
||||
<li><div> <code>sceneNode</code> is the node containing the scene (can be the rootNode).</div> |
||||
</li> |
||||
<li><div> <code>duration</code> is the duration of the whole scene in seconds.</div> |
||||
</li> |
||||
<li><div> Each Cinematic is a set of CinematicEvents, that are triggered at a given moment on the timeline.</div> |
||||
</li> |
||||
</ul> |
||||
</li> |
||||
<li><div> Create one CinematicEvent for each line of your movie script. </div> |
||||
<ul> |
||||
<li><div> <code>track</code> is one motion of a moving object. You can add several tracks. More details below.</div> |
||||
</li> |
||||
<li><div> <code>starttime</code> is the time when this particular cinematic event starts on the timeline. Specify the start time in seconds since the beginning of the cinematic.</div> |
||||
</li> |
||||
</ul> |
||||
</li> |
||||
<li><div> Attach the Cinematic to the SimpleApplication's stateManager. </div> |
||||
</li> |
||||
<li><div> Play, stop and pause the Cinematic from your code.</div> |
||||
</li> |
||||
</ol> |
||||
<div><table> |
||||
<tr> |
||||
<th>Method</th><th>Usage</th> |
||||
</tr> |
||||
<tr> |
||||
<td>cinematic.play()</td><td>Starts playing the cinematic from the start, or from where it was paused.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>cinematic.stop()</td><td>Stops playing the cinematic and rewinds it.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>cinematic.pause()</td><td>Pauses the cinematic.</td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT4 TABLE [2215-2427] --> |
||||
</div> |
||||
<!-- EDIT3 SECTION "How to Use a Cinematic" [1124-2428] --> |
||||
<h2><a>Tracks (CinematicEvents)</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Just like a movie script consists of lines with instructions to the actors, each Cinematic consists of a series of tracks. |
||||
</p> |
||||
|
||||
<p> |
||||
Here is the list of available CinematicEvents that you use as tracks. Each track remote-controls scene objects in a different way: |
||||
|
||||
</p> |
||||
<div><table> |
||||
<tr> |
||||
<th>Tracks (CinematicEvents)</th><th>Description</th> |
||||
</tr> |
||||
<tr> |
||||
<td>MotionTrack</td><td>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. </td> |
||||
</tr> |
||||
<tr> |
||||
<td>PositionTrack</td><td>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.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>RotationTrack</td><td>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.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>ScaleTrack</td><td>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.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>SoundTrack</td><td>Use a SoundTrack to play a <a href="/com/jme3/gde/core/docs/jme3/advanced/audio.html">sound</a> at a given time for the given duration.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>GuiTrack</td><td>Displays a <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui.html">Nifty GUI</a> at a given time for the given duration. Use it to display subtitles or HUD elements. Bind the Nifty <acronym title="Graphical User Interface">GUI</acronym> <acronym title="Extensible Markup Language">XML</acronym> to the cinematic using <code>cinematic.bindUi("path/to/nifty/file.xml");</code></td> |
||||
</tr> |
||||
<tr> |
||||
<td>AnimationTrack</td><td>Use this to start playing a model <a href="/com/jme3/gde/core/docs/jme3/advanced/animation.html">animation</a> at a given time (a character walking animation for example)</td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT6 TABLE [2723-4144] --> |
||||
<p> |
||||
|
||||
The jMonkey team can add more types of tracks, just ask in the forum. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT5 SECTION "Tracks (CinematicEvents)" [2429-4218] --> |
||||
<h3><a>MotionTrack</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
A MotionTrack moves a Spatial along a complex path. |
||||
|
||||
</p> |
||||
<pre>MotionTrack track = new MotionTrack(thingNode, path);</pre> |
||||
|
||||
<p> |
||||
Details of the constructor: |
||||
</p> |
||||
<ul> |
||||
<li><div> <code>thingNode</code> is the Spatial to be moved.</div> |
||||
</li> |
||||
<li><div> <code>path</code> is a complex <a href="/com/jme3/gde/core/docs/jme3/advanced/motionpath.html">MotionPath</a>.</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
|
||||
To create a MotionTrack, do the following: |
||||
</p> |
||||
<ol> |
||||
<li><div> <a href="/com/jme3/gde/core/docs/jme3/advanced/motionpath.html">Create a MotionPath</a></div> |
||||
</li> |
||||
<li><div> Create a MotionTrack based on the MotionPath.</div> |
||||
</li> |
||||
<li><div> Configure your MotionTrack (see below).</div> |
||||
</li> |
||||
<li><div> Add the MotionTrack to a Cinematic.</div> |
||||
</li> |
||||
</ol> |
||||
<div><table> |
||||
<tr> |
||||
<th>MotionTrack configuration method</th><th>Usage</th> |
||||
</tr> |
||||
<tr> |
||||
<td>track.setLoopMode(LoopMode.Loop)</td><td>Sets whether the animation along this path should loop (LoopMode.Loop) or play only once (LoopMode.DontLoop).</td> |
||||
</tr> |
||||
<tr> |
||||
<td>track.setDirectionType(MotionTrack.Direction.None)</td><td>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.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>track.setDirectionType(MotionTrack.Direction.LookAt)</td><td>The spatial turns (rotates) to keep facing a certain point while moving. Specify the point with the <code>setLookAt()</code> method.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>track.setDirectionType(MotionTrack.Direction.Path)</td><td>The spatial always faces in the direction of the path while moving.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>track.setDirectionType(MotionTrack.Direction.PathAndRotation)</td><td>The spatial faces the direction of the path, plus an added rotation. Use together with the <code>setRotation()</code> method.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>track.setDirectionType(MotionTrack.Direction.Rotation)</td><td>The spatial spins (rotates) while moving. You describe the spin by a custom quaternion. Use together with the <code>setRotation()</code> method.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>track.setLookAt(teapot.getWorldTranslation(), Vector3f.UNIT_Y)</td><td>The spatial always faces towards this location. Use together with <code>MotionTrack.Direction.LookAt</code>.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>track.setRotation(quaternion)</td><td>Sets the rotation. Use together with <code>MotionTrack.Direction.Rotation</code> or <code>MotionTrack.Direction.PathAndRotation</code>.</td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT8 TABLE [4701-6109] --> |
||||
<p> |
||||
|
||||
<strong>Tip:</strong> Most likely you remote-control more than one object in your scene. Give the tracks and paths useful names such as <code>dragon_track</code>, <code>dragon_path</code>, <code>hero_track</code>, <code>hero_path</code>, etc. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT7 SECTION "MotionTrack" [4219-6305] --> |
||||
<h3><a>PositionTrack</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
A PositionTrack moves a Spatial in a straight line from its current position to the end position. |
||||
|
||||
</p> |
||||
<pre>PositionTrack track = new PositionTrack( |
||||
thingNode, endPosition, duration, loopMode);</pre> |
||||
|
||||
<p> |
||||
Details of the constructor: |
||||
</p> |
||||
<ul> |
||||
<li><div> <code>thingNode</code> is the Spatial to be moved.</div> |
||||
</li> |
||||
<li><div> <code>endPosition</code> is the target location as Vector3f. </div> |
||||
</li> |
||||
<li><div> <code>duration</code> is the time that it should take from start to end point.</div> |
||||
</li> |
||||
<li><div> <code>loopMode</code> can be LoopMode.Loop, LoopMode.DontLoop, LoopMode.Cycle.</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
|
||||
The start location is always the current location of the Spatial. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT9 SECTION "PositionTrack" [6306-6882] --> |
||||
<h3><a>RotationTrack</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
A RotationTrack remote-controls the rotation of a spatial. |
||||
|
||||
</p> |
||||
<pre>RotationTrack thingRotationControl = new RotationTrack( |
||||
thingNode, endRotation, duration, loopMode);</pre> |
||||
|
||||
<p> |
||||
Details of the constructor: |
||||
</p> |
||||
<ul> |
||||
<li><div> <code>thingNode</code> is the Spatial to be rotated.</div> |
||||
</li> |
||||
<li><div> <code>endRotation</code> is the target rotation in Quaternion format. </div> |
||||
</li> |
||||
<li><div> <code>duration</code> is the time that it should take from start to target rotation.</div> |
||||
</li> |
||||
<li><div> <code>loopMode</code> can be LoopMode.Loop, LoopMode.DontLoop, LoopMode.Cycle.</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT10 SECTION "RotationTrack" [6883-7386] --> |
||||
<h3><a>ScaleTrack</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
A ScaleTrack remote-controls whether a spatial grows or shrinks. |
||||
</p> |
||||
<pre>ScaleTrack thingScaleControl = new ScaleTrack( |
||||
thingNode, endScale, duration, loopMode);</pre> |
||||
|
||||
<p> |
||||
Details of the constructor: |
||||
</p> |
||||
<ul> |
||||
<li><div> <code>thingNode</code> is the Spatial to be resized.</div> |
||||
</li> |
||||
<li><div> <code>endScale</code> is the target Scale in Vector3f format. </div> |
||||
</li> |
||||
<li><div> <code>duration</code> is the time that it should take from start to target scale.</div> |
||||
</li> |
||||
<li><div> <code>loopMode</code> can be LoopMode.Loop, LoopMode.DontLoop, LoopMode.Cycle.</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT11 SECTION "ScaleTrack" [7387-7871] --> |
||||
<h3><a>SoundTrack</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
A SoundTrack plays a sound as part of the cinematic. |
||||
|
||||
</p> |
||||
<pre>SoundTrack( audioPath, isStream, duration, loopMode )</pre> |
||||
|
||||
<p> |
||||
|
||||
Details of the constructor: |
||||
</p> |
||||
<ul> |
||||
<li><div> <code>audioPath</code> is the path to an audio file as String, e.g. "Sounds/mySound.wav".</div> |
||||
</li> |
||||
<li><div> <code>isStream</code> toggles between streaming and buffering. Set to true to stream long audio file, set to false to play short buffered sounds.</div> |
||||
</li> |
||||
<li><div> <code>duration</code> is the time that it should take to play.</div> |
||||
</li> |
||||
<li><div> <code>loopMode</code> can be LoopMode.Loop, LoopMode.DontLoop, LoopMode.Cycle.</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT12 SECTION "SoundTrack" [7872-8404] --> |
||||
<h3><a>GuiTrack</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
A GuiTrack shows or hide a NiftyGUI as part of a cinematic. |
||||
|
||||
</p> |
||||
<pre>GuiTrack( screen, duration, loopMode )</pre> |
||||
|
||||
<p> |
||||
|
||||
You must use this together with bindUI() to specify the Nifty <acronym title="Graphical User Interface">GUI</acronym> <acronym title="Extensible Markup Language">XML</acronym> file that you want to load: |
||||
|
||||
</p> |
||||
<pre>cinematic.bindUi("Interface/subtitle.xml");</pre> |
||||
|
||||
<p> |
||||
Details of the constructor: |
||||
</p> |
||||
<ul> |
||||
<li><div> <code>screen</code> is the name of the Nifty <acronym title="Graphical User Interface">GUI</acronym> screen to load, as String. </div> |
||||
</li> |
||||
<li><div> <code>duration</code> is the time that it should take to play.</div> |
||||
</li> |
||||
<li><div> <code>loopMode</code> can be LoopMode.Loop, LoopMode.DontLoop, LoopMode.Cycle.</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT13 SECTION "GuiTrack" [8405-8934] --> |
||||
<h3><a>AnimationTrack</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
An AnimationTrack triggers an animation as part of a cinematic. |
||||
|
||||
</p> |
||||
<pre>AnimationTrack( thingNode, animationName, duration, loopMode )</pre> |
||||
|
||||
<p> |
||||
|
||||
Details of the constructor: |
||||
</p> |
||||
<ul> |
||||
<li><div> <code>thingNode</code> is the Spatial whose animation you want to play.</div> |
||||
</li> |
||||
<li><div> <code>animationName</code> the name of the animation stored in the animated model that you want to trigger, as a String.</div> |
||||
</li> |
||||
<li><div> <code>duration</code> is the time that it should take to play.</div> |
||||
</li> |
||||
<li><div> <code>loopMode</code> can be LoopMode.Loop, LoopMode.DontLoop, LoopMode.Cycle.</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT14 SECTION "AnimationTrack" [8935-9447] --> |
||||
<h3><a>Customizations</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
You can extend individual CinematicEvents. The <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/animation/SubtitleTrack.java"><param name="text" value="<html><u>SubtitleTrack.java example</u></html>"><param name="textColor" value="blue"></object> shows how to extend a GuiTrack to script subtitles. See how the subtitles are used in the <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/animation/TestCinematic.java"><param name="text" value="<html><u>TestCinematic.java example</u></html>"><param name="textColor" value="blue"></object>. |
||||
</p> |
||||
|
||||
<p> |
||||
You can also create new CinematicEvent by extending <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/core/com/jme3/cinematic/events/AbstractCinematicEvent.java"><param name="text" value="<html><u>AbstractCinematicEvent</u></html>"><param name="textColor" value="blue"></object>. An AbstractCinematicEvent implements the CinematicEvent interface and provides duration, time, speed, etc??? management. Look at the <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/animation/TestCinematic.java"><param name="text" value="<html><u>TestCinematic.java example</u></html>"><param name="textColor" value="blue"></object> is to use this for a custom fadeIn/fadeOut effect in combination with a com.jme3.post.filters.FadeFilter. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT15 SECTION "Customizations" [9448-10493] --> |
||||
<h2><a>Interacting with Cinematics</a></h2> |
||||
<div> |
||||
|
||||
</div> |
||||
<!-- EDIT16 SECTION "Interacting with Cinematics" [10494-10534] --> |
||||
<h3><a>CinematicEventListener</a></h3> |
||||
<div> |
||||
<pre>CinematicEventListener cel = new CinematicEventListener() { |
||||
public void onPlay(CinematicEvent cinematic) { |
||||
chaseCam.setEnabled(false); |
||||
System.out.println("play"); |
||||
} |
||||
|
||||
public void onPause(CinematicEvent cinematic) { |
||||
chaseCam.setEnabled(true); |
||||
System.out.println("pause"); |
||||
} |
||||
|
||||
public void onStop(CinematicEvent cinematic) { |
||||
chaseCam.setEnabled(true); |
||||
System.out.println("stop"); |
||||
} |
||||
} |
||||
cinematic.addListener(cel);</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT17 SECTION "CinematicEventListener" [10535-11030] --> |
||||
<h3><a>Physics Interaction</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Upcoming. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT18 SECTION "Physics Interaction" [11031-11072] --> |
||||
<h2><a>More Information</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
See also: <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://jmonkeyengine.org/groups/development-discussion-jme3/forum/topic/cinematics-system-for-jme3/"><param name="text" value="<html><u>Cinematics by Nehon</u></html>"><param name="textColor" value="blue"></object> |
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT19 SECTION "More Information" [11073-] --> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:cinematics?do=export_xhtmlbody">view online version</a></em></p> |
@ -1,241 +0,0 @@ |
||||
|
||||
<h1><a>Collision and Intersection</a></h1> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
The term collision can be used to refer to <a href="/com/jme3/gde/core/docs/jme3/advanced/physics_listeners.html">physical interactions</a> (where <a href="/com/jme3/gde/core/docs/jme3/advanced/physics.html">physical objects</a> collide, push and bump off one another), and also to non-physical <em>intersections</em> in 3D space. This article is about the non-physical (mathematical) collisions. |
||||
</p> |
||||
|
||||
<p> |
||||
Non-physical collision detection is interesting because it uses less computing resources than physical collision detection. The non-physical calculations are faster because they do not have any side effects such as pushing other objects or bumping off of them. Tasks such as <a href="/com/jme3/gde/core/docs/jme3/advanced/mouse_picking.html">mouse picking</a> are easily implemented using using mathematical techniques such as ray casting and intersections. Experienced developers optimize their games by finding ways to simulate certain (otherwise expensive physical) interactions in a non-physical way. |
||||
</p> |
||||
|
||||
<p> |
||||
<strong>Example:</strong> One example for an optimization is a physical vehicle's wheels. You could make the wheels fully physical disks, and have jME calculate every tiny force ??? sounds very accurate? It's total overkill and too slow for a racing game. A more performant solution is to cast four invisible rays down from the vehicle and calculate the intersections with the floor. These non-physical wheels require (in the simplest case) only four calculations per tick to achieve an effect that players can hardly distinguish from the real thing. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT1 SECTION "Collision and Intersection" [1-1438] --> |
||||
<h2><a>Collidable</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
The interface com.jme3.collision.Collidable declares one method that returns how many collisions were found between two Collidables: <code>collideWith(Collidable other, CollisionResults results)</code>. |
||||
</p> |
||||
<ul> |
||||
<li><div> A <code>com.jme3.collision.CollisionResults</code> object is an ArrayList of comparable <code>com.jme3.collision.CollisionResult</code> objects.</div> |
||||
</li> |
||||
<li><div> You can iterate over the CollisionResults to identify the other parties involved in the collision. <br/> |
||||
Note that jME counts <em>all</em> collisions, this means a ray intersecting a box will be counted as two hits, one on the front where the ray enters, and one on the back where the ray exits.</div> |
||||
</li> |
||||
</ul> |
||||
<div><table> |
||||
<tr> |
||||
<th>CollisionResults Method</th><th>Usage</th> |
||||
</tr> |
||||
<tr> |
||||
<td>size() </td><td>Returns the number of CollisionResult objects.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>getClosestCollision() </td><td>Returns the CollisionResult with the lowest distance.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>getFarthestCollision()</td><td>Returns the CollisionResult with the farthest distance.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>getCollision(i) </td><td>Returns the CollisionResult at index i.</td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT3 TABLE [2081-2409] --> |
||||
<p> |
||||
A CollisionResult object contains information about the second party of the collision event. |
||||
</p> |
||||
<div><table> |
||||
<tr> |
||||
<th>CollisionResult Method</th><th>Usage</th> |
||||
</tr> |
||||
<tr> |
||||
<td>getContactPoint()</td><td>Returns the contact point coordinate on the second party, as Vector3f.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>getContactNormal()</td><td>Returns the Normal vector at the contact point, as Vector3f.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>getDistance()</td><td>Returns the distance between the Collidable and the second party, as float.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>getGeometry()</td><td>Returns the Geometry of the second party.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>getTriangle(t)</td><td>Binds t to the triangle t on the second party's mesh that was hit.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>getTriangleIndex()</td><td>Returns the index of the triangle on the second party's mesh that was hit.</td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT4 TABLE [2503-3036] --> |
||||
</div> |
||||
<!-- EDIT2 SECTION "Collidable" [1439-3037] --> |
||||
<h3><a>Code Sample</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Assume you have two collidables a and b and want to detect collisions between them. The collision parties can be Geometries, Nodes with Geometries attached (including the rootNode), Planes, Quads, Lines, or Rays. An important restriction is that you can only collide geometry vs bounding volumes or rays. (This means for example that a must be of Type Node or Geometry and b respectively of Type BoundingBox, BoundingSphere or Ray.) |
||||
</p> |
||||
|
||||
<p> |
||||
The following code snippet can be triggered by listeners (e.g. after an input action such as a click), or timed in the update loop. |
||||
</p> |
||||
<pre> // Calculate detection results |
||||
CollisionResults results = new CollisionResults(); |
||||
a.collideWith(b, results); |
||||
System.out.println("Number of Collisions between" + |
||||
a.getName()+ " and " + b.getName() + ": " + results.size()); |
||||
// Use the results |
||||
if (results.size() > 0) { |
||||
// how to react when a collision was detected |
||||
CollisionResult closest = results.getClosestCollision(); |
||||
System.out.println("What was hit? " + closest.getGeometry().getName() ); |
||||
System.out.println("Where was it hit? " + closest.getContactPoint() ); |
||||
System.out.println("Distance? " + closest.getDistance() ); |
||||
} else { |
||||
// how to react when no collision occured |
||||
} |
||||
}</pre> |
||||
|
||||
<p> |
||||
You can also loop over all results and trigger different reactions depending on what was hit and where it was hit. In this example, we simply print info about them. |
||||
</p> |
||||
<pre> // Calculate Results |
||||
CollisionResults results = new CollisionResults(); |
||||
a.collideWith(b, results); |
||||
System.out.println("Number of Collisions between" + a.getName()+ " and " |
||||
+ b.getName() " : " + results.size()); |
||||
// Use the results |
||||
for (int i = 0; i < results.size(); i++) { |
||||
// For each hit, we know distance, impact point, name of geometry. |
||||
float dist = results.getCollision(i).getDistance(); |
||||
Vector3f pt = results.getCollision(i).getContactPoint(); |
||||
String party = results.getCollision(i).getGeometry().getName(); |
||||
int tri = results.getCollision(i).getTriangleIndex(); |
||||
Vector3f norm = results.getCollision(i).getTriangle(new Triangle()).getNormal(); |
||||
System.out.println("Details of Collision #" + i + ":"); |
||||
System.out.println(" Party " + party + " was hit at " + pt + ", " + dist + " wu away."); |
||||
System.out.println(" The hit triangle #" + tri + " has a normal vector of " + norm); |
||||
}</pre> |
||||
|
||||
<p> |
||||
Knowing the distance of the collisions is useful for example when you intersect Lines and Rays with other objects. |
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT5 SECTION "Code Sample" [3038-5576] --> |
||||
<h2><a>Bounding Volumes</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
A <code>com.jme3.bounding.BoundingVolume</code> is an interface for dealing with containment of a collection of points. All BoundingVolumes are <code>Collidable</code> and are used as optimization to calculate non-physical collisions more quickly: It's always faster to calculate an intersection between simple shapes like spheres and boxes than between complex shapes like models. |
||||
</p> |
||||
|
||||
<p> |
||||
jME3 computes bounding volumes for all objects. These bounding volumes are later used for frustum culling, which is making sure only objects visible on-screen are actually sent for rendering. |
||||
</p> |
||||
|
||||
<p> |
||||
All fast-paced action and shooter games use BoundingVolumes as an optimization. Wrap all complex models into simpler shapes ??? in the end, you get equally useful collision detection results, but faster. <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://en.wikipedia.org/wiki/Bounding_volume"><param name="text" value="<html><u>More about bounding volumes...</u></html>"><param name="textColor" value="blue"></object> |
||||
</p> |
||||
|
||||
<p> |
||||
Supported types: |
||||
<img src="/wiki/lib/exe/fetch.php"> |
||||
</p> |
||||
<ul> |
||||
<li><div> Type.AABB = Axis-aligned bounding box, that means it doesn't rotate, which makes it less precise. A <code>com.jme3.bounding.BoundingBox</code> is an axis-aligned cuboid used as a container for a group of vertices of a piece of geometry. A BoundingBox has a center and extents from that center along the x, y and z axis. This is the default bounding volume, since it is fairly fast to generate and gives better accuracy than the bounding sphere.</div> |
||||
</li> |
||||
<li><div> Type.Sphere: <code>com.jme3.bounding.BoundingSphere</code> is a sphere used as a container for a group of vertices of a piece of geometry. A BoundingSphere has a center and a radius.</div> |
||||
</li> |
||||
<li><div> Type.OBB = Oriented bounding box. This bounding box is more precise because it can rotate with its content, but is computationally more expensive. (Currently not supported.)</div> |
||||
</li> |
||||
<li><div> Type.Capsule = Cylinder with rounded ends, also called "swept sphere". Typically used for mobile characters. (Currently not supported.)</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
|
||||
<p><div>Note: If you are looking for bounding volumes for physical objects, use <a href="/com/jme3/gde/core/docs/jme3/advanced/physics.html">CollisionShapes</a>. |
||||
</div></p> |
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT6 SECTION "Bounding Volumes" [5577-7620] --> |
||||
<h3><a>Usage</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
For example you can use Bounding Volumes on custom meshes, or complex non-physical shapes. |
||||
|
||||
</p> |
||||
<pre>mesh.setBound(new BoundingSphere()); |
||||
mesh.updateBound();</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT7 SECTION "Usage" [7621-7802] --> |
||||
<h2><a>Mesh and Scene Graph Collision</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
One of the supported <code>Collidable</code>s are meshes and scene graph objects. To execute a collision detection query against a scene graph, use <code>Spatial.collideWith()</code>. This will traverse the scene graph and return any mesh collisions that were detected. Note that the first collision against a particular scene graph may take a long time, this is because a special data structure called <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://en.wikipedia.org/wiki/Bounding_interval_hierarchy"><param name="text" value="<html><u>|Bounding Interval Hierarchy (BIH)</u></html>"><param name="textColor" value="blue"></object> needs to be generated for the meshes. At a later point, the mesh could change and the BIH tree would become out of date, in that case, call <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://jmonkeyengine.org/javadoc/com/jme3/scene/Mesh.html#createCollisionData()"><param name="text" value="<html><u>Mesh.createCollisionData()</u></html>"><param name="textColor" value="blue"></object> on the changed mesh to update the BIH tree. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT8 SECTION "Mesh and Scene Graph Collision" [7803-8623] --> |
||||
<h2><a>Intersection</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
A <code>com.jme3.math.Ray</code> is an infinite line with a beginning, a direction, and no end; whereas a <code>com.jme3.math.Line</code> is an infinite line with only a direction (no beginning, no end). |
||||
</p> |
||||
|
||||
<p> |
||||
Rays are used to perform line-of-sight calculations. This means you can detect what users were "aiming at" when they clicked or pressed a key. You can also use this to detect whether game characters can see something (or someone) or not. |
||||
</p> |
||||
<ul> |
||||
<li><div> <strong>Click to select:</strong> You can determine what a user has clicked by casting a ray from the camera forward in the direction of the camera. Now identify the closest collision of the ray with the rootNode, and you have the clicked object.</div> |
||||
</li> |
||||
<li><div> <strong>Line of sight:</strong> Cast a ray from a player in the direction of another player. Then you detect all collisions of this ray with other entities (walls versus foliage versus window panes) and use this to calculate how likely it is that one can see the other.</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
|
||||
<p><div>These simple but powerful ray-surface intersection tests are called Ray Casting. As opposed to the more advanced Ray Tracing technique, Ray Casting does not follow the ray's reflection after the first hit ??? the ray just goes straight on. |
||||
</div></p> |
||||
</p> |
||||
|
||||
<p> |
||||
Learn the details of how to implement <a href="/com/jme3/gde/core/docs/jme3/advanced/mouse_picking.html">Mouse Picking</a> here. |
||||
</p> |
||||
<hr/> |
||||
|
||||
<p> |
||||
TODO: |
||||
</p> |
||||
<ul> |
||||
<li><div> Bounding Interval Hierarchy (<code>com.jme3.collision.bih.BIHNode</code>)</div> |
||||
</li> |
||||
<li><div> com.jme3.scene.CollisionData</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT9 SECTION "Intersection" [8624-] --> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:collision_and_intersection?do=export_xhtmlbody">view online version</a></em></p> |
@ -1,270 +0,0 @@ |
||||
|
||||
<h1><a>Combo Moves</a></h1> |
||||
<div> |
||||
|
||||
<p> |
||||
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. <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://en.wikipedia.org/wiki/Combo_%28video_gaming%29"><param name="text" value="<html><u>More background info</u></html>"><param name="textColor" value="blue"></object> |
||||
</p> |
||||
|
||||
<p> |
||||
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". |
||||
</p> |
||||
|
||||
<p> |
||||
Usage: |
||||
</p> |
||||
<ol> |
||||
<li><div> Create input triggers </div> |
||||
</li> |
||||
<li><div> Define combos</div> |
||||
</li> |
||||
<li><div> Detect combos in ActionListener </div> |
||||
</li> |
||||
<li><div> Execute combos in update loop </div> |
||||
</li> |
||||
</ol> |
||||
|
||||
<p> |
||||
|
||||
Copy the two classes ComboMoveExecution.java and ComboMove.java into your application and adjust them to your package paths. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT1 SECTION "Combo Moves" [1-824] --> |
||||
<h2><a>Example Code</a></h2> |
||||
<div> |
||||
<ul> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/input/combomoves/TestComboMoves.java"><param name="text" value="<html><u>TestComboMoves.java</u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/input/combomoves/ComboMoveExecution.java"><param name="text" value="<html><u>ComboMoveExecution.java</u></html>"><param name="textColor" value="blue"></object> ??? required</div> |
||||
</li> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/input/combomoves/ComboMove.java"><param name="text" value="<html><u>ComboMove.java</u></html>"><param name="textColor" value="blue"></object> ??? required</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT2 SECTION "Example Code" [825-1321] --> |
||||
<h2><a>Create Input Triggers</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
First you <a href="/com/jme3/gde/core/docs/jme3/advanced/input_handling.html">define your game's inputs</a> as you usually do: Implement the com.jme3.input.controls.ActionListener interface for your class, and add triggers mappings such as com.jme3.input.controls.KeyTrigger and com.jme3.input.KeyInput. |
||||
</p> |
||||
|
||||
<p> |
||||
For example: |
||||
</p> |
||||
<pre>inputManager.addMapping("Left", new KeyTrigger(KeyInput.KEY_LEFT)); |
||||
inputManager.addMapping("Right", new KeyTrigger(KeyInput.KEY_RIGHT)); |
||||
inputManager.addMapping("Up", new KeyTrigger(KeyInput.KEY_UP)); |
||||
inputManager.addMapping("Down", new KeyTrigger(KeyInput.KEY_DOWN)); |
||||
inputManager.addMapping("Attack1", new KeyTrigger(KeyInput.KEY_SPACE)); |
||||
... |
||||
inputManager.addListener(this, "Left", "Right", "Up", "Down", "Attack1");</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT3 SECTION "Create Input Triggers" [1322-2092] --> |
||||
<h2><a>Define Combos</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
For each of your combo moves, you specify the series of inputs that will trigger it. The order in which you define them is the order the player has to press them for the step to be recorded. When all steps have been recorded, the combo is triggered. |
||||
</p> |
||||
|
||||
<p> |
||||
The following example shows how a fireball combo move is triggered by pressing the navigation keys for "down, down+right, right", in this order. |
||||
</p> |
||||
<pre>ComboMove fireball = new ComboMove("Fireball"); |
||||
fireball.press("Down").notPress("Right").done(); |
||||
fireball.press("Right", "Down").done(); |
||||
fireball.press("Right").notPress("Down").done(); |
||||
fireball.notPress("Right", "Down").done(); |
||||
fireball.setUseFinalState(false);</pre> |
||||
|
||||
<p> |
||||
Also create a ComboMoveExecution object for each ComboMove. You need it later to execute the detected combo. |
||||
</p> |
||||
<pre>ComboMoveExecution fireballExec = new ComboMoveExecution(fireball);</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT4 SECTION "Define Combos" [2093-3001] --> |
||||
<h3><a>ComboMove Class Methods</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Use the following ComboMove methods to specify the combo: |
||||
|
||||
</p> |
||||
<div><table> |
||||
<tr> |
||||
<th>ComboMove Method</th><th>Description</th> |
||||
</tr> |
||||
<tr> |
||||
<td>press("A").done(); <br/> |
||||
press("A","B").done();</td><td>Combo step is recorded if A is entered. <br/> |
||||
Combo step is recorded if A and B are entered simultaneously.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>notPress("A").done(); <br/> |
||||
notPress("A","B").done();</td><td>Combo step is recorded if A is released. <br/> |
||||
Combo step is recorded if A and B are both released.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>press("A").notPress("B").done();</td><td>Combo step is recorded if A is entered, and not B</td> |
||||
</tr> |
||||
<tr> |
||||
<td>press("A").notPress("B").timeElapsed(0.11f).done();</td><td>Combo step is recorded a certain time after A and not B is entered. <br/> |
||||
etc, etc ???</td> |
||||
</tr> |
||||
<tr> |
||||
<td>setPriority(0.5f);</td><td>If there is an ambiguity, a high-priority combo will trigger instead of a low-priority combo. This prevents that a similar looking combo step "hijacks" another Combo. Use only once per ComboMove.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>setUseFinalState(false); <br/> |
||||
setUseFinalState(true);</td><td>This is the final command of the series. <br/> |
||||
False: Do not wait on a final state, chain combo steps. (?) <br/> |
||||
True: This is the final state, do not chain combo steps. (?)</td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT6 TABLE [3096-4090] --> |
||||
<p> |
||||
|
||||
The <code>press()</code> and <code>notPress()</code> methods accept sets of Input Triggers, e.g. <code>fireball.press("A","B","C").done()</code>. |
||||
</p> |
||||
|
||||
<p> |
||||
The following getters give you more information about the game state: |
||||
|
||||
</p> |
||||
<div><table> |
||||
<tr> |
||||
<th>ComboMove Method</th><th>Usage</th> |
||||
</tr> |
||||
<tr> |
||||
<td>getCastTime()</td><td>Returns the time since the last step has been recorded. (?)</td> |
||||
</tr> |
||||
<tr> |
||||
<td>getMoveName()</td><td>Returns the string of the current combo</td> |
||||
</tr> |
||||
<tr> |
||||
<td>getPriority()</td><td>Returns the priority of this move</td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT7 TABLE [4283-4489] --> |
||||
</div> |
||||
<!-- EDIT5 SECTION "ComboMove Class Methods" [3002-4490] --> |
||||
<h2><a>Detect Combos in ActionListener</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Now that you have specified the combo steps, you want to detect them. You do that in the onAction() method that you get from the ActionListener interface. |
||||
</p> |
||||
|
||||
<p> |
||||
Create a HashSet <code>pressMappings</code> to track curently pressed mappings, and a ComboMove object <code>currentMove</code> to track the current move. |
||||
</p> |
||||
|
||||
<p> |
||||
We also track the cast time of a combo to determine if it has timed out (see update loop below). |
||||
</p> |
||||
<pre>private HashSet<String> pressedMappings = new HashSet<String>(); |
||||
private ComboMove currentMove = null; |
||||
private float currentMoveCastTime = 0; |
||||
private float time = 0; |
||||
... |
||||
|
||||
public void onAction(String name, boolean isPressed, float tpf) { |
||||
// Record pressed mappings |
||||
if (isPressed){ |
||||
pressedMappings.add(name); |
||||
}else{ |
||||
pressedMappings.remove(name); |
||||
} |
||||
|
||||
// The pressed mappings have changed: Update ComboExecution objects |
||||
List<ComboMove> invokedMoves = new ArrayList<ComboMove>(); |
||||
if (fireballExec.updateState(pressedMappings, time)){ |
||||
invokedMoves.add(fireball); |
||||
} |
||||
// ... add more ComboExecs here... |
||||
|
||||
// If any ComboMoves have been sucessfully triggered: |
||||
if (invokedMoves.size() > 0){ |
||||
// identify the move with highest priority |
||||
float priority = 0; |
||||
ComboMove toExec = null; |
||||
for (ComboMove move : invokedMoves){ |
||||
if (move.getPriority() > priority){ |
||||
priority = move.getPriority(); |
||||
toExec = move; |
||||
} |
||||
} |
||||
if (currentMove != null && currentMove.getPriority() > toExec.getPriority()){ |
||||
return; // skip lower-priority moves |
||||
} |
||||
|
||||
// If a ComboMove has been identified, store it in currentMove |
||||
currentMove = toExec; |
||||
currentMoveCastTime = currentMove.getCastTime(); |
||||
} |
||||
}</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT8 SECTION "Detect Combos in ActionListener" [4491-6314] --> |
||||
<h2><a>Execute Combos in the Update Loop</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Now that you have detected the current move, you want to execute it. You do that in the update loop. |
||||
</p> |
||||
<pre>@Override |
||||
public void simpleUpdate(float tpf){ |
||||
time += tpf; |
||||
fireballExec.updateExpiration(time); |
||||
// ... update more ComboExecs here.... |
||||
|
||||
if (currentMove != null){ |
||||
currentMoveCastTime -= tpf; |
||||
if (currentMoveCastTime <= 0){ |
||||
System.out.println("THIS COMBO WAS TRIGGERED: " + currentMove.getMoveName()); |
||||
// TODO: for each combo, implement special actions here |
||||
currentMoveCastTime = 0; |
||||
currentMove = null; |
||||
} |
||||
} |
||||
}</pre> |
||||
|
||||
<p> |
||||
Test <code>currentMove.getMoveName()</code> and proceed to call methods that implement any special actions and bonuses. This is up to you and depends individually on your game. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT9 SECTION "Execute Combos in the Update Loop" [6315-7152] --> |
||||
<h2><a>Why Combos?</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Depending on the game genre, the designer can reward the players' intrinsical or extrinsical skills: |
||||
|
||||
</p> |
||||
<ul> |
||||
<li><div> (intrinsical:) RPGs typically calculate the success of an attack from the character's in-game training level: The player plays the role of a character whose skill level is defined in numbers. RPGs typically do not offer any Combos.</div> |
||||
</li> |
||||
<li><div> (extrinsical:) Sport and fighter games typically choose to reward the player's "manual" skills: The success of a special move solely depends on the player's own dexterity. These games typically offer optional Combos.</div> |
||||
</li> |
||||
</ul> |
||||
<div><span> |
||||
<a href="/wiki/doku.php/tag:keyinput?do=showtag&tag=tag%3Akeyinput">keyinput</a>, |
||||
<a href="/wiki/doku.php/tag:input?do=showtag&tag=tag%3Ainput">input</a>, |
||||
<a href="/wiki/doku.php/tag:documentation?do=showtag&tag=tag%3Adocumentation">documentation</a> |
||||
</span></div> |
||||
|
||||
</div> |
||||
<!-- EDIT10 SECTION "Why Combos?" [7153-] --> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:combo_moves?do=export_xhtmlbody">view online version</a></em></p> |
@ -1,391 +0,0 @@ |
||||
|
||||
<h1><a>Custom Controls</a></h1> |
||||
<div> |
||||
|
||||
<p> |
||||
A <code>com.jme3.scene.control.Control</code> is a customizable jME3 interface that allows you to cleanly steer the behaviour of game entities (Spatials), such as artificially intelligent behaviour in NPCs, traps, automatic alarms and doors, animals and pets, self-steering vehicles or platforms ??? anything that moves and interacts. Several instances of customs Controls together implement the behaviours of a type of Spatial. |
||||
</p> |
||||
|
||||
<p> |
||||
To control global game behaviour see <a href="/com/jme3/gde/core/docs/jme3/advanced/application_states.html">Application States</a> ??? you often use AppStates and Control together. |
||||
</p> |
||||
<ul> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://www.youtube.com/watch?v=MNDiZ9YHIpM"><param name="text" value="<html><u>Quick video introduction to Custom Controls</u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
|
||||
To control the behaviour of spatials: |
||||
</p> |
||||
<ol> |
||||
<li><div> Create one control for each <em>type of behavior</em>. When you add several controls to one spatial, they will be executed in the order they were added. <br/> |
||||
For example, one NPC can be controlled by a PhysicsControl instance and an AIControl instance.</div> |
||||
</li> |
||||
<li><div> Define the custom control and implement its behaviour in the Control's update method:</div> |
||||
<ul> |
||||
<li><div> You can pass arguments into your custom control.</div> |
||||
</li> |
||||
<li><div> In the control class, the object <code>spatial</code> gives you access to the spatial and subspatials that the control is attached to.</div> |
||||
</li> |
||||
<li><div> Here you modify the <code>spatial</code>'s transformation (move, scale, rotate), play animations, check its environement, define how it acts and reacts. </div> |
||||
</li> |
||||
</ul> |
||||
</li> |
||||
<li><div> Add an instance of the Control to a spatial to give it this behavior. The spatial's game state is updated automatically from now on. <pre>spatial.addControl(myControl);</pre> |
||||
</div> |
||||
</li> |
||||
</ol> |
||||
|
||||
<p> |
||||
|
||||
To implement game logic for a type of spatial, you will either extend AbstractControl (most common case), or implement the Control interface, as explained in this article. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT1 SECTION "Custom Controls" [1-1747] --> |
||||
<h2><a>Usage</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Use <span><a href="/com/jme3/gde/core/docs/jme3/advanced/custom_controls.html">Controls</a></span> to implement the <em>behaviour of types of game entities</em>. |
||||
</p> |
||||
<ul> |
||||
<li><div> Use Controls to add a type of behaviour (that is, methods and fields) to individual Spatials. </div> |
||||
</li> |
||||
<li><div> Each Control has its own <code>update()</code> loop that hooks into <code>simpleUpdate()</code>. Use Controls to move blocks of code out of the <code>simpleUpdate()</code> loop.</div> |
||||
</li> |
||||
<li><div> One Spatial can be influenced by several Controls. (Very powerful and modular!) </div> |
||||
</li> |
||||
<li><div> Each Spatial needs its own instance of the Control. </div> |
||||
</li> |
||||
<li><div> A Control only has access to and control over the Spatial it is attached to.</div> |
||||
</li> |
||||
<li><div> Controls can be saved as .j3o file together with a Spatial. </div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
|
||||
Examples: You can write |
||||
</p> |
||||
<ul> |
||||
<li><div> A WalkerNavControl, SwimmerNavControl, FlyerNavControl??? that defines how a type of NPC finds their way around. All NPCs can walk, some can fly, others can swim, and some can all three, etc.</div> |
||||
</li> |
||||
<li><div> A PlayerNavControl that is steered by user-configurable keyboard and mouse input.</div> |
||||
</li> |
||||
<li><div> A generic animation control that acts as a common interface that triggers animations (walk, stand, attack, defend) for various entities.</div> |
||||
</li> |
||||
<li><div> A DefensiveBehaviourControl that remote-controls NPC behaviour in fight situations. </div> |
||||
</li> |
||||
<li><div> An IdleBehaviourControl that remote-controls NPC behaviour in neutral situations. </div> |
||||
</li> |
||||
<li><div> A DestructionControl that automatically replaces a structure with an appropriate piece of debris after collision with a projectile??? </div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
|
||||
The possibilities are endless. <img src="/wiki/lib/images/smileys/icon_smile.gif" class="middle" alt=":-)"/> |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT2 SECTION "Usage" [1748-3215] --> |
||||
<h2><a>Example Code</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Other examples include the built-in RigidBodyControl in JME's physics integration, the built-in TerrainLODControl that updates the terrain's level of detail depending on the viewer's perspective, etc. |
||||
</p> |
||||
|
||||
<p> |
||||
Existing examples in the code base include: |
||||
</p> |
||||
<ul> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/core/com/jme3/animation/AnimControl.java"><param name="text" value="<html><u>AnimControl.java</u></html>"><param name="textColor" value="blue"></object> allows manipulation of skeletal animation, including blending and multiple channels.</div> |
||||
</li> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/core/com/jme3/scene/control/CameraControl.java"><param name="text" value="<html><u>CameraControl.java</u></html>"><param name="textColor" value="blue"></object> allows you to sync the camera position with the position of a given spatial.</div> |
||||
</li> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/core/com/jme3/scene/control/BillboardControl.java"><param name="text" value="<html><u>BillboardControl.java</u></html>"><param name="textColor" value="blue"></object> displays a flat picture orthogonally, e.g. a speech bubble or informational dialog.</div> |
||||
</li> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/#src%2Fjbullet%2Fcom%2Fjme3%2Fbullet%2Fcontrol"><param name="text" value="<html><u>PhysicsControl</u></html>"><param name="textColor" value="blue"></object> subclasses (such as CharacterControl, RigidBodyControl, VehicleControl) allow you to add physical properties to any spatial. PhysicsControls tie into capabilities provided by the BulletAppState.</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT3 SECTION "Example Code" [3216-4500] --> |
||||
<h2><a>AbstractControl Class</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
<p><div>The most common way to create a Control is to create a class that extends AbstractControl. |
||||
</div></p> |
||||
</p> |
||||
|
||||
<p> |
||||
The AbstractControl can be found under <code>com.jme3.scene.control.AbstractControl</code>. This is a default abstract class that implements the Control interface. |
||||
</p> |
||||
<ul> |
||||
<li><div> You have access to a boolean <code>isEnabled()</code>.</div> |
||||
</li> |
||||
<li><div> You have access to the Spatial object <code>spatial</code>. </div> |
||||
</li> |
||||
<li><div> You override the <code>controlUpdate()</code> method to implement the Spatial's behaviour. </div> |
||||
</li> |
||||
<li><div> You have access to a <code>setEnabled(boolean)</code> method. This activates or deactivates this Control's behaviour in this spatial temporarily. While the AbstractControl is toggled to be disabled, the <code>controlUpdate()</code> loop is no longer executed. <br/> |
||||
For example, you disable your IdleBehaviourControl when you enable your DefensiveBehaviourControl in a spatial.</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
|
||||
Usage: Your custom subclass implements the three methods <code>controlUpdate()</code>, <code>controlRender()</code>, <code>setSpatial()</code>, and <code>cloneForSpatial()</code> as shown here: |
||||
</p> |
||||
<pre>public class MyControl extends AbstractControl implements Savable, Cloneable { |
||||
private int index; // can have custom fields -- example |
||||
|
||||
public MyControl(){} // empty serialization constructor |
||||
|
||||
<span>/** Optional custom constructor with arguments that can init custom fields. |
||||
* Note: you cannot modify the spatial here yet! */</span> |
||||
public MyControl(int i){ |
||||
// index=i; // example |
||||
} |
||||
|
||||
<span>/** This is your init method. Optionally, you can modify |
||||
* the spatial from here (transform it, initialize userdata, etc). */</span> |
||||
@Override |
||||
public void setSpatial(Spatial spatial) { |
||||
super.setSpatial(spatial); |
||||
// spatial.setUserData("index", i); // example |
||||
} |
||||
|
||||
|
||||
<span>/** Implement your spatial's behaviour here. |
||||
* From here you can modify the scene graph and the spatial |
||||
* (transform them, get and set userdata, etc). |
||||
* This loop controls the spatial while the Control is enabled. */</span> |
||||
@Override |
||||
protected void controlUpdate(float tpf){ |
||||
if(spatial != null) { |
||||
// spatial.rotate(tpf,tpf,tpf); // example behaviour |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public Control cloneForSpatial(Spatial spatial){ |
||||
final MyControl control = new MyControl(); |
||||
/* Optional: use setters to copy userdata into the cloned control */ |
||||
// control.setIndex(i); // example |
||||
control.setSpatial(spatial); |
||||
return control; |
||||
} |
||||
|
||||
@Override |
||||
protected void controlRender(RenderManager rm, ViewPort vp){ |
||||
/* Optional: rendering manipulation (for advanced users) */ |
||||
} |
||||
|
||||
@Override |
||||
public void read(JmeImporter im) throws IOException { |
||||
super.read(im); |
||||
// im.getCapsule(this).read(...); |
||||
} |
||||
|
||||
@Override |
||||
public void write(JmeExporter ex) throws IOException { |
||||
super.write(ex); |
||||
// ex.getCapsule(this).write(...); |
||||
} |
||||
|
||||
}</pre> |
||||
|
||||
<p> |
||||
See also: |
||||
</p> |
||||
<ul> |
||||
<li><div> To learn more about <code>write()</code> and <code>read()</code>, see <a href="/com/jme3/gde/core/docs/jme3/advanced/save_and_load.html">Save and Load</a></div> |
||||
</li> |
||||
<li><div> To learn more about <code>setUserData()</code>, see <a href="/com/jme3/gde/core/docs/jme3/advanced/spatial.html">Spatial</a>.</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT4 SECTION "AbstractControl Class" [4501-7447] --> |
||||
<h2><a>The Control Interface</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
<p><div>In the less common case that you want to create a Control that also extends another class, create a custom interface that extends jME3's Control interface. Your class can become a Control by implement the Control interface, and at the same time extend another class. |
||||
</div></p> |
||||
</p> |
||||
|
||||
<p> |
||||
The Control interface can be found under <code>com.jme3.scene.control.Control</code>. It has the following method signatures: |
||||
</p> |
||||
<ul> |
||||
<li><div> <code>cloneForSpatial(Spatial)</code>: Clones the Control and attaches it to a clone of the given Spatial. <br/> |
||||
Implement this method to be able to <a href="/com/jme3/gde/core/docs/jme3/advanced/save_and_load.html">save() and load()</a> Spatials carrying this Control. <br/> |
||||
The AssetManager also uses this method if the same spatial is loaded twice. You can specify which fields you want your object to reuse (e.g. collisionshapes) in this case. </div> |
||||
</li> |
||||
<li><div> <code>setEnabled(boolean)</code>: Toggles a boolean that enables or disables the Control. Goes with accessor <code>isEnabled();</code>. You test for it in the <code>update(float tpf)</code> loop before you execute anything.</div> |
||||
</li> |
||||
<li><div> There are also some internal methods that you do not call from user code: <code>setSpatial(Spatial s)</code>, <code>update(float tpf);</code>, <code>render(RenderManager rm, ViewPort vp)</code>.</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
|
||||
Usage example: |
||||
1. Create a custom control interface |
||||
|
||||
</p> |
||||
<pre>public interface MyControlInterface extends Control { |
||||
public void setSomething(int x); // optionally, add custom methods |
||||
}</pre> |
||||
|
||||
<p> |
||||
|
||||
2. Create custom Controls implementing your Control interface. |
||||
|
||||
</p> |
||||
<pre>public class MyControl extends MyCustomClass implements MyControlInterface { |
||||
|
||||
protected Spatial spatial; |
||||
|
||||
protected boolean enabled = true; |
||||
|
||||
public MyControl() { } // empty serialization constructor |
||||
|
||||
public MyControl(int x) { // custom constructor |
||||
super(x); |
||||
} |
||||
|
||||
@Override |
||||
public void update(float tpf) { |
||||
if (enabled && spatial != null) { |
||||
// Write custom code to control the spatial here! |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void render(RenderManager rm, ViewPort vp) { |
||||
// optional for advanced users, e.g. to display a debug shape |
||||
} |
||||
|
||||
@Override |
||||
public Control cloneForSpatial(Spatial spatial) { |
||||
MyControl control = new MyControl(); |
||||
// set custom properties |
||||
control.setSpatial(spatial); |
||||
control.setEnabled(isEnabled()); |
||||
// set some more properties here... |
||||
return control; |
||||
} |
||||
|
||||
@Override |
||||
public void setEnabled(boolean enabled) { |
||||
this.enabled = enabled; |
||||
} |
||||
|
||||
@Override |
||||
public boolean isEnabled() { |
||||
return enabled; |
||||
} |
||||
|
||||
@Override |
||||
public void setSomething(int z) { |
||||
// You can add custom methods ... |
||||
} |
||||
|
||||
@Override |
||||
public void write(JmeExporter ex) throws IOException { |
||||
super.write(ex); |
||||
OutputCapsule oc = ex.getCapsule(this); |
||||
oc.write(enabled, "enabled", true); |
||||
oc.write(spatial, "spatial", null); |
||||
// write custom variables .... |
||||
} |
||||
@Override |
||||
public void read(JmeImporter im) throws IOException { |
||||
super.read(im); |
||||
InputCapsule ic = im.getCapsule(this); |
||||
enabled = ic.readBoolean("enabled", true); |
||||
spatial = (Spatial) ic.readSavable("spatial", null); |
||||
// read custom variables .... |
||||
} |
||||
}</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT5 SECTION "The Control Interface" [7448-10699] --> |
||||
<h2><a>Best Practices</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
<strong>Tip:</strong> Use the getControl() accessor to get Control objects from Spatials. No need to pass around lots of object references. |
||||
Here an example from the <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/monkeyzone/"><param name="text" value="<html><u>MonkeyZone</u></html>"><param name="textColor" value="blue"></object> code: |
||||
|
||||
</p> |
||||
<pre>public class CharacterAnimControl implements Control { |
||||
... |
||||
public void setSpatial(Spatial spatial) { |
||||
... |
||||
animControl = spatial.getControl(AnimControl.class); |
||||
characterControl = spatial.getControl(CharacterControl.class); |
||||
... |
||||
} |
||||
}</pre> |
||||
|
||||
<p> |
||||
|
||||
<strong>Tip:</strong> You can create custom Control interfaces so a set of different Controls provide the same methods and can be accessed with the interface class type. |
||||
|
||||
</p> |
||||
<pre>public interface ManualControl extends Control { |
||||
public void steerX(float value); |
||||
public void steerY(float value); |
||||
public void moveX(float value); |
||||
public void moveY(float value); |
||||
public void moveZ(float value); |
||||
... |
||||
}</pre> |
||||
|
||||
<p> |
||||
|
||||
Then you create custom sub-Controls and implement the methods accordingly to the context: |
||||
|
||||
</p> |
||||
<pre>public class ManualVehicleControl extends ManualControl {...}</pre> |
||||
|
||||
<p> |
||||
and |
||||
|
||||
</p> |
||||
<pre>public class ManualCharacterControl extends ManualControl {...}</pre> |
||||
|
||||
<p> |
||||
|
||||
Then add the appropriate controls to spatials: |
||||
|
||||
</p> |
||||
<pre>characterSpatial.addControl(new ManualCharacterControl()); |
||||
... |
||||
vehicleSpatial.addControl(new ManualVehicleControl()); |
||||
...</pre> |
||||
|
||||
<p> |
||||
|
||||
<strong>Tip:</strong> Use the getControl() method on a Spatial to get a specific Control object, and activate its behaviour! |
||||
|
||||
</p> |
||||
<pre>ManualControl c = mySpatial.getControl(ManualControl.class); |
||||
c.steerX(steerX);</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT6 SECTION "Best Practices" [10700-] --> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:custom_controls?do=export_xhtmlbody">view online version</a></em></p> |
@ -1,323 +0,0 @@ |
||||
|
||||
<h1><a>Custom Mesh Shapes</a></h1> |
||||
<div> |
||||
|
||||
<p> |
||||
<img src="/wiki/lib/exe/fetch.php"> |
||||
Use the Mesh class to create custom shapes that go beyond Quad, Box, Cylinder, and Sphere, even procedural shapes are possible. Thank you to KayTrance for providing the sample code! |
||||
In this tutorial, we (re)create a very simple rectangular mesh, and we have a look at different ways of coloring it. A flat rectangle may not look useful because it's exactly the same as a <code>com.jme3.scene.shape.Quad</code>. We choose this simple example in order to show you how to build any shape out of triangles ??? without the distractions of more complex shapes. |
||||
</p> |
||||
<ul> |
||||
<li><div> Full code sample: <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://jmonkeyengine.googlecode.com/svn/branches/stable-alpha4/engine/src/test/jme3test/model/shape/TestCustomMesh.java"><param name="text" value="<html><u>TestCustomMesh.java</u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT1 SECTION "Custom Mesh Shapes" [1-811] --> |
||||
<h2><a>Polygon Meshes</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
Polygon meshes are made up of triangles. The corners of the triangles are vertices. So, when ever you create a new shape, you break it down into triangles. |
||||
Let's look at a cube. A cube is made up of 6 rectangles. Each rectangle can be broken down into two triangles. This means you need 12 triangles to create a cube mesh. You also need to know the 8 corner coordinates (vertices). The trick is that you have to specify the vertices in a certain order: Each triangle separately, counter-clockwise. |
||||
Sounds worse than it is ??? here is an example: |
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT2 SECTION "Polygon Meshes" [812-1383] --> |
||||
<h2><a>Creating a Quad Mesh</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
Okay, we want to create a Quad. A quad has four vertices, and is made up of two triangles. |
||||
The base class for creating meshes is <code>com.jme3.scene.Mesh</code>. |
||||
|
||||
</p> |
||||
<pre>Mesh mesh = new Mesh();</pre> |
||||
|
||||
<p> |
||||
|
||||
If you create your own Mesh-based class, replace <code>mesh</code> by <code>this</code> in the following examples: |
||||
|
||||
</p> |
||||
<pre>public class MyMesh extends Mesh { }</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT3 SECTION "Creating a Quad Mesh" [1384-1766] --> |
||||
<h3><a>Vertices</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
To define your own shape, determine its vertex positions in space. Store them in an array using com.jme3.math.Vector3f. For a Quad, we need four vertices: Bottom left, bottom right, top left, top right. We name the array <code>vertices[]</code>. |
||||
|
||||
</p> |
||||
<pre>Vector3f [] vertices = new Vector3f[4]; |
||||
vertices[0] = new Vector3f(0,0,0); |
||||
vertices[1] = new Vector3f(3,0,0); |
||||
vertices[2] = new Vector3f(0,3,0); |
||||
vertices[3] = new Vector3f(3,3,0);</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT4 SECTION "Vertices" [1767-2222] --> |
||||
<h3><a>Texture Coordinates</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
Next, define the Quad's 2D texture coordinates for each vertex, in the same order: Bottom left, bottom right, top left, top right. We name this array <code>texCoord[]</code> |
||||
|
||||
</p> |
||||
<pre>Vector2f[] texCoord = new Vector2f[4]; |
||||
texCoord[0] = new Vector2f(0,0); |
||||
texCoord[1] = new Vector2f(1,0); |
||||
texCoord[2] = new Vector2f(0,1); |
||||
texCoord[3] = new Vector2f(1,1);</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT5 SECTION "Texture Coordinates" [2223-2608] --> |
||||
<h3><a>Connecting the Dots</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
Next we turn the unrelated coordinates into triangles ??? We define the order in which the mesh is constructed. Think of these indexes as coming in groups of three. Each group of indexes describes one triangle. Note that you must specify the vertices counter-clockwise! |
||||
|
||||
</p> |
||||
<pre>int [] indexes = { 2,0,1, 1,3,2 };</pre> |
||||
<ul> |
||||
<li><div> The 2,0,1 triangle starts at top left, continues bottom left, and ends at bottom right.</div> |
||||
</li> |
||||
<li><div> The 1,3,2 triangle start at bottom right, continues top right, and ends at top left.</div> |
||||
</li> |
||||
</ul> |
||||
<pre>2\2--3 |
||||
| \ | Counter-clockwise |
||||
| \ | |
||||
0--1\1</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT6 SECTION "Connecting the Dots" [2609-3204] --> |
||||
<h3><a>Setting the Mesh Buffer</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
The Mesh data is stored in a buffer. |
||||
</p> |
||||
<ol> |
||||
<li><div> Using <code>com.jme3.util.BufferUtils</code>, we create three buffers for the three types of information we have:</div> |
||||
<ul> |
||||
<li><div> vertex positions,</div> |
||||
</li> |
||||
<li><div> texture coordinates,</div> |
||||
</li> |
||||
<li><div> indices.</div> |
||||
</li> |
||||
</ul> |
||||
</li> |
||||
<li><div> We assign the data to the appropriate type of buffer inside the mesh object. The three buffer types are taken from an enum in <code>com.jme3.scene.VertexBuffer.Type</code>.</div> |
||||
</li> |
||||
<li><div> The third parameter describes the number of components of the values. Vertex postions are 3 float values, texture coordinates are 2 float values, and the indices are 3 ints representing 3 vertices in a triangle.</div> |
||||
</li> |
||||
<li><div> In order for jMonkey to correctly show the mesh in the scene, it needs to know the bounds of our new mesh. This can easily be achieved by calling the updateBound() method on it.</div> |
||||
</li> |
||||
</ol> |
||||
<pre>mesh.setBuffer(Type.Position, 3, BufferUtils.createFloatBuffer(vertices)); |
||||
mesh.setBuffer(Type.TexCoord, 2, BufferUtils.createFloatBuffer(texCoord)); |
||||
mesh.setBuffer(Type.Index, 3, BufferUtils.createIntBuffer(indexes)); |
||||
mesh.updateBound();</pre> |
||||
|
||||
<p> |
||||
|
||||
Our Mesh is ready! Now we want to see it. |
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT7 SECTION "Setting the Mesh Buffer" [3205-4320] --> |
||||
<h2><a>Using the Mesh in a Scene</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
We create a <code>com.jme3.scene.Geometry</code>, apply a simple color material to it, and attach it to the rootNode to make it appear in the scene. |
||||
|
||||
</p> |
||||
<pre>Geometry geo = new Geometry("OurMesh", mesh); |
||||
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); |
||||
mat.setColor("Color", ColorRGBA.Blue); |
||||
geo.setMaterial(mat); |
||||
rootNode.attachChild(geo);</pre> |
||||
|
||||
<p> |
||||
|
||||
Ta-daa! |
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT8 SECTION "Using the Mesh in a Scene" [4321-4740] --> |
||||
<h2><a>Dynamic Meshes</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
If modifying a mesh dynamically in a way which would change the model's bounds then you need to call updateModelBound() on the Geometry object containing the mesh after calling updateBounds() on the mesh object. There is a warning on updateModelBounds about not usually needing to use it but that can be ignored in this special case. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT9 SECTION "Dynamic Meshes" [4741-5102] --> |
||||
<h2><a>Optional Mesh Features</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
There are more vertex buffers in a Mesh than the three shown above. For an overview, see also <a href="/com/jme3/gde/core/docs/jme3/advanced/mesh.html">mesh</a>. |
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT10 SECTION "Optional Mesh Features" [5103-5241] --> |
||||
<h3><a>Example: Vertex Colors</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
Vertex coloring is a simple way of coloring meshes. Instead of just assigning one solid color, each vertex (corner) has a color assigned. The faces between the vertices are then colored with a gradient. You can use the same mesh <code>mesh</code> object that you defined above. |
||||
|
||||
</p> |
||||
<pre>Geometry geo = new Geometry ("ColoredMesh", mesh); |
||||
Material matVC = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); |
||||
matVC.setBoolean("VertexColor", true);</pre> |
||||
|
||||
<p> |
||||
|
||||
You create a float array color buffer: |
||||
</p> |
||||
<ul> |
||||
<li><div> Assign 4 color values, RGBA, to each vertex.</div> |
||||
<ul> |
||||
<li><div> To loop over the 4 color values, use a color index <pre>int colorIndex = 0;</pre> |
||||
</div> |
||||
</li> |
||||
</ul> |
||||
</li> |
||||
<li><div> The color buffer contains four color values for each vertex.</div> |
||||
<ul> |
||||
<li><div> The Quad in this example has 4 vertices. <pre>float[] colorArray = new float[4*4];</pre> |
||||
</div> |
||||
</li> |
||||
<li><div> Tip: If your mesh has a different number of vertices, you would write: <pre>float[] colorArray = new float[yourVertexCount * 4]</pre> |
||||
</div> |
||||
</li> |
||||
</ul> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
Loop over the colorArray buffer to quickly set some RGBA value for each vertex. As usual, RGBA color values range from 0.0f to 1.0f. <strong>Note that the color values in this example are arbitrarily chosen.</strong> It's just a quick loop to give every vertex a different RGBA value (a purplish gray, purple, a greenish gray, green, see screenshot), without writing too much code. For your own mesh, you'd assign meaningful values for the color buffer depending on which color you want your mesh to have. |
||||
|
||||
</p> |
||||
<pre>for(int i = 0; i < 4; i++){ |
||||
// Red value (is increased by .2 on each next vertex here) |
||||
colorArray[colorIndex++]= 0.1f+(.2f*i); |
||||
// Green value (is reduced by .2 on each next vertex) |
||||
colorArray[colorIndex++]= 0.9f-(0.2f*i); |
||||
// Blue value (remains the same in our case) |
||||
colorArray[colorIndex++]= 0.5f; |
||||
// Alpha value (no transparency set here) |
||||
colorArray[colorIndex++]= 1.0f; |
||||
}</pre> |
||||
|
||||
<p> |
||||
|
||||
Next, set the color buffer. An RGBA color value contains four float components, thus the parameter <code>4</code>. |
||||
|
||||
</p> |
||||
<pre>mesh.setBuffer(Type.Color, 4, colorArray); |
||||
geo.setMaterial(matVC);</pre> |
||||
|
||||
<p> |
||||
|
||||
Now you see a gradient color extending from each vertex. |
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT11 SECTION "Example: Vertex Colors" [5242-7391] --> |
||||
<h3><a>Example: Shaded Mesh with Normals</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
The examples used the mesh together with the Unshaded.j3md material. If you want to use the Mesh with a Phong illuminated material (such as Lighting.j3md), the mesh needs to include information about its normals. (The Normals encode in which direction a mesh polygon is facing, which is important for calculating light and shadow.) |
||||
|
||||
</p> |
||||
<pre>float[] normals = new float[12]; |
||||
normals = new float[]{0,0,1, 0,0,1, 0,0,1, 0,0,1}; |
||||
mesh.setBuffer(Type.Normal, 3, BufferUtils.createFloatBuffer(normals));</pre> |
||||
|
||||
<p> |
||||
|
||||
You need as many normals as the polygon has vertices. For a flat quad, they point all in the same direction. In this case, the direction is the Z unit vector (Vector3f.UNIT_Z), this means the quad is facing the camera. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT12 SECTION "Example: Shaded Mesh with Normals" [7392-8163] --> |
||||
<h3><a>Example: Point Mode</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
Alternatively, you can show the vertices as colored points instead of coloring the faces. |
||||
|
||||
</p> |
||||
<pre>Geometry coloredMesh = new Geometry ("ColoredMesh", cMesh); |
||||
... |
||||
mesh.setMode(Mesh.Mode.Points); |
||||
mesh.setPointSize(10f); |
||||
mesh.updateBound(); |
||||
mesh.setStatic(); |
||||
Geometry points = new Geometry("Points", mesh); |
||||
points.setMaterial(mat); |
||||
rootNode.attachChild(points); |
||||
rootNode.attachChild(geo);</pre> |
||||
|
||||
<p> |
||||
|
||||
This will result in a 10 px dot being rendered for each of the four vertices. The dot has the vertex color you specified above. The Quad's faces are not rendered at all. This can be used for a special debugging or editing mode. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT13 SECTION "Example: Point Mode" [8164-8819] --> |
||||
<h2><a>Debugging Tip: Culling</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
By default, jME3 optimizes a mesh by culling (not drawing) its backfaces. It determines which side the front or backface of a mesh is by the order of the vertices: The frontface is the one where the vertices are specified counter-clockwise. |
||||
</p> |
||||
|
||||
<p> |
||||
This means for you that your custom mesh is invisible when seen from "behind" or from the inside. This may not be a problem, often this is even intended because it's faster. The player will not look at the inside of most things anyway. For example, if your custom mesh is a closed polyhedron, or a flat wallpaper-like object, then rendering the backfaces (the inside of the pillar, the back of the painting, etc) would indeed be a waste of resources. |
||||
</p> |
||||
|
||||
<p> |
||||
In case however that your usecase requires the backfaces to be visible, you have two options: |
||||
</p> |
||||
<ul> |
||||
<li><div> If you have a very simple scene, you can just deactivate backface culling for this one mesh's material. <br/> |
||||
<code>mat.getAdditionalRenderState().setFaceCullMode(FaceCullMode.Off);</code></div> |
||||
</li> |
||||
<li><div> The recommended solution is to specify each triangle twice, the second time with the opposite order of vertices. The second, reversed triangle is a second frontface that replaces the culled backface. <br/> |
||||
<code>int[] indexes = { 2,0,1, 1,3,2, 2,3,1, 1,0,2 }; </code></div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
|
||||
See also: <a href="/com/jme3/gde/core/docs/jme3/advanced/spatial.html">Spatial</a> ??? contains more info about how to debug custom meshes (that do not render as expected) by changing the default culling behaviour. |
||||
</p> |
||||
<div><span> |
||||
<a href="/wiki/doku.php/tag:spatial?do=showtag&tag=tag%3Aspatial">spatial</a>, |
||||
<a href="/wiki/doku.php/tag:node?do=showtag&tag=tag%3Anode">node</a>, |
||||
<a href="/wiki/doku.php/tag:mesh?do=showtag&tag=tag%3Amesh">mesh</a>, |
||||
<a href="/wiki/doku.php/tag:geometry?do=showtag&tag=tag%3Ageometry">geometry</a>, |
||||
<a href="/wiki/doku.php/tag:scenegraph?do=showtag&tag=tag%3Ascenegraph">scenegraph</a> |
||||
</span></div> |
||||
|
||||
</div> |
||||
<!-- EDIT14 SECTION "Debugging Tip: Culling" [8820-] --> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:custom_meshes?do=export_xhtmlbody">view online version</a></em></p> |
Before Width: | Height: | Size: 38 KiB |
@ -1,275 +0,0 @@ |
||||
|
||||
<h1><a>Debugging</a></h1> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
When you deal with complex game engine features like animations or physics it is handy to get feedback from the engine how it interpreted the current state. Is the physical object's collision shape really where you think it is? Is the skeleton of the animated character moving like you think it should? This document shows you how to activate visual debug aides. |
||||
</p> |
||||
|
||||
<p> |
||||
What if you just want to quickly write code that loads models and brings them in their start position? You may not want to hunt for a sample model, convert it, add lights, and load materials. Instead you use "hasslefree" simple shapes, and a "hasslefree" unshaded material or wireframe: No model, no light source, no materials are needed to see them in your test scene. |
||||
</p> |
||||
|
||||
<p> |
||||
If you ever have problems with objects appearing in the wrong spot, with the wrong scale, or wrong orientation, simply attach debug shapes to your scene to have a point of reference in 3D space ??? just like a giant ruler. If your code positions the debug shapes correctly, but models remain invisible when you apply the same code to them, you know that the problem must be either the model (where is its origin coordinate?), or the light (too dark? too bright? missing?), or the model's material (missing?) ??? and not the positioning code. |
||||
</p> |
||||
|
||||
<p> |
||||
Here are some different debug shapes: |
||||
</p> |
||||
|
||||
<p> |
||||
<img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/debug-shapes.png"> |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT1 SECTION "Debugging" [1-1389] --> |
||||
<h2><a>Debug Shapes</a></h2> |
||||
<div> |
||||
|
||||
</div> |
||||
<!-- EDIT2 SECTION "Debug Shapes" [1390-1415] --> |
||||
<h3><a>Coordinate Axes</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
The coordinate axes (com.jme3.scene.debug.Arrow) help you see the cardinal directions (X,Y,Z) from their center point. Scale the arrows to use them as a "ruler" for a certain length. |
||||
</p> |
||||
<pre>private void attachCoordinateAxes(Vector3f pos){ |
||||
Arrow arrow = new Arrow(Vector3f.UNIT_X); |
||||
arrow.setLineWidth(4); // make arrow thicker |
||||
putShape(arrow, ColorRGBA.Red).setLocalTranslation(pos); |
||||
|
||||
arrow = new Arrow(Vector3f.UNIT_Y); |
||||
arrow.setLineWidth(4); // make arrow thicker |
||||
putShape(arrow, ColorRGBA.Green).setLocalTranslation(pos); |
||||
|
||||
arrow = new Arrow(Vector3f.UNIT_Z); |
||||
arrow.setLineWidth(4); // make arrow thicker |
||||
putShape(arrow, ColorRGBA.Blue).setLocalTranslation(pos); |
||||
} |
||||
|
||||
private Geometry putShape(Mesh shape, ColorRGBA color){ |
||||
Geometry g = new Geometry("coordinate axis", shape); |
||||
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); |
||||
mat.getAdditionalRenderState().setWireframe(true); |
||||
mat.setColor("Color", color); |
||||
g.setMaterial(mat); |
||||
rootNode.attachChild(g); |
||||
return g; |
||||
}</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT3 SECTION "Coordinate Axes" [1416-2483] --> |
||||
<h3><a>Wireframe Grid</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Use a wireframe grid (com.jme3.scene.debug.Grid) as a ruler or simple floor. |
||||
</p> |
||||
<pre>private void attachGrid(Vector3f pos, float size, ColorRGBA color){ |
||||
Geometry g = new Geometry("wireframe grid", new Grid(size, size, 0.2f) ); |
||||
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); |
||||
mat.getAdditionalRenderState().setWireframe(true); |
||||
mat.setColor("Color", color); |
||||
g.setMaterial(mat); |
||||
g.center().move(pos); |
||||
rootNode.attachChild(g); |
||||
return g; |
||||
}</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT4 SECTION "Wireframe Grid" [2484-3005] --> |
||||
<h3><a>Wireframe Cube</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Use a wireframe cube (com.jme3.scene.debug.WireBox) as a stand-in object to see whether your code scales, positions, or orients, loaded models right. |
||||
</p> |
||||
<pre>public void attachWireBox(Vector3f pos, float size, ColorRGBA color){ |
||||
Geometry g = new Geometry("wireframe cube", new WireBox(size, size, size)); |
||||
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); |
||||
mat.getAdditionalRenderState().setWireframe(true); |
||||
mat.setColor("Color", color); |
||||
g.setMaterial(mat); |
||||
g.setLocalTranslation(pos); |
||||
rootNode.attachChild(g); |
||||
return g; |
||||
}</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT5 SECTION "Wireframe Cube" [3006-3611] --> |
||||
<h3><a>Wireframe Sphere</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Use a wireframe sphere (com.jme3.scene.debug.WireSphere) as a stand-in object to see whether your code scales, positions, or orients, loaded models right. |
||||
</p> |
||||
<pre>private void attachWireSphere(Vector3f pos, float size, ColorRGBA color){ |
||||
Geometry g = new Geometry("wireframe sphere", new WireSphere(size)); |
||||
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); |
||||
mat.getAdditionalRenderState().setWireframe(true); |
||||
mat.setColor("Color", color); |
||||
g.setMaterial(mat); |
||||
g.setLocalTranslation(pos); |
||||
rootNode.attachChild(g); |
||||
return g; |
||||
}</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT6 SECTION "Wireframe Sphere" [3612-4220] --> |
||||
<h2><a>Wireframe for Physics</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
You can display a wireframe of the (usually invisible) collision shape around all physical objects. Use this for debugging when analyzing unexpected behaviour. Does not work with DETACHED physics, please switch to PARALLEL or SEQUENTIAL for debugging. |
||||
</p> |
||||
<pre>physicsSpace.enableDebug(assetManager);</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT7 SECTION "Wireframe for Physics" [4221-4567] --> |
||||
<h2><a>Wireframe for Animations</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Making the skeleton visible inside animated models can be handy for debugging animations. The <code>control</code> object is an AnimControl, <code>player</code> is the loaded model. |
||||
</p> |
||||
<pre> SkeletonDebugger skeletonDebug = |
||||
new SkeletonDebugger("skeleton", control.getSkeleton()); |
||||
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); |
||||
mat.setColor("Color", ColorRGBA.Green); |
||||
mat.getAdditionalRenderState().setDepthTest(false); |
||||
skeletonDebug.setMaterial(mat); |
||||
player.attachChild(skeletonDebug);</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT8 SECTION "Wireframe for Animations" [4568-5159] --> |
||||
<h2><a>Example: Toggle Wireframe on Model</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
We assume that you have loaded a model with a material <code>mat</code>. |
||||
</p> |
||||
|
||||
<p> |
||||
Then you can add a switch to toggle the model's wireframe on and off, like this: |
||||
|
||||
</p> |
||||
<ol> |
||||
<li><div> Create a key input trigger that switches between the two materials: E.g. we toggle when the T key is pressed: <pre> inputManager.addMapping("toggle wireframe", new KeyTrigger(KeyInput.KEY_T)); |
||||
inputManager.addListener(actionListener, "toggle wireframe");</pre> |
||||
</div> |
||||
</li> |
||||
<li><div> Now add the toggle action to the action listener <pre> private ActionListener actionListener = new ActionListener() { |
||||
@Override |
||||
public void onAction(String name, boolean pressed, float tpf) { |
||||
// toggle wireframe |
||||
if (name.equals("toggle wireframe") && !pressed) { |
||||
wireframe = !wireframe; // toggle boolean |
||||
mat.getAdditionalRenderState().setWireframe(wireframe); |
||||
} |
||||
// else ... other input tests. |
||||
} |
||||
};</pre> |
||||
</div> |
||||
</li> |
||||
<li><div> Alternatively you could traverse over the whole scene and toggle for all Geometry objects in there if you don't want to create a new SceneProcessor <pre> private ActionListener actionListener = new ActionListener() { |
||||
boolean wireframe = false; |
||||
|
||||
@Override |
||||
public void onAction(String name, boolean pressed, float tpf) { |
||||
// toggle wireframe |
||||
if (name.equals("toggle wireframe") && !pressed) { |
||||
wireframe = !wireframe; // toggle boolean |
||||
rootNode.depthFirstTraversal(new SceneGraphVisitor() { |
||||
public void visit(Spatial spatial) { |
||||
if (spatial instanceof Geometry) |
||||
((Geometry)spatial).getMaterial().getAdditionalRenderState().setWireframe(wireframe); |
||||
} |
||||
}); |
||||
} |
||||
// else ... other input tests. |
||||
} |
||||
};</pre> |
||||
</div> |
||||
</li> |
||||
</ol> |
||||
|
||||
<p> |
||||
TIP :: To set the line width of wireframe display, use mesh.setLineWidth(lineWidth). Default line width is 1. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT9 SECTION "Example: Toggle Wireframe on Model" [5160-7050] --> |
||||
<h2><a>Example: Toggle Wireframe on the scene</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
To display the wireframe of the entire scene instead on one material at a time, first create the following Scene Processor |
||||
</p> |
||||
<pre>public class WireProcessor implements SceneProcessor { |
||||
|
||||
RenderManager renderManager; |
||||
Material wireMaterial; |
||||
|
||||
public WireProcessor(AssetManager assetManager) { |
||||
wireMaterial = new Material(assetManager, "/Common/MatDefs/Misc/Unshaded.j3md"); |
||||
wireMaterial.setColor("Color", ColorRGBA.Blue); |
||||
wireMaterial.getAdditionalRenderState().setWireframe(true); |
||||
} |
||||
|
||||
public void initialize(RenderManager rm, ViewPort vp) { |
||||
renderManager = rm; |
||||
} |
||||
|
||||
public void reshape(ViewPort vp, int w, int h) { |
||||
throw new UnsupportedOperationException("Not supported yet."); |
||||
} |
||||
|
||||
public boolean isInitialized() { |
||||
return renderManager != null; |
||||
} |
||||
|
||||
public void preFrame(float tpf) { |
||||
} |
||||
|
||||
public void postQueue(RenderQueue rq) { |
||||
renderManager.setForcedMaterial(wireMaterial); |
||||
} |
||||
|
||||
public void postFrame(FrameBuffer out) { |
||||
renderManager.setForcedMaterial(null); |
||||
} |
||||
|
||||
public void cleanup() { |
||||
renderManager.setForcedMaterial(null); |
||||
} |
||||
|
||||
}</pre> |
||||
|
||||
<p> |
||||
Then attach the scene processor to the <acronym title="Graphical User Interface">GUI</acronym> Viewport. |
||||
</p> |
||||
<pre>getViewPort().addProcessor(new WireProcessor());</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT10 SECTION "Example: Toggle Wireframe on the scene" [7051-8424] --> |
||||
<h2><a>See also</a></h2> |
||||
<div> |
||||
<ul> |
||||
<li><div> <a href="/com/jme3/gde/core/docs/jme3/advanced/spatial.html">Spatial</a> ??? if you can't see certain spatials, you can modify the culling behaviour to identify problems (such as inside-out custom meshes)</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT11 SECTION "See also" [8425-] --> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:debugging?do=export_xhtmlbody">view online version</a></em></p> |
Before Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 104 KiB |
@ -1,321 +0,0 @@ |
||||
|
||||
<h1><a>jME3 Special Effects Overview</a></h1> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
jME3 supports several types of special effects: Post-Processor Filters, SceneProcessors, and Particle Emitters (also known as particle systems). This list contains screenshots and links to sample code that demonstrates how to add the effect to a scene. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT1 SECTION "jME3 Special Effects Overview" [1-299] --> |
||||
<h2><a>Sample Code</a></h2> |
||||
<div> |
||||
<ul> |
||||
<li><div> There is one <code>com.jme3.effect.ParticleEmitter</code> class for all Particle Systems. </div> |
||||
</li> |
||||
<li><div> There is one <code>com.jme3.post.FilterPostProcessor</code> class and several <code>com.jme3.post.filters.*</code> classes (all Filters have <code>*Filter</code> in their names). </div> |
||||
</li> |
||||
<li><div> There are several <code>SceneProcessor</code> classes in various packages, including e.g. <code>com.jme3.shadow.*</code> and <code>com.jme3.water.*</code> (SceneProcessor have <code>*Processor</code> or <code>*Renderer</code> in their names).</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT2 SECTION "Sample Code" [300-768] --> |
||||
<h3><a>Particle Emitter</a></h3> |
||||
<div> |
||||
<pre>public class MyGame extends SimpleApplication { |
||||
public void simpleInitApp() { |
||||
ParticleEmitter pm = new ParticleEmitter("my particle effect", Type.Triangle, 60); |
||||
Material pmMat = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md"); |
||||
pmMat.setTexture("Texture", assetManager.loadTexture("Effects/spark.png")); |
||||
pm.setMaterial(pmMat); |
||||
pm.setImagesX(1); |
||||
pm.setImagesY(1); |
||||
rootNode.attachChild(pm); // attach one or more emitters to any node |
||||
} |
||||
}</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT3 SECTION "Particle Emitter" [769-1298] --> |
||||
<h3><a>Scene Processor</a></h3> |
||||
<div> |
||||
<pre>public class MyGame extends SimpleApplication { |
||||
private BasicShadowRenderer bsr; |
||||
|
||||
public void simpleInitApp() { |
||||
bsr = new BasicShadowRenderer(assetManager, 1024); |
||||
bsr.setDirection(new Vector3f(.3f, -0.5f, -0.5f)); |
||||
viewPort.addProcessor(bsr); // add one or more sceneprocessor to viewport |
||||
}</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT4 SECTION "Scene Processor" [1299-1674] --> |
||||
<h3><a>Post-Processor Filter</a></h3> |
||||
<div> |
||||
<pre>public class MyGame extends SimpleApplication { |
||||
private FilterPostProcessor fpp; // one FilterPostProcessor per app |
||||
private SomeFilter sf; // one or more Filters per app |
||||
|
||||
public void simpleInitApp() { |
||||
fpp = new FilterPostProcessor(assetManager); |
||||
viewPort.addProcessor(fpp); // add one FilterPostProcessor to viewPort |
||||
|
||||
sf = new SomeFilter(); |
||||
fpp.addFilter(sf); // add one or more Filters to FilterPostProcessor |
||||
}</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT5 SECTION "Post-Processor Filter" [1675-2201] --> |
||||
<h2><a>Water</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
<img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/water-post.png"><img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/water.png"> |
||||
The jMonkeyEngine's <a href="/com/jme3/gde/core/docs/jme3/advanced/water.html">"SeaMonkey" WaterFilter</a> simulates ocean waves, foam, including cool underwater caustics. |
||||
Use the SimpleWaterProcessor (SceneProcessor) for small, limited bodies of water, such as puddles, drinking troughs, pools, fountains. |
||||
</p> |
||||
|
||||
<p> |
||||
See also the <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://jmonkeyengine.org/2011/01/15/new-advanced-water-effect-for-jmonkeyengine-3"><param name="text" value="<html><u>Rendering Water as Post-Process Effect</u></html>"><param name="textColor" value="blue"></object> announcement with video. |
||||
</p> |
||||
<ul> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/water/TestSceneWater.java"><param name="text" value="<html><u>jme3/src/test/jme3test/water/TestSceneWater.java</u></html>"><param name="textColor" value="blue"></object> ??? SimpleWaterProcessor (SceneProcessor)</div> |
||||
</li> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/water/TestSimpleWater.java"><param name="text" value="<html><u>jme3/src/test/jme3test/water/TestSimpleWater.java</u></html>"><param name="textColor" value="blue"></object> ??? SimpleWaterProcessor (SceneProcessor)</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
<img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/water-reflection-muddy.png"><img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/underwater2.jpg"> |
||||
</p> |
||||
<ul> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/water/TestPostWater.java"><param name="text" value="<html><u>jme3/src/test/jme3test/water/TestPostWater.java</u></html>"><param name="textColor" value="blue"></object> ??? WaterFilter</div> |
||||
</li> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/water/TestPostWaterLake.java"><param name="text" value="<html><u>jme3/src/test/jme3test/water/TestPostWaterLake.java</u></html>"><param name="textColor" value="blue"></object> ??? WaterFilter</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT6 SECTION "Water" [2202-3620] --> |
||||
<h2><a>Environment Effects</a></h2> |
||||
<div> |
||||
|
||||
</div> |
||||
<!-- EDIT7 SECTION "Environment Effects" [3621-3653] --> |
||||
<h3><a>Depth of Field Blur</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
<img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/dof-blur.png"><img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/light-scattering-filter.png"> |
||||
</p> |
||||
<ul> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/post/TestDepthOfField.java"><param name="text" value="<html><u>jme3/src/test/jme3test/post/TestDepthOfField.java</u></html>"><param name="textColor" value="blue"></object> ??? DepthOfFieldFilter</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT8 SECTION "Depth of Field Blur" [3654-3972] --> |
||||
<h3><a>Fog</a></h3> |
||||
<div> |
||||
<ul> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/post/TestFog.java"><param name="text" value="<html><u>jme3/src/test/jme3test/post/TestFog.java</u></html>"><param name="textColor" value="blue"></object> ??? FogFilter</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT9 SECTION "Fog" [3973-4152] --> |
||||
<h3><a>Light Scattering</a></h3> |
||||
<div> |
||||
<ul> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/post/TestLightScattering.java"><param name="text" value="<html><u>jme3/src/test/jme3test/post/TestLightScattering.java</u></html>"><param name="textColor" value="blue"></object> ??? LightScatteringFilter</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT10 SECTION "Light Scattering" [4153-4381] --> |
||||
<h3><a>Vegetation</a></h3> |
||||
<div> |
||||
<ul> |
||||
<li><div> Contribution: <a href="/com/jme3/gde/core/docs/jme3/contributions/vegetationsystem/grass.html">Grass System</a></div> |
||||
</li> |
||||
<li><div> Contribution: <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://jmonkeyengine.org/groups/user-code-projects/forum/topic/generating-vegetation-paged-geometry-style/"><param name="text" value="<html><u>Trees (WIP)</u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT11 SECTION "Vegetation" [4382-4619] --> |
||||
<h2><a>Light and Shadows</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
<img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/tanlglow1.png"><img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/shadow-sponza-ssao.png"> |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT12 SECTION "Light and Shadows" [4620-4743] --> |
||||
<h3><a>Bloom and Glow</a></h3> |
||||
<div> |
||||
<ul> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/post/TestBloom.java"><param name="text" value="<html><u>jme3/src/test/jme3test/post/TestBloom.java</u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
<li><div> More details: <a href="/com/jme3/gde/core/docs/jme3/advanced/bloom_and_glow.html">Bloom and Glow</a> ??? BloomFilter</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT13 SECTION "Bloom and Glow" [4744-4990] --> |
||||
<h3><a>Light</a></h3> |
||||
<div> |
||||
<ul> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/light/TestSimpleLighting.java"><param name="text" value="<html><u>jme3/src/test/jme3test/light/TestSimpleLighting.java</u></html>"><param name="textColor" value="blue"></object> ??? DirectionalLight, PointLight</div> |
||||
</li> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/light/TestLightRadius.java"><param name="text" value="<html><u>jme3/src/test/jme3test/light/TestLightRadius.java</u></html>"><param name="textColor" value="blue"></object> ??? DirectionalLight, PointLight</div> |
||||
</li> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/light/TestManyLights.java"><param name="text" value="<html><u>jme3/src/test/jme3test/light/TestManyLights.java</u></html>"><param name="textColor" value="blue"></object> ??? .j3o scene</div> |
||||
</li> |
||||
<li><div> More details: <a href="/com/jme3/gde/core/docs/jme3/advanced/light_and_shadow.html">Light and Shadow</a></div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
|
||||
<img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/shadow.png"><img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/light-sources.png"> |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT14 SECTION "Light" [4991-5735] --> |
||||
<h3><a>Shadow</a></h3> |
||||
<div> |
||||
<ul> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/light/TestShadow.java"><param name="text" value="<html><u>jme3/src/test/jme3test/light/TestShadow.java</u></html>"><param name="textColor" value="blue"></object> ??? BasicShadowRenderer (SceneProcessor)</div> |
||||
</li> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/light/TestPssmShadow.java"><param name="text" value="<html><u>jme3/src/test/jme3test/light/TestPssmShadow.java</u></html>"><param name="textColor" value="blue"></object> ??? PssmShadowRenderer (SceneProcessor), also known as Parallel-Split Shadow Mapping (PSSM).</div> |
||||
</li> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/post/TestSSAO.java"><param name="text" value="<html><u>jme3/src/test/jme3test/post/TestSSAO.java</u></html>"><param name="textColor" value="blue"></object>, <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/post/TestSSAO2.java"><param name="text" value="<html><u>jme3/src/test/jme3test/post/TestSSAO2.java</u></html>"><param name="textColor" value="blue"></object> ??? SSAOFilter, also known as Screen-Space Ambient Occlusion shadows (SSOA).</div> |
||||
</li> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/post/TestTransparentSSAO.java"><param name="text" value="<html><u>jme3/src/test/jme3test/post/TestTransparentSSAO.java</u></html>"><param name="textColor" value="blue"></object> ??? SSAOFilter, also known as Screen-Space Ambient Occlusion shadows (SSOA), plus transparancy</div> |
||||
</li> |
||||
<li><div> More details: <a href="/com/jme3/gde/core/docs/jme3/advanced/light_and_shadow.html">Light and Shadow</a></div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT15 SECTION "Shadow" [5736-6917] --> |
||||
<h2><a>Special: Glass, Metal, Dissolve, Toon</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
<img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/toon-dino.png"> |
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT16 SECTION "Special: Glass, Metal, Dissolve, Toon" [6918-7010] --> |
||||
<h3><a>Toon Effect</a></h3> |
||||
<div> |
||||
<ul> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/post/TestCartoonEdge.java"><param name="text" value="<html><u>jme3/src/test/jme3test/post/TestCartoonEdge.java</u></html>"><param name="textColor" value="blue"></object> ??? CartoonEdgeFilter</div> |
||||
</li> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/post/TestTransparentCartoonEdge.java"><param name="text" value="<html><u>jme3/src/test/jme3test/post/TestTransparentCartoonEdge.java</u></html>"><param name="textColor" value="blue"></object> ??? CartoonEdgeFilter</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT17 SECTION "Toon Effect" [7011-7431] --> |
||||
<h3><a>Fade in / Fade out</a></h3> |
||||
<div> |
||||
<ul> |
||||
<li><div> <a href="/com/jme3/gde/core/docs/jme3/advanced/fade.html">Fade</a> ??? FadeFilter</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT18 SECTION "Fade in / Fade out" [7432-7503] --> |
||||
<h3><a>User Contributed</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
<img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/shaderblow_light1.jpg"><img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/shaderblow_glass.jpg"><img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/shaderblow_matcap.jpg"><img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/shaderblow_light2.jpg"> |
||||
</p> |
||||
|
||||
<p> |
||||
<a href="/com/jme3/gde/core/docs/sdk/plugin/shaderblow.html">ShaderBlow - GLSL Shader Library</a> |
||||
</p> |
||||
<ul> |
||||
<li><div> LightBlow Shader ??? blend material texture maps</div> |
||||
</li> |
||||
<li><div> FakeParticleBlow Shader ??? jet, fire effect</div> |
||||
</li> |
||||
<li><div> ToonBlow Shader ??? Toon Shading, toon edges </div> |
||||
</li> |
||||
<li><div> Dissolve Shader ??? Scifi teleportation/dissolve effect</div> |
||||
</li> |
||||
<li><div> MatCap Shader ??? Gold, metals, glass, toons???!</div> |
||||
</li> |
||||
<li><div> Glass Shader ??? Glass</div> |
||||
</li> |
||||
<li><div> Force Shield Shader ??? Scifi impact-on-force-field effect</div> |
||||
</li> |
||||
<li><div> SimpleSprite Shader ??? Animated textures</div> |
||||
</li> |
||||
<li><div> SimpleSpriteParticle Shader ??? Sprite library</div> |
||||
</li> |
||||
<li><div> MovingTexture Shader ??? Animated cloud/mist texture</div> |
||||
</li> |
||||
<li><div> SoftParticles Shader ??? Fire, clouds, smoke etc</div> |
||||
</li> |
||||
<li><div> Displace Shader ??? Deformation effect: Ripple, wave, pulse, swell!</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
|
||||
Thanks for your awesome contributions! Keep them coming! |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT19 SECTION "User Contributed" [7504-8465] --> |
||||
<h2><a>Particle Emitters: Explosions, Fire, Smoke</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
<img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/explosion-5.png"><img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/particle.png"> |
||||
<a href="/com/jme3/gde/core/docs/jme3/advanced/particle_emitters.html">Particle emitter effects</a> are highly configurable and can have any texture. They can simulate smoke, dust, leaves, meteors, snowflakes, mosquitos, fire, explosions, clusters, embers, sparks??? |
||||
</p> |
||||
<ul> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/effect/TestExplosionEffect.java"><param name="text" value="<html><u>jme3/src/test/jme3test/effect/TestExplosionEffect.java</u></html>"><param name="textColor" value="blue"></object> ??? debris, flame, flash, shockwave, smoke, sparks</div> |
||||
</li> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/effect/TestPointSprite.java"><param name="text" value="<html><u>jme3/src/test/jme3test/effect/TestPointSprite.java</u></html>"><param name="textColor" value="blue"></object> ??? cluster of points </div> |
||||
</li> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/effect/TestMovingParticle.java"><param name="text" value="<html><u>jme3/src/test/jme3test/effect/TestMovingParticle.java</u></html>"><param name="textColor" value="blue"></object> ??? dust, smoke</div> |
||||
</li> |
||||
</ul> |
||||
<hr/> |
||||
|
||||
<p> |
||||
See also: |
||||
</p> |
||||
<ul> |
||||
<li><div> <a href="/com/jme3/gde/core/docs/jme3/advanced/particle_emitters.html">Particle Emitters</a></div> |
||||
</li> |
||||
<li><div> <a href="/com/jme3/gde/core/docs/jme3/advanced/bloom_and_glow.html">Bloom and Glow</a></div> |
||||
</li> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://www.smashingmagazine.com/2008/08/07/50-photoshop-tutorials-for-sky-and-space-effects/"><param name="text" value="<html><u>Photoshop Tutorial for Sky and space effects (article)</u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
</ul> |
||||
<div><span> |
||||
<a href="/wiki/doku.php/tag:documentation?do=showtag&tag=tag%3Adocumentation">documentation</a>, |
||||
<a href="/wiki/doku.php/tag:effect?do=showtag&tag=tag%3Aeffect">effect</a>, |
||||
<a href="/wiki/doku.php/tag:light?do=showtag&tag=tag%3Alight">light</a>, |
||||
<a href="/wiki/doku.php/tag:water?do=showtag&tag=tag%3Awater">water</a> |
||||
</span></div> |
||||
|
||||
</div> |
||||
<!-- EDIT20 SECTION "Particle Emitters: Explosions, Fire, Smoke" [8466-] --> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:effects_overview?do=export_xhtmlbody">view online version</a></em></p> |
Before Width: | Height: | Size: 53 KiB |
@ -1,115 +0,0 @@ |
||||
|
||||
<h1><a>Endless Terrain</a></h1> |
||||
<div> |
||||
|
||||
<p> |
||||
TerrainGrid is an extension built on top of the TerraMonkey tools like TerrainQuad and HeightMap, that provides "infinite" Terrain paging routines. <br/> |
||||
|
||||
Thanks to G??bor (@anthyon) and Brent (@sploreg) for this contribution! |
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT1 SECTION "Endless Terrain" [1-254] --> |
||||
<h2><a>Sample Code</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
The classes with source code can be found in the org.jme3.terrain.geomipmapping and org.jme3.terrain.heightmap packages. Also there are 3 tests prepared in the jme3test.terrain package: |
||||
</p> |
||||
<ul> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/terrain/TerrainGridTest.java"><param name="text" value="<html><u>TerrainGridTest.java</u></html>"><param name="textColor" value="blue"></object>: uses an ImageBasedHeightMapGrid instance to load the tiles</div> |
||||
</li> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/terrain/TerrainFractalGridTest.java"><param name="text" value="<html><u>TerrainFractalGridTest.java</u></html>"><param name="textColor" value="blue"></object>: makes use of the FractalHeightMapGrid class, and generates a terrain from noise</div> |
||||
</li> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/terrain/TerrainGridAlphaMapTest.java"><param name="text" value="<html><u>TerrainGridAlphaMapTest.java</u></html>"><param name="textColor" value="blue"></object>: shows how to use TerrainGridListener to change the material of the tiles</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT2 SECTION "Sample Code" [255-1134] --> |
||||
<h2><a>Specification</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
TerrainGrid is made up of the TerrainGrid class, and the HeightMapGrid and TerrainGridListener interfaces. |
||||
</p> |
||||
<ul> |
||||
<li><div> TerrainGrid is the central class of the system. It takes care for handling camera movement in LODUpdate, loading and unloading terrain tiles on demand, and notifying any registered listeners of changes.</div> |
||||
</li> |
||||
<li><div> TerrainGridListener defines two events to listen to:</div> |
||||
<ul> |
||||
<li><div> gridMoved(Vector3f): gets the new center as parameter after terrain update, so any objects can be added or removed as needed.</div> |
||||
</li> |
||||
<li><div> Material tileLoaded(Material material, Vector3f cell): notifies the system about a tile being loaded. Parameters are a cloned value of the material added to the TerrainGrid, and the cell of the new tile. The system can change the material according to this information (eg. load required alphamaps, etc).</div> |
||||
</li> |
||||
</ul> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
<br/> |
||||
|
||||
Multiple listeners can be added to the TerrainGrid, they will be called in the order of addition, so it???s possible to have multiple changes to the material before completing the load of the tile. |
||||
<br/> |
||||
|
||||
HeightMapGrid adds the possibility of loading terrain tiles on demand instead of having a simple height array. There???s no predefined way of how to store these tiles, it only takes care of loading one HeightMap object at given location at a time. |
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT3 SECTION "Specification" [1135-2425] --> |
||||
<h2><a>Motivation</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
After playing around with the terrain in jME3, soon comes the requirement of having larger explorable lands. Increasing the size of one TerrainQuad leads to more memory usage, while it will still be easy to reach the worlds boundaries. That???s why TerrainGrid was designed. It extends the TerraindQuad class and uses 4 HeightMaps (dark blue) as the four sub-quad. This means that a terrain of size 513 will use tiles of 257. Also an LRUCache is built into the terrain package, so surrounding tiles (green) can be pre-cached on a different thread, lowering the loading time. The quads are updated as the camera approaches the boundary of the light blue section. |
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT4 SECTION "Motivation" [2426-3108] --> |
||||
<h2><a>Rationale</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
The design of the TerrainGrid system was chosen carefully, so that minimal effort needs to be taken to switch from previous TerrainQuad uses. It has the same constructors with the small exception that instead of an array of heightmap it takes a HeightMapGrid instance. All other parameters are forwarded down to the underlying TerrainQuad system. |
||||
There exist also two basic HeightMapGrid implementations: |
||||
</p> |
||||
<ul> |
||||
<li><div> ImageBasedHeightMapGrid: uses a sequentially numbered, 16 bit grayscale heightmaps. The physical filename of these files can be generated through the Namer interface. When a tile cannot be found by the assetManager, an empty (all-zero) heightmap is created, and a warning is added to the log.</div> |
||||
</li> |
||||
<li><div> FractalHeightMapGrid: uses a noise library to create a landscape on the fly. The shape of the terrain can be controlled by the various parameters and postfilters of the fractals. With the help of this grid implementation there???s no limitation ??? above of floating point precision limits ??? how far the camera can get. The tiles generated this way can be cached to the filesystem, for later modification. The FractalHeightMapGrid will always load from cache if a tile exists there!</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT5 SECTION "Rationale" [3109-4319] --> |
||||
<h2><a>Usage</a></h2> |
||||
<div> |
||||
<ol> |
||||
<li><div> instantiate a TerrainGrid object</div> |
||||
</li> |
||||
<li><div> set material, listeners, translation, scale, etc.</div> |
||||
</li> |
||||
<li><div> add a LODControl instance to the object</div> |
||||
</li> |
||||
<li><div> call initialize with the camera location</div> |
||||
</li> |
||||
<li><div> (optional) add it to the physicsSpace as you would a TerrainQuad</div> |
||||
</li> |
||||
</ol> |
||||
|
||||
<p> |
||||
Further information about terrain and TerrainQuad can be found in the wiki at: |
||||
</p> |
||||
<ul> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://jmonkeyengine.org/wiki/doku.php/jme3:beginner:hello_terrain"><param name="text" value="<html><u>http://jmonkeyengine.org/wiki/doku.php/jme3:beginner:hello_terrain</u></html>"><param name="textColor" value="blue"></object> and</div> |
||||
</li> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:terrain"><param name="text" value="<html><u>http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:terrain</u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT6 SECTION "Usage" [4320-] --> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:endless_terraingrid?do=export_xhtmlbody">view online version</a></em></p> |
Before Width: | Height: | Size: 22 KiB |
@ -1,50 +0,0 @@ |
||||
|
||||
<h1><a>Fade-in / Fade-out Effect</a></h1> |
||||
<div> |
||||
|
||||
<p> |
||||
You can use a fade in/fade out effect to make smooth transitions, for example between game levels. The effect fades in from black to the initialized scene, or fades out from the scene to black. |
||||
The effect uses com.jme3.post.FilterPostProcessor and com.jme3.post.filters.FadeFilter. |
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT1 SECTION "Fade-in / Fade-out Effect" [1-320] --> |
||||
<h2><a>Setting up</a></h2> |
||||
<div> |
||||
<ol> |
||||
<li><div> Create one FilterPostProcessor object per application.</div> |
||||
</li> |
||||
<li><div> Create a FadeFilter object.</div> |
||||
</li> |
||||
<li><div> Give the FadeFilter constructor the fade duration in seconds as parameter. If you use the parameter-less constructor, the duration is 1 sec by default.</div> |
||||
</li> |
||||
<li><div> Add the FadeFilter to the FilterPostProcessor.</div> |
||||
</li> |
||||
<li><div> Add the FilterPostProcessor to the default viewPort.</div> |
||||
</li> |
||||
</ol> |
||||
<pre>private FilterPostProcessor fpp; |
||||
private FadeFilter fade; |
||||
public void simpleInitApp() { |
||||
... |
||||
fpp = new FilterPostProcessor(assetManager); |
||||
fade = new FadeFilter(2); // e.g. 2 seconds |
||||
fpp.addFilter(fade); |
||||
viewPort.addProcessor(fpp); |
||||
... |
||||
}</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT2 SECTION "Setting up" [321-965] --> |
||||
<h2><a>Fading in and out</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
Now call the <code>fade.fadeIn()</code> and <code>fade.fadeOut()</code> methods to trigger the effect. |
||||
You can also change the fade duration using <code>fade.setDuration()</code>. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT3 SECTION "Fading in and out" [966-] --> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:fade?do=export_xhtmlbody">view online version</a></em></p> |
Before Width: | Height: | Size: 14 KiB |
@ -1,95 +0,0 @@ |
||||
|
||||
<h1><a>jME3 Headless Server</a></h1> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
When adding multiplayer to your game, you may find that your server needs to know about game state (e.g. where are players, objects? Was that a direct hit? etc.) You can code all this up yourself, but there's an easier way. |
||||
</p> |
||||
|
||||
<p> |
||||
It's very easy to change your current (client) game to function as a server as well. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT1 SECTION "jME3 Headless Server" [1-348] --> |
||||
<h2><a>What Does Headless Mean?</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
A headless server??? |
||||
</p> |
||||
<ul> |
||||
<li><div> does not display any output ??? no window opens, no audio plays, no graphics are rendered.</div> |
||||
</li> |
||||
<li><div> ignores all input ??? no input handling.</div> |
||||
</li> |
||||
<li><div> keeps game state ??? you can attach to, transform, and save the rootNode, although the scene is not displayed.</div> |
||||
</li> |
||||
<li><div> calls the <code>simpleUpdate()</code> loop ??? you can run tests and trigger events as usual.</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT2 SECTION "What Does Headless Mean?" [349-748] --> |
||||
<h2><a>Client Code</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
First, let's take a look at the default way of creating a new game (in its simplest form): |
||||
</p> |
||||
<pre>public static void main(String[] args) { |
||||
Application app = new Main(); |
||||
app.start(); |
||||
}</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT3 SECTION "Client Code" [749-975] --> |
||||
<h2><a>Headless Server Code</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Now, with a simple change you can start your game in Headless mode. This means that all input and audio/visual output will be ignored. That's a good thing for a server. |
||||
</p> |
||||
<pre>import com.jme3.system.JmeContext; |
||||
import com.jme3.system.JmeContext.Type; |
||||
|
||||
public static void main(String[] args) { |
||||
Application app = new Main(); |
||||
app.start(JmeContext.Type.Headless); |
||||
}</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT4 SECTION "Headless Server Code" [976-1390] --> |
||||
<h2><a>Next steps</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Okay, so you can now start your game in a headless 'server mode', where to go from here? |
||||
|
||||
</p> |
||||
<ul> |
||||
<li><div> Parse <code>String[] args</code> from the <code>main</code>-method to enable server mode on demand (e.g. start your server like <code>java -jar mygame.jar ???server</code>.</div> |
||||
</li> |
||||
<li><div> Integrate <a href="/com/jme3/gde/core/docs/jme3/advanced/networking.html">SpiderMonkey</a>, to provide game updates to the server over a network.</div> |
||||
</li> |
||||
<li><div> Only execute code that's needed. (E.g. place all rendering code inside an <code>if (servermode)</code>-block) (or <code>if (!servermode)</code> for the client).</div> |
||||
</li> |
||||
<li><div> Add decent <a href="/com/jme3/gde/core/docs/jme3/advanced/logging.html">logging</a> so your server actually makes sense.</div> |
||||
</li> |
||||
</ul> |
||||
<div><span> |
||||
<a href="/wiki/doku.php/tag:server?do=showtag&tag=tag%3Aserver">server</a>, |
||||
<a href="/wiki/doku.php/tag:spidermonkey?do=showtag&tag=tag%3Aspidermonkey">spidermonkey</a>, |
||||
<a href="/wiki/doku.php/tag:headless?do=showtag&tag=tag%3Aheadless">headless</a>, |
||||
<a href="/wiki/doku.php/tag:network?do=showtag&tag=tag%3Anetwork">network</a>, |
||||
<a href="/wiki/doku.php/tag:documentation?do=showtag&tag=tag%3Adocumentation">documentation</a> |
||||
</span></div> |
||||
|
||||
</div> |
||||
<!-- EDIT5 SECTION "Next steps" [1391-] --> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:headless_server?do=export_xhtmlbody">view online version</a></em></p> |
@ -1,235 +0,0 @@ |
||||
|
||||
<h1><a>Physical Hinges and Joints</a></h1> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
The jMonkeyEngine3 has built-in support for <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://jbullet.advel.cz"><param name="text" value="<html><u>jBullet physics</u></html>"><param name="textColor" value="blue"></object> via the <code>com.jme3.bullet</code> package. |
||||
</p> |
||||
|
||||
<p> |
||||
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. |
||||
</p> |
||||
|
||||
<p> |
||||
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). |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT1 SECTION "Physical Hinges and Joints" [1-692] --> |
||||
<h2><a>Sample Code</a></h2> |
||||
<div> |
||||
<ul> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/bullet/TestPhysicsHingeJoint.java"><param name="text" value="<html><u>TestPhysicsHingeJoint.java</u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT2 SECTION "Sample Code" [693-871] --> |
||||
<h2><a>Overview of this Physics Application</a></h2> |
||||
<div> |
||||
<ol> |
||||
<li><div> Create a SimpleApplication with a <a href="/com/jme3/gde/core/docs/jme3/advanced/physics.html">BulletAppState</a> </div> |
||||
<ul> |
||||
<li><div> This gives us a PhysicsSpace for PhysicsControls</div> |
||||
</li> |
||||
</ul> |
||||
</li> |
||||
<li><div> For the pendulum, we use a Spatial with a PhysicsControl, and we apply physical forces to them.</div> |
||||
<ul> |
||||
<li><div> The parts of the "pendulum" are Physics Control'ed Spatials with Collision Shapes. </div> |
||||
</li> |
||||
<li><div> We create a fixed <code>hookNode</code> and a dynamic <code>pendulumNode</code>. </div> |
||||
</li> |
||||
</ul> |
||||
</li> |
||||
<li><div> We can "crank the handle" and rotate the joint like a hinge, or we can let loose and expose the joints freely to gravity. </div> |
||||
<ul> |
||||
<li><div> For physical forces we will use the method <code>joint.enableMotor();</code></div> |
||||
</li> |
||||
</ul> |
||||
</li> |
||||
</ol> |
||||
|
||||
</div> |
||||
<!-- EDIT3 SECTION "Overview of this Physics Application" [872-1519] --> |
||||
<h2><a>Creating a Fixed Node</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
The hookNode is the fixed point from which the pendulum hangs. It has no mass. |
||||
</p> |
||||
<pre>Node hookNode=PhysicsTestHelper.createPhysicsTestNode( |
||||
assetManager, new BoxCollisionShape(new Vector3f( .1f, .1f, .1f)),0); |
||||
hookNode.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(0f,0,0f)); |
||||
|
||||
rootNode.attachChild(hookNode); |
||||
getPhysicsSpace().add(hookNode);</pre> |
||||
|
||||
<p> |
||||
For a rope bridge, there would be two fixed nodes where the bridge is attached to the mountainside. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT4 SECTION "Creating a Fixed Node" [1520-2039] --> |
||||
<h2><a>Creating a Dynamic Node</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
The pendulumNode is the dynamic part of the construction. It has a mass. |
||||
</p> |
||||
<pre>Node pendulumNode=PhysicsTestHelper.createPhysicsTestNode( |
||||
assetManager, new BoxCollisionShape(new Vector3f( .3f, .3f, .3f)),1); |
||||
pendulumNode.getControl(RigidBodyControl.class).setPhysicsLocation(new Vector3f(0f,-1,0f)); |
||||
rootNode.attachChild(pendulumNode); |
||||
getPhysicsSpace().add(pendulumNode);</pre> |
||||
|
||||
<p> |
||||
For a rope bridge, each set of planks would be one dynamic node. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT5 SECTION "Creating a Dynamic Node" [2040-2537] --> |
||||
<h2><a>Understanding DOF, Joints, and Hinges</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
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 <em>mechanical degree of freedom</em> (DOF) of another object. |
||||
</p> |
||||
|
||||
<p> |
||||
Consider a free falling, "unchained" object in physical 3D space: It has 6 DOFs: |
||||
</p> |
||||
<ul> |
||||
<li><div> It translates along 3 axes</div> |
||||
</li> |
||||
<li><div> It rotates around 3 axes</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
|
||||
Now consider some examples of objects with joints: |
||||
</p> |
||||
<ul> |
||||
<li><div> An individual chain link is free to spin and move around, but joined into a chain, the link's movement is restricted to stay with the surrounding links.</div> |
||||
</li> |
||||
<li><div> A person's arm can rotate around some axes, but not around others. The shoulder joint allows one and restricts the other.</div> |
||||
</li> |
||||
<li><div> A door hinge is one of the most restricted types of joint: It can only rotate around one axis. </div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
|
||||
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 <a href="/com/jme3/gde/core/docs/jme3/advanced/ragdoll.html">ragDoll</a> character's limbs, jME even offers a special joint, <code>ConeJoint</code>. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT6 SECTION "Understanding DOF, Joints, and Hinges" [2538-3728] --> |
||||
<h2><a>Creating the Joint</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
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. |
||||
</p> |
||||
<pre>private HingeJoint joint; |
||||
... |
||||
public void simpleInitApp() { |
||||
... |
||||
// hookNode and pendulumNode are created here... |
||||
... |
||||
|
||||
joint=new HingeJoint(hookNode.getControl(RigidBodyControl.class), // A |
||||
pendulumNode.getControl(RigidBodyControl.class), // B |
||||
new Vector3f(0f, 0f, 0f), // pivot point local to A |
||||
new Vector3f(0f, 1f, 0f), // pivot point local to B |
||||
Vector3f.UNIT_Z, // DoF Axis of A (Z axis) |
||||
Vector3f.UNIT_Z ); // DoF Axis of B (Z axis)</pre> |
||||
|
||||
<p> |
||||
|
||||
The pivot point's position will be at <code>(0,0,0)</code> in the global 3D space. In A's local space that is at <code>(0,0,0)</code> and in B's local space (remember B's position was set to <code>(0,-1,0)</code>) that is at <code>(0,1,0)</code>. |
||||
</p> |
||||
|
||||
<p> |
||||
Specify the following parameters for each joint: |
||||
</p> |
||||
<ul> |
||||
<li><div> PhysicsControl A and B ??? the two nodes that are to be joined</div> |
||||
</li> |
||||
<li><div> Vector3f pivot A and pivot B ??? coordinates of the attachment point relative to A and B</div> |
||||
<ul> |
||||
<li><div> The points typically lie on the surface of the PhysicsControl's Spatials, rarely in the middle.</div> |
||||
</li> |
||||
</ul> |
||||
</li> |
||||
<li><div> Vector3f axisA and axisB ??? around which axes each node is allowed to spin.</div> |
||||
<ul> |
||||
<li><div> In our example, we constrain the pendulum to swing only along the Z axis.</div> |
||||
</li> |
||||
</ul> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
|
||||
Remember to add all joint objects to the physicsSpace, just like you would do with any physical objects. |
||||
</p> |
||||
<pre>bulletAppState.getPhysicsSpace().add(joint);</pre> |
||||
|
||||
<p> |
||||
<strong>Tip:</strong> If you want the joint to be visible, attach a geometry to the dynamic node, and translate it to its start position. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT7 SECTION "Creating the Joint" [3729-5628] --> |
||||
<h2><a>Apply Physical Forces</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
You can apply forces to dynamic nodes (the ones that have a mass), and see how other joined ("chained") objects are dragged along. |
||||
</p> |
||||
|
||||
<p> |
||||
Alternatively, you can also apply forces to the joint itself. In a game, you may want to spin an automatic revolving door, or slam a door closed in a spooky way, or dramatically open the lid of a treasure chest. |
||||
</p> |
||||
|
||||
<p> |
||||
The method to call on the joint is <code>enableMotor()</code>. |
||||
</p> |
||||
<pre>joint.enableMotor(true, 1, .1f); |
||||
joint.enableMotor(true, -1, .1f);</pre> |
||||
<ol> |
||||
<li><div> Switch the motor on by supplying <code>true</code></div> |
||||
</li> |
||||
<li><div> Specify the velocity with which the joint should rotate around the specified axis. </div> |
||||
<ul> |
||||
<li><div> Use positive and negative numbers to change direction.</div> |
||||
</li> |
||||
</ul> |
||||
</li> |
||||
<li><div> Specify the impulse for this motor. Heavier masses need a bigger impulse to be moved.</div> |
||||
</li> |
||||
</ol> |
||||
|
||||
<p> |
||||
|
||||
When you disable the motor, the chained nodes are exposed to gravity again: |
||||
|
||||
</p> |
||||
<pre>joint.enableMotor(false, 0, 0);</pre> |
||||
<div><span> |
||||
<a href="/wiki/doku.php/tag:documentation?do=showtag&tag=tag%3Adocumentation">documentation</a>, |
||||
<a href="/wiki/doku.php/tag:physics?do=showtag&tag=tag%3Aphysics">physics</a>, |
||||
<a href="/wiki/doku.php/tag:joint?do=showtag&tag=tag%3Ajoint">joint</a> |
||||
</span></div> |
||||
|
||||
</div> |
||||
<!-- EDIT8 SECTION "Apply Physical Forces" [5629-] --> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:hinges_and_joints?do=export_xhtmlbody">view online version</a></em></p> |
Before Width: | Height: | Size: 96 KiB |
@ -1,220 +0,0 @@ |
||||
|
||||
<h1><a>Head-Up Display (HUD)</a></h1> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
<img src="/wiki/lib/exe/fetch.php"> |
||||
</p> |
||||
|
||||
<p> |
||||
A HUD (Head-Up Display) is part of a game's visual user interface. It's an overlay that displays additional information as (typically) 2-dimensional text or icons on the screen, on top of the 3D scene. Not all games have, or need a HUD. To avoid breaking the immersion and cluttering the screen, only use a HUD if it is the only way to convey certain information. |
||||
</p> |
||||
|
||||
<p> |
||||
HUDs are used to supply players with essential information about the game state. |
||||
</p> |
||||
<ul> |
||||
<li><div> Status: Score, minimap, points, stealth mode, ???</div> |
||||
</li> |
||||
<li><div> Resources: Ammunition, lives/health, time, ???</div> |
||||
</li> |
||||
<li><div> Vehicle instruments: Cockpit, speedometer, ???</div> |
||||
</li> |
||||
<li><div> Navigational aides: Crosshairs, mouse pointer or hand, ???</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
|
||||
You have two options how to create HUDs. |
||||
|
||||
</p> |
||||
<div><table> |
||||
<tr> |
||||
<th>Option</th><th>Pros</th><th>Cons</th> |
||||
</tr> |
||||
<tr> |
||||
<th>Attach elements to default guiNode:</th><td>Easy to learn. jMonkeyEngine built-in <acronym title="Application Programming Interface">API</acronym> for attaching plain images and bitmap text.</td><td>Only basic features. <br/> |
||||
You will have to write custom controls / buttons / effects if you need them.</td> |
||||
</tr> |
||||
<tr> |
||||
<th>Use advanced <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui.html">Nifty GUI</a> integration:</th><td>Full-featured interactive user interface. <br/> |
||||
Includes buttons, effects, controls. <br/> |
||||
Supports <acronym title="Extensible Markup Language">XML</acronym> and Java layouts.</td><td>Steeper learning curve.</td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT2 TABLE [834-1259] --> |
||||
<p> |
||||
|
||||
Using the <acronym title="Graphical User Interface">GUI</acronym> Node is the default approach in jme3 to create simple HUDs. If you just quickly want to display a line of text, or a simple icon on the screen, use the no-frills <acronym title="Graphical User Interface">GUI</acronym> Node, it's easier. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT1 SECTION "Head-Up Display (HUD)" [1-1460] --> |
||||
<h2><a>Simple HUD: GUI Node</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
You already know the <code>rootNode</code> that holds the 3-dimensional scene graph. jME3 also offers a 2-dimension (orthogonal) node, the <code>guiNode</code>. |
||||
</p> |
||||
|
||||
<p> |
||||
This is how you use the guiNode for HUDs: |
||||
</p> |
||||
<ul> |
||||
<li><div> Create a <acronym title="Graphical User Interface">GUI</acronym> element: a BitmapText or Picture object.</div> |
||||
</li> |
||||
<li><div> Attach the element to the guiNode. </div> |
||||
</li> |
||||
<li><div> Place the element in the orthogonal render queue using <code>setQueueBucket(Bucket.Gui)</code>. </div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
The BitmapTexts and Pictures appear as 2 dimensional element on the screen. |
||||
</p> |
||||
|
||||
<p> |
||||
<p><div>By default, the guiNode has some scene graph statistics attached. To clear the guiNode before you attach your own <acronym title="Graphical User Interface">GUI</acronym> elements, use the following methods: |
||||
</p> |
||||
<pre>setDisplayStatView(false); setDisplayFps(false);</pre> |
||||
|
||||
<p> |
||||
|
||||
</div></p> |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT3 SECTION "Simple HUD: GUI Node" [1461-2189] --> |
||||
<h3><a>Displaying Pictures in the HUD</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
A simple image can be displayed using <code>com.jme3.ui.Picture</code>. |
||||
</p> |
||||
<pre>Picture pic = new Picture("HUD Picture"); |
||||
pic.setImage(assetManager, "Textures/ColoredTex/Monkey.png", true); |
||||
pic.setWidth(settings.getWidth()/2); |
||||
pic.setHeight(settings.getHeight()/2); |
||||
pic.setPosition(settings.getWidth()/4, settings.getHeight()/4); |
||||
guiNode.attachChild(pic);</pre> |
||||
|
||||
<p> |
||||
When you set the last boolean in setImage() to true, the alpha channel of your image is rendered transparent/translucent. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT4 SECTION "Displaying Pictures in the HUD" [2190-2714] --> |
||||
<h3><a>Displaying Text in the HUD</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
You use <code>com.jme3.font.BitmapText</code> to display text on the screen. |
||||
</p> |
||||
<pre>BitmapText hudText = new BitmapText(guiFont, false); |
||||
hudText.setSize(guiFont.getCharSet().getRenderedSize()); // font size |
||||
hudText.setColor(ColorRGBA.Blue); // font color |
||||
hudText.setText("You can write any string here"); // the text |
||||
hudText.setLocalTranslation(300, hudText.getLineHeight(), 0); // position |
||||
guiNode.attachChild(hudText);</pre> |
||||
|
||||
<p> |
||||
The BitmapFont object <code>guiFont</code> is a default font provided by SimpleApplication. Copy you own fonts as .fnt plus .png files into the <code>assets/Interface/Fonts</code> directory and load them like this: |
||||
</p> |
||||
<pre>BitmapFont myFont = assetManager.loadFont("Interface/Fonts/Console.fnt"); |
||||
hudText = new BitmapText(myFont, false);</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT5 SECTION "Displaying Text in the HUD" [2715-3562] --> |
||||
<h3><a>Positioning HUD Elements</a></h3> |
||||
<div> |
||||
<ul> |
||||
<li><div> When positioning <acronym title="Graphical User Interface">GUI</acronym> text and images in 2D, the <strong>bottom left corner</strong> of the screen is <code>(0f,0f)</code>, and the <strong>top right corner</strong> is at <code>(settings.getWidth(),settings.getHeight())</code>.</div> |
||||
</li> |
||||
<li><div> If you have several 2D elements in the <acronym title="Graphical User Interface">GUI</acronym> bucket that overlap, define their depth order by specifing a Z value. For example use <code>pic.move(x, y, -1)</code> to move the picture to the background, or <code>hudText.setLocalTranslation(x,y,1)</code> to move text to the foreground.</div> |
||||
</li> |
||||
<li><div> Size and length values in the orthogonal render queue are treated like pixels. A 20*20-wu big quad is rendered 20 pixels wide.</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT6 SECTION "Positioning HUD Elements" [3563-4187] --> |
||||
<h3><a>Displaying Geometries in the HUD</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
It is technically possible to attach Quads and 3D Geometries to the HUD. They show up as flat, static <acronym title="Graphical User Interface">GUI</acronym> elements. The size unit for the guiNode is pixels, not world units. If you attach a Geometry that uses a lit Material, you must add a light to the guiNode. |
||||
</p> |
||||
|
||||
<p> |
||||
<p><div>If you don't see an attached object in the <acronym title="Graphical User Interface">GUI</acronym>, check it's position and material (add a light to guiNode). Also verify whether it is not too tiny to be seen. For comparison: A 1 world-unit wide cube is only 1 pixel wide when attached to the guiNode! You may need to scale it bigger. |
||||
</div></p> |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT7 SECTION "Displaying Geometries in the HUD" [4188-4803] --> |
||||
<h3><a>Keeping the HUD Up-To-Date</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Use the update loop to keep the content up-to-date. |
||||
</p> |
||||
<pre>public void simpleUpdate(float tpf) { |
||||
... |
||||
hudText.setText("Score: " + score); |
||||
... |
||||
picture.setImage(assetManager, "Interface/statechange.png", true); |
||||
... |
||||
}</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT8 SECTION "Keeping the HUD Up-To-Date" [4804-5078] --> |
||||
<h2><a>Advanced HUD: Nifty GUI</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
The recommended approach to create HUDs is using <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui.html">Nifty GUI</a>. |
||||
</p> |
||||
<ol> |
||||
<li><div> Lay out the <acronym title="Graphical User Interface">GUI</acronym> in one or several Nifty <acronym title="Extensible Markup Language">XML</acronym> or Java files. </div> |
||||
</li> |
||||
<li><div> Write the controller classes in Java.</div> |
||||
</li> |
||||
<li><div> Load the <acronym title="Extensible Markup Language">XML</acronym> file with the controller object in your game's simpleInit() method.</div> |
||||
</li> |
||||
</ol> |
||||
|
||||
<p> |
||||
|
||||
The advantage of Nifty <acronym title="Graphical User Interface">GUI</acronym> is that it is well integrated into jME and the jMonkeyEngine <acronym title="Software Development Kit">SDK</acronym>, and that it offers all the features that you expect from a professional modern user interface. |
||||
</p> |
||||
|
||||
<p> |
||||
For HUDs, you basically follow the same instructions as for creating a normal <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui.html">Nifty GUI</a>, you just don't pause the game while the HUD is up. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT9 SECTION "Advanced HUD: Nifty GUI" [5079-5722] --> |
||||
<h2><a>See also</a></h2> |
||||
<div> |
||||
<ul> |
||||
<li><div> <a href="/com/jme3/gde/core/docs/jme3/external/fonts.html">Fonts</a></div> |
||||
</li> |
||||
</ul> |
||||
<div><span> |
||||
<a href="/wiki/doku.php/tag:gui?do=showtag&tag=tag%3Agui">gui</a>, |
||||
<a href="/wiki/doku.php/tag:display?do=showtag&tag=tag%3Adisplay">display</a>, |
||||
<a href="/wiki/doku.php/tag:documentation?do=showtag&tag=tag%3Adocumentation">documentation</a>, |
||||
<a href="/wiki/doku.php/tag:hud?do=showtag&tag=tag%3Ahud">hud</a> |
||||
</span></div> |
||||
|
||||
</div> |
||||
<!-- EDIT10 SECTION "See also" [5723-] --> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:hud?do=export_xhtmlbody">view online version</a></em></p> |
Before Width: | Height: | Size: 260 B |
@ -1,388 +0,0 @@ |
||||
|
||||
<h1><a>Input Handling</a></h1> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Users interact with your jME3 application with different input devices ??? the mouse, the keyboard, or a joystick. To respond to inputs we use the <code>inputManager</code> object in <code>SimpleApplication</code>. |
||||
</p> |
||||
|
||||
<p> |
||||
This is how you add interaction to your game: |
||||
|
||||
</p> |
||||
<ol> |
||||
<li><div> For each action, choose the trigger(s) (a key or mouse click etc)</div> |
||||
</li> |
||||
<li><div> For each action, add a trigger mapping to the inputManager</div> |
||||
</li> |
||||
<li><div> Create at least one listener in SimpleApplication</div> |
||||
</li> |
||||
<li><div> For each action, register its mappings to a listener</div> |
||||
</li> |
||||
<li><div> Implement each action in the listener</div> |
||||
</li> |
||||
</ol> |
||||
|
||||
</div> |
||||
<!-- EDIT1 SECTION "Input Handling" [1-561] --> |
||||
<h2><a>Code Samples</a></h2> |
||||
<div> |
||||
<ul> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/input/TestControls.java"><param name="text" value="<html><u>TestControls.java</u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/input/TestJoystick.java"><param name="text" value="<html><u>TestJoystick.java</u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT2 SECTION "Code Samples" [562-858] --> |
||||
<h2><a>1. Choose Trigger</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Choose one or several key/mouse events for the interaction. We use <code>KeyTrigger</code>, <code>MouseAxisTrigger</code>, <code>MouseButtonTrigger</code>, <code>JoyAxisTrigger</code> and <code>JoyButtonTrigger</code> constants from the <code>com.jme3.input.controls</code> package. |
||||
</p> |
||||
|
||||
<p> |
||||
<strong>Note:</strong> The MouseAxis and JoyAxis triggers go along the X axis (right/left) or Y axis (up/down). These Triggers come with extra booleans for the negative half of the axis (left, down). Remember to write code that listens to the negative (true) and positive (false) axis! |
||||
|
||||
</p> |
||||
<div><table> |
||||
<tr> |
||||
<th> Trigger </th><th> Code </th> |
||||
</tr> |
||||
<tr> |
||||
<td> Mouse button: Left Click </td><td> MouseButtonTrigger(MouseInput.BUTTON_LEFT) </td> |
||||
</tr> |
||||
<tr> |
||||
<td> Mouse button: Right Click </td><td> MouseButtonTrigger(MouseInput.BUTTON_RIGHT) </td> |
||||
</tr> |
||||
<tr> |
||||
<td> Mouse button: Middle Click </td><td> MouseButtonTrigger(MouseInput.BUTTON_MIDDLE) </td> |
||||
</tr> |
||||
<tr> |
||||
<td> Mouse movement: Right </td><td> MouseAxisTrigger(MouseInput.AXIS_X, true) </td> |
||||
</tr> |
||||
<tr> |
||||
<td> Mouse movement: Left </td><td> MouseAxisTrigger(MouseInput.AXIS_X, false)</td> |
||||
</tr> |
||||
<tr> |
||||
<td> Mouse movement: Up </td><td> MouseAxisTrigger(MouseInput.AXIS_Y, true) </td> |
||||
</tr> |
||||
<tr> |
||||
<td> Mouse movement: Down </td><td> MouseAxisTrigger(MouseInput.AXIS_Y, false) </td> |
||||
</tr> |
||||
<tr> |
||||
<td> Mouse wheel: Up </td><td> MouseAxisTrigger(MouseInput.AXIS_WHEEL,false) </td> |
||||
</tr> |
||||
<tr> |
||||
<td> Mouse wheel: Down </td><td> MouseAxisTrigger(MouseInput.AXIS_WHEEL,true) </td> |
||||
</tr> |
||||
<tr> |
||||
<td> NumPad: 1, 2, 3, ??? </td><td> KeyTrigger(KeyInput.KEY_NUMPAD1) ??? </td> |
||||
</tr> |
||||
<tr> |
||||
<td> Keyboard: 1, 2 , 3, ??? </td><td> KeyTrigger(KeyInput.KEY_1) ??? </td> |
||||
</tr> |
||||
<tr> |
||||
<td> Keyboard: A, B, C, ??? </td><td> KeyTrigger(KeyInput.KEY_A) ??? </td> |
||||
</tr> |
||||
<tr> |
||||
<td> Keyboard: Spacebar </td><td> KeyTrigger(KeyInput.KEY_SPACE) </td> |
||||
</tr> |
||||
<tr> |
||||
<td> Keyboard: Shift </td><td> KeyTrigger(KeyInput.KEY_RSHIFT), <br/> |
||||
KeyTrigger(KeyInput.KEY_LSHIFT) </td> |
||||
</tr> |
||||
<tr> |
||||
<td> Keyboard: F1, F2, ??? </td><td> KeyTrigger(KeyInput.KEY_F1) ??? </td> |
||||
</tr> |
||||
<tr> |
||||
<td> Keyboard: Return, Enter </td><td> KeyTrigger(KeyInput.KEY_RETURN), <br/> |
||||
KeyTrigger(KeyInput.KEY_NUMPADENTER) </td> |
||||
</tr> |
||||
<tr> |
||||
<td> Keyboard: PageUp, PageDown </td><td> KeyTrigger(KeyInput.KEY_PGUP), <br/> |
||||
KeyTrigger(KeyInput.KEY_PGDN) </td> |
||||
</tr> |
||||
<tr> |
||||
<td> Keyboard: Delete, Backspace </td><td> KeyTrigger(KeyInput.KEY_BACK), <br/> |
||||
KeyTrigger(KeyInput.KEY_DELETE) </td> |
||||
</tr> |
||||
<tr> |
||||
<td> Keyboard: Escape </td><td> KeyTrigger(KeyInput.KEY_ESCAPE) </td> |
||||
</tr> |
||||
<tr> |
||||
<td> Keyboard: Arrows </td><td> KeyTrigger(KeyInput.KEY_DOWN), <br/> |
||||
KeyTrigger(KeyInput.KEY_UP) <br/> |
||||
KeyTrigger(KeyInput.KEY_LEFT), KeyTrigger(KeyInput.KEY_RIGHT) </td> |
||||
</tr> |
||||
<tr> |
||||
<td> Joystick Button: </td><td> JoyButtonTrigger(0, JoyInput.AXIS_POV_X), <br/> |
||||
JoyButtonTrigger(0, JoyInput.AXIS_POV_Y) ? </td> |
||||
</tr> |
||||
<tr> |
||||
<td> Joystick Movement: Right </td><td> JoyAxisTrigger(0, JoyInput.AXIS_POV_X, true) </td> |
||||
</tr> |
||||
<tr> |
||||
<td> Joystick Movement: Left </td><td> JoyAxisTrigger(0, JoyInput.AXIS_POV_X, false) </td> |
||||
</tr> |
||||
<tr> |
||||
<td> Joystick Movement: Forward </td><td> JoyAxisTrigger(0, JoyInput.AXIS_POV_Z, true) </td> |
||||
</tr> |
||||
<tr> |
||||
<td> Joystick Movement: Backward</td><td> JoyAxisTrigger(0, JoyInput.AXIS_POV_Z, false) </td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT4 TABLE [1395-3373] --> |
||||
<p> |
||||
|
||||
In your IDE, use code completion to quickly look up Trigger literals. In the jMonkeyEngine <acronym title="Software Development Kit">SDK</acronym> for example, press ctrl-space or ctrl-/ after <code>KeyInput.|</code> to choose from the list of all keys. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT3 SECTION "1. Choose Trigger" [859-3568] --> |
||||
<h2><a>2. Remove Default Trigger Mappings</a></h2> |
||||
<div> |
||||
<pre>inputManager.deleteMapping( SimpleApplication.INPUT_MAPPING_MEMORY );</pre> |
||||
<div><table> |
||||
<tr> |
||||
<th>Default Mapping</th><th>Key</th><th>Description</th> |
||||
</tr> |
||||
<tr> |
||||
<td>INPUT_MAPPING_HIDE_STATS</td><td>F5</td><td>Hides the statistics in the bottom left.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>INPUT_MAPPING_CAMERA_POS</td><td>KEY_C</td><td>Prints debug output about the camera.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>INPUT_MAPPING_MEMORY</td><td>KEY_M</td><td>Prints debug output for memtory usage.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>INPUT_MAPPING_EXIT</td><td>KEY_ESCAPE</td><td>Closes the application by calling <code>stop();</code>. Typically you do not remove this, unless you replace it by another way of quitting gracefully.</td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT6 TABLE [3701-4118] --> |
||||
</div> |
||||
<!-- EDIT5 SECTION "2. Remove Default Trigger Mappings" [3569-4119] --> |
||||
<h2><a>3. Add Custom Trigger Mapping</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
When initializing the application, add a Mapping for each Trigger. |
||||
</p> |
||||
|
||||
<p> |
||||
Give the mapping a meaningful name. The name should reflect the action, not the button/key (because buttons/keys can change). Here some examples: |
||||
</p> |
||||
<pre>inputManager.addMapping("Pause Game", new KeyTrigger(KeyInput.KEY_P)); |
||||
inputManager.addMapping("Rotate", new KeyTrigger(KeyInput.KEY_SPACE)); |
||||
...</pre> |
||||
|
||||
<p> |
||||
There are cases where you may want to provide more then one trigger for one action. For example, some users prefer the WASD keys to navigate, while others prefer the arrow keys. Add several triggers for one mapping, by separating the Trigger objects with commas: |
||||
</p> |
||||
<pre>inputManager.addMapping("Left", new KeyTrigger(KeyInput.KEY_A), |
||||
new KeyTrigger(KeyInput.KEY_LEFT)); // A and left arrow |
||||
inputManager.addMapping("Right", new KeyTrigger(KeyInput.KEY_D), |
||||
new KeyTrigger(KeyInput.KEY_RIGHT)); // D and right arrow |
||||
...</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT7 SECTION "3. Add Custom Trigger Mapping" [4120-5184] --> |
||||
<h2><a>4. Create Listeners</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
The jME3 input manager supports two types of event listeners for inputs: AnalogListener and ActionListener. You can use one or both listeners in the same application. Add one or both of the following code snippets to your main SimpleApplication-based class to activate the listeners. |
||||
</p> |
||||
|
||||
<p> |
||||
<strong>Note:</strong> The two input listeners do not know, and do not care, which actual key was pressed. They only know which <em>named input mapping</em> was triggered. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT8 SECTION "4. Create Listeners" [5185-5658] --> |
||||
<h3><a>ActionListener</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
<code>com.jme3.input.controls.ActionListener</code> |
||||
</p> |
||||
<ul> |
||||
<li><div> Use for absolute "button pressed or released?", "on or off?" actions. </div> |
||||
<ul> |
||||
<li><div> Examples: Pause/unpause, a rifle or revolver shot, jump, click to select.</div> |
||||
</li> |
||||
</ul> |
||||
</li> |
||||
<li><div> JME gives you access to:</div> |
||||
<ul> |
||||
<li><div> The mapping name of the triggered action.</div> |
||||
</li> |
||||
<li><div> A boolean whether the trigger is still pressed or has just been released.</div> |
||||
</li> |
||||
<li><div> A float of the current time-per-frame as timing factor</div> |
||||
</li> |
||||
</ul> |
||||
</li> |
||||
<li><div> </div> |
||||
</li> |
||||
</ul> |
||||
<pre>private ActionListener actionListener = new ActionListener() { |
||||
public void onAction(String name, boolean keyPressed, float tpf) { |
||||
/** TODO: test for mapping names and implement actions */ |
||||
} |
||||
};</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT9 SECTION "ActionListener" [5659-6325] --> |
||||
<h3><a>AnalogListener</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
<code>com.jme3.input.controls.AnalogListener</code> |
||||
</p> |
||||
<ul> |
||||
<li><div> Use for continuous and gradual actions.</div> |
||||
<ul> |
||||
<li><div> Examples: Walk, run, rotate, accelerate vehicle, strafe, (semi-)automatic weapon shot</div> |
||||
</li> |
||||
</ul> |
||||
</li> |
||||
<li><div> JME gives you access to:</div> |
||||
<ul> |
||||
<li><div> The mapping name of the triggered action.</div> |
||||
</li> |
||||
<li><div> A gradual float value between how long the trigger has been pressed.</div> |
||||
</li> |
||||
<li><div> A float of the current time-per-frame as timing factor</div> |
||||
</li> |
||||
</ul> |
||||
</li> |
||||
</ul> |
||||
<pre>private AnalogListener analogListener = new AnalogListener() { |
||||
public void onAnalog(String name, float keyPressed, float tpf) { |
||||
/** TODO: test for mapping names and implement actions */ |
||||
} |
||||
};</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT10 SECTION "AnalogListener" [6326-6962] --> |
||||
<h2><a>4. Register Mappings to Listeners</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
To activate the mappings, you must register them to a Listener. Write your registration code after the code block where you have added the mappings to the inputManager. |
||||
</p> |
||||
|
||||
<p> |
||||
In the following example, you register the "Pause Game" mapping to the <code>actionListener</code> object, because pausing a game is in "either/or" decision. |
||||
</p> |
||||
<pre>inputManager.addListener(actionListener, new String[]{"Pause Game"});</pre> |
||||
|
||||
<p> |
||||
In the following example, you register navigational mappings to the <code>analogListener</code> object, because walking is a continuous action. Players typically keep the key pressed to express continuity, for example when they want to "walk on" or "accelerate". |
||||
</p> |
||||
<pre>inputManager.addListener(analogListener, new String[]{"Left", "Right"});</pre> |
||||
|
||||
<p> |
||||
As you see, you can add several listeners in one String array. You can call the addListener() method more than once, each time with a subset of your list, if that helps you keep you code tidy. Again, the Listeners do not care about actual which keys are configured, you only register named trigger mappings. |
||||
</p> |
||||
|
||||
<p> |
||||
<p><div>Did you register an action, but it does not work? Check the string's capitalization and spelling, it's case sensitive! |
||||
</div></p> |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT11 SECTION "4. Register Mappings to Listeners" [6963-8211] --> |
||||
<h2><a>5. Implement Actions in Listeners</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
You specify the action to be triggered where it says TODO in the Listener code snippets. Typically, you write a series of if/else conditions, testing for all the mapping names, and then calling the respective action. |
||||
</p> |
||||
|
||||
<p> |
||||
Make use of the distinction between <code>if</code> and <code>else if</code> in this conditional. |
||||
</p> |
||||
<ul> |
||||
<li><div> If several actions can be triggered simultaneously, test for all of these with a series of bare <code>if</code>s. For example, a character can be running forward <em>and</em> to the left.</div> |
||||
</li> |
||||
<li><div> If certain actions exclude one another, test for them with <code>else if</code>, the the rest of the exclusive tests can be skipped and you save some miliseconds. For example, you either shoot or pick something up.</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT12 SECTION "5. Implement Actions in Listeners" [8212-8947] --> |
||||
<h3><a>ActionListener</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
In the most common case, you want an action to be triggered once, in the moment when the button or key trigger is released. For example, when the player presses a key to open a door, or clicks to pick up an item. For these cases, use an ActionListener and test for <code>&& !keyPressed</code>, like shown in the following example. |
||||
</p> |
||||
<pre>private ActionListener actionListener = new ActionListener() { |
||||
public void onAction(String name, boolean keyPressed, float tpf) { |
||||
|
||||
if (name.equals("Pause Game") && !keyPressed) { // test? |
||||
isRunning = !isRunning; // action! |
||||
} |
||||
|
||||
if ... |
||||
|
||||
} |
||||
};</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT13 SECTION "ActionListener" [8948-9619] --> |
||||
<h3><a>AnalogListener</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
The following example shows how you define actions with an AnalogListener. Thiese actions are triggered continuously, as long (intensity <code>value</code>) as the named key or mouse button is down. Use this listeners for semi-automatic weapons and navigational actions. |
||||
</p> |
||||
<pre>private AnalogListener analogListener = new AnalogListener() { |
||||
public void onAnalog(String name, float value, float tpf) { |
||||
|
||||
if (name.equals("Rotate")) { // test? |
||||
player.rotate(0, value*speed, 0); // action! |
||||
} |
||||
|
||||
if ... |
||||
|
||||
} |
||||
};</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT14 SECTION "AnalogListener" [9620-10200] --> |
||||
<h2><a>Let Users Remap Keys</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
It is likely that your players have different keyboard layouts, are used to "reversed" mouse navigation, or prefer different navigational keys than the ones that you defined. You should create an options screen that lets users customize their mouse/key triggers for your mappings. Replace the trigger literals in the <code>inputManager.addMapping()</code> lines with variables, and load sets of triggers when the game starts. |
||||
</p> |
||||
|
||||
<p> |
||||
The abstraction of separating triggers and mappings has the advantage that you can remap triggers easily. Your code only needs to remove and add some trigger mappings. The core of the code (the listeners and actions) remains unchanged. |
||||
</p> |
||||
<div><span> |
||||
<a href="/wiki/doku.php/tag:keyinput?do=showtag&tag=tag%3Akeyinput">keyinput</a>, |
||||
<a href="/wiki/doku.php/tag:input?do=showtag&tag=tag%3Ainput">input</a>, |
||||
<a href="/wiki/doku.php/tag:documentation?do=showtag&tag=tag%3Adocumentation">documentation</a> |
||||
</span></div> |
||||
|
||||
</div> |
||||
<!-- EDIT15 SECTION "Let Users Remap Keys" [10201-] --> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:input_handling?do=export_xhtmlbody">view online version</a></em></p> |
@ -1,362 +0,0 @@ |
||||
|
||||
<h1><a>Saving and Loading Materials with .j3m Files</a></h1> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
In the <a href="/com/jme3/gde/core/docs/jme3/advanced/material_definitions.html">Material Definitions</a> article you learned how to configure <a href="/com/jme3/gde/core/docs/jme3/advanced/materials_overview.html">Materials</a> 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. |
||||
</p> |
||||
|
||||
<p> |
||||
If you want to colorize simple shapes (one texture all around), then .j3m are the most easily customizable solution. J3m files can contain texture mapped materials, but as usual you have to create the textures in an external editor, especially if you use UV-mapped textures. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT1 SECTION "Saving and Loading Materials with .j3m Files" [1-753] --> |
||||
<h2><a>Writing the .j3m File</a></h2> |
||||
<div> |
||||
<ol> |
||||
<li><div> For every Material, create a file and give it a name that describes it: e.g. <code>SimpleBump.j3m</code></div> |
||||
</li> |
||||
<li><div> Place the file in your project's <code>assets/Materials/</code> directory, e.g. <code>MyGame/src/assets/Materials/SimpleBump.j3m</code></div> |
||||
</li> |
||||
<li><div> Edit the file and add content using the following Syntax, e.g.:<pre>Material shiny bumpy rock : Common/MatDefs/Light/Lighting.j3md { |
||||
MaterialParameters { |
||||
Shininess: 8.0 |
||||
NormalMap: Textures/bump_rock_normal.png |
||||
UseMaterialColors : true |
||||
Ambient : 0.0 0.0 0.0 1.0 |
||||
Diffuse : 1.0 1.0 1.0 1.0 |
||||
Specular : 0.0 0.0 0.0 1.0 |
||||
} |
||||
}</pre> |
||||
</div> |
||||
</li> |
||||
</ol> |
||||
|
||||
<p> |
||||
|
||||
How to this file is structured: |
||||
</p> |
||||
<ol> |
||||
<li><div> Header</div> |
||||
<ol> |
||||
<li><div> <code>Material</code> is a fixed keyword, keep it.</div> |
||||
</li> |
||||
<li><div> <code>shiny bumpy rock</code> is a descriptive string that you can make up. Choose a name to help you remember for what you intend to use this material.</div> |
||||
</li> |
||||
<li><div> After the colon, specify on which <a href="/com/jme3/gde/core/docs/jme3/advanced/materials_overview.html">Material</a> definition you base this Material.</div> |
||||
</li> |
||||
</ol> |
||||
</li> |
||||
<li><div> Now look up the choosen Material Definition's parameters and their parameter types from the <a href="/com/jme3/gde/core/docs/jme3/advanced/materials_overview.html">Material</a> table. Add one line for each parameter.</div> |
||||
<ul> |
||||
<li><div> For example: The series of four numbers in the example above represent RGBA color values.</div> |
||||
</li> |
||||
</ul> |
||||
</li> |
||||
<li><div> Check the detailed syntax reference below if you are unsure.</div> |
||||
</li> |
||||
</ol> |
||||
|
||||
<p> |
||||
|
||||
<p><div>In the jMonkeyEngine <acronym title="Software Development Kit">SDK</acronym>, use File???New File???Material???Empty Material File to create .j3m files. You can edit .j3m files directly in the <acronym title="Software Development Kit">SDK</acronym>. On the other hand, they are plain text files, so you can also create them in any plain text editor. |
||||
</div></p> |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT2 SECTION "Writing the .j3m File" [754-2349] --> |
||||
<h2><a>How to Use .j3m Materials</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
This is how you use the prepared .j3m Material on a Spatial. Since you have saved the .j3m file to your project's Assets directory, the .j3m path is relative to <code>MyGame/src/assets/???</code>. |
||||
</p> |
||||
<pre>myGeometry.setMaterial(assetManager.loadMaterial("Materials/SimpleBump.j3m"));</pre> |
||||
|
||||
<p> |
||||
<strong>Tip:</strong> In the jMonkeyEngine <acronym title="Software Development Kit">SDK</acronym>, open Windows>Palette and drag the <code>JME Material: Set J3M</code> snippet into your code. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT3 SECTION "How to Use .j3m Materials" [2350-2795] --> |
||||
<h2><a>Syntax Reference for .j3m Files</a></h2> |
||||
<div> |
||||
|
||||
</div> |
||||
<!-- EDIT4 SECTION "Syntax Reference for .j3m Files" [2796-2840] --> |
||||
<h3><a>Paths</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Make sure to get the paths to the textures (.png, .jpg) and material definitions (.j3md) right. |
||||
|
||||
</p> |
||||
<ul> |
||||
<li><div> The paths to the built-in .j3md files are relative to jME3's Core Data directory. Just copy the path stated in the <a href="/com/jme3/gde/core/docs/jme3/advanced/materials_overview.html">Material</a> table. <br/> |
||||
<code>Common/MatDefs/Misc/Unshaded.j3md</code> is resolved to <code>jme3/src/src/core-data/Common/MatDefs/Misc/Unshaded.j3md</code>.</div> |
||||
</li> |
||||
<li><div> The paths to your textures are relative to your project's assets directory. <br/> |
||||
<code>Textures/bump_rock_normal.png</code> is resolved to <code>MyGame/src/assets/Textures/bump_rock_normal.png</code></div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT5 SECTION "Paths" [2841-3417] --> |
||||
<h3><a>Data Types</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
All data types (except Color) are specified in com.jme3.shader.VarType. |
||||
"Color" is specified as Vector4 in J3MLoader.java. |
||||
|
||||
</p> |
||||
<div><table> |
||||
<tr> |
||||
<th>Name</th><th>jME Java class</th><th>.j3m file syntax</th> |
||||
</tr> |
||||
<tr> |
||||
<td> Float</td><td> (basic Java type) </td><td> a float (e.g. 0.72) , no comma or parentheses </td> |
||||
</tr> |
||||
<tr> |
||||
<td> Vector2</td><td> <code>com.jme3.math.Vector2f</code></td><td> Two floats, no comma or parentheses </td> |
||||
</tr> |
||||
<tr> |
||||
<td> Vector3 </td><td> <code>com.jme3.math.Vector3f</code> </td><td> Three floats, no comma or parentheses </td> |
||||
</tr> |
||||
<tr> |
||||
<td> Vector4</td><td> <code>com.jme3.math.Vector4f</code> </td><td> Four floats, no comma or parentheses </td> |
||||
</tr> |
||||
<tr> |
||||
<td> Texture2D </td><td> <code>com.jme3.texture.Texture2D</code> </td><td> Path to texture in <code>assets</code> directory, no quotation marks </td> |
||||
</tr> |
||||
<tr> |
||||
<td> Texture3D</td><td> <code>com.jme3.texture.Texture3D</code> </td><td> Same as texture 2D except it is interpreted as a 3D texture </td> |
||||
</tr> |
||||
<tr> |
||||
<td> TextureCubeMap</td><td> <code>com.jme3.texture.TextureCubeMap</code> </td><td> Same as texture 2D except it is interpreted as a cubemap texture </td> |
||||
</tr> |
||||
<tr> |
||||
<td> Boolean</td><td> (basic Java type) </td><td> <code>true</code> or <code>false</code> </td> |
||||
</tr> |
||||
<tr> |
||||
<td> Int</td><td> (basic Java type) </td><td> Integer number, no comma or parentheses </td> |
||||
</tr> |
||||
<tr> |
||||
<td> Color </td><td> <code>com.jme3.math.ColorRGBA</code> </td><td> Four floats, no comma or parentheses </td> |
||||
</tr> |
||||
<tr> |
||||
<td> FloatArray</td><td> </td><td> (Currently not supported in J3M) </td> |
||||
</tr> |
||||
<tr> |
||||
<td> Vector2Array</td><td> </td><td> (Currently not supported in J3M) </td> |
||||
</tr> |
||||
<tr> |
||||
<td> Vector3Array</td><td> </td><td> (Currently not supported in J3M) </td> |
||||
</tr> |
||||
<tr> |
||||
<td> Vector4Array</td><td> </td><td> (Currently not supported in J3M) </td> |
||||
</tr> |
||||
<tr> |
||||
<td> Matrix3</td><td> </td><td> (Currently not supported in J3M) </td> |
||||
</tr> |
||||
<tr> |
||||
<td> Matrix4</td><td> </td><td> (Currently not supported in J3M) </td> |
||||
</tr> |
||||
<tr> |
||||
<td> Matrix3Array</td><td> </td><td> (Currently not supported in J3M) </td> |
||||
</tr> |
||||
<tr> |
||||
<td> Matrix4Array</td><td> </td><td> (Currently not supported in J3M) </td> |
||||
</tr> |
||||
<tr> |
||||
<td> TextureBuffer</td><td> </td><td> (Currently not supported in J3M) </td> |
||||
</tr> |
||||
<tr> |
||||
<td> TextureArray</td><td> </td><td> (Currently not supported in J3M) </td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT7 TABLE [3565-4979] --> |
||||
</div> |
||||
<!-- EDIT6 SECTION "Data Types" [3418-4981] --> |
||||
<h3><a>Flip and Repeat Syntax</a></h3> |
||||
<div> |
||||
<ul> |
||||
<li><div> A texture can be flipped using the following syntax <code>NormalMap: Flip Textures/bump_rock_normal.png</code></div> |
||||
</li> |
||||
<li><div> A texture can be set to repeat using the following syntax <code>NormalMap: Repeat Textures/bump_rock_normal.png</code></div> |
||||
</li> |
||||
<li><div> If a texture is set to both being flipped and repeated, Flip must come before Repeat</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT8 SECTION "Flip and Repeat Syntax" [4982-5325] --> |
||||
<h3><a>Syntax for Additional Render States</a></h3> |
||||
<div> |
||||
<ul> |
||||
<li><div> A Boolean can be "On" or "Off"</div> |
||||
</li> |
||||
<li><div> Float is "123.0" etc</div> |
||||
</li> |
||||
<li><div> Enum - values depend on the enum</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
|
||||
See the <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://jmonkeyengine.org/javadoc/com/jme3/material/RenderState.html"><param name="text" value="<html><u>RenderState</u></html>"><param name="textColor" value="blue"></object> javadoc for a detailed explanation of render states. |
||||
|
||||
</p> |
||||
<div><table> |
||||
<tr> |
||||
<th>Name</th><th>Type</th><th>Purpose</th> |
||||
</tr> |
||||
<tr> |
||||
<td> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://jmonkeyengine.org/javadoc/com/jme3/material/RenderState.html#setWireframe(boolean)"><param name="text" value="<html><u>Wireframe</u></html>"><param name="textColor" value="blue"></object> </td><td>(Boolean)</td><td> Enable wireframe rendering mode </td> |
||||
</tr> |
||||
<tr> |
||||
<td> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://jmonkeyengine.org/javadoc/com/jme3/material/RenderState.html#setFaceCullMode(com.jme3.material.RenderState.FaceCullMode)"><param name="text" value="<html><u>FaceCull</u></html>"><param name="textColor" value="blue"></object> </td><td>(Enum: FaceCullMode)</td><td> Set face culling mode (Off, Front, Back, FrontAndBack) </td> |
||||
</tr> |
||||
<tr> |
||||
<td> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://jmonkeyengine.org/javadoc/com/jme3/material/RenderState.html#setDepthWrite(boolean)"><param name="text" value="<html><u>DepthWrite</u></html>"><param name="textColor" value="blue"></object> </td><td>(Boolean)</td><td> Enable writing depth to the depth buffer </td> |
||||
</tr> |
||||
<tr> |
||||
<td> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://jmonkeyengine.org/javadoc/com/jme3/material/RenderState.html#setDepthTest(boolean)"><param name="text" value="<html><u>DepthTest</u></html>"><param name="textColor" value="blue"></object> </td><td>(Boolean)</td><td> Enable depth testing </td> |
||||
</tr> |
||||
<tr> |
||||
<td> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://jmonkeyengine.org/javadoc/com/jme3/material/RenderState.html#setBlendMode(com.jme3.material.RenderState.BlendMode)"><param name="text" value="<html><u>Blend</u></html>"><param name="textColor" value="blue"></object> </td><td>(Enum: BlendMode)</td><td> Set the blending mode </td> |
||||
</tr> |
||||
<tr> |
||||
<td> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://jmonkeyengine.org/javadoc/com/jme3/material/RenderState.html#setAlphaFallOff(float)"><param name="text" value="<html><u>AlphaTestFalloff</u></html>"><param name="textColor" value="blue"></object> </td><td>(Float)</td><td> Set the alpha testing alpha falloff value (if set, it will enable alpha testing) </td> |
||||
</tr> |
||||
<tr> |
||||
<td> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://jmonkeyengine.org/javadoc/com/jme3/material/RenderState.html#setPolyOffset(float, float)"><param name="text" value="<html><u>PolyOffset</u></html>"><param name="textColor" value="blue"></object> </td><td>(Float, Float)</td><td> Set the polygon offset factor and units </td> |
||||
</tr> |
||||
<tr> |
||||
<td> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://jmonkeyengine.org/javadoc/com/jme3/material/RenderState.html#setColorWrite(boolean)"><param name="text" value="<html><u>ColorWrite</u></html>"><param name="textColor" value="blue"></object> </td><td>(Boolean)</td><td> Enable color writing</td> |
||||
</tr> |
||||
<tr> |
||||
<td> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://jmonkeyengine.org/javadoc/com/jme3/material/RenderState.html#setPointSprite(boolean)"><param name="text" value="<html><u>PointSprite</u></html>"><param name="textColor" value="blue"></object> </td><td>(Boolean)</td><td> Enable point sprite rendering for point meshes </td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT10 TABLE [5617-7185] --> |
||||
</div> |
||||
<!-- EDIT9 SECTION "Syntax for Additional Render States" [5326-7187] --> |
||||
<h2><a>Examples</a></h2> |
||||
<div> |
||||
|
||||
</div> |
||||
<!-- EDIT11 SECTION "Examples" [7188-7209] --> |
||||
<h3><a>Example 1: Shiny</a></h3> |
||||
<div> |
||||
<pre>Spatial signpost = (Spatial) assetManager.loadAsset( |
||||
new OgreMeshKey("Models/Sign Post/Sign Post.mesh.xml", null)); |
||||
signpost.setMaterial( assetManager.loadMaterial( |
||||
new AssetKey("Models/Sign Post/Sign Post.j3m"))); |
||||
TangentBinormalGenerator.generate(signpost); |
||||
rootNode.attachChild(signpost);</pre> |
||||
|
||||
<p> |
||||
The file <code>assets/Models/Sign Post/Sign Post.j3m</code> contains: |
||||
</p> |
||||
<pre>Material Signpost : Common/MatDefs/Light/Lighting.j3md { |
||||
MaterialParameters { |
||||
Shininess: 4.0 |
||||
DiffuseMap: Models/Sign Post/Sign Post.jpg |
||||
NormalMap: Models/Sign Post/Sign Post_normal.jpg |
||||
SpecularMap: Models/Sign Post/Sign Post_specular.jpg |
||||
UseMaterialColors : true |
||||
Ambient : 0.5 0.5 0.5 1.0 |
||||
Diffuse : 1.0 1.0 1.0 1.0 |
||||
Specular : 1.0 1.0 1.0 1.0 |
||||
} |
||||
}</pre> |
||||
|
||||
<p> |
||||
The <acronym title="Joint Photographics Experts Group">JPG</acronym> files are in the same directory, <code>assets/Models/Sign Post/???</code>. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT12 SECTION "Example 1: Shiny" [7210-8142] --> |
||||
<h3><a>Example 2: Repeating Texture</a></h3> |
||||
<div> |
||||
<pre>Material mat = assetManager.loadMaterial( |
||||
"Textures/Terrain/Pond/Pond.j3m"); |
||||
mat.setColor("Ambient", ColorRGBA.DarkGray); |
||||
mat.setColor("Diffuse", ColorRGBA.White); |
||||
mat.setBoolean("UseMaterialColors", true);</pre> |
||||
|
||||
<p> |
||||
The file <code>assets/Textures/Terrain/Pond/Pond.j3m</code> contains: |
||||
</p> |
||||
<pre>Material Pong Rock : Common/MatDefs/Light/Lighting.j3md { |
||||
MaterialParameters { |
||||
Shininess: 8.0 |
||||
DiffuseMap: Repeat Textures/Terrain/Pond/Pond.png |
||||
NormalMap: Repeat Textures/Terrain/Pond/Pond_normal.png |
||||
} |
||||
}</pre> |
||||
|
||||
<p> |
||||
The <acronym title="Portable Network Graphics">PNG</acronym> files are in the same directory, <code>assets/Textures/Terrain/Pond/</code> |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT13 SECTION "Example 2: Repeating Texture" [8143-8810] --> |
||||
<h3><a>Example 3: Transparent</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
The file <code>assets/Models/Tree/Leaves.j3m</code> contains: |
||||
</p> |
||||
<pre>Material Leaves : Common/MatDefs/Light/Lighting.j3md { |
||||
|
||||
Transparent On |
||||
|
||||
MaterialParameters { |
||||
DiffuseMap : Models/Tree/Leaves.png |
||||
UseAlpha : true |
||||
AlphaDiscardThreshold : 0.5 |
||||
UseMaterialColors : true |
||||
Ambient : .5 .5 .5 .5 |
||||
Diffuse : 0.7 0.7 0.7 1 |
||||
Specular : 0 0 0 1 |
||||
Shininess : 16 |
||||
} |
||||
AdditionalRenderState { |
||||
Blend Alpha |
||||
AlphaTestFalloff 0.50 |
||||
FaceCull Off |
||||
} |
||||
}</pre> |
||||
|
||||
<p> |
||||
The <acronym title="Portable Network Graphics">PNG</acronym> file is in the same directory, <code>assets/Models/Tree/???</code> |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT14 SECTION "Example 3: Transparent" [8811-9444] --> |
||||
<h2><a>Related Links</a></h2> |
||||
<div> |
||||
<ul> |
||||
<li><div> <a href="/com/jme3/gde/core/docs/jme3/advanced/material_specification.html">Developer specification of the jME3 material system (.j3md,.j3m)</a></div> |
||||
</li> |
||||
</ul> |
||||
<div><span> |
||||
<a href="/wiki/doku.php/tag:material?do=showtag&tag=tag%3Amaterial">material</a>, |
||||
<a href="/wiki/doku.php/tag:texture?do=showtag&tag=tag%3Atexture">texture</a>, |
||||
<a href="/wiki/doku.php/tag:file?do=showtag&tag=tag%3Afile">file</a>, |
||||
<a href="/wiki/doku.php/tag:sdk?do=showtag&tag=tag%3Asdk">sdk</a>, |
||||
<a href="/wiki/doku.php/tag:wireframe?do=showtag&tag=tag%3Awireframe">wireframe</a>, |
||||
<a href="/wiki/doku.php/tag:documentation?do=showtag&tag=tag%3Adocumentation">documentation</a> |
||||
</span></div> |
||||
|
||||
</div> |
||||
<!-- EDIT15 SECTION "Related Links" [9445-] --> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:j3m_material_files?do=export_xhtmlbody">view online version</a></em></p> |
@ -1,467 +0,0 @@ |
||||
|
||||
<h1><a>JME3 and Shaders</a></h1> |
||||
<div> |
||||
|
||||
<p> |
||||
<br/> |
||||
|
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT1 SECTION "JME3 and Shaders" [1-36] --> |
||||
<h1><a>Shaders Basics</a></h1> |
||||
<div> |
||||
|
||||
<p> |
||||
Shaders are sets of instructions that are executed on the GPU. They are used to take advantage of hardware acceleration available on the GPU for rendering purposes.<br/> |
||||
|
||||
This paper only covers Vertex and Fragment shaders because they are the only ones supported by JME3 for the moment. But be aware that there are some other types of shaders (geometry, tessellation,???).<br/> |
||||
|
||||
There are multiple frequently used languages that you may encounter to code shaders but as JME3 is based on OpenGL, shaders in JME use GLSL and any example in this paper will be written in GLSL.<br/> |
||||
|
||||
<br/> |
||||
|
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT2 SECTION "Shaders Basics" [37-634] --> |
||||
<h3><a>How Does it work?</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
To keep it Simple: The Vertex shader is executed once for each vertex in the view, then the Fragment shader (also called the Pixel shader) is executed once for each pixel on the screen.<br/> |
||||
|
||||
The main purpose of the Vertex shader is to compute the screen coordinate of a vertex (where this vertex will be displayed on screen) while the main purpose of the Fragment shader is to compute the color of a pixel.<br/> |
||||
|
||||
This is a very simplified graphic to describe the call stack: <br/> |
||||
|
||||
<img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/jme3andshaders.png"><br/> |
||||
|
||||
The main program sends mesh data to the vertex shader (vertex position in object space, normals, tangents, etc..). The vertex shader computes the screen position of the vertex and sends it to the Fragment shader. The fragment shader computes the color, and the result is displayed on screen or in a texture. |
||||
<br/> |
||||
|
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT3 SECTION "How Does it work?" [635-1483] --> |
||||
<h3><a>Variables scope</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
There are different types of scope for variables in a shader : |
||||
</p> |
||||
<ul> |
||||
<li><div> uniform : User defined variables that are passed by the main program to the vertex and fragment shader, these variables are global for a given execution of a shader.</div> |
||||
</li> |
||||
<li><div> attribute : Per-vertex variables passed by the engine to the shader, like position, normal, etc (Mesh data in the graphic)</div> |
||||
</li> |
||||
<li><div> varying : Variables passed from the vertex shader to the fragment shader.</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
There is a large panel of variable types to be used, for more information about it I recommend reading the GLSL specification <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://www.opengl.org/registry/doc/GLSLangSpec.Full.1.20.8.pdf"><param name="text" value="<html><u>here</u></html>"><param name="textColor" value="blue"></object>.<br/> |
||||
|
||||
<br/> |
||||
|
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT4 SECTION "Variables scope" [1484-2149] --> |
||||
<h3><a>Spaces and Matrices</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
To understand the coming example you must know about the different spaces in 3D computer graphics, and the matrices used to translate coordinate from one space to another.<br/> |
||||
|
||||
<img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/jme3andshaders-1.png"><br/> |
||||
|
||||
The engine passes the object space coordinates to the vertex shader. We need to compute its position in projection space. To do that we transform the object space position by the WorldViewProjectionMatrix which is a combination of the World, View, Projection matrices (who would have guessed?).<br/> |
||||
|
||||
<br/> |
||||
|
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT5 SECTION "Spaces and Matrices" [2150-2694] --> |
||||
<h3><a>Simple example : rendering a solid color on an object</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
Here is the simplest application to shaders, rendering a solid color.<br/> |
||||
|
||||
Vertex Shader : <br/> |
||||
|
||||
|
||||
</p> |
||||
<pre>//the global uniform World view projection matrix |
||||
//(more on global uniforms below) |
||||
uniform mat4 g_WorldViewProjectionMatrix; |
||||
//The attribute inPosition is the Object space position of the vertex |
||||
attribute vec3 inPosition; |
||||
void main(){ |
||||
//Transformation of the object space coordinate to projection space |
||||
//coordinates. |
||||
//- gl_Position is the standard GLSL variable holding projection space |
||||
//position. It must be filled in the vertex shader |
||||
//- To convert position we multiply the worldViewProjectionMatrix by |
||||
//by the position vector. |
||||
//The multiplication must be done in this order. |
||||
gl_Position = g_WorldViewProjectionMatrix * vec4(inPosition, 1.0); |
||||
}</pre> |
||||
|
||||
<p> |
||||
|
||||
Fragment Shader : <br/> |
||||
|
||||
|
||||
</p> |
||||
<pre>void main(){ |
||||
//returning the color of the pixel (here solid blue) |
||||
//- gl_FragColor is the standard GLSL variable that holds the pixel |
||||
//color. It must be filled in the Fragment Shader. |
||||
gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0); |
||||
}</pre> |
||||
|
||||
<p> |
||||
|
||||
For example applying this shader to a sphere would render a solid blue sphere on screen.<br/> |
||||
|
||||
<br/> |
||||
|
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT6 SECTION "Simple example : rendering a solid color on an object" [2695-3932] --> |
||||
<h1><a>How to use shaders in JME3</a></h1> |
||||
<div> |
||||
|
||||
<p> |
||||
You probably heard that JME3 is ???shader oriented???, but what does that mean?<br/> |
||||
|
||||
Usually to use shaders you must create what is called a program. This program specify the vertex shader and the fragment shader to use.<br/> |
||||
|
||||
JME3 encloses this in the material system. Every material in JME3 uses shaders.<br/> |
||||
|
||||
For example let???s have a look at the SolidColor.j3md file : <br/> |
||||
|
||||
|
||||
</p> |
||||
<pre>MaterialDef Solid Color { |
||||
//This is the complete list of user defined uniforms to be used in the |
||||
//shaders |
||||
MaterialParameters { |
||||
Vector4 Color |
||||
} |
||||
Technique { |
||||
//This is where the vertex and fragment shader files are |
||||
//specified |
||||
VertexShader GLSL100: Common/MatDefs/Misc/SolidColor.vert |
||||
FragmentShader GLSL100: Common/MatDefs/Misc/SolidColor.frag |
||||
//This is where you specify which global uniform you need for your |
||||
//shaders |
||||
WorldParameters { |
||||
WorldViewProjectionMatrix |
||||
} |
||||
} |
||||
Technique FixedFunc { |
||||
} |
||||
}</pre> |
||||
|
||||
<p> |
||||
|
||||
For more information on JME3 material system, i suggest you read this <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://jmonkeyengine.org/groups/development-discussion-jme3/forum/topic/jmonkeyengine3-material-system-full-explanation"><param name="text" value="<html><u>topic</u></html>"><param name="textColor" value="blue"></object>.<br/> |
||||
|
||||
<br/> |
||||
|
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT7 SECTION "How to use shaders in JME3" [3933-5176] --> |
||||
<h3><a>JME3 Global uniforms</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
JME3 can expose pre-computed global uniforms to your shaders. You must specify the one that are required for your shader in the WorldParameters section of the material definition file (.j3md).<br/> |
||||
|
||||
Note that in the shader the uniform names will be prefixed by a ???g_???.<br/> |
||||
|
||||
In the example above, WorldViewProjectionMatrix is declared as uniform mat4 g_WorldViewProjectionMatrix in the shader.<br/> |
||||
|
||||
The complete list of global uniforms that can be used in JME3 can be found <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/core/com/jme3/shader/UniformBinding.java"><param name="text" value="<html><u>here</u></html>"><param name="textColor" value="blue"></object>.<br/> |
||||
|
||||
<br/> |
||||
|
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT8 SECTION "JME3 Global uniforms" [5177-5798] --> |
||||
<h3><a>JME3 Lighting Global uniforms</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
JME3 uses some global uniforms for lighting : |
||||
</p> |
||||
<ul> |
||||
<li><div> g_LightDirection (vec4) : the direction of the light</div> |
||||
<ul> |
||||
<li><div> use for SpotLight : x,y,z contain the world direction vector of the light, the w component contains the spotlight angle cosine </div> |
||||
</li> |
||||
</ul> |
||||
</li> |
||||
<li><div> g_LightColor (vec4) : the color of the light</div> |
||||
</li> |
||||
<li><div> g_LightPosition : the position of the light</div> |
||||
<ul> |
||||
<li><div> use for SpotLight : x,y,z contain the world position of the light, the w component contains 1/lightRange</div> |
||||
</li> |
||||
<li><div> use for PointLight : x,y,z contain the world position of the light, the w component contains 1/lightRadius</div> |
||||
</li> |
||||
<li><div> use for DirectionalLight : strangely enough it's used for the direction of the light???this might change though. The fourth component contains -1 and it's used in the lighting shader to know if it's a directionalLight or not.</div> |
||||
</li> |
||||
</ul> |
||||
</li> |
||||
<li><div> g_AmbientLightColor the color of the ambient light.</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
these uniforms are passed to the shader without having to declare them in the j3md file, but you have to specify in the technique definition " LightMode MultiPass" see lighting.j3md for more information. |
||||
<br/> |
||||
|
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT9 SECTION "JME3 Lighting Global uniforms" [5799-6889] --> |
||||
<h3><a>JME3 attributes</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
Those are different attributes that are always passed to your shader.<br/> |
||||
|
||||
You can find a complete list of those attribute in the Type enum of the VertexBuffer <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/core/com/jme3/scene/VertexBuffer.java"><param name="text" value="<html><u>here</u></html>"><param name="textColor" value="blue"></object>.<br/> |
||||
|
||||
Note that in the shader the attributes names will be prefixed by an ???in???.<br/> |
||||
|
||||
<br/> |
||||
|
||||
When the enumeration lists some usual types for each attribute (for example texCoord specifies two floats) then that is the format expected by all standard JME3 shaders that use that attribute. When writing your own shaders though you can use alternative formats such as placing three floats in texCoord simply by declaring the attribute as vec3 in the shader and passing 3 as the component count into the mesh setBuffer call. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT10 SECTION "JME3 attributes" [6890-7701] --> |
||||
<h3><a>User's uniforms</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
At some point when making your own shader you'll need to pass your own uniforms<br/> |
||||
|
||||
Any uniform has to be declared in the material definition file (.j3md) in the "MaterialParameters" section.<br/> |
||||
|
||||
|
||||
</p> |
||||
<pre> MaterialParameters { |
||||
Vector4 Color |
||||
Texture2D ColorMap |
||||
}</pre> |
||||
|
||||
<p> |
||||
You can also pass some define to your vertex/fragment programs to know if an uniform as been declared. <br/> |
||||
|
||||
You simply add it in the Defines section of your Technique in the definition file. <br/> |
||||
|
||||
|
||||
</p> |
||||
<pre> Defines { |
||||
COLORMAP : ColorMap |
||||
}</pre> |
||||
|
||||
<p> |
||||
For integer and floating point parameters, the define will contain the value that was set.<br/> |
||||
|
||||
For all other types of parameters, the value 1 is defined.<br/> |
||||
|
||||
If no value is set for that parameter, the define is not declared in the shader.<br/> |
||||
|
||||
</p> |
||||
|
||||
<p> |
||||
Those material parameters will be sent from the engine to the shader as follows, |
||||
there are setXXXX methods for any type of uniform you want to pass.<br/> |
||||
|
||||
|
||||
</p> |
||||
<pre> material.setColor("Color", new ColorRGBA(1.0f, 0.0f, 0.0f, 1.0f); // red color |
||||
material.setTexture("ColorMap", myTexture); // bind myTexture for that sampler uniform</pre> |
||||
|
||||
<p> |
||||
To use this uniform in the shader, you need to declare it in the .frag or .vert files (depending on where you need it). |
||||
You can make use of the defines here and later in the code: |
||||
<strong>Note that the "m_" prefix specifies that the uniform is a material parameter.</strong><br/> |
||||
|
||||
|
||||
</p> |
||||
<pre> uniform vec4 m_Color; |
||||
#ifdef COLORMAP |
||||
uniform sampler2D m_ColorMap; |
||||
#endif</pre> |
||||
|
||||
<p> |
||||
The uniforms will be populated at runtime with the value you sent. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT11 SECTION "User's uniforms" [7702-9304] --> |
||||
<h3><a>Example: Adding Color Keying to the Lighting.j3md Material Definition</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
Color Keying is useful in games involving many players. It consists of adding some <br/> |
||||
|
||||
player-specific color on models textures. <br/> |
||||
|
||||
The easiest way of doing this is to use a keyMap which will contain the amount of <br/> |
||||
|
||||
color to add in its alpha channel. <br/> |
||||
|
||||
Here I will use this color map: <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://wstaw.org/m/2011/10/24/plasma-desktopxB2787.jpg"><param name="text" value="<html><u>http://wstaw.org/m/2011/10/24/plasma-desktopxB2787.jpg</u></html>"><param name="textColor" value="blue"></object> <br/> |
||||
|
||||
to blend color on this texture: <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://wstaw.org/m/2011/10/24/plasma-desktopbq2787.jpg"><param name="text" value="<html><u>http://wstaw.org/m/2011/10/24/plasma-desktopbq2787.jpg</u></html>"><param name="textColor" value="blue"></object> <br/> |
||||
|
||||
<br/> |
||||
|
||||
We need to pass 2 new parameters to the Lighting.j3md definition, MaterialParameters section : |
||||
|
||||
</p> |
||||
<pre>// Keying Map |
||||
Texture2D KeyMap |
||||
|
||||
// Key Color |
||||
Color KeyColor</pre> |
||||
|
||||
<p> |
||||
Below, add a new Define in the main Technique section: |
||||
|
||||
</p> |
||||
<pre>KEYMAP : KeyMap</pre> |
||||
|
||||
<p> |
||||
In the Lighting.frag file, define the new uniforms: |
||||
|
||||
</p> |
||||
<pre>#ifdef KEYMAP |
||||
uniform sampler2D m_KeyMap; |
||||
uniform vec4 m_KeyColor; |
||||
#endif</pre> |
||||
|
||||
<p> |
||||
Further, when obtaining the diffuseColor from the DiffuseMap texture, check |
||||
if we need to blend it: |
||||
|
||||
</p> |
||||
<pre> #ifdef KEYMAP |
||||
vec4 keyColor = texture2D(m_KeyMap, newTexCoord); |
||||
diffuseColor.rgb = (1.0-keyColor.a) * diffuseColor.rgb + keyColor.a * m_KeyColor.rgb; |
||||
#endif</pre> |
||||
|
||||
<p> |
||||
This way, a transparent pixel in the KeyMap texture doesn't modify the color. <br/> |
||||
|
||||
A black pixel replaces it for the m_KeyColor and values in between are blended.<br/> |
||||
|
||||
<br/> |
||||
|
||||
A result preview can be seen here: <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://wstaw.org/m/2011/10/24/plasma-desktopuV2787.jpg"><param name="text" value="<html><u>http://wstaw.org/m/2011/10/24/plasma-desktopuV2787.jpg</u></html>"><param name="textColor" value="blue"></object> |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT12 SECTION "Example: Adding Color Keying to the Lighting.j3md Material Definition" [9305-10795] --> |
||||
<h3><a>Step by step</a></h3> |
||||
<div> |
||||
<ul> |
||||
<li><div> Create a vertex shader (.vert) file</div> |
||||
</li> |
||||
<li><div> Create a fragment shader (.frag) file</div> |
||||
</li> |
||||
<li><div> Create a material definition (j3md) file specifying the user defined uniforms, path to the shaders and the global uniforms to use</div> |
||||
</li> |
||||
<li><div> In your initSimpleApplication, create a material using this definition, apply it to a geometry</div> |
||||
</li> |
||||
<li><div> That???s it!!</div> |
||||
</li> |
||||
</ul> |
||||
<pre> // A cube |
||||
Box box= new Box(Vector3f.ZERO, 1f,1f,1f); |
||||
Geometry cube = new Geometry("box", box); |
||||
Material mat = new Material(assetManager,"Path/To/My/materialDef.j3md"); |
||||
cube.setMaterial(mat); |
||||
rootNode.attachChild(cube);</pre> |
||||
|
||||
<p> |
||||
|
||||
<br/> |
||||
|
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT13 SECTION "Step by step" [10796-11415] --> |
||||
<h3><a>JME3 and OpenGL 3 & 4 compatibility</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
GLSL 1.0 to 1.2 comes with built in attributes and uniforms (ie, gl_Vertex, gl_ModelViewMatrix, etc???).<br/> |
||||
Those attributes are deprecated since GLSL 1.3 (opengl 3), hence JME3 global uniforms and attributes. Here is a list of deprecated attributes and their equivalent in JME3<br/> |
||||
|
||||
</p> |
||||
<div><table> |
||||
<tr> |
||||
<th>GLSL 1.2 attributes</th><th>JME3 equivalent</th> |
||||
</tr> |
||||
<tr> |
||||
<td>gl_Vertex </td><td>inPosition</td> |
||||
</tr> |
||||
<tr> |
||||
<td>gl_Normal </td><td>inNormal</td> |
||||
</tr> |
||||
<tr> |
||||
<td>gl_Color </td><td>inColor</td> |
||||
</tr> |
||||
<tr> |
||||
<td>gl_MultiTexCoord0 </td><td>inTexCoord</td> |
||||
</tr> |
||||
<tr> |
||||
<td>gl_ModelViewMatrix </td><td>g_WorldViewMatrix</td> |
||||
</tr> |
||||
<tr> |
||||
<td>gl_ProjectionMatrix </td><td>g_ProjectionMatrix</td> |
||||
</tr> |
||||
<tr> |
||||
<td>gl_ModelViewProjectionMatrix </td><td>g_WorldViewProjectionMatrix</td> |
||||
</tr> |
||||
<tr> |
||||
<td>gl_NormalMatrix </td><td>g_NormalMatrix</td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT15 TABLE [11741-12052] --> |
||||
</div> |
||||
<!-- EDIT14 SECTION "JME3 and OpenGL 3 & 4 compatibility" [11416-12052] --> |
||||
<h3><a>Useful links</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
<object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://www.eng.utah.edu/~cs5610/lectures/GLSL-ATI-Intro.pdf"><param name="text" value="<html><u>http://www.eng.utah.edu/~cs5610/lectures/GLSL-ATI-Intro.pdf</u></html>"><param name="textColor" value="blue"></object> |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT16 SECTION "Useful links" [12053-] --> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:jme3_shaders?do=export_xhtmlbody">view online version</a></em></p> |
Before Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 31 KiB |
@ -1,380 +0,0 @@ |
||||
|
||||
<h1><a>Light and Shadow</a></h1> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
<img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/shading-ani.gif"> |
||||
</p> |
||||
|
||||
<p> |
||||
Light and Shadow are two separate things in 3D engines, although we percieve them together in real life: |
||||
</p> |
||||
<ul> |
||||
<li><div> Lighting means that an object is brighter on the side facing the light direction, and darker on the backside. Computationally, this is relatively easy. </div> |
||||
</li> |
||||
<li><div> Lighting does not mean that objects cast a shadow on the floor or other objects: Activating shadow processing is an additional step described here. Since casting shadows has an impact on performance, drop shadows and ambient occlusion shading are not activated by default.</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
|
||||
<p><div>A light source with a direction or location is required for all Geometries with Lighting.j3md-based Materials. An ambient light is not sufficient. In a scene with no appropriate light sources, Geometries with Lighting.j3md-based Materials do not render. Only Geometries with Unshaded.j3md-based Materials are visible independent of any light sources. |
||||
</div></p> |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT1 SECTION "Light and Shadow" [1-1017] --> |
||||
<h2><a>Light Sources and Colors</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
<img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/light-sources.png"> |
||||
</p> |
||||
|
||||
<p> |
||||
You can add several types of light sources to a scene using <code>rootNode.addLight(mylight)</code>. |
||||
</p> |
||||
|
||||
<p> |
||||
The available light sources in <code>com.???jme3.???light</code> are: |
||||
</p> |
||||
<ul> |
||||
<li><div> SpotLight </div> |
||||
</li> |
||||
<li><div> PointLight</div> |
||||
</li> |
||||
<li><div> AmbientLight</div> |
||||
</li> |
||||
<li><div> DirectionalLight</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
|
||||
You control the color and intensity of each light source. Typically you set the color to white (<code>new ColorRGBA(1.0f,1.0f,1.0f,1.0f)</code> or <code>ColorRGBA.White</code>), which makes all scene elements appear in their natural color. |
||||
</p> |
||||
|
||||
<p> |
||||
You can choose to use lights in other colors than white, or darker colors. This influences the scene's atmosphere and will make the scene appear colder (e.g. <code>ColorRGBA.Cyan</code>) or warmer (<code>ColorRGBA.Yellow</code>), brighter (higher values) or darker (lower values). |
||||
</p> |
||||
|
||||
<p> |
||||
You can get a list of all lights added to a Spatial by calling <code>getWorldLightList()</code> (includes inherited lights) or <code>getLocalLightList()</code> (only directly added lights), and iterating over the result. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT2 SECTION "Light Sources and Colors" [1018-2059] --> |
||||
<h3><a>PointLight</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
<img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/elephant-pointlights.png"> |
||||
</p> |
||||
|
||||
<p> |
||||
A PointLight has a location and shines from there in all directions as far as its radius reaches. The light intensity decreases with increased distance from the light source. A PointLight can at the moment not be used for casting shadows (using the PssmShadowRenderer - read more about this below). |
||||
</p> |
||||
|
||||
<p> |
||||
<strong>Typical example:</strong> Lamp, lightbulb, torch, candle. |
||||
</p> |
||||
<pre>PointLight lamp_light = new PointLight(); |
||||
lamp_light.setColor(ColorRGBA.Yellow); |
||||
lamp_light.setRadius(4f); |
||||
lamp_light.setPosition(new Vector3f(lamp_geo.getLocalTranslation())); |
||||
rootNode.addLight(lamp_light);</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT3 SECTION "PointLight" [2060-2762] --> |
||||
<h3><a>DirectionalLight</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
<img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/house-directionallight.png"> |
||||
</p> |
||||
|
||||
<p> |
||||
A DirectionalLight has no position, only a direction. It sends out parallel beams of light and is considered "infinitely" far away. You typically have one directional light per scene. A DirectionalLight can be used together with shadows. |
||||
</p> |
||||
|
||||
<p> |
||||
<strong>Typically example:</strong> Sun light. |
||||
</p> |
||||
<pre>DirectionalLight sun = new DirectionalLight(); |
||||
sun.setColor(ColorRGBA.White); |
||||
sun.setDirection(new Vector3f(-.5f,-.5f,-.5f).normalizeLocal()); |
||||
rootNode.addLight(sun);</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT4 SECTION "DirectionalLight" [2763-3367] --> |
||||
<h3><a>SpotLight</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
<img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/spotlight.png"> |
||||
</p> |
||||
|
||||
<p> |
||||
A SpotLight sends out a distinct beam or cone of light. A SpotLight has a direction, a position, distance (range) and two angles. The inner angle is the central maximum of the light cone, the outer angle the edge of the light cone. Everything outside the light cone's angles is not affected by the light. |
||||
</p> |
||||
|
||||
<p> |
||||
<strong>Typical Example:</strong> Flashlight |
||||
</p> |
||||
<pre>SpotLight spot = new SpotLight(); |
||||
spot.setSpotRange(100f); // distance |
||||
spot.setSpotInnerAngle(15f * FastMath.DEG_TO_RAD); // inner light cone (central beam) |
||||
spot.setSpotOuterAngle(35f * FastMath.DEG_TO_RAD); // outer light cone (edge of the light) |
||||
spot.setColor(ColorRGBA.White.mult(1.3f)); // light color |
||||
spot.setPosition(cam.getLocation()); // shine from camera loc |
||||
spot.setDirection(cam.getDirection()); // shine forward from camera loc |
||||
rootNode.addLight(spot);</pre> |
||||
|
||||
<p> |
||||
If you want the spotlight to follow the flycam, repeat the setDirection(???) and setPosition(???) calls in the update loop, and kee syncing them with the camera position and direction. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT5 SECTION "SpotLight" [3368-4502] --> |
||||
<h3><a>AmbientLight</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
An AmbientLight simply influences the brightness and color of the scene globally. It has no direction and no location and shines equally everywhere. An AmbientLight does not cast any shadows, and it lights all sides of Geometries evenly, which makes 3D objects look unnaturally flat; this is why you typically do not use an AmbientLight alone without one of the other lights. |
||||
</p> |
||||
|
||||
<p> |
||||
<strong>Typical example:</strong> Regulate overall brightness, tinge the whole scene in a warm or cold color. |
||||
</p> |
||||
<pre>AmbientLight al = new AmbientLight(); |
||||
al.setColor(ColorRGBA.White.mult(1.3f)); |
||||
rootNode.addLight(al);</pre> |
||||
|
||||
<p> |
||||
<p><div>You can increase the brightness of a light source gradually by multiplying the light color to values greater than 1.0f. <br/> |
||||
Example: <code>mylight.setColor(ColorRGBA.White.mult(1.3f));</code> |
||||
</div></p> |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT6 SECTION "AmbientLight" [4503-5325] --> |
||||
<h2><a>Light Follows Spatial</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
You can use a <code>com.jme3.scene.control.LightControl</code> to make a SpotLight or PointLight follow a Spatial. This can be used for a flashlight being carried by a character, or for car headlights, or an aircraft's spotlight, etc. |
||||
</p> |
||||
<pre>PointLight myLight = new PointLight(); |
||||
rootNode.addLight(myLight); |
||||
LightControl lightControl = new LightControl(myLight); |
||||
spatial.addControl(lightControl); // this spatial controls the position of this light.</pre> |
||||
|
||||
<p> |
||||
Obviously, this does apply to AmbientLights which have no position. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT7 SECTION "Light Follows Spatial" [5326-5886] --> |
||||
<h2><a>Simple Lighting</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Full sample code: |
||||
</p> |
||||
<ul> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/light/TestSimpleLighting.java"><param name="text" value="<html><u>TestSimpleLighting.java</u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/light/TestLightRadius.java"><param name="text" value="<html><u>TestLightRadius.java</u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
|
||||
For Simple Lighting we use Geometries with Materials based on Lighting.j3md (learn <a href="/com/jme3/gde/core/docs/jme3/advanced/materials_overview.html">more about Materials</a> here). Lighting.j3md-based materials dynamically support Shininess, and Ambient, Diffuse, and Specular light if there is a light source present. Note that this lighting method alone does not make the Geometry cast a shadow onto other Geometries automatically (see below for how to add drop shadows etc). |
||||
</p> |
||||
|
||||
<p> |
||||
<img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/teapot-phong-illuminated.png"> |
||||
</p> |
||||
<pre>Geometry teapot = (Geometry) assetManager.loadModel("Models/Teapot/Teapot.obj"); |
||||
TangentBinormalGenerator.generate(teapot.getMesh(), true); |
||||
Material mat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); |
||||
mat.setBoolean("m_UseMaterialColors", true); |
||||
mat.setColor("m_Ambient", ColorRGBA.Orange); |
||||
mat.setColor("m_Diffuse", ColorRGBA.Orange); |
||||
mat.setColor("m_Specular", ColorRGBA.White); |
||||
mat.setFloat("m_Shininess", 12); |
||||
rootNode.attachChild(teapot);</pre> |
||||
|
||||
<p> |
||||
The above example uses material colors and no textures. You can of course also use Lighting.j3md to create a lit Material that uses Texture Maps. The following example uses Shininess, Diffuse Map and Normal Map (a.k.a Bump Map). |
||||
</p> |
||||
|
||||
<p> |
||||
<img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/bump-mapped-sphere.png"> |
||||
</p> |
||||
<pre>Sphere rock = new Sphere(32,32, 2f); |
||||
Geometry shiny_rock = new Geometry("Shiny rock", rock); |
||||
rock.setTextureMode(Sphere.TextureMode.Projected); // better quality on spheres |
||||
TangentBinormalGenerator.generate(rock); // for lighting effect |
||||
Material mat_lit = new Material( |
||||
assetManager, "Common/MatDefs/Light/Lighting.j3md"); |
||||
mat_lit.setTexture("m_DiffuseMap", // surface color |
||||
assetManager.loadTexture("Textures/Terrain/Pond/Pond.png")); |
||||
mat_lit.setTexture("m_NormalMap", // surface bumps |
||||
assetManager.loadTexture("Textures/Terrain/Pond/Pond_normal.png")); |
||||
mat_lit.setFloat("m_Shininess", 5f); // surface smoothness [1,128] |
||||
shiny_rock.setMaterial(mat_lit); |
||||
rootNode.attachChild(shiny_rock);</pre> |
||||
|
||||
<p> |
||||
These light effects update live when the object or light source moves. If you shine a colored PointLight at this object, you will see a light reflection tinged in the color of the PointLight. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT8 SECTION "Simple Lighting" [5887-8536] --> |
||||
<h2><a>BasicShadowRenderer</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Full code sample |
||||
</p> |
||||
<ul> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/light/TestShadow.java"><param name="text" value="<html><u>TestShadow.java</u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
|
||||
Use the Shadow Renderer to make Geometries with Lighting.j3md-based Materials cast and receive basic drop shadows. This fast and simple implementation of a shadow effect is good for scenes with flat floors, but looks less realistic on uneven terrains. To use it, you add a jME SceneProcessor named com.jme3.shadow.BasicShadowRenderer to the viewPort. |
||||
</p> |
||||
|
||||
<p> |
||||
<img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/drop-shadows.png"> |
||||
</p> |
||||
<pre>BasicShadowRenderer bsr; |
||||
... |
||||
public void simpleInitApp() { |
||||
... |
||||
bsr = new BasicShadowRenderer(assetManager, 256); |
||||
bsr.setDirection(new Vector3f(-.5f,-.5f,-.5f).normalizeLocal()); // light direction |
||||
viewPort.addProcessor(bsr); |
||||
...</pre> |
||||
|
||||
<p> |
||||
Shadow calculations (cast and receive) have a performance impact, therefor we recommend to use them smartly. Switch off the default shadow mode for the whole scene graph, and then specify the shadow behaviour individually for every scene node that needs shadows: You specifiy whether it casts shadows, receives shadows, both (slower), or neither (faster). |
||||
</p> |
||||
<pre>rootNode.setShadowMode(ShadowMode.Off); // reset all |
||||
wall.setShadowMode(ShadowMode.CastAndReceive); // normal behaviour (slow) |
||||
floor.setShadowMode(ShadowMode.Receive); // can't see shadow cast below floor anyway... |
||||
airplane.setShadowMode(ShadowMode.Cast); // nothing casts shadows onto airplane anyway... |
||||
ghost.setShadowMode(ShadowMode.Off); // ghost is translucent anyway...</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT9 SECTION "BasicShadowRenderer" [8537-10206] --> |
||||
<h2><a>Parallel-Split Shadow Map</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Full sample code |
||||
</p> |
||||
<ul> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/light/TestPssmShadow.java"><param name="text" value="<html><u>TestPssmShadow.java</u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
|
||||
The more advanced PSSM shadow renderer can cast real-time shadows, even on curved surfaces such as terrains. It is a bit more resource hungry than the BasicShadowRenderer. To activate PSSM drop shadows, add a jME SceneProcessor named <code>com.jme3.shadow.PssmShadowRenderer</code> to the viewPort. PSSM stands for the Parallel-Split Shadow Map technique. |
||||
</p> |
||||
|
||||
<p> |
||||
<img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/shadow.png"> |
||||
</p> |
||||
<pre>private PssmShadowRenderer pssmRenderer; |
||||
... |
||||
public void simpleInitApp() { |
||||
.... |
||||
pssmRenderer = new PssmShadowRenderer(assetManager, 1024, 3); |
||||
pssmRenderer.setDirection(new Vector3f(-.5f,-.5f,-.5f).normalizeLocal()); // light direction |
||||
viewPort.addProcessor(pssmRenderer);</pre> |
||||
|
||||
<p> |
||||
The constructor expects the following values: |
||||
</p> |
||||
<ul> |
||||
<li><div> Your assetManager object</div> |
||||
</li> |
||||
<li><div> The size of the rendered shadowmaps (512, 1024, 2048, etc???)</div> |
||||
</li> |
||||
<li><div> The number of shadow maps rendered (the more shadow maps, the more quality, the less FPS).</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
|
||||
You can set the following properties on the <code>pssmRenderer</code> object: |
||||
</p> |
||||
<ul> |
||||
<li><div> setDirection(Vector3f) ??? the direction of the light</div> |
||||
</li> |
||||
<li><div> setLambda(0.65f) ??? Factor to use to reduce the split size</div> |
||||
</li> |
||||
<li><div> setShadowIntensity(0.7f) ??? shadow darkness (1 black, 0 invisible)</div> |
||||
</li> |
||||
<li><div> setShadowZextend() ??? distance how far away from camera shadows will still be computed</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
|
||||
As said above, it's more efficient to specify individual shadow behaviour for each Geometry. |
||||
</p> |
||||
<pre>teapot.setShadowMode(ShadowMode.CastAndReceive); |
||||
terrain.setShadowMode(ShadowMode.Receive); </pre> |
||||
|
||||
</div> |
||||
<!-- EDIT10 SECTION "Parallel-Split Shadow Map" [10207-11929] --> |
||||
<h2><a>Screen Space Ambient Occlusion</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Full sample code |
||||
</p> |
||||
<ul> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/post/TestSSAO.java"><param name="text" value="<html><u>jme3/src/test/jme3test/post/TestSSAO.java</u></html>"><param name="textColor" value="blue"></object>, <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/post/TestSSAO2.java"><param name="text" value="<html><u>jme3/src/test/jme3test/post/TestSSAO2.java</u></html>"><param name="textColor" value="blue"></object> ??? Screen-Space Ambient Occlusion shadows</div> |
||||
</li> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/post/TestTransparentSSAO.java"><param name="text" value="<html><u>jme3/src/test/jme3test/post/TestTransparentSSAO.java</u></html>"><param name="textColor" value="blue"></object> ??? Screen-Space Ambient Occlusion shadows plus transparancy</div> |
||||
</li> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://jmonkeyengine.org/2010/08/16/screen-space-ambient-occlusion-for-jmonkeyengine-3-0/#more-321"><param name="text" value="<html><u>Screen Space Ambient Occlusion for jMonkeyEngine (article)</u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
|
||||
Ambient Occlusion refers to the shadows that nearby objects cast on each other under an ambient lighting. It???s an approximation of how light radiates in a real life scene. To activate Ambient Occlusion shadows, add a jME SceneProcessor named <code>com.jme3.post.SSAOFilter</code> to the viewPort. SSAO stands for the Screen Space Ambient Occlusion technique. |
||||
</p> |
||||
<pre>FilterPostProcessor fpp = new FilterPostProcessor(assetManager); |
||||
SSAOFilter ssaoFilter = new SSAOFilter(12.94f, 43.92f, 0.33f, 0.61f); |
||||
fpp.addFilter(ssaoFilter); |
||||
viewPort.addProcessor(fpp);</pre> |
||||
|
||||
<p> |
||||
<img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/shading-textured-ani.gif"> |
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT11 SECTION "Screen Space Ambient Occlusion" [11930-] --> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:light_and_shadow?do=export_xhtmlbody">view online version</a></em></p> |
@ -1,567 +0,0 @@ |
||||
|
||||
<h3><a>Nifty Loading Screen (Progress Bar)</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
There is a good tutorial about creating a nifty progress bar here: |
||||
<object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://sourceforge.net/apps/mediawiki/nifty-gui/index.php?title=Create_your_own_Control_%28A_Nifty_Progressbar%29"><param name="text" value="<html><u>http://sourceforge.net/apps/mediawiki/nifty-gui/index.php?title=Create_your_own_Control_%28A_Nifty_Progressbar%29</u></html>"><param name="textColor" value="blue"></object> |
||||
</p> |
||||
|
||||
<p> |
||||
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) |
||||
</p> |
||||
|
||||
<p> |
||||
<img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/inner1.png"> |
||||
<img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/border1.png"> |
||||
</p> |
||||
|
||||
<p> |
||||
This is the progress bar at 90%: |
||||
</p> |
||||
|
||||
<p> |
||||
<img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/loadingscreen.png"> |
||||
</p> |
||||
|
||||
<p> |
||||
nifty_loading.xml |
||||
|
||||
</p> |
||||
<pre><span><?xml version="1.0" encoding="UTF-8"?></span> |
||||
<span><span><nifty></span></span> |
||||
<span><useStyles filename="nifty-default-styles.xml" /></span> |
||||
<span><useControls filename="nifty-default-controls.xml" /></span> |
||||
|
||||
<span><controlDefinition name = "loadingbar" controller = "jme3test.TestLoadingScreen"></span> |
||||
<span><image filename="Interface/border.png" childLayout="absolute" </span> |
||||
<span> imageMode="resize:15,2,15,15,15,2,15,2,15,2,15,15"></span> |
||||
<span><image id="progressbar" x="0" y="0" filename="Interface/inner.png" width="32px" height="100%"</span> |
||||
<span> imageMode="resize:15,2,15,15,15,2,15,2,15,2,15,15" /></span> |
||||
<span><span></image></span></span> |
||||
<span><span></controlDefinition></span></span> |
||||
|
||||
<span><screen id="start" controller = "jme3test.TestLoadingScreen"></span> |
||||
<span><layer id="layer" childLayout="center"></span> |
||||
<span><panel id = "panel2" height="30%" width="50%" align="center" valign="center" childLayout="vertical"</span> |
||||
<span> visibleToMouse="true"></span> |
||||
<span><control id="startGame" name="button" backgroundColor="#0000" label="Load Game" align="center"></span> |
||||
<span><interact onClick="showLoadingMenu()" /></span> |
||||
<span><span></control></span></span> |
||||
<span><span></panel></span></span> |
||||
<span><span></layer></span></span> |
||||
<span><span></screen></span></span> |
||||
|
||||
<span><screen id="loadlevel" controller = "jme3test.TestLoadingScreen"></span> |
||||
<span><layer id="loadinglayer" childLayout="center" backgroundColor="#000000"></span> |
||||
<span><panel id = "loadingpanel" childLayout="vertical" align="center" valign="center" height="32px" width="70%"></span> |
||||
<span><control name="loadingbar" align="center" valign="center" width="100%" height="100%" /></span> |
||||
<span><control id="loadingtext" name="label" align="center" </span> |
||||
<span> text=" "/></span> |
||||
<span><span></panel></span></span> |
||||
<span><span></layer></span></span> |
||||
<span><span></screen></span></span> |
||||
|
||||
<span><screen id="end" controller = "jme3test.TestLoadingScreen"></span> |
||||
<span><span></screen></span></span> |
||||
|
||||
<span><span></nifty></span></span></pre> |
||||
|
||||
</div> |
||||
|
||||
<h4><a>Understanding Nifty XML</a></h4> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
The progress bar and text is done statically using nifty <acronym title="Extensible Markup Language">XML</acronym>. |
||||
A custom control is created, which represents the progress bar. |
||||
|
||||
</p> |
||||
<pre> <span><controlDefinition name = "loadingbar" controller = "jme3test.TestLoadingScreen"></span> |
||||
<span><image filename="Interface/border.png" childLayout="absolute" </span> |
||||
<span> imageMode="resize:15,2,15,15,15,2,15,2,15,2,15,15"></span> |
||||
<span><image id="progressbar" x="0" y="0" filename="Interface/inner.png" width="32px" height="100%"</span> |
||||
<span> imageMode="resize:15,2,15,15,15,2,15,2,15,2,15,15"/></span> |
||||
<span><span></image></span></span> |
||||
<span><span></controlDefinition></span></span></pre> |
||||
|
||||
<p> |
||||
This screen simply displays a button in the middle of the screen, which could be seen as a simple main menu UI. |
||||
|
||||
</p> |
||||
<pre> <span><screen id="start" controller = "jme3test.TestLoadingScreen"></span> |
||||
<span><layer id="layer" childLayout="center"></span> |
||||
<span><panel id = "panel2" height="30%" width="50%" align="center" valign="center" childLayout="vertical"</span> |
||||
<span> visibleToMouse="true"></span> |
||||
<span><control id="startGame" name="button" backgroundColor="#0000" label="Load Game" align="center"></span> |
||||
<span><interact onClick="showLoadingMenu()" /></span> |
||||
<span><span></control></span></span> |
||||
<span><span></panel></span></span> |
||||
<span><span></layer></span></span> |
||||
<span><span></screen></span></span></pre> |
||||
|
||||
<p> |
||||
This screen displays our custom progress bar control with a text control |
||||
|
||||
</p> |
||||
<pre> <span><screen id="loadlevel" controller = "jme3test.TestLoadingScreen"></span> |
||||
<span><layer id="loadinglayer" childLayout="center" backgroundColor="#000000"></span> |
||||
<span><panel id = "loadingpanel" childLayout="vertical" align="center" valign="center" height="32px" width="400px"></span> |
||||
<span><control name="loadingbar" align="center" valign="center" width="400px" height="32px" /></span> |
||||
<span><control id="loadingtext" name="label" align="center"</span> |
||||
<span> text=" "/></span> |
||||
<span><span></panel></span></span> |
||||
<span><span></layer></span></span> |
||||
<span><span></screen></span></span></pre> |
||||
|
||||
</div> |
||||
<!-- EDIT1 SECTION "Nifty Loading Screen (Progress Bar)" [1-4344] --> |
||||
<h3><a>Creating the bindings to use the Nifty XML</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
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. |
||||
</p> |
||||
|
||||
<p> |
||||
Something like this in a single thread will not work: |
||||
|
||||
</p> |
||||
<pre>load_scene(); |
||||
update_bar(30%); |
||||
load_characters(); |
||||
update_bar(60%); |
||||
load_sounds(); |
||||
update_bar(100%);</pre> |
||||
|
||||
<p> |
||||
|
||||
If you do all of this in a single frame, then it is sent to the graphics card only after the whole code block has executed. By this time the bar has reached 100% and the game has already begun ??? for the user, the progressbar on the screen would not have visibly changed. |
||||
</p> |
||||
|
||||
<p> |
||||
The 2 main good solutions are: |
||||
</p> |
||||
<ol> |
||||
<li><div> Updating explicitly over many frames</div> |
||||
</li> |
||||
<li><div> Multi-threading</div> |
||||
</li> |
||||
</ol> |
||||
|
||||
</div> |
||||
|
||||
<h4><a>Updating progress bar over a number of frames</a></h4> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
The idea is to break down the loading of the game into discrete parts |
||||
|
||||
</p> |
||||
<pre>package jme3test; |
||||
|
||||
import com.jme3.niftygui.NiftyJmeDisplay; |
||||
import de.lessvoid.nifty.Nifty; |
||||
import de.lessvoid.nifty.elements.Element; |
||||
import de.lessvoid.nifty.input.NiftyInputEvent; |
||||
import de.lessvoid.nifty.screen.Screen; |
||||
import de.lessvoid.nifty.screen.ScreenController; |
||||
import de.lessvoid.nifty.tools.SizeValue; |
||||
import com.jme3.app.SimpleApplication; |
||||
import com.jme3.material.Material; |
||||
import com.jme3.renderer.Camera; |
||||
import com.jme3.terrain.geomipmap.TerrainLodControl; |
||||
import com.jme3.terrain.heightmap.AbstractHeightMap; |
||||
import com.jme3.terrain.geomipmap.TerrainQuad; |
||||
import com.jme3.terrain.heightmap.ImageBasedHeightMap; |
||||
import com.jme3.texture.Texture; |
||||
import com.jme3.texture.Texture.WrapMode; |
||||
import de.lessvoid.nifty.controls.Controller; |
||||
import de.lessvoid.nifty.elements.render.TextRenderer; |
||||
import de.lessvoid.xml.xpp3.Attributes; |
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
import java.util.Properties; |
||||
import jme3tools.converters.ImageToAwt; |
||||
|
||||
public class TestLoadingScreen extends SimpleApplication implements ScreenController, Controller { |
||||
|
||||
private NiftyJmeDisplay niftyDisplay; |
||||
private Nifty nifty; |
||||
private Element progressBarElement; |
||||
private TerrainQuad terrain; |
||||
private Material mat_terrain; |
||||
private float frameCount = 0; |
||||
private boolean load = false; |
||||
private TextRenderer textRenderer; |
||||
|
||||
public static void main(String[] args) { |
||||
TestLoadingScreen app = new TestLoadingScreen(); |
||||
app.start(); |
||||
} |
||||
|
||||
@Override |
||||
public void simpleInitApp() { |
||||
flyCam.setEnabled(false); |
||||
niftyDisplay = new NiftyJmeDisplay(assetManager, |
||||
inputManager, |
||||
audioRenderer, |
||||
guiViewPort); |
||||
nifty = niftyDisplay.getNifty(); |
||||
|
||||
nifty.fromXml("Interface/nifty_loading.xml", "start", this); |
||||
|
||||
guiViewPort.addProcessor(niftyDisplay); |
||||
} |
||||
|
||||
@Override |
||||
public void simpleUpdate(float tpf) { |
||||
|
||||
if (load) { //loading is done over many frames |
||||
if (frameCount == 1) { |
||||
Element element = nifty.getScreen("loadlevel").findElementByName("loadingtext"); |
||||
textRenderer = element.getRenderer(TextRenderer.class); |
||||
|
||||
mat_terrain = new Material(assetManager, "Common/MatDefs/Terrain/Terrain.j3md"); |
||||
mat_terrain.setTexture("Alpha", assetManager.loadTexture("Textures/Terrain/splat/alphamap.png")); |
||||
setProgress(0.2f, "Loading grass"); |
||||
|
||||
} else if (frameCount == 2) { |
||||
Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); |
||||
grass.setWrap(WrapMode.Repeat); |
||||
mat_terrain.setTexture("Tex1", grass); |
||||
mat_terrain.setFloat("Tex1Scale", 64f); |
||||
setProgress(0.4f, "Loading dirt"); |
||||
|
||||
} else if (frameCount == 3) { |
||||
Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); |
||||
|
||||
dirt.setWrap(WrapMode.Repeat); |
||||
mat_terrain.setTexture("Tex2", dirt); |
||||
mat_terrain.setFloat("Tex2Scale", 32f); |
||||
setProgress(0.5f, "Loading rocks"); |
||||
|
||||
} else if (frameCount == 4) { |
||||
Texture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg"); |
||||
|
||||
rock.setWrap(WrapMode.Repeat); |
||||
|
||||
mat_terrain.setTexture("Tex3", rock); |
||||
mat_terrain.setFloat("Tex3Scale", 128f); |
||||
setProgress(0.6f, "Creating terrain"); |
||||
|
||||
} else if (frameCount == 5) { |
||||
AbstractHeightMap heightmap = null; |
||||
Texture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/mountains512.png"); |
||||
heightmap = new ImageBasedHeightMap(heightMapImage.getImage()); |
||||
|
||||
heightmap.load(); |
||||
terrain = new TerrainQuad("my terrain", 65, 513, heightmap.getHeightMap()); |
||||
setProgress(0.8f, "Positioning terrain"); |
||||
|
||||
} else if (frameCount == 6) { |
||||
terrain.setMaterial(mat_terrain); |
||||
|
||||
terrain.setLocalTranslation(0, -100, 0); |
||||
terrain.setLocalScale(2f, 1f, 2f); |
||||
rootNode.attachChild(terrain); |
||||
setProgress(0.9f, "Loading cameras"); |
||||
|
||||
} else if (frameCount == 7) { |
||||
List<Camera> cameras = new ArrayList<Camera>(); |
||||
cameras.add(getCamera()); |
||||
TerrainLodControl control = new TerrainLodControl(terrain, cameras); |
||||
terrain.addControl(control); |
||||
setProgress(1f, "Loading complete"); |
||||
|
||||
} else if (frameCount == 8) { |
||||
nifty.gotoScreen("end"); |
||||
nifty.exit(); |
||||
guiViewPort.removeProcessor(niftyDisplay); |
||||
flyCam.setEnabled(true); |
||||
flyCam.setMoveSpeed(50); |
||||
} |
||||
|
||||
frameCount++; |
||||
} |
||||
} |
||||
|
||||
public void setProgress(final float progress, String loadingText) { |
||||
final int MIN_WIDTH = 32; |
||||
int pixelWidth = (int) (MIN_WIDTH + (progressBarElement.getParent().getWidth() - MIN_WIDTH) * progress); |
||||
progressBarElement.setConstraintWidth(new SizeValue(pixelWidth + "px")); |
||||
progressBarElement.getParent().layoutElements(); |
||||
|
||||
textRenderer.setText(loadingText); |
||||
} |
||||
|
||||
public void showLoadingMenu() { |
||||
nifty.gotoScreen("loadlevel"); |
||||
load = true; |
||||
} |
||||
|
||||
@Override |
||||
public void onStartScreen() { |
||||
} |
||||
|
||||
@Override |
||||
public void onEndScreen() { |
||||
} |
||||
|
||||
@Override |
||||
public void bind(Nifty nifty, Screen screen) { |
||||
progressBarElement = nifty.getScreen("loadlevel").findElementByName("progressbar"); |
||||
} |
||||
|
||||
// methods for Controller |
||||
@Override |
||||
public boolean inputEvent(final NiftyInputEvent inputEvent) { |
||||
return false; |
||||
} |
||||
|
||||
@Override |
||||
public void bind(Nifty nifty, Screen screen, Element elmnt, Properties prprts, Attributes atrbts) { |
||||
progressBarElement = elmnt.findElementByName("progressbar"); |
||||
} |
||||
|
||||
@Override |
||||
public void init(Properties prprts, Attributes atrbts) { |
||||
} |
||||
|
||||
public void onFocus(boolean getFocus) { |
||||
} |
||||
}</pre> |
||||
|
||||
<p> |
||||
Note: |
||||
</p> |
||||
<ul> |
||||
<li><div> Try and add all controls near the end, as their update loops may begin executing</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
|
||||
<h4><a>Using multithreading</a></h4> |
||||
<div> |
||||
|
||||
<p> |
||||
For more info on multithreading: <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:multithreading"><param name="text" value="<html><u>http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:multithreading</u></html>"><param name="textColor" value="blue"></object> |
||||
</p> |
||||
|
||||
<p> |
||||
Make sure to change the <acronym title="Extensible Markup Language">XML</acronym> file to point the controller to TestLoadingScreen<strong>1</strong> |
||||
|
||||
</p> |
||||
<pre>package jme3test; |
||||
|
||||
import com.jme3.niftygui.NiftyJmeDisplay; |
||||
import de.lessvoid.nifty.Nifty; |
||||
import de.lessvoid.nifty.elements.Element; |
||||
import de.lessvoid.nifty.input.NiftyInputEvent; |
||||
import de.lessvoid.nifty.screen.Screen; |
||||
import de.lessvoid.nifty.screen.ScreenController; |
||||
import de.lessvoid.nifty.tools.SizeValue; |
||||
import com.jme3.app.SimpleApplication; |
||||
import com.jme3.material.Material; |
||||
import com.jme3.renderer.Camera; |
||||
import com.jme3.terrain.geomipmap.TerrainLodControl; |
||||
import com.jme3.terrain.heightmap.AbstractHeightMap; |
||||
import com.jme3.terrain.geomipmap.TerrainQuad; |
||||
import com.jme3.terrain.heightmap.ImageBasedHeightMap; |
||||
import com.jme3.texture.Texture; |
||||
import com.jme3.texture.Texture.WrapMode; |
||||
import de.lessvoid.nifty.controls.Controller; |
||||
import de.lessvoid.nifty.elements.render.TextRenderer; |
||||
import de.lessvoid.xml.xpp3.Attributes; |
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
import java.util.Properties; |
||||
import java.util.concurrent.Callable; |
||||
import java.util.concurrent.Future; |
||||
import java.util.concurrent.ScheduledThreadPoolExecutor; |
||||
import jme3tools.converters.ImageToAwt; |
||||
|
||||
public class TestLoadingScreen1 extends SimpleApplication implements ScreenController, Controller { |
||||
|
||||
private NiftyJmeDisplay niftyDisplay; |
||||
private Nifty nifty; |
||||
private Element progressBarElement; |
||||
private TerrainQuad terrain; |
||||
private Material mat_terrain; |
||||
private boolean load = false; |
||||
private ScheduledThreadPoolExecutor exec = new ScheduledThreadPoolExecutor(2); |
||||
private Future loadFuture = null; |
||||
private TextRenderer textRenderer; |
||||
|
||||
public static void main(String[] args) { |
||||
TestLoadingScreen1 app = new TestLoadingScreen1(); |
||||
app.start(); |
||||
} |
||||
|
||||
@Override |
||||
public void simpleInitApp() { |
||||
flyCam.setEnabled(false); |
||||
niftyDisplay = new NiftyJmeDisplay(assetManager, |
||||
inputManager, |
||||
audioRenderer, |
||||
guiViewPort); |
||||
nifty = niftyDisplay.getNifty(); |
||||
|
||||
nifty.fromXml("Interface/nifty_loading.xml", "start", this); |
||||
|
||||
guiViewPort.addProcessor(niftyDisplay); |
||||
} |
||||
|
||||
@Override |
||||
public void simpleUpdate(float tpf) { |
||||
if (load) { |
||||
if (loadFuture == null) { |
||||
//if we have not started loading yet, submit the Callable to the executor |
||||
loadFuture = exec.submit(loadingCallable); |
||||
} |
||||
//check if the execution on the other thread is done |
||||
if (loadFuture.isDone()) { |
||||
//these calls have to be done on the update loop thread, |
||||
//especially attaching the terrain to the rootNode |
||||
//after it is attached, it's managed by the update loop thread |
||||
// and may not be modified from any other thread anymore! |
||||
nifty.gotoScreen("end"); |
||||
nifty.exit(); |
||||
guiViewPort.removeProcessor(niftyDisplay); |
||||
flyCam.setEnabled(true); |
||||
flyCam.setMoveSpeed(50); |
||||
rootNode.attachChild(terrain); |
||||
load = false; |
||||
} |
||||
} |
||||
} |
||||
//this is the callable that contains the code that is run on the other thread. |
||||
//since the assetmananger is threadsafe, it can be used to load data from any thread |
||||
//we do *not* attach the objects to the rootNode here! |
||||
Callable<Void> loadingCallable = new Callable<Void>() { |
||||
|
||||
public Void call() { |
||||
|
||||
Element element = nifty.getScreen("loadlevel").findElementByName("loadingtext"); |
||||
textRenderer = element.getRenderer(TextRenderer.class); |
||||
|
||||
mat_terrain = new Material(assetManager, "Common/MatDefs/Terrain/Terrain.j3md"); |
||||
mat_terrain.setTexture("Alpha", assetManager.loadTexture("Textures/Terrain/splat/alphamap.png")); |
||||
//setProgress is thread safe (see below) |
||||
setProgress(0.2f, "Loading grass"); |
||||
|
||||
Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); |
||||
grass.setWrap(WrapMode.Repeat); |
||||
mat_terrain.setTexture("Tex1", grass); |
||||
mat_terrain.setFloat("Tex1Scale", 64f); |
||||
setProgress(0.4f, "Loading dirt"); |
||||
|
||||
Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); |
||||
|
||||
dirt.setWrap(WrapMode.Repeat); |
||||
mat_terrain.setTexture("Tex2", dirt); |
||||
mat_terrain.setFloat("Tex2Scale", 32f); |
||||
setProgress(0.5f, "Loading rocks"); |
||||
|
||||
Texture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg"); |
||||
|
||||
rock.setWrap(WrapMode.Repeat); |
||||
|
||||
mat_terrain.setTexture("Tex3", rock); |
||||
mat_terrain.setFloat("Tex3Scale", 128f); |
||||
setProgress(0.6f, "Creating terrain"); |
||||
|
||||
AbstractHeightMap heightmap = null; |
||||
Texture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/mountains512.png"); |
||||
heightmap = new ImageBasedHeightMap(heightMapImage.getImage()); |
||||
|
||||
heightmap.load(); |
||||
terrain = new TerrainQuad("my terrain", 65, 513, heightmap.getHeightMap()); |
||||
setProgress(0.8f, "Positioning terrain"); |
||||
|
||||
terrain.setMaterial(mat_terrain); |
||||
|
||||
terrain.setLocalTranslation(0, -100, 0); |
||||
terrain.setLocalScale(2f, 1f, 2f); |
||||
setProgress(0.9f, "Loading cameras"); |
||||
|
||||
List<Camera> cameras = new ArrayList<Camera>(); |
||||
cameras.add(getCamera()); |
||||
TerrainLodControl control = new TerrainLodControl(terrain, cameras); |
||||
terrain.addControl(control); |
||||
setProgress(1f, "Loading complete"); |
||||
|
||||
return null; |
||||
} |
||||
}; |
||||
|
||||
public void setProgress(final float progress, final String loadingText) { |
||||
//since this method is called from another thread, we enqueue the changes to the progressbar to the update loop thread |
||||
enqueue(new Callable() { |
||||
|
||||
public Object call() throws Exception { |
||||
final int MIN_WIDTH = 32; |
||||
int pixelWidth = (int) (MIN_WIDTH + (progressBarElement.getParent().getWidth() - MIN_WIDTH) * progress); |
||||
progressBarElement.setConstraintWidth(new SizeValue(pixelWidth + "px")); |
||||
progressBarElement.getParent().layoutElements(); |
||||
|
||||
textRenderer.setText(loadingText); |
||||
return null; |
||||
} |
||||
}); |
||||
|
||||
} |
||||
|
||||
public void showLoadingMenu() { |
||||
nifty.gotoScreen("loadlevel"); |
||||
load = true; |
||||
} |
||||
|
||||
@Override |
||||
public void onStartScreen() { |
||||
} |
||||
|
||||
@Override |
||||
public void onEndScreen() { |
||||
} |
||||
|
||||
@Override |
||||
public void bind(Nifty nifty, Screen screen) { |
||||
progressBarElement = nifty.getScreen("loadlevel").findElementByName("progressbar"); |
||||
} |
||||
|
||||
// methods for Controller |
||||
@Override |
||||
public boolean inputEvent(final NiftyInputEvent inputEvent) { |
||||
return false; |
||||
} |
||||
|
||||
@Override |
||||
public void bind(Nifty nifty, Screen screen, Element elmnt, Properties prprts, Attributes atrbts) { |
||||
progressBarElement = elmnt.findElementByName("progressbar"); |
||||
} |
||||
|
||||
@Override |
||||
public void init(Properties prprts, Attributes atrbts) { |
||||
} |
||||
|
||||
public void onFocus(boolean getFocus) { |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void stop() { |
||||
super.stop(); |
||||
//the pool executor needs to be shut down so the application properly exits. |
||||
exec.shutdown(); |
||||
} |
||||
}</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT2 SECTION "Creating the bindings to use the Nifty XML" [4345-] --> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:loading_screen?do=export_xhtmlbody">view online version</a></em></p> |
Before Width: | Height: | Size: 2.1 KiB |
@ -1,183 +0,0 @@ |
||||
|
||||
<h1><a>Localizing jME 3 Games</a></h1> |
||||
<div> |
||||
|
||||
</div> |
||||
<!-- EDIT1 SECTION "Localizing jME 3 Games" [1-38] --> |
||||
<h2><a>Scope</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Localizing an application can mean several things: |
||||
|
||||
</p> |
||||
<ul> |
||||
<li><div> At minimum you translate all messages and dialogs in the user interface to your target languages.</div> |
||||
</li> |
||||
<li><div> You should also translate the "read me", help, and other documentation.</div> |
||||
</li> |
||||
<li><div> Also translating web content related to the application makes sure international users find out about your localized game.</div> |
||||
</li> |
||||
<li><div> If you go the whole way of internationalization, you also "translate" metaphors in icons or symbols used. <br/> |
||||
E.g. For localizations to right-to-left languages, you must also adjust the whole flow of the UI (order of menus and buttons).</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
|
||||
There are tools that assist you with localizing Java Swing GUIs. jME3 applications do not typically have a Swing <acronym title="Graphical User Interface">GUI</acronym>, so those tools are not of much help. Just stick to the normal Java rules about using Bundle Properties: |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT2 SECTION "Scope" [39-879] --> |
||||
<h2><a>Preparing the Localization</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
<strong>Tip:</strong> The jMonkeyEngine <acronym title="Software Development Kit">SDK</acronym> supports opening and editing Bundle.properties files. Also note the Tools > Localization menu. |
||||
</p> |
||||
|
||||
<p> |
||||
To prepare the application for localization, you have to first identify all hard-coded messages. |
||||
|
||||
</p> |
||||
<ol> |
||||
<li><div> Find every line in your jME3 game where you hard-coded message strings, e.g. <br/> |
||||
<pre>System.out.print("Hello World!"); |
||||
UiText.setText("Score: "+score);</pre> |
||||
</div> |
||||
</li> |
||||
<li><div> Create one file named <code>Bundle.properties</code> in each directory where there are Java file that contain messages.</div> |
||||
</li> |
||||
<li><div> For every hard-coded message, you add one line to the <code>Bundle.properties</code> file: First specify a unique key that identifies this string; then an equal sign; and the literal string itself. <br/> |
||||
<pre>greeting=Hello World! |
||||
score.display=Score: </pre> |
||||
</div> |
||||
</li> |
||||
<li><div> In the source code, replace every occurence of a hard-coded message with the appropriate Resource Bundle call to its unique key: <pre>System.out.print(ResourceBundle.getBundle("Bundle").getString("greeting")); |
||||
UiText.setText(ResourceBundle.getBundle("Bundle").getString("score.display")+score);</pre> |
||||
</div> |
||||
</li> |
||||
</ol> |
||||
|
||||
<p> |
||||
|
||||
The language used in the Bundle.properties files will be the default language for your game. |
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT3 SECTION "Preparing the Localization" [880-2088] --> |
||||
<h2><a>Translating the Messages</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
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. |
||||
</p> |
||||
|
||||
<p> |
||||
To translate the messages to another language, for example, German: |
||||
|
||||
</p> |
||||
<ol> |
||||
<li><div> Make a copy of the <code>Bundle.properties</code> files.</div> |
||||
</li> |
||||
<li><div> Name the copy <code>Bundle_de.properties</code> for German. Note the added suffix _de.</div> |
||||
</li> |
||||
<li><div> Translate all strings (text on the right side of the equal sign) in the <code>Bundle_de.properties</code> to German. <pre>greeting=Hallo Welt! |
||||
score.display=Spielstand: </pre> |
||||
|
||||
<p> |
||||
<strong>Important:</strong> Do not modify any of the keys (text to the left of the equal sign)! |
||||
</p> |
||||
</div> |
||||
</li> |
||||
<li><div> To test the German localization, start the application from the command line with <code>-Duser.language=de</code>. Note the parameter <code>de</code>.</div> |
||||
</li> |
||||
</ol> |
||||
|
||||
<p> |
||||
|
||||
<strong>Tip:</strong> In the jMonkeyEngine <acronym title="Software Development Kit">SDK</acronym>, 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. |
||||
</p> |
||||
|
||||
<p> |
||||
To get the full list of language suffixes use |
||||
|
||||
</p> |
||||
<pre>System.out.println(Arrays.toString(Locale.getISOLanguages()));</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT4 SECTION "Translating the Messages" [2089-3243] --> |
||||
<h2><a>Which Strings Not to Translate</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
<strong>Important:</strong> In the Bundle.properties file, do not include any strings that are asset paths, node or geometry names, input mappings, or material layers. |
||||
</p> |
||||
<ul> |
||||
<li><div> Keep material layers: <pre>mat.setTexture("ColorMap", tex);</pre> |
||||
</div> |
||||
</li> |
||||
<li><div> Keep paths: <pre>teapot = assetManager.loadModel("Models/Teapot/Teapot.obj");</pre> |
||||
</div> |
||||
</li> |
||||
<li><div> Keep geometry and node names: <pre>Geometry thing=new Geometry("A thing", mesh); |
||||
Node vehicle = new Node("Vehicle");</pre> |
||||
</div> |
||||
</li> |
||||
<li><div> Keep mappings: <pre>inputManager.addMapping("Shoot", trigger); |
||||
inputManager.addListener(actionListener, "Shoot");</pre> |
||||
</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
|
||||
Only localize messages and UI text! |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT5 SECTION "Which Strings Not to Translate" [3244-3918] --> |
||||
<h2><a>Common Localization Problems</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Typical problems include: |
||||
</p> |
||||
<ul> |
||||
<li><div> Localized strings will be of vastly different lengths and will totally break your UI layout. ??? Test every localization.</div> |
||||
</li> |
||||
<li><div> Strings with variable text or numbers don't work the same in different languages. ??? Either work in grammatical cases/numbers/gender for each language, or use <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://www.gnu.org/software/gettext/manual/gettext.html#Plural-forms"><param name="text" value="<html><u>gettext</u></html>"><param name="textColor" value="blue"></object> or <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://userguide.icu-project.org/formatparse/messages"><param name="text" value="<html><u>ICU4J</u></html>"><param name="textColor" value="blue"></object>.</div> |
||||
</li> |
||||
<li><div> The localizer only sees the strings, without any context. E.g. does "Search History" mean "display the history of searches", or "search through the history"? ??? Use clear key labels. Work closely with the localizers if they require extra info, and add that info as comments to the translation file.</div> |
||||
</li> |
||||
<li><div> Broken international characters ??? Make sure the files are saved with the same character encoding as the font file(s) you're using. Nowadays, that usually means UTF-8 since font files tend to come for Unicode.</div> |
||||
</li> |
||||
<li><div> Missing international characters ??? Make sure that there's a glyph for every needed character in your font, either by using more complete font files or by having the translation changed.</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT6 SECTION "Common Localization Problems" [3919-5131] --> |
||||
<h2><a>More Documentation</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
<object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://java.sun.com/developer/technicalArticles/Intl/ResourceBundles/"><param name="text" value="<html><u>http://java.sun.com/developer/technicalArticles/Intl/ResourceBundles/</u></html>"><param name="textColor" value="blue"></object> |
||||
</p> |
||||
|
||||
<p> |
||||
<object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://sourceforge.net/apps/mediawiki/nifty-gui/index.php?title=Localisation"><param name="text" value="<html><u>http://sourceforge.net/apps/mediawiki/nifty-gui/index.php?title=Localisation</u></html>"><param name="textColor" value="blue"></object> |
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT7 SECTION "More Documentation" [5132-] --> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:localization?do=export_xhtmlbody">view online version</a></em></p> |
@ -1,120 +0,0 @@ |
||||
|
||||
<h1><a>Logging and Monitoring</a></h1> |
||||
<div> |
||||
|
||||
</div> |
||||
<!-- EDIT1 SECTION "Logging and Monitoring" [1-38] --> |
||||
<h2><a>Logging Like a Newbie</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Many developers just use <code>System.out.println()</code> to print diagnostic strings to the terminal. The problem with that is that before the release, you have to go through all your code and make certain you removed all these <code>println()</code> calls. You do not want your customers to see them, and needlessly worry about ominous outdated debugging diagnostics. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT2 SECTION "Logging Like a Newbie" [39-428] --> |
||||
<h2><a>Logging Like a Pro</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Instead of <code>println()</code>, use the standard Java logger from <code>java.util.logging</code>. It has many advantages for professional game development: |
||||
</p> |
||||
<ul> |
||||
<li><div> You tag each message with its <strong>log level</strong>: Severe error, informative warning, etc.</div> |
||||
</li> |
||||
<li><div> You can <strong>switch off or on printing of log messages</strong> up to certain log level with just one line of code.</div> |
||||
<ul> |
||||
<li><div> During development, you would set the log level to <code>fine</code>, because you want all warnings printed.</div> |
||||
</li> |
||||
<li><div> For the release, you set the log level to only report <code>severe</code> errors, and never print informative diagnostics.</div> |
||||
</li> |
||||
</ul> |
||||
</li> |
||||
<li><div> The logger message string is <strong>localizable</strong> and can use variables. Optimally, you localize all error messages.</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
|
||||
To print comments like a pro, you use the following logger syntax. |
||||
</p> |
||||
<ol> |
||||
<li><div> Declare the logger object once per file. In the following code, replace <code>HelloWorld</code> by the name of the class where you are using this line.<pre>private static final Logger logger = Logger.getLogger(HelloWorld.class.getName());</pre> |
||||
</div> |
||||
</li> |
||||
<li><div> Declare the info that you want to include in the message. The variables (here <code>a, b, c</code>) can be any printable Java object. <br/> |
||||
Example: <code>Vector3f a = cam.getLocation();</code> </div> |
||||
</li> |
||||
<li><div> Put the variables in a new <code>Object</code> array. Refer to the variables as <code>{0},{1},{2}</code> etc in the message string. Variables are numbered in the order you put them into the <code>Object</code> array. </div> |
||||
</li> |
||||
<li><div> Add the logger line and specify the log level:</div> |
||||
<ul> |
||||
<li><div> Usecase 1: During debugging, a developer uses a warning to remind himself of a bug:<pre>logger.log(Level.WARNING, "why is {0} set to {1} again?!", |
||||
new Object[]{a , b});</pre> |
||||
</div> |
||||
</li> |
||||
<li><div> Usecase 2: For the release, you inform the customer of a problem and how to solve it. <pre>logger.log(Level.SEVERE, "MyGame error: {0} must not be {1} after {2}! Adjust flux generator settings.", |
||||
new Object[]{a , b , c});</pre> |
||||
</div> |
||||
</li> |
||||
</ul> |
||||
</li> |
||||
</ol> |
||||
|
||||
<p> |
||||
|
||||
<p><div>As you see in the examples, you should phrase potentially "customer facing" errors in a neutral way and offer <em>a reason and a solution</em> for the error (if you don't, it has no value to your customer). If your deveopment team uses WARNINGs as replacement for casual printlns, make sure you deactivate them for the release. |
||||
</div></p> |
||||
</p> |
||||
|
||||
<p> |
||||
More details about <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://download.oracle.com/javase/6/docs/api/java/util/logging/Level.html"><param name="text" value="<html><u>Java log levels</u></html>"><param name="textColor" value="blue"></object> here. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT3 SECTION "Logging Like a Pro" [429-2826] --> |
||||
<h2><a>Switching the Logger on and off</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
In the release version you will deactivate the logging output to the terminal. |
||||
</p> |
||||
|
||||
<p> |
||||
To deactivate the default logger for a release, you set the log level to only report <code>severe</code> messages: |
||||
|
||||
</p> |
||||
<pre>Logger.getLogger(??????).setLevel(Level.SEVERE);</pre> |
||||
|
||||
<p> |
||||
During development or a beta test, you can tune down the default logger, and set the log level to only report <code>warning</code>s: |
||||
|
||||
</p> |
||||
<pre>Logger.getLogger(??????).setLevel(Level.WARNING);</pre> |
||||
|
||||
<p> |
||||
To activate full logging, e.g. for debugging and testing, use the <code>fine</code> level: |
||||
|
||||
</p> |
||||
<pre>Logger.getLogger(??????).setLevel(Level.FINE);</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT4 SECTION "Switching the Logger on and off" [2827-3468] --> |
||||
<h2><a>Advanced Error Handling</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
When an uncaught exception reaches certain parts of the jME3 system then the default response is to log the error and then exit the application. This is because an error happening every frame will rapidly fill logs with repeated failings and potentially mask or over-write the original cause of the problem or even the application may continue for a while and then suffer other errors caused by the first and make the root cause hard to determine. |
||||
</p> |
||||
|
||||
<p> |
||||
This behaviour can be partially modified by overriding the method handleError in SimpleApplication, for example to display a custom message to users, or to provide users with information on how to report a bug or even to change the way that the error is logged. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT5 SECTION "Advanced Error Handling" [3469-] --> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:logging?do=export_xhtmlbody">view online version</a></em></p> |
@ -1,177 +0,0 @@ |
||||
|
||||
<h1><a>Making the Camera Follow a 3rd-Person Character</a></h1> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
When players steer a game character with 1st-person view, they directly steer the camera (<code>flyCam.setEnabled(true);</code>), 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. |
||||
</p> |
||||
|
||||
<p> |
||||
There are two ways how the camera can do that: |
||||
</p> |
||||
<ul> |
||||
<li><div> Registering a chase camera to the player and the input manager.</div> |
||||
</li> |
||||
<li><div> Attaching the camera to the character using a camera node.</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
|
||||
<strong>Important:</strong> Using third-person view requires you to deactivate the default flyCam (first-person view). This means that you have to configure your own navigation (<a href="/com/jme3/gde/core/docs/jme3/advanced/input_handling.html">key inputs and analogListener</a>) that make your player character walk. For moving a physical player character, use <code>player.setWalkDirection()</code>, for a non-pysical character you can use <code>player.move()</code>. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT1 SECTION "Making the Camera Follow a 3rd-Person Character" [1-989] --> |
||||
<h2><a>Code Samples</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
Press the WASD or arrow keys to move. Drag with the left mouse button to rotate. |
||||
</p> |
||||
<ul> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/input/TestChaseCamera.java"><param name="text" value="<html><u>TestChaseCamera.java</u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/input/TestCameraNode.java"><param name="text" value="<html><u>TestCameraNode.java</u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT2 SECTION "Code Samples" [990-1371] --> |
||||
<h2><a>Camera Node</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
To make the camera follow a target node, add this camera node code to your init method (e.g. <code>simpleInitApp()</code>). The <code>target</code> spatial is typically the player node. |
||||
</p> |
||||
<pre>// Disable the default flyby cam |
||||
flyCam.setEnabled(false); |
||||
//create the camera Node |
||||
camNode = new CameraNode("Camera Node", cam); |
||||
//This mode means that camera copies the movements of the target: |
||||
camNode.setControlDir(ControlDirection.SpatialToCamera); |
||||
//Attach the camNode to the target: |
||||
target.attachChild(camNode); |
||||
//Move camNode, e.g. behind and above the target: |
||||
camNode.setLocalTranslation(new Vector3f(0, 5, -5)); |
||||
//Rotate the camNode to look at the target: |
||||
camNode.lookAt(target.getLocalTranslation(), Vector3f.UNIT_Y);</pre> |
||||
|
||||
<p> |
||||
<strong>Important:</strong> Where the example says <code>camNode.setLocalTranslation(new Vector3f(0, 5, -5));</code>, 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. |
||||
|
||||
</p> |
||||
<div><table> |
||||
<tr> |
||||
<th>Methods</th><th>Description</th> |
||||
</tr> |
||||
<tr> |
||||
<td>setControlDir(ControlDirection.SpatialToCamera)</td><td>User input steers the target spatial, and the camera follows the spatial.<br/> |
||||
The spatial's transformation is copied over the camera's transformation. <br/> |
||||
Example: Use with <a href="/com/jme3/gde/core/docs/jme3/advanced/physics.html">CharacterControl</a>led spatial.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>setControlDir(ControlDirection.CameraToSpatial)</td><td>User input steers the camera, and the target spatial follows the camera. <br/> |
||||
The camera's transformation is copied over the spatial's transformation. Use with first-person flyCam.</td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT4 TABLE [2445-2956] --> |
||||
<p> |
||||
|
||||
<strong>Code sample:</strong> |
||||
</p> |
||||
<ul> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/input/TestCameraNode.java"><param name="text" value="<html><u>TestCameraNode.java</u></html>"><param name="textColor" value="blue"></object> ??? Press the WASD or arrow keys to move. Drag with the left mouse button to rotate.</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT3 SECTION "Camera Node" [1372-3197] --> |
||||
<h2><a>Chase Camera</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
To activate the chase camera, add the following code to your init method (e.g. <code>simpleInitApp()</code>). The <code>target</code> spatial is typically the player node. You will be able to rotate the target by dragging (keeping the left mouse button pressed and moving the mouse). |
||||
</p> |
||||
<pre>// Disable the default flyby cam |
||||
flyCam.setEnabled(false); |
||||
// Enable a chase cam for this target (typically the player). |
||||
ChaseCamera chaseCam = new ChaseCamera(cam, target, inputManager); |
||||
chaseCam.setSmoothMotion(true);</pre> |
||||
<div><table> |
||||
<tr> |
||||
<th>Method</th><th>Description</th> |
||||
</tr> |
||||
<tr> |
||||
<td>setInvertVerticalAxis(true)</td><td>Invert the camera's vertical rotation Axis </td> |
||||
</tr> |
||||
<tr> |
||||
<td>setInvertHorizontalAxis(true)</td><td>Invert the camera's horizontal rotation Axis</td> |
||||
</tr> |
||||
<tr> |
||||
<td>setTrailingEnabled(true)</td><td>Camera follows the target and flies around and behind when the target moves towards the camera. Trailing only works with smooth motion enabled. (Default)</td> |
||||
</tr> |
||||
<tr> |
||||
<td>setTrailingEnabled(false)</td><td>Camera follows the target, but does not rotate around the target when the target changes direction.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>setSmoothMotion(true)</td><td>Activate SmoothMotion when trailing. This means the camera seems to accelerate and fly after the character, when it has caught up, it slows down again.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>setSmoothMotion(false)</td><td>Disable smooth camera motion. Disabling SmoothMotion also disables trailing.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>setLookAtOffset(Vector3f.UNIT_Y.mult(3))</td><td>Camera looks at a point 3 world units above the target.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>setToggleRotationTrigger(new MouseButtonTrigger(MouseInput.BUTTON_MIDDLE))</td><td>Enable rotation by keeping the middle mouse button pressed (like in Blender). This disables the rotation on right and left mouse button click.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>setToggleRotationTrigger(new MouseButtonTrigger(<br/> |
||||
MouseInput.BUTTON_MIDDLE),<br/> |
||||
new KeyTrigger(KeyInput.KEY_SPACE))</td><td>Activate mutiple triggers for the rotation of the camera, e.g. spacebar and middle mouse button, etc.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>setRotationSensitivity(5f)</td><td>How fast the camera rotates. Use values around <1.0f (all bigger values are ignored).</td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT6 TABLE [3732-5144] --> |
||||
<p> |
||||
|
||||
<strong>Code sample:</strong> |
||||
</p> |
||||
<ul> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/input/TestChaseCamera.java"><param name="text" value="<html><u>TestChaseCamera.java</u></html>"><param name="textColor" value="blue"></object> ??? Press the WASD or arrow keys to move. Drag with the left mouse button to rotate.</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT5 SECTION "Chase Camera" [3198-5387] --> |
||||
<h2><a>Which to Choose?</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
What is the difference of the two code samples above? |
||||
|
||||
</p> |
||||
<div><table> |
||||
<tr> |
||||
<th>CameraNode</th><th>ChaseCam</th> |
||||
</tr> |
||||
<tr> |
||||
<td>Camera follows immediately, flies at same speed as target.</td><td>Camera moves smoothly and accelerates and decelerates, flies more slowly than the target and catches up.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>Camera stays attached to the target at a constant distance.</td><td>Camera orbits the target and approaches slowly.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>Drag-to-Rotate rotates the target and the camera. You always see the target from behind.</td><td>Drag-to-Rotate rotates only the camera. You can see the target from various sides.</td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT8 TABLE [5473-5944] --> |
||||
</div> |
||||
<!-- EDIT7 SECTION "Which to Choose?" [5388-] --> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:making_the_camera_follow_a_character?do=export_xhtmlbody">view online version</a></em></p> |
@ -1,193 +0,0 @@ |
||||
|
||||
<h1><a>How to Use Material Definitions (.j3md)</a></h1> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
All Geometries need a Material to be visible. Every Material is based on a Material Definition. Material definitions provide the "logic" for the material, and a shader draws the material according to the parameters specified in the definition. The J3MD file abstracts the shader and its configuration away from the user, allowing a simple interface where the user can simply set a few parameters on the material to change its appearance and the way its handled by the shaders. |
||||
</p> |
||||
|
||||
<p> |
||||
The most common Material Definitions are included in the engine, advanced users can create custom ones. In this case you will also be interested in the <a href="/com/jme3/gde/core/docs/jme3/advanced/material_specification.html">in-depth developer specification of the jME3 material system</a>. |
||||
</p> |
||||
|
||||
<p> |
||||
<strong>Example:</strong> |
||||
|
||||
</p> |
||||
<pre>Spatial myGeometry = assetManager.loadModel("Models/Teapot/Teapot.j3o"); |
||||
Material mat = new Material(assetManager, // Create new material and... |
||||
"Common/MatDefs/Misc/Unshaded.j3md"); // ... specify a Material Definition file, here "Unshaded.j3md"! |
||||
mat.setColor("Color", ColorRGBA.Blue); // Set one or more material parameters. |
||||
myGeometry.setMaterial(mat); // Use material on this Geometry.</pre> |
||||
|
||||
<p> |
||||
<p><div>If you use one custom material with certain settings very often, learn about storing material settings in <a href="/com/jme3/gde/core/docs/jme3/advanced/j3m_material_files.html">j3m Material Files</a>. You either <a href="/com/jme3/gde/core/docs/sdk/material_editing.html">use the jMonkeyEngine SDK to create .j3m files</a> (user-friendly), or you <a href="/com/jme3/gde/core/docs/jme3/advanced/j3m_material_files.html">write .j3m files in a text editor</a> (IDE-independent). |
||||
</div></p> |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT1 SECTION "How to Use Material Definitions (.j3md)" [1-1585] --> |
||||
<h2><a>Preparing a Material</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
In the <a href="/com/jme3/gde/core/docs/jme3/advanced/materials_overview.html">Materials Overview</a> list: |
||||
</p> |
||||
<ol> |
||||
<li><div> Choose a Material Definition that has the features that you need. </div> |
||||
<ul> |
||||
<li><div> Tip: If you don't know, start with <code>Unshaded.j3md</code> or <code>Lighting.j3md</code>.</div> |
||||
</li> |
||||
</ul> |
||||
</li> |
||||
<li><div> Look at the applicable parameters of the Material Definition and determine which parameters you need to achieve the desired effect (e.g. "glow" or "color"). Most parameters are optional! </div> |
||||
</li> |
||||
<li><div> Create and save the necessary Texture files to your <code>assets/Textures</code> directory.</div> |
||||
<ul> |
||||
<li><div> E.g. mytex_diffuse.png as ColorMap / DiffuseMap, mytex_normal.png as NormalMap, mytex_alpha.png as AlphaMap, etc???</div> |
||||
</li> |
||||
</ul> |
||||
</li> |
||||
<li><div> Determine the required values to achieve the effect that you want.</div> |
||||
<ul> |
||||
<li><div> E.g. set colors, floats, booleans, etc??? </div> |
||||
</li> |
||||
</ul> |
||||
</li> |
||||
</ol> |
||||
|
||||
</div> |
||||
<!-- EDIT2 SECTION "Preparing a Material" [1586-2329] --> |
||||
<h2><a>Using a Material</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
In your Java code, |
||||
</p> |
||||
<ol> |
||||
<li><div> Create a Material object based on the chosen Material Definition (.j3md file): <pre>Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");</pre> |
||||
</div> |
||||
</li> |
||||
<li><div> Configure your Material by setting the appropriate values listed in the <a href="/com/jme3/gde/core/docs/jme3/advanced/materials_overview.html">Materials Overview</a> table. <pre>mat.setColor("Color", ColorRGBA.Yellow ); // and more</pre> |
||||
</div> |
||||
</li> |
||||
<li><div> Apply your prepared Material to a Geometry: <pre>myGeometry.setMaterial(mat);</pre> |
||||
</div> |
||||
</li> |
||||
<li><div> (Optional) Adjust the texture scale of the mesh: <pre>myGeometryMesh.scaleTextureCoordinates(new Vector2f(2f, 2f));</pre> |
||||
</div> |
||||
</li> |
||||
</ol> |
||||
|
||||
<p> |
||||
|
||||
For details see also: <a href="/com/jme3/gde/core/docs/jme3/intermediate/how_to_use_materials.html">How to Use Materials</a> |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT3 SECTION "Using a Material" [2330-3036] --> |
||||
<h3><a>Examples</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Here are examples of the methods that set the different data types: |
||||
</p> |
||||
<ul> |
||||
<li><div> <code>mat.setColor( "Color", ColorRGBA.White );</code> </div> |
||||
</li> |
||||
<li><div> <code>mat.setTexture( "ColorMap", assetManager.loadTexture("Interface/Logo/Monkey.png" ));</code></div> |
||||
</li> |
||||
<li><div> <code>mat.setFloat( "Shininess", 5f);</code></div> |
||||
</li> |
||||
<li><div> <code>mat.setBoolean( "SphereMap", true);</code></div> |
||||
</li> |
||||
<li><div> <code>mat.setVector3( "NormalScale", new Vector3f(1f,1f,1f));</code></div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
|
||||
A simpled textured material. |
||||
|
||||
</p> |
||||
<pre>Material mat = new Material(assetManager, |
||||
"Common/MatDefs/Misc/Unshaded.j3md"); |
||||
mat.setTexture("ColorMap", assetManager.loadTexture( |
||||
"Interface/Logo/Monkey.jpg"));</pre> |
||||
|
||||
<p> |
||||
A textured material with a color bleeding through transparent areas. |
||||
|
||||
</p> |
||||
<pre>Material mat = new Material(assetManager, |
||||
"Common/MatDefs/Misc/Unshaded.j3md"); |
||||
mat.setTexture("ColorMap", assetManager.loadTexture( |
||||
"Textures/ColoredTex/Monkey.png")); |
||||
mat.setColor("Color", ColorRGBA.Blue);</pre> |
||||
|
||||
<p> |
||||
You can test these examples within the following code snippet. It creates a box and applies the material: |
||||
</p> |
||||
<pre> Box b = new Box(Vector3f.ZERO, 1, 1, 1); |
||||
Geometry geom = new Geometry("Box", b); |
||||
// ... insert Material definition... |
||||
geom.setMaterial(mat); |
||||
rootNode.attachChild(geom);</pre> |
||||
|
||||
<p> |
||||
<p><div>You can find these and other common code snippets in the jMonkeyEngine <acronym title="Software Development Kit">SDK</acronym> Code Palette. Drag and drop them into your source code. |
||||
</div></p> |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT4 SECTION "Examples" [3037-4410] --> |
||||
<h2><a>Creating a Custom Material Definition</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
First read the <a href="/com/jme3/gde/core/docs/jme3/advanced/material_specification.html">developer specification of the jME3 material system (.j3md,.j3m)</a>. Also check out the <a href="/com/jme3/gde/core/docs/jme3/build_from_sources.html">engine source code</a> and have a look at how some Material Definitions are implemented. |
||||
</p> |
||||
|
||||
<p> |
||||
You can create your own Material Definitions and place them in your project's <code>assets/MatDefs</code> directory. |
||||
|
||||
</p> |
||||
<ol> |
||||
<li><div> Find the existing MatDefs in <code>engine/src/core-data/Common/MatDefs/</code>. </div> |
||||
</li> |
||||
<li><div> Open a Something.j3md file in a text editor. You see that this .j3md file defines Material Parameters and Techniques.</div> |
||||
<ul> |
||||
<li><div> Material Parameters are the ones that you set in Materials, as shown in the examples above.</div> |
||||
</li> |
||||
<li><div> The Techniques rely on VertexShaders and FragmentShaders: You find those in the files Something.vert and Something.frag in the same directory.</div> |
||||
</li> |
||||
</ul> |
||||
</li> |
||||
<li><div> Learn about GLSL (OpenGL Shading Language) to understand the .vert and .frag syntax, then write your own.</div> |
||||
</li> |
||||
</ol> |
||||
|
||||
</div> |
||||
<!-- EDIT5 SECTION "Creating a Custom Material Definition" [4411-5384] --> |
||||
<h2><a>Related Links</a></h2> |
||||
<div> |
||||
<ul> |
||||
<li><div> <a href="/com/jme3/gde/core/docs/jme3/advanced/material_specification.html">Developer specification of the jME3 material system (.j3md,.j3m)</a></div> |
||||
</li> |
||||
</ul> |
||||
<div><span> |
||||
<a href="/wiki/doku.php/tag:material?do=showtag&tag=tag%3Amaterial">Material</a>, |
||||
<a href="/wiki/doku.php/tag:sdk?do=showtag&tag=tag%3Asdk">SDK</a>, |
||||
<a href="/wiki/doku.php/tag:matdef?do=showtag&tag=tag%3Amatdef">MatDef</a>, |
||||
<a href="/wiki/doku.php/tag:file?do=showtag&tag=tag%3Afile">file</a>, |
||||
<a href="/wiki/doku.php/tag:documentation?do=showtag&tag=tag%3Adocumentation">documentation</a> |
||||
</span></div> |
||||
|
||||
</div> |
||||
<!-- EDIT6 SECTION "Related Links" [5385-] --> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:material_definitions?do=export_xhtmlbody">view online version</a></em></p> |
@ -1,402 +0,0 @@ |
||||
|
||||
<h1><a>Material Definition Properties</a></h1> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
In jMonkeyEngine 3, colors and textures are represented as Material objects. |
||||
|
||||
</p> |
||||
<ul> |
||||
<li><div> All Geometries must have Materials. 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 several tree models.) </div> |
||||
</li> |
||||
<li><div> Each Material is based on one of jme3's default Material Definitions (.j3md files) that are included in the engine. Advanced users can create additional custom Material Definitions (see how it's done in the <a href="/com/jme3/gde/core/docs/jme3/build_from_sources.html">jme3 sources</a>).</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
|
||||
<p><div>Find out quickly <a href="/com/jme3/gde/core/docs/jme3/intermediate/how_to_use_materials.html">How to Use Materials</a>, including the most commonly used code samples and RenderStates. <br/> |
||||
Or find more background info on <a href="/com/jme3/gde/core/docs/jme3/advanced/material_definitions.html">How to use Material Definitions</a>. |
||||
</div></p> |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT1 SECTION "Material Definition Properties" [1-841] --> |
||||
<h2><a>All Materials Definition Properties</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
The following Materials table shows you the Material Definitions that jMonkeyEngine 3 supports. |
||||
</p> |
||||
|
||||
<p> |
||||
<p><div>Looks confusing? <br/> |
||||
1) Start learning about <code>Unshaded.j3md</code> and <code>Lighting.j3md</code>, they cover 90% of the cases. <br/> |
||||
2) Use <a href="/com/jme3/gde/core/docs/sdk/material_editing.html">the SDK's visual material editor</a> to try out and save material settings easily. <br/> |
||||
3) The <a href="/com/jme3/gde/core/docs/sdk/code_editor.html">SDK's Palette</a> contains drag&drop code snippets for loading materials. |
||||
</div></p> |
||||
</p> |
||||
|
||||
<p> |
||||
Most Material parameters are optional. For example, it is okay to specify solely the <code>DiffuseMap</code> and <code>NormalMap</code> when using <code>Lighting.j3md</code>, and leave the other texture maps empty. In this case, you are only using a subset of the possible features, but that's fine if it already makes in the material look the way that you want. You can always add more texture maps later. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT2 SECTION "All Materials Definition Properties" [842-1717] --> |
||||
<h3><a>Unshaded Coloring and Textures</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
jMonkeyEngine supports illuminated and unshaded Material Definitions. |
||||
</p> |
||||
<ul> |
||||
<li><div> Phong Illuminated materials look more naturalistic.</div> |
||||
</li> |
||||
<li><div> Unshaded materials look more abstract. </div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
|
||||
"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. |
||||
|
||||
</p> |
||||
<div><table> |
||||
<tr> |
||||
<th> Standard Unshaded Material Definition </th><th> Usage </th><th> Material Parameters </th> |
||||
</tr> |
||||
<tr> |
||||
<td> Common/MatDefs/Misc/Unshaded.j3md </td><td> Standard, non-illuminated Materials. <br/> |
||||
Use this for simple coloring and texturing, glow, and transparency. <br/> |
||||
See also: <a href="/com/jme3/gde/core/docs/jme3/beginner/hello_material.html">Hello Material</a> </td><td> <strong>Texture Maps</strong> <br/> |
||||
setTexture("ColorMap", assetManager.loadTexture("")); <br/> |
||||
setBoolean("SeparateTexCoord",true); <br/> |
||||
setTexture("LightMap", assetManager.loadTexture("")); <br/> |
||||
<strong>Colors</strong> <br/> |
||||
setColor("Color", ColorRGBA.White); <br/> |
||||
setBoolean("VertexColor",true); <br/> |
||||
<strong>Glow</strong> <br/> |
||||
setTexture("GlowMap", assetManager.loadTexture("")); <br/> |
||||
setColor("GlowColor", ColorRGBA.White); </td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT4 TABLE [2273-2913] --> |
||||
<p> |
||||
|
||||
Other useful, but less commonly used material definitions: |
||||
|
||||
</p> |
||||
<div><table> |
||||
<tr> |
||||
<th> Special Unshaded Material Definitions </th><th> Usage </th><th> Material Parameters </th> |
||||
</tr> |
||||
<tr> |
||||
<td> Common/MatDefs/Misc/Sky.j3md </td><td> A solid skyblue, or use with a custom SkyDome texture. <br/> |
||||
See also: <a href="/com/jme3/gde/core/docs/jme3/advanced/sky.html">Sky</a> </td><td> setTexture("TextureCubeMap", assetManager.loadTexture("")); <br/> |
||||
setBoolean("SphereMap",true); <br/> |
||||
setVector3("NormalScale", new Vector3f(0,0,0)); </td> |
||||
</tr> |
||||
<tr> |
||||
<td> Common/MatDefs/Terrain/Terrain.j3md </td><td> Splat textures for e.g. terrains. <br/> |
||||
See also: <a href="/com/jme3/gde/core/docs/jme3/beginner/hello_terrain.html">Hello Terrain</a> </td><td> setTexture("Texture1", assetManager.loadTexture("")); (red) <br/> |
||||
setFloat("Texture1Scale",1f); <br/> |
||||
setTexture("Texture2", assetManager.loadTexture("")); (green) <br/> |
||||
setFloat("Texture2Scale",1f); <br/> |
||||
setTexture("Texture3", assetManager.loadTexture("")); (blue) <br/> |
||||
setFloat("Texture3Scale",1f); <br/> |
||||
setTexture("Alpha", assetManager.loadTexture("")); </td> |
||||
</tr> |
||||
<tr> |
||||
<td>Common/MatDefs/Terrain/HeightBasedTerrain.j3md</td><td>A multi-layered texture for terrains. <br/> |
||||
Specify four textures and a Vector3f describing the region in which each texture should appear: <br/> |
||||
X = start height, <br/> |
||||
Y = end height, <br/> |
||||
Z = texture scale. <br/> |
||||
Texture regions can overlap. <br/> |
||||
For example: Specify a seafloor texture for the lowest areas, <br/> |
||||
a sandy texture for the beaches, <br/> |
||||
a grassy texure for inland areas, <br/> |
||||
and a rocky texture for mountain tops.</td><td> setFloat("terrainSize",512f); <br/> |
||||
setTexture("region1ColorMap", assetManager.loadTexture("")); <br/> |
||||
setTexture("region2ColorMap", assetManager.loadTexture("")); <br/> |
||||
setTexture("region3ColorMap", assetManager.loadTexture("")); <br/> |
||||
setTexture("region4ColorMap", assetManager.loadTexture("")); <br/> |
||||
setVector3("region1", new Vector3f(0,0,0)); <br/> |
||||
setVector3("region2", new Vector3f(0,0,0)); <br/> |
||||
setVector3("region3", new Vector3f(0,0,0)); <br/> |
||||
setVector3("region4", new Vector3f(0,0,0)); <br/> |
||||
<strong>Settings for steep areas:</strong> <br/> |
||||
setTexture("slopeColorMap", assetManager.loadTexture("")); <br/> |
||||
setFloat("slopeTileFactor",1f);</td> |
||||
</tr> |
||||
<tr> |
||||
<td> Common/MatDefs/Misc/Particle.j3md </td><td> Used with texture masks for particle effects, or for point sprites. <br/> |
||||
The Quadratic value scales the particle for perspective view (<object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/core/com/jme3/effect/ParticleEmitter.java"><param name="text" value="<html><u>formula</u></html>"><param name="textColor" value="blue"></object>). <br/> |
||||
Does support an optional colored glow effect. <br/> |
||||
See also: <a href="/com/jme3/gde/core/docs/jme3/beginner/hello_effects.html">Hello Effects</a> </td><td> setTexture("Texture", assetManager.loadTexture("")); <br/> |
||||
setTexture("GlowMap", assetManager.loadTexture("")); <br/> |
||||
setColor("GlowColor", ColorRGBA.White); <br/> |
||||
setFloat("Quadratic",1f); <br/> |
||||
setBoolean("PointSprite",true); </td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT5 TABLE [2975-5491] --> |
||||
</div> |
||||
<!-- EDIT3 SECTION "Unshaded Coloring and Textures" [1718-5492] --> |
||||
<h3><a>Phong Illuminated</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
jMonkeyEngine supports illuminated and unshaded Material Definitions. |
||||
</p> |
||||
<ul> |
||||
<li><div> Phong Illuminated materials look more naturalistic.</div> |
||||
</li> |
||||
<li><div> Unshaded materials look more abstract.</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
|
||||
Illuminated materials require a <a href="/com/jme3/gde/core/docs/jme3/advanced/light_and_shadow.html">light source</a> 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 <a href="/com/jme3/gde/core/docs/jme3/advanced/light_and_shadow.html">drop shadows</a> unless you use a FilterPostProcessor. |
||||
|
||||
</p> |
||||
<div><table> |
||||
<tr> |
||||
<th>Standard Illuminated Material Definition </th><th> Usage </th><th> Material Parameters </th> |
||||
</tr> |
||||
<tr> |
||||
<td> Common/MatDefs/Light/Lighting.j3md </td><td> Commonly used Material with Phong illumination. <br/> |
||||
Use this material together with DiffuseMap, SpecularMap, BumpMap (NormalMaps, ParalaxMap) textures. <br/> |
||||
Supports shininess, transparency, and plain material colors (Diffuse, Ambient, Specular colors). <br/> |
||||
See also: <a href="/com/jme3/gde/core/docs/jme3/beginner/hello_material.html">Hello Material</a> </td><td> <strong>Texture Maps</strong> <br/> |
||||
setTexture("DiffuseMap", assetManager.loadTexture("")); <br/> |
||||
setBoolean("UseAlpha",true);<sup><a href="#fn__1">1)</a></sup> <br/> |
||||
setTexture("NormalMap", assetManager.loadTexture("")); <br/> |
||||
setBoolean("LATC",true); <sup><a href="#fn__2">2)</a></sup> <br/> |
||||
setTexture("SpecularMap", assetManager.loadTexture("")); <br/> |
||||
setFloat("Shininess",64f); <br/> |
||||
setTexture("ParallaxMap", assetManager.loadTexture("")); <br/> |
||||
setTexture("AlphaMap", assetManager.loadTexture("")); <br/> |
||||
setFloat("AlphaDiscardThreshold",1f); <br/> |
||||
setTexture("ColorRamp", assetManager.loadTexture("")); <br/> |
||||
<strong>Glow</strong> <br/> |
||||
setTexture("GlowMap", assetManager.loadTexture("")); <br/> |
||||
setColor("GlowColor", ColorRGBA.White); <br/> |
||||
<strong>Performance and quality</strong> <br/> |
||||
setBoolean("VertexLighting",true); <br/> |
||||
setBoolean("UseVertexColor",true); <br/> |
||||
setBoolean("LowQuality",true); <br/> |
||||
setBoolean("HighQuality",true); <br/> |
||||
<strong>Material Colors</strong> <br/> |
||||
setBoolean("UseMaterialColors",true); <br/> |
||||
setColor("Diffuse", ColorRGBA.White); <br/> |
||||
setColor("Ambient", ColorRGBA.White); <br/> |
||||
setColor("Specular", ColorRGBA.White); <br/> |
||||
<strong>Tangent shading:</strong> <br/> |
||||
setBoolean("VTangent",true); <br/> |
||||
setBoolean("Minnaert",true);<sup><a href="#fn__3">3)</a></sup> <br/> |
||||
setBoolean("WardIso",true);<sup><a href="#fn__4">4)</a></sup> </td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT7 TABLE [6152-7870] --><div><table> |
||||
<tr> |
||||
<th>Special Illuminated Material Definitions </th><th> Usage </th><th> Material Parameters </th> |
||||
</tr> |
||||
<tr> |
||||
<td>Common/MatDefs/Terrain/TerrainLighting.j3md</td><td>Same kind of multi-layered splat texture as Terrain.j3md, but with illumination and shading. <br/> |
||||
Typically used for terrains, but works on any mesh. <br/> |
||||
For every 3 splat textures, you need one alpha map. <br/> |
||||
You can use a total of 11 texture maps in the terrain's splat texture: <br/> |
||||
Note that diffuse and normal maps all count against that. <br/> |
||||
For example, you can use a maximum of 9 diffuse textures, two of which can have normal maps; <br/> |
||||
or, five textures with both diffuse and normal maps.</td><td><strong>Texture Splat Maps</strong> <br/> |
||||
setTexture("DiffuseMap", assetManager.loadTexture("")); <br/> |
||||
setFloat("DiffuseMap_0_scale",1f); <br/> |
||||
setTexture("NormalMap", assetManager.loadTexture("")); <br/> |
||||
setTexture("DiffuseMap_1", assetManager.loadTexture("")); <br/> |
||||
setFloat("DiffuseMap_1_scale",1f); <br/> |
||||
setTexture("NormalMap_1", assetManager.loadTexture("")); <br/> |
||||
setTexture("DiffuseMap_2", assetManager.loadTexture("")); <br/> |
||||
setFloat("DiffuseMap_2_scale",1f); <br/> |
||||
setTexture("NormalMap_2", assetManager.loadTexture("")); <br/> |
||||
setTexture("DiffuseMap_3", assetManager.loadTexture("")); <br/> |
||||
setFloat("DiffuseMap_3_scale",1f); <br/> |
||||
setTexture("NormalMap_3", assetManager.loadTexture("")); <br/> |
||||
etc, up to 11. <br/> |
||||
<strong>Alpha Maps</strong> <br/> |
||||
setTexture("AlphaMap", assetManager.loadTexture("")); <br/> |
||||
setTexture("AlphaMap_1", assetManager.loadTexture("")); <br/> |
||||
setTexture("AlphaMap_2", assetManager.loadTexture("")); <br/> |
||||
<strong>Glowing</strong> <br/> |
||||
setTexture("GlowMap", assetManager.loadTexture("")); <br/> |
||||
setColor("GlowColor", ColorRGBA.White); <br/> |
||||
<strong>Miscellaneous</strong> <br/> |
||||
setColor("Diffuse", ColorRGBA.White); <br/> |
||||
setColor("Ambient", ColorRGBA.White); <br/> |
||||
setFloat("Shininess",64f); <br/> |
||||
setColor("Specular", ColorRGBA.White); <br/> |
||||
setTexture("SpecularMap", assetManager.loadTexture("")); <br/> |
||||
setBoolean("WardIso",true); <br/> |
||||
setBoolean("useTriPlanarMapping",true); <br/> |
||||
setBoolean("isTerrainGrid",true); </td> |
||||
</tr> |
||||
<tr> |
||||
<td> Common/MatDefs/Light/Reflection.j3md </td><td> Reflective glass material with environment map (CubeMap/SphereMap). See also: <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/texture/TestCubeMap.java"><param name="text" value="<html><u>TestCubeMap.java</u></html>"><param name="textColor" value="blue"></object> </td><td> setTexture("Texture", assetManager.loadTexture("")); <br/> |
||||
setBoolean("SphereMap",true); </td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT8 TABLE [7872-10158] --> |
||||
</div> |
||||
<!-- EDIT6 SECTION "Phong Illuminated" [5493-10159] --> |
||||
<h3><a>Other: Test and Debug</a></h3> |
||||
<div> |
||||
<div><table> |
||||
<tr> |
||||
<th> Material Definition </th><th> Usage </th> |
||||
</tr> |
||||
<tr> |
||||
<td> Common/MatDefs/Misc/ShowNormals.j3md </td><td> 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 and no lights, or as fall-back default material. This built-in material has no parameters. </td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT10 TABLE [10193-10564] --> |
||||
</div> |
||||
<!-- EDIT9 SECTION "Other: Test and Debug" [10160-10565] --> |
||||
<h2><a>RenderStates</a></h2> |
||||
<div> |
||||
|
||||
</div> |
||||
<!-- EDIT11 SECTION "RenderStates" [10566-10591] --> |
||||
<h3><a>Transparency</a></h3> |
||||
<div> |
||||
<div><table> |
||||
<tr> |
||||
<th>Material Option</th><th>Description</th><th>Example</th> |
||||
</tr> |
||||
<tr> |
||||
<td>getAdditionalRenderState().setBlendMode(BlendMode.Off);</td><td>This is the default, no transparency.</td><td>Use for all opaque objects like walls, floors, people???</td> |
||||
</tr> |
||||
<tr> |
||||
<td>getAdditionalRenderState().setBlendMode(BlendMode.Alpha);</td><td>Interpolates the background pixel with the current pixel by using the current pixel's alpha.</td><td>Use this for normal every-day translucency: Frosted window panes, ice, glass, alpha-blended vegetation textures??? </td> |
||||
</tr> |
||||
<tr> |
||||
<td>getAdditionalRenderState().setDepthWrite(false);</td><td>Disables writing of the pixel's depth value to the depth buffer.</td><td>Use this on Materials if you have several transparent/translucent objects obscuring one another, but you want to see through both.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>getAdditionalRenderState().setAlphaFallOff(0.5f); <br/> |
||||
getAdditionalRenderState().setAlphaTest(true)</td><td>Enables Alpha Testing with a "AlphaDiscardThreshold" in the AlphaMap.</td><td>Activate Alpha Testing for (partially) <strong>transparent</strong> objects such as foliage, hair, etc. <br/> |
||||
Deactivate Alpha Testing for gradually <strong>translucent</strong> objects, such as colored glass, smoked glass, ghosts.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>getAdditionalRenderState().setBlendMode(BlendMode.Additive);</td><td>Additive alpha blending adds colors in a commutative way, i.e. the result does not depend on the order of transparent layers, since it adds the scene's background pixel color to the current pixel color. This is useful if you have lots of transparent textures overlapping and don't care about the order. <br/> |
||||
<strong>Note:</strong> Viewed in front of a white background, Additive textures become fully transparent! </td><td> This is the default for Particle.j3md-based textures that have a black color background. </td> |
||||
</tr> |
||||
<tr> |
||||
<td>getAdditionalRenderState().setBlendMode(BlendMode.AlphaAdditive);</td><td>Same as "Additive", except first it multiplies the current pixel color by the pixel alpha.</td><td>This can be used for particle effects that have alpha as background. </td> |
||||
</tr> |
||||
<tr> |
||||
<td>getAdditionalRenderState().setBlendMode(BlendMode.Color);</td><td>Blends by color.</td><td>Generally useless.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>getAdditionalRenderState().setBlendMode(BlendMode.Modulate);</td><td>Multiplies the background pixel by the current pixel.</td><td>?</td> |
||||
</tr> |
||||
<tr> |
||||
<td>getAdditionalRenderState().setBlendMode(BlendMode.ModulateX2);</td><td>Same as "Modulate", except the result is doubled.</td><td>?</td> |
||||
</tr> |
||||
<tr> |
||||
<td>getAdditionalRenderState().setBlendMode(BlendMode.PremultAlpha);</td><td>Pre-multiplied alpha blending. E.g. if the color of the object has already been multiplied by its alpha, this is used instead of "Alpha" blend mode.</td><td>For use with Premult Alpha textures.</td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT13 TABLE [10616-13066] --> |
||||
<p> |
||||
|
||||
If the DiffuseMap has an alpha channel, use: |
||||
|
||||
</p> |
||||
<pre>mat.setBoolean("UseAlpha",true);</pre> |
||||
|
||||
<p> |
||||
Later, put the Geometry (not the Material!) in the appropriate render queue |
||||
</p> |
||||
<ul> |
||||
<li><div> <pre>geo.setQueueBucket(Bucket.Translucent);</pre> |
||||
</div> |
||||
</li> |
||||
<li><div> <pre>geo.setQueueBucket(Bucket.Transparent);</pre> |
||||
</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT12 SECTION "Transparency" [10592-13365] --> |
||||
<h3><a>Culling</a></h3> |
||||
<div> |
||||
<div><table> |
||||
<tr> |
||||
<th>Material Option</th><th>Usage</th><th>Example</th> |
||||
</tr> |
||||
<tr> |
||||
<td>getAdditionalRenderState().setFaceCullMode(FaceCullMode.Back); </td><td>Activates back-face culling. Mesh faces that are facing away from the camera are not rendered, which saves time. *Backface culling is activated by default as a major optimization.* </td><td>The invisible backsides and insides of models are not calculated. </td> |
||||
</tr> |
||||
<tr> |
||||
<td>getAdditionalRenderState().setFaceCullMode(FaceCullMode.Off); </td><td>No meshes are culled. Both mesh faces are rendered, even if they face away from the camera. Slow.</td><td>Sometimes used to debug custom meshes if you messed up some of the polygon sides, or for special shadow effects.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>getAdditionalRenderState().setFaceCullMode(FaceCullMode.Front); </td><td>Activates front-face culling. Mesh faces facing the camera are not rendered.</td><td>No example ??? Typically not used because you wouldn't see anything meaningful.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>getAdditionalRenderState().setFaceCullMode(FaceCullMode.FrontAndBack)</td><td>Culls both backfaces and frontfaces.</td><td>Use this as an efficient way to make an object temporarily invisible, while keeping all its other in-game properties (such as node attachment, collision shapes, interactions, etc) active.</td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT15 TABLE [13385-14527] --> |
||||
</div> |
||||
<!-- EDIT14 SECTION "Culling" [13366-14528] --> |
||||
<h3><a>Miscellaneous</a></h3> |
||||
<div> |
||||
<div><table> |
||||
<tr> |
||||
<td>getAdditionalRenderState().setColorWrite(false);</td><td>Disable writing the color of pixels.</td><td>Use this together with setDepthWrite(true) to write pixels only to the depth buffer, for example. </td> |
||||
</tr> |
||||
<tr> |
||||
<td>getAdditionalRenderState().setPointSprite(true);</td><td>Enables point-sprite mode, e.g. meshes with "Mode.Points" will be rendered as textured sprites. Note that gl_PointCoord must be set in the shader.</td><td>Point sprites are used internally for hardware accelerated particle effects.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>getAdditionalRenderState().setPolyOffset();</td><td>Enable polygon offset.</td><td>Use this when you have meshes that have triangles really close to each over (e.g. <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://en.wikipedia.org/wiki/Coplanarity"><param name="text" value="<html><u>Coplanar</u></html>"><param name="textColor" value="blue"></object>), it will shift the depth values to prevent <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://en.wikipedia.org/wiki/Z-fighting"><param name="text" value="<html><u>Z-fighting</u></html>"><param name="textColor" value="blue"></object>.</td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT17 TABLE [14554-15320] --> |
||||
<p> |
||||
|
||||
<strong>Related Links</strong> |
||||
|
||||
</p> |
||||
<ul> |
||||
<li><div> <a href="/com/jme3/gde/core/docs/jme3/advanced/material_specification.html">Developer specification of the jME3 material system (.j3md,.j3m)</a></div> |
||||
</li> |
||||
</ul> |
||||
<div><span> |
||||
<a href="/wiki/doku.php/tag:material?do=showtag&tag=tag%3Amaterial">material</a>, |
||||
<a href="/wiki/doku.php/tag:texture?do=showtag&tag=tag%3Atexture">texture</a>, |
||||
<a href="/wiki/doku.php/tag:matdefs?do=showtag&tag=tag%3Amatdefs">MatDefs</a>, |
||||
<a href="/wiki/doku.php/tag:light?do=showtag&tag=tag%3Alight">light</a>, |
||||
<a href="/wiki/doku.php/tag:culling?do=showtag&tag=tag%3Aculling">culling</a>, |
||||
<a href="/wiki/doku.php/tag:renderstates?do=showtag&tag=tag%3Arenderstates">RenderStates</a>, |
||||
<a href="/wiki/doku.php/tag:documentation?do=showtag&tag=tag%3Adocumentation">documentation</a> |
||||
</span></div> |
||||
|
||||
</div> |
||||
<!-- EDIT16 SECTION "Miscellaneous" [14529-] --><div> |
||||
<div><sup><a href="#fnt__1">1)</a></sup> |
||||
UseAlpha specifies whether DiffuseMap uses the alpha channel</div> |
||||
<div><sup><a href="#fnt__2">2)</a></sup> |
||||
LATC Specifies whether NormalMap is BC5/ATI2n/LATC/3Dc-compressed</div> |
||||
<div><sup><a href="#fnt__3">3)</a></sup> |
||||
Minnaert is a shader type.</div> |
||||
<div><sup><a href="#fnt__4">4)</a></sup> |
||||
WardIso is a shader type.</div> |
||||
</div> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:materials_overview?do=export_xhtmlbody">view online version</a></em></p> |
@ -1,171 +0,0 @@ |
||||
|
||||
<h1><a>Polygon Meshes</a></h1> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
<img src="nbdocs:/com/jme3/gde/core/docs/jme3/dolphin-mesh.png"> |
||||
</p> |
||||
|
||||
<p> |
||||
All visible game elements in a scene, whether it is a Model or a Shape, are made up of polygon meshes. JME3 has a com.jme3.scene.Mesh class that represents all meshes. |
||||
|
||||
</p> |
||||
<ul> |
||||
<li><div> Meshes are made up of triangles. <br/> |
||||
<code>getTriangleCount(???)</code> and <code>getTriangle(???)</code></div> |
||||
</li> |
||||
<li><div> Each mesh has a unique ID <br/> |
||||
<code>getId()</code></div> |
||||
</li> |
||||
<li><div> Meshes have transformations: Location (local translation), rotation, scale.</div> |
||||
</li> |
||||
<li><div> Meshes have a bounding volume. jME3 can detect intersections (that is, non-physical collisions) between meshes, or between meshes and 2D elements such as rays. <br/> |
||||
<code>collideWith()</code>.</div> |
||||
</li> |
||||
<li><div> Meshes are locked with <code>setStatic()</code> and unlocked with <code>setDynamic()</code>. </div> |
||||
<ul> |
||||
<li><div> Static Meshes cannot be modified, but are more optimized and faster (they can be precalculated). </div> |
||||
</li> |
||||
<li><div> Dynamic Meshes can be modified live, but are not optimized and slower. </div> |
||||
</li> |
||||
</ul> |
||||
</li> |
||||
<li><div> (Optional) Meshes can have a LOD (level of detail optimization) that renders more or less details depending on distance from the camera.</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
|
||||
You can use default <a href="/com/jme3/gde/core/docs/jme3/advanced/shape.html">Shape</a>s as meshes; load <a href="/com/jme3/gde/core/docs/jme3/advanced/3d_models.html">3D models</a> (i.e. meshes created in external applications); or create free-form <a href="/com/jme3/gde/core/docs/jme3/advanced/custom_meshes.html">custom meshes</a> programmatically. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT1 SECTION "Polygon Meshes" [1-1216] --> |
||||
<h2><a>Vertex Buffer</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
The VertexBuffer contains a particular type of geometry data used by Meshes. Every VertexBuffer set on a Mesh is sent as an attribute to the vertex shader to be processed. |
||||
|
||||
</p> |
||||
<div><table> |
||||
<tr> |
||||
<th>Vertex Buffer Type</th><th>Description</th> |
||||
</tr> |
||||
<tr> |
||||
<td>Type.Position </td><td>Position of the vertex (3 floats)</td> |
||||
</tr> |
||||
<tr> |
||||
<td>Type.Index </td><td> Specifies the index buffer, must contain integer data.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>Type.TexCoord </td><td> Texture coordinate</td> |
||||
</tr> |
||||
<tr> |
||||
<td>Type.TexCoord2 </td><td> Texture coordinate #2</td> |
||||
</tr> |
||||
<tr> |
||||
<td>Type.Normal </td><td> Normal vector, normalized.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>Type.Tangent </td><td> Tangent vector, normalized.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>Type.Binormal </td><td> Binormal vector, normalized.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>Type.Color </td><td> Color and Alpha (4 floats)</td> |
||||
</tr> |
||||
<tr> |
||||
<td>Type.Size </td><td>The size of the point when using point buffers.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>Type.InterleavedData </td><td> Specifies the source data for various vertex buffers when interleaving is used.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>Type.BindPosePosition </td><td> Inital vertex position, used with animation.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>Type.BindPoseNormal </td><td> Inital vertex normals, used with animation</td> |
||||
</tr> |
||||
<tr> |
||||
<td>Type.BoneWeight </td><td> Bone weights, used with animation</td> |
||||
</tr> |
||||
<tr> |
||||
<td>Type.BoneIndex </td><td> Bone indices, used with animation</td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT3 TABLE [1417-2236] --><div><table> |
||||
<tr> |
||||
<th>Mesh method</th><th>Description</th> |
||||
</tr> |
||||
<tr> |
||||
<td>setLineWidth(1)</td> |
||||
</tr> |
||||
<tr> |
||||
<td>setPointSize(4.0f)</td> |
||||
</tr> |
||||
<tr> |
||||
<td>setBound(boundingVolume)</td> |
||||
</tr> |
||||
<tr> |
||||
<td>setStatic()</td><td>Locks the mesh so you cannot modify it anymore, thus optimizing its data (faster).</td> |
||||
</tr> |
||||
<tr> |
||||
<td>setDynamic()</td><td>Unlocks the mesh so you can modified it, but this will un-optimize the data (slower).</td> |
||||
</tr> |
||||
<tr> |
||||
<td>setMode(Mesh.Mode.Points)</td><td> Used to set mesh modes, see below</td> |
||||
</tr> |
||||
<tr> |
||||
<td>getId()</td> |
||||
</tr> |
||||
<tr> |
||||
<td>getTriangle(int,tri)</td> |
||||
</tr> |
||||
<tr> |
||||
<td>scaleTextureCoordinates(Vector2f)</td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT4 TABLE [2238-2665] --><div><table> |
||||
<tr> |
||||
<th>Mesh Mode</th><th>Description</th> |
||||
</tr> |
||||
<tr> |
||||
<td>Mesh.Mode.Points</td><td>Show only corner points</td> |
||||
</tr> |
||||
<tr> |
||||
<td>Mesh.Mode.Lines</td><td>Show lines</td> |
||||
</tr> |
||||
<tr> |
||||
<td>Mesh.Mode.LineLoop</td><td>?</td> |
||||
</tr> |
||||
<tr> |
||||
<td>Mesh.Mode.LineStrip</td><td>?</td> |
||||
</tr> |
||||
<tr> |
||||
<td>Mesh.Mode.Triangles</td><td>?</td> |
||||
</tr> |
||||
<tr> |
||||
<td>Mesh.Mode.TriangleStrip</td><td>?</td> |
||||
</tr> |
||||
<tr> |
||||
<td>Mesh.Mode.TriangleFan</td><td>?</td> |
||||
</tr> |
||||
<tr> |
||||
<td>Mesh.Mode.Hybrid</td><td>?</td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT5 TABLE [2667-2908] --><div><span> |
||||
<a href="/wiki/doku.php/tag:spatial?do=showtag&tag=tag%3Aspatial">spatial</a>, |
||||
<a href="/wiki/doku.php/tag:node?do=showtag&tag=tag%3Anode">node</a>, |
||||
<a href="/wiki/doku.php/tag:mesh?do=showtag&tag=tag%3Amesh">mesh</a>, |
||||
<a href="/wiki/doku.php/tag:geometry?do=showtag&tag=tag%3Ageometry">geometry</a>, |
||||
<a href="/wiki/doku.php/tag:scenegraph?do=showtag&tag=tag%3Ascenegraph">scenegraph</a> |
||||
</span></div> |
||||
|
||||
</div> |
||||
<!-- EDIT2 SECTION "Vertex Buffer" [1217-] --> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:mesh?do=export_xhtmlbody">view online version</a></em></p> |
@ -1,341 +0,0 @@ |
||||
|
||||
<h1><a>Monkey Zone: Multi-player Sample Project</a></h1> |
||||
<div> |
||||
|
||||
<p> |
||||
MonkeyZone is an multi-player demo game provided by the jME core developer team. |
||||
</p> |
||||
<ul> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://monkeyzone.googlecode.com/svn/trunk/"><param name="text" value="<html><u>Download source code</u></html>"><param name="textColor" value="blue"></object> (Subversion Repository)</div> |
||||
</li> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://www.youtube.com/watch?v=98yITEoJvqE"><param name="text" value="<html><u>Watch pre-alpha video footage</u></html>"><param name="textColor" value="blue"></object> (YouTube Video)</div> |
||||
</li> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://jmonkeyengine.org/2011/02/13/monkeyzone-a-jme3-game-from-the-core/"><param name="text" value="<html><u>Read "MonkeyZone ??? a jME3 game from the core"</u></html>"><param name="textColor" value="blue"></object> (news article)</div> |
||||
</li> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://jmonkeyengine.org/groups/user-code-projects/forum/topic/open-game-finder/"><param name="text" value="<html><u>Related forum thread: Open Game Finder</u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
This open-source demo: |
||||
</p> |
||||
<ol> |
||||
<li><div> showcases one possible way to implement a game with jME3, and</div> |
||||
</li> |
||||
<li><div> helps the jME team verify the jME3 <acronym title="Application Programming Interface">API</acronym> in terms of usability.</div> |
||||
</li> |
||||
</ol> |
||||
|
||||
<p> |
||||
The game idea is based on ???BattleZone??? arcade game from the 1980s, a first-person shooter the with real-time strategy elements. |
||||
The game was written using the jMonkeyEngine <acronym title="Software Development Kit">SDK</acronym>, and it's based off the BasicGame project template. It took us one week to create a playable pre-alpha, including networking. |
||||
The project design follows best practices that make it possible to edit maps, vehicles, etc, in jMonkeyEngine <acronym title="Software Development Kit">SDK</acronym> without having to change the code ??? This allows 3D graphic designers to contribute models more easily. (If you feel like contributing assets or working on parts of the game code, drop us a note!) |
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT1 SECTION "Monkey Zone: Multi-player Sample Project" [1-1376] --> |
||||
<h2><a>Implementation</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
MonkeyZone is a multi-player game with a physics simulation. Both, clients and server, run the physics simulation. The clients send input data from the player group to the server, where they control the entities, and also broadcast to the clients. Additionally, the server sends regular syncronization data for all objects in the game to prevent drifting. |
||||
When a human user or an AI performs an action (presses a button), the actual logic is done on the server. The results are broadcast as data messages to the entities. When the entity is controlled by an AI, the actual AI code (that determines where the entity should move, and when it should perform an action) is executed on the client. |
||||
<br/> |
||||
<br/> |
||||
|
||||
<em>The way MonkeyZone is implemented is just one of the many possible ways to do a game like this in jME. Some things might be done more efficiently, some might be done in another way completely. MonkeyZone tries to do things the way that are most appropriate to implement the game at hand and it shows nicely how jME3 and the standard Java <acronym title="Application Programming Interface">API</acronym> can make game development easier and faster. Also note that the way MonkeyZone is designed is not scalable to a MMO style game, it will only work in a FPS style environment where the whole game world can be loaded at once.</em> |
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT2 SECTION "Implementation" [1377-2671] --> |
||||
<h3><a>Terminology</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
The game uses certain terms that might be familiar to you but maybe used in another way, so heres a quick rundown on the terms being used. |
||||
</p> |
||||
<ul> |
||||
<li><div> Player ??? Logical human or AI player that can enter entities and generally act, only exists as PlayerData ???database??? with an id.</div> |
||||
</li> |
||||
<li><div> Entity ??? Spatial with UserData, a world object like character, vehicle, box or factory. The base form is defined only by a String pointing to the j3o which already has all userdata like hitpoints, speed etc.</div> |
||||
</li> |
||||
<li><div> User ??? Human player using a client</div> |
||||
</li> |
||||
<li><div> Player Group ??? Group of players that play together (e.g. one human player and one AI companion per client). For now that's the same as client_id of human player for all AIControl???ed players originating from that client.</div> |
||||
</li> |
||||
<li><div> Client ??? Computer connected to server</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT3 SECTION "Terminology" [2672-3492] --> |
||||
<h3><a>Manager Classes</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
The WorldManager does the main work of organizing players, entities and the world and synchronizing them between the server and client. Both client and server use this class. Some other managers like ClientEffectsManager only exist on the client or server and manage e.g. effects display. |
||||
The gameplay is largely controlled by the ServerGameManager which does gameplay logic on the server, combined with the actions issued by the AI and user on the client (see below) it implements the gameplay. It extensively uses the functions exposed by the WorldManager to perform actions and gather data. This is also the class where the actions of the players are actually executed on the server to determine the outcome (ray testing for shooting etc.). |
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT4 SECTION "Manager Classes" [3493-4262] --> |
||||
<h3><a>Use of Controls</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
<a href="/com/jme3/gde/core/docs/jme3/advanced/custom_controls.html">Controls</a> are used extensively in MonkeyZone for many aspects of the game. When a player enters an entity, the Spatials Controls are configured based on the player that enters. For example when the human user enters an entity, Controls that update the user interface (DefaultHUDControl) or user input (UserInputControl) are added to the current entity Spatial. |
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
|
||||
<h4><a>...As entity capabilities</a></h4> |
||||
<div> |
||||
|
||||
<p> |
||||
Controls attached to Spatials are generally used like an ???array of capabilities??? that the entity posesses. So when an entity has a VehicleControl its expected to be a vehicle, when its got a CharacterControl its expected to be a character. |
||||
Other Controls work completely on their own, like CharacterAnimControl which just uses the CharacterControl of the entity to check if the character is running, jumping etc. and then animates the entity if it has an AnimControl. |
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
|
||||
<h4><a>... to abstract</a></h4> |
||||
<div> |
||||
|
||||
<p> |
||||
Furthermore theres special interfaces for Controls that allow abstraction of different Controls into one base interface. For example ManualControl and AutonomousControl are interfaces for controls that manage the movement of a spatial in a generalized way. This way AI code and e.g. the UserInputControl only have to check for a valid AutonomousControl or ManualControl on the spatial to control and move it. The details of the movement are handled by classes like ManualVehicleControl and AutonomousCharacterControl. |
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
|
||||
<h4><a>... for AI functions</a></h4> |
||||
<div> |
||||
|
||||
<p> |
||||
A special Control called CommandControl handles the Commands that can be executed by user controlled players, see below. |
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT5 SECTION "Use of Controls" [4263-5866] --> |
||||
<h3><a>Artificial Intelligence</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
MonkeyZone includes simple AI functions based on a command queue. |
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
|
||||
<h4><a>Commands</a></h4> |
||||
<div> |
||||
|
||||
<p> |
||||
To implement autonomous AI players MonkeyZone uses a system of Commands that are managed by a CommandControl that is attached to each AI player entity controlled by the user. This CommandControl manages a list of Commands that are executed based on priority. For example theres a MoveCommand, a FollowCommand and an AttackCommand, Commands can however implement more complete behavior than that, e.g. the complete logic for a scavenging entity. |
||||
</p> |
||||
<ul> |
||||
<li><div> Press the WASD keys and use the mouse to move</div> |
||||
</li> |
||||
<li><div> press space to jump</div> |
||||
</li> |
||||
<li><div> Aim and click to shoot</div> |
||||
</li> |
||||
<li><div> Type 1 to select the first Ogre</div> |
||||
<ul> |
||||
<li><div> Aim at the floor and press F1 to tell it where to go.</div> |
||||
</li> |
||||
<li><div> Aim at a target and press F2 to tell it who to follow.</div> |
||||
</li> |
||||
<li><div> Aim at the car and press F3 to make it drive the car.</div> |
||||
</li> |
||||
<li><div> Aim at a target and press F4 to tell it who to attack.</div> |
||||
</li> |
||||
<li><div> Walk close to the car and press enter to drive the car.</div> |
||||
</li> |
||||
</ul> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
|
||||
<h4><a>Triggers</a></h4> |
||||
<div> |
||||
|
||||
<p> |
||||
The SphereTrigger is a TriggerControl that is also attached to each AI players current entity. It consists of a GhostControl that checks the overlapping entities around the entity its attached to. It can be assigned a command that is checked with every entity entering the SphereTrigger and executed if applicable (e.g. normal ???attack enemy??? mode). |
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
|
||||
<h4><a>NavMesh</a></h4> |
||||
<div> |
||||
|
||||
<p> |
||||
For each map a navigation mesh is generated that allows the entities to navigate the terrain. Autonomous entities automatically get a NavigationControl based on the current map. The AutonomousControl implementations automatically recognize the NavigationControl attached to the Spatial and use it for navigation. The NavMeshNavigationControl implementation contains a reference to the levels NavMesh and implements a navigation algorithm similar to the A* algorithm. |
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT6 SECTION "Artificial Intelligence" [5867-7721] --> |
||||
<h3><a>Networking</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
Networking is realized in the PhysicsSyncManager which we hope to extend to a state where it can serve as a general sync system for physics based network games. |
||||
The sync manager basically puts a timestamp on every message sent from the server and then buffers all arriving messages on the client within a certain time window. This allows to compensate for messages arriving too soon or too late within the constraints of the buffer, a future version might step the clients physics space different to compensate for network delays without ???snapping???. |
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT7 SECTION "Networking" [7722-8296] --> |
||||
<h2><a>Use of jMonkeyEngine SDK tools</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
All assets used in the game, like entity models and loaded maps can be preconfigured and edited using the jMonkeyEngine <acronym title="Software Development Kit">SDK</acronym>. For example, to add a new vehicle type, a vehicle is created in the jMonkeyEngine <acronym title="Software Development Kit">SDK</acronym> vehicle editor and UserData like Speed, HitPoints etc. is applied directly in the editor. When the model is loaded in the game it is automatically configured based on these settings, the same accounts for maps that are loaded, special Nodes that mark e.g. player start locations are recognized automatically etc. |
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT8 SECTION "Use of jMonkeyEngine SDK tools" [8297-8863] --> |
||||
<h3><a>UserData</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
Entities (Nodes and Geometries) that are loaded from disk have certain UserData like HitPoints, Speed etc. that is used to configure the entity at runtime. The jMonkeyEngine <acronym title="Software Development Kit">SDK</acronym> allows adding and editing this UserData, so entity properties are editable visually. |
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT9 SECTION "UserData" [8864-9145] --> |
||||
<h3><a>Physics</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
VehicleControls, CharacterControls and RigidBodyControls with mesh collision shape for terrain and objects are generated in the jMonkeyEngine <acronym title="Software Development Kit">SDK</acronym> and saved in the entity j3o file. When an entity is loaded, the type of entity is identified based on the available controls and UserData and it is configured accordingly. |
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT10 SECTION "Physics" [9146-9480] --> |
||||
<h2><a>API Info</a></h2> |
||||
<div> |
||||
|
||||
</div> |
||||
<!-- EDIT11 SECTION "API Info" [9481-9501] --> |
||||
<h3><a>Designer Infos</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
Editable UserData of entity Spatials: |
||||
</p> |
||||
<ul> |
||||
<li><div> (float) HitPoints</div> |
||||
</li> |
||||
<li><div> (float) MaxHitPoints</div> |
||||
</li> |
||||
<li><div> (float) Speed</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
Entity Spatial marking Node names: |
||||
</p> |
||||
<ul> |
||||
<li><div> AimNode</div> |
||||
</li> |
||||
<li><div> CameraAttachment</div> |
||||
</li> |
||||
<li><div> ShootAttachment</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
Level Spatial marking Node names: |
||||
</p> |
||||
<ul> |
||||
<li><div> StartPoint</div> |
||||
</li> |
||||
<li><div> PowerSource</div> |
||||
</li> |
||||
<li><div> MetalField</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
|
||||
<h4><a>Developer Infos</a></h4> |
||||
<div> |
||||
|
||||
<p> |
||||
Programmatic UserData of entities: |
||||
</p> |
||||
<ul> |
||||
<li><div> (long) entity_id</div> |
||||
</li> |
||||
<li><div> (int) group_id</div> |
||||
</li> |
||||
<li><div> (long) player_id</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
Programmatic PlayerData: |
||||
</p> |
||||
<ul> |
||||
<li><div> (long) id</div> |
||||
</li> |
||||
<li><div> (int) group_id</div> |
||||
</li> |
||||
<li><div> (long) entity_id</div> |
||||
</li> |
||||
<li><div> (long) character_entity_id</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT12 SECTION "Designer Infos" [9502-10027] --> |
||||
<h2><a>The Future</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
Have a look at the code and feel free to ask about it, if you want any new features, you are free to implement them. ;) |
||||
MonkeyZone is hosted at GoogleCode, where you can check out the jMonkeyEngine <acronym title="Software Development Kit">SDK</acronym>-ready project via svn: |
||||
</p> |
||||
<ol> |
||||
<li><div> jMonkeyEngine <acronym title="Software Development Kit">SDK</acronym>???Team???Subversion???Checkout,</div> |
||||
</li> |
||||
<li><div> Enter the SVN <acronym title="Uniform Resource Locator">URL</acronym> <code><object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://monkeyzone.googlecode.com/svn/trunk/"><param name="text" value="<html><u>http://monkeyzone.googlecode.com/svn/trunk/</u></html>"><param name="textColor" value="blue"></object></code></div> |
||||
</li> |
||||
<li><div> Download, open, and build the project</div> |
||||
</li> |
||||
<li><div> Run the server first (com.jme3.monkeyzone.ServerMain), and then a client (com.jme3.monkeyzone.ClientMain).</div> |
||||
</li> |
||||
</ol> |
||||
|
||||
</div> |
||||
<!-- EDIT13 SECTION "The Future" [10028-10550] --> |
||||
<h2><a>Troubleshooting</a></h2> |
||||
<div> |
||||
<ol> |
||||
<li><div> After download, errors could appear because jme3tools.navmesh.util\NavMeshGenerator.java import com.jme3.terrain.Terrain is not known, you should correct this by setting Project Properties > Libraries > Add Library > jme3-libraries-terrain </div> |
||||
</li> |
||||
</ol> |
||||
<div><span> |
||||
<a href="/wiki/doku.php/tag:network?do=showtag&tag=tag%3Anetwork">network</a>, |
||||
<a href="/wiki/doku.php/tag:basegame?do=showtag&tag=tag%3Abasegame">basegame</a>, |
||||
<a href="/wiki/doku.php/tag:physics?do=showtag&tag=tag%3Aphysics">physics</a>, |
||||
<a href="/wiki/doku.php/tag:inputs?do=showtag&tag=tag%3Ainputs">inputs</a>, |
||||
<a href="/wiki/doku.php/tag:spidermonkey?do=showtag&tag=tag%3Aspidermonkey">spidermonkey</a> |
||||
</span></div> |
||||
|
||||
</div> |
||||
<!-- EDIT14 SECTION "Troubleshooting" [10551-] --> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:monkey_zone?do=export_xhtmlbody">view online version</a></em></p> |
@ -1,12 +0,0 @@ |
||||
<h1><a |
||||
name="motion_path">Motion path</a></h1><div |
||||
class="level1"><p> When creating cinematics, we need a convenient way of making objects follow a path, or making smooth camera travelings. |
||||
That's where the MotionPath come in handy.</p></div><h2><a |
||||
name="description">Description</a></h2><div |
||||
class="level2"><p> The MotionPath is a control over a Spatial object. that means that it's able to update the Spatial position on each frame.<br/> It contains a list of way points that are positions in world space that determine the general shape of the path.<br/> The accurate shape is computed using a linear interpolation or a <a |
||||
href="http://www.mvps.org/directx/articles/catmull/">Catmull-Rom</a> spline interpolation.</p><ul><li |
||||
class="level1"><div |
||||
class="li"> Linear interpolation result in straight segments between the way points.</div></li><li |
||||
class="level1"><div |
||||
class="li"> Catmull-Rom splines allow to create a very smooth path with few way points, ensure that the curve goes through each way point, with the possibility to adjust the tension of the curve. This is the interpolation you are going to use in most cases</div></li></ul><p> more to come…</p></div> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:motion_path?do=export_xhtmlbody">view online version</a></em></p> |
@ -1,121 +0,0 @@ |
||||
|
||||
<h1><a>MotionPath</a></h1> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
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. |
||||
</p> |
||||
|
||||
<p> |
||||
<strong>Tip:</strong> If you want to remote-control a whole cutscene with several spatials moving at various times, then we recommened you use MotionPaths together with <a href="/com/jme3/gde/core/docs/jme3/advanced/cinematics.html">Cinematics</a>. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT1 SECTION "MotionPath" [1-365] --> |
||||
<h2><a>Sample Code</a></h2> |
||||
<div> |
||||
<ul> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/animation/TestMotionPath.java"><param name="text" value="<html><u>TestMotionPath.java</u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/animation/TestCameraMotionPath.java"><param name="text" value="<html><u>TestCameraMotionPath.java</u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT2 SECTION "Sample Code" [366-689] --> |
||||
<h2><a>What Are Way Points?</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
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. |
||||
</p> |
||||
|
||||
<p> |
||||
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. |
||||
</p> |
||||
<ul> |
||||
<li><div> <strong>A way point</strong> is one positions on a path. </div> |
||||
</li> |
||||
<li><div> <strong>A MotionPath</strong> contains a list of all way points of one path. </div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
The final shape of the path is computed using a linear interpolation or a <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://www.mvps.org/directx/articles/catmull/"><param name="text" value="<html><u>Catmull-Rom</u></html>"><param name="textColor" value="blue"></object> spline interpolation on the way points. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT3 SECTION "What Are Way Points?" [690-1498] --> |
||||
<h2><a>Create a MotionPath</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Create a Motionpath object and add way points to it. |
||||
|
||||
</p> |
||||
<pre>MotionPath path = new MotionPath(); |
||||
path.addWayPoint(new Vector3f(10, 3, 0)); |
||||
path.addWayPoint(new Vector3f(8, -2, 1)); |
||||
...</pre> |
||||
|
||||
<p> |
||||
You can configure the path as follows. |
||||
|
||||
</p> |
||||
<div><table> |
||||
<tr> |
||||
<th> MotionPath Method </th><th> Usage </th> |
||||
</tr> |
||||
<tr> |
||||
<td>path.setCycle(true)</td><td>Sets whether the motion along this path should be closed (true) or open-ended (false). </td> |
||||
</tr> |
||||
<tr> |
||||
<td>path.addWayPoint(vector)</td><td>Adds individual waypoints to this path. The order is relevant.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>path.removeWayPoint(vector) <br/> |
||||
removeWayPoint(index)</td><td>Removes a way point from this path. You can specify the point that you want to remove as vector or as integer index.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>path.setCurveTension(0.83f)</td><td>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.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>path.getNbWayPoints()</td><td>Returns the number of waypoints in this path.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>path.enableDebugShape(assetManager,rootNode)</td><td>Shows a line that visualizes the path. Use this during development and for debugging so you see what you are doing.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>path.disableDebugShape()</td><td>Hides the line that visualizes the path. Use this for the release build.</td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT5 TABLE [1769-2660] --> |
||||
</div> |
||||
<!-- EDIT4 SECTION "Create a MotionPath" [1499-2661] --> |
||||
<h2><a>MotionPathListener</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
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 <code>control</code>, and an integer value representing the current wayPointIndex. |
||||
</p> |
||||
|
||||
<p> |
||||
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). |
||||
</p> |
||||
<pre>path.addListener( new MotionPathListener() { |
||||
public void onWayPointReach(MotionTrack control, int wayPointIndex) { |
||||
if (path.getNbWayPoints() == wayPointIndex + 1) { |
||||
println(control.getSpatial().getName() + " has finished moving. "); |
||||
} else { |
||||
println(control.getSpatial().getName() + " has reached way point " + wayPointIndex); |
||||
} |
||||
} |
||||
});</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT6 SECTION "MotionPathListener" [2662-] --> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:motionpath?do=export_xhtmlbody">view online version</a></em></p> |
Before Width: | Height: | Size: 27 KiB |
@ -1,150 +0,0 @@ |
||||
|
||||
<h1><a>Mouse Picking</a></h1> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
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. |
||||
</p> |
||||
|
||||
<p> |
||||
<img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/mouse-picking.png"> |
||||
</p> |
||||
|
||||
<p> |
||||
See <a href="/com/jme3/gde/core/docs/jme3/advanced/input_handling.html">Input Handling</a> for details on how to define the necessary input triggers, input mappings, and input listeners. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT1 SECTION "Mouse Picking" [1-533] --> |
||||
<h2><a>Pick a Target Using Fixed Crosshairs</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
The following <code>pick target</code> 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. |
||||
|
||||
</p> |
||||
<ol> |
||||
<li><div> Activate the first-person camera: <code>flyCam.setEnabled(true);</code></div> |
||||
</li> |
||||
<li><div> Keep mouse pointer invisible using <code>inputManager.setCursorVisible(false)</code>.</div> |
||||
</li> |
||||
<li><div> Map the <code>pick target</code> action to a MouseButtonTrigger. </div> |
||||
</li> |
||||
<li><div> Implement the action in the Listener.</div> |
||||
</li> |
||||
</ol> |
||||
|
||||
<p> |
||||
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). |
||||
</p> |
||||
<pre> private AnalogListener analogListener = new AnalogListener() { |
||||
public void onAnalog(String name, float intensity, float tpf) { |
||||
if (name.equals("pick target")) { |
||||
// Reset results list. |
||||
CollisionResults results = new CollisionResults(); |
||||
// Aim the ray from camera location in camera direction |
||||
// (assuming crosshairs in center of screen). |
||||
Ray ray = new Ray(cam.getLocation(), cam.getDirection()); |
||||
// Collect intersections between ray and all nodes in results list. |
||||
rootNode.collideWith(ray, results); |
||||
// Print the results so we see what is going on |
||||
for (int i = 0; i < results.size(); i++) { |
||||
// For each ???hit???, we know distance, impact point, geometry. |
||||
float dist = results.getCollision(i).getDistance(); |
||||
Vector3f pt = results.getCollision(i).getContactPoint(); |
||||
String target = results.getCollision(i).getGeometry().getName(); |
||||
System.out.println("Selection #" + i + ": " + target + " at " + pt + ", " + dist + " WU away."); |
||||
} |
||||
// 5. Use the results -- we rotate the selected geometry. |
||||
if (results.size() > 0) { |
||||
// The closest result is the target that the player picked: |
||||
Geometry target = results.getClosestCollision().getGeometry(); |
||||
// Here comes the action: |
||||
if(target.getName().equals("Red Box")) |
||||
target.rotate(0, - intensity, 0); |
||||
else if(target.getName().equals("Blue Box")) |
||||
target.rotate(0, intensity, 0); |
||||
} |
||||
} // else if ... |
||||
} |
||||
};</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT2 SECTION "Pick a Target Using Fixed Crosshairs" [534-3109] --> |
||||
<h2><a>Pick a Target Using the Mouse Pointer</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
The following <code>pick target</code> input mapping implements an action that determines what a user clicked. It assumes that the mouse pointer is visible, and the user aims the cursor at an object in the scene. You use ray casting to determine the geometry that was picked by the user. |
||||
</p> |
||||
|
||||
<p> |
||||
<strong>Note:</strong> Picking with a visible pouse pointer implies that your application can no longer use the default flyCam where the MouseAxisTrigger rotates the camera. You have to deactivate the flyCam mappings and provide custom mappings. Either different inputs rotate the camera, or the camera is fixed. |
||||
|
||||
</p> |
||||
<ol> |
||||
<li><div> Map the <code>pick target</code> action to a MouseButtonTrigger. </div> |
||||
</li> |
||||
<li><div> Make the mouse pointer visible using <code>inputManager.setCursorVisible(true)</code>.</div> |
||||
</li> |
||||
<li><div> Remap the inputs for camera rotation, or deactivate camera rotation. </div> |
||||
</li> |
||||
<li><div> Implement the action in the Listener.</div> |
||||
</li> |
||||
</ol> |
||||
|
||||
<p> |
||||
|
||||
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). |
||||
</p> |
||||
<pre>private AnalogListener analogListener = new AnalogListener() { |
||||
public void onAnalog(String name, float intensity, float tpf) { |
||||
if (name.equals("pick target")) { |
||||
// Reset results list. |
||||
CollisionResults results = new CollisionResults(); |
||||
// Convert screen click to 3d position |
||||
Vector2f click2d = inputManager.getCursorPosition(); |
||||
Vector3f click3d = cam.getWorldCoordinates(new Vector2f(click2d.x, click2d.y), 0f).clone(); |
||||
Vector3f dir = cam.getWorldCoordinates(new Vector2f(click2d.x, click2d.y), 1f).subtractLocal(click3d).normalizeLocal(); |
||||
// Aim the ray from the clicked spot forwards. |
||||
Ray ray = new Ray(click3d, dir); |
||||
// Collect intersections between ray and all nodes in results list. |
||||
rootNode.collideWith(ray, results); |
||||
// (Print the results so we see what is going on:) |
||||
for (int i = 0; i < results.size(); i++) { |
||||
// (For each ???hit???, we know distance, impact point, geometry.) |
||||
float dist = results.getCollision(i).getDistance(); |
||||
Vector3f pt = results.getCollision(i).getContactPoint(); |
||||
String target = results.getCollision(i).getGeometry().getName(); |
||||
System.out.println("Selection #" + i + ": " + target + " at " + pt + ", " + dist + " WU away."); |
||||
} |
||||
// Use the results -- we rotate the selected geometry. |
||||
if (results.size() > 0) { |
||||
// The closest result is the target that the player picked: |
||||
Geometry target = results.getClosestCollision().getGeometry(); |
||||
// Here comes the action: |
||||
if (target.getName().equals("Red Box")) { |
||||
target.rotate(0, -intensity, 0); |
||||
} else if (target.getName().equals("Blue Box")) { |
||||
target.rotate(0, intensity, 0); |
||||
} |
||||
} |
||||
} // else if ... |
||||
} |
||||
};</pre> |
||||
<div><span> |
||||
<a href="/wiki/doku.php/tag:documentation?do=showtag&tag=tag%3Adocumentation">documentation</a>, |
||||
<a href="/wiki/doku.php/tag:node?do=showtag&tag=tag%3Anode">node</a>, |
||||
<a href="/wiki/doku.php/tag:ray?do=showtag&tag=tag%3Aray">ray</a>, |
||||
<a href="/wiki/doku.php/tag:click?do=showtag&tag=tag%3Aclick">click</a>, |
||||
<a href="/wiki/doku.php/tag:collision?do=showtag&tag=tag%3Acollision">collision</a>, |
||||
<a href="/wiki/doku.php/tag:keyinput?do=showtag&tag=tag%3Akeyinput">keyinput</a>, |
||||
<a href="/wiki/doku.php/tag:input?do=showtag&tag=tag%3Ainput">input</a> |
||||
</span></div> |
||||
|
||||
</div> |
||||
<!-- EDIT3 SECTION "Pick a Target Using the Mouse Pointer" [3110-] --> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:mouse_picking?do=export_xhtmlbody">view online version</a></em></p> |
@ -1,233 +0,0 @@ |
||||
|
||||
<h1><a>Multiple Camera Views</a></h1> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
You can split the screen and look into the 3D scene from different camera angles at the same time. E.g. you can have two rootnodes with different scene graphs, and two viewPorts, each of which can only see its own subset of the scene with its own subset of port-processing filters, so you get two very different views of the scene. |
||||
</p> |
||||
|
||||
<p> |
||||
The packages used in this example are <code>com.jme3.renderer.Camera</code> and <code>com.jme3.renderer.ViewPort</code>. You can get the full sample code here: <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/renderer/TestMultiViews.java"><param name="text" value="<html><u>TestMultiViews.java</u></html>"><param name="textColor" value="blue"></object> |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT1 SECTION "Multiple Camera Views" [1-650] --> |
||||
<h2><a>How to resize and Position ViewPorts</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
The default viewPort is as big as the window. If you have several, they 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 they should be? |
||||
</p> |
||||
|
||||
<p> |
||||
Imagine the window as a 1.0f x 1.0f rectangle. The default cam's viewPort is set to |
||||
|
||||
</p> |
||||
<pre>cam.setViewPort(0f, 1f, 0f, 1f);</pre> |
||||
|
||||
<p> |
||||
|
||||
This setting makes the ViewPort take up the whole rectangle. |
||||
</p> |
||||
|
||||
<p> |
||||
The four values are read in the following order: |
||||
</p> |
||||
<pre>cam.setViewPort(x1,x2 , y1,y2);</pre> |
||||
<ul> |
||||
<li><div> <strong>X-axis</strong> from left to right</div> |
||||
</li> |
||||
<li><div> <strong>Y-axis</strong> upwards from bottom to top</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
|
||||
Here are a few examples: |
||||
|
||||
</p> |
||||
<pre>cam1.setViewPort( 0.0f , 1.0f , 0.0f , 1.0f ); |
||||
cam2.setViewPort( 0.5f , 1.0f , 0.0f , 0.5f );</pre> |
||||
|
||||
<p> |
||||
These viewport parameters are, (in this order) the left-right extend, and the bottom-top extend of a views's rectangle on the screen. |
||||
</p> |
||||
<pre>0.0 , 1.0 1.0 , 1.0 |
||||
+-----+-----+ |
||||
|cam1 | |
||||
| | |
||||
| +-----+ |
||||
| | | |
||||
| |cam2 | |
||||
+-----+-----+ |
||||
0.0 , 0.0 1.0 , 0.0</pre> |
||||
|
||||
<p> |
||||
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) |
||||
</p> |
||||
|
||||
<p> |
||||
<p><div>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: <code>Camera cam5 = new Camera(100,100);</code> |
||||
</div></p> |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT2 SECTION "How to resize and Position ViewPorts" [651-2294] --> |
||||
<h2><a>Four-Time Split Screen</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
In this example, you create four views (2x2) with the same aspect ratio as the window, but each is only half the width and height. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT3 SECTION "Four-Time Split Screen" [2295-2463] --> |
||||
<h3><a>Set up the First View</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
You use the preconfigured Camera <code>cam</code> and <code>viewPort</code> from <code>SimpleApplication</code> for the first view. It's in the bottom right. |
||||
|
||||
</p> |
||||
<pre>cam.setViewPort(.5f, 1f, 0f, 0.5f); // Resize the viewPort to half its size, bottom right.</pre> |
||||
|
||||
<p> |
||||
|
||||
Optionally, place the main camera in the scene and rotate it in its start position. |
||||
|
||||
</p> |
||||
<pre>cam.setLocation(new Vector3f(3.32f, 4.48f, 4.28f)); |
||||
cam.setRotation(new Quaternion (-0.07f, 0.92f, -0.25f, -0.27f));</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT4 SECTION "Set up the First View" [2464-2960] --> |
||||
<h3><a>Set Up Three More Views</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Here is the outline for how you create the three other cams and viewPorts (<object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/renderer/TestMultiViews.java"><param name="text" value="<html><u>Full code sample is here</u></html>"><param name="textColor" value="blue"></object>.) In the code snippet, <code>cam_n</code> stand for <code>cam_2</code> - <code>cam_4</code>, respectively, same for <code>view_n</code>. |
||||
|
||||
</p> |
||||
<ol> |
||||
<li><div> Clone the first cam to reuse its settings</div> |
||||
</li> |
||||
<li><div> Resize and position the cam's viewPort with setViewPort().</div> |
||||
</li> |
||||
<li><div> (Optionally) Move the cameras in the scene and rotate them so they face what you want to see.</div> |
||||
</li> |
||||
<li><div> Create a ViewPort for each camera</div> |
||||
</li> |
||||
<li><div> Reset the camera's enabled statuses</div> |
||||
</li> |
||||
<li><div> Attach the Node to be displayed to this ViewPort. <br/> |
||||
The camera doesn't have to look at the rootNode, but that is the most common use case.</div> |
||||
</li> |
||||
</ol> |
||||
|
||||
<p> |
||||
|
||||
Here is the abstract code sample for camera <code>n</code>: |
||||
|
||||
</p> |
||||
<pre>Camera cam_n = cam.clone(); |
||||
cam_n.setViewPort(...); // resize the viewPort |
||||
cam_n.setLocation(new Vector3f(...)); |
||||
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);</pre> |
||||
|
||||
<p> |
||||
To visualize what you do, use the following drawing of the viewport positions: |
||||
</p> |
||||
<pre>0.0 , 1.0 1.0 , 1.0 |
||||
+-----+-----+ |
||||
| | | |
||||
|cam3 |cam4 | |
||||
+-----------+ |
||||
| | | |
||||
|cam2 |cam1 | |
||||
+-----+-----+ |
||||
0.0 , 0.0 1.0 , 0.0</pre> |
||||
|
||||
<p> |
||||
This are the lines of code that set the four cameras to create a four-times split screen. |
||||
</p> |
||||
<pre>cam1.setViewPort( 0.5f , 1.0f , 0.0f , 0.5f); |
||||
... |
||||
cam2.setViewPort( 0.0f , 0.5f , 0.0f , 0.5f); |
||||
... |
||||
cam3.setViewPort( 0.0f , 0.5f , 0.5f , 1.0f); |
||||
... |
||||
cam4.setViewPort( 0.5f , 1.0f , 0.5f , 1.0f);</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT5 SECTION "Set Up Three More Views" [2961-4771] --> |
||||
<h2><a>Picture in Picture</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
The following code snippet sets up two views, one covers the whole screen, and the second is a small view in the top center. |
||||
</p> |
||||
<pre> +-----+-----+ |
||||
| |cam| | |
||||
| | 2 | | |
||||
+ +---+ + |
||||
| | |
||||
| cam | |
||||
+-----+-----+</pre> |
||||
<pre>// Setup first full-window view |
||||
cam.setViewPort(0f, 1f, 0f, 1f); |
||||
cam.setLocation(new Vector3f(3.32f, 4.48f, 4.28f)); |
||||
cam.setRotation(new Quaternion(-0.07f, 0.92f, -0.25f, -0.27f)); |
||||
|
||||
// Setup second, smaller PiP view |
||||
Camera cam2 = cam.clone(); |
||||
cam2.setViewPort(.4f, .6f, 0.8f, 1f); |
||||
cam2.setLocation(new Vector3f(-0.10f, 1.57f, 4.81f)); |
||||
cam2.setRotation(new Quaternion(0.00f, 0.99f, -0.04f, 0.02f)); |
||||
ViewPort viewPort2 = renderManager.createMainView("PiP", cam2); |
||||
viewPort2.setClearFlags(true, true, true); |
||||
viewPort2.attachScene(rootNode);</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT6 SECTION "Picture in Picture" [4772-5652] --> |
||||
<h2><a>ViewPort Settings</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
You can customize the camera and the viewPort of each view individually. For example, each view can have a different background color: |
||||
|
||||
</p> |
||||
<pre>viewPort.setBackgroundColor(ColorRGBA.Blue);</pre> |
||||
|
||||
<p> |
||||
|
||||
You have full control to determine which Nodes the camera can see! It can see the full rootNode??? |
||||
|
||||
</p> |
||||
<pre>viewPort1.attachScene(rootNode);</pre> |
||||
|
||||
<p> |
||||
|
||||
??? or you can give each camera a special node whose content it can see: |
||||
|
||||
</p> |
||||
<pre>viewPort2.attachScene(spookyGhostDetectorNode);</pre> |
||||
<div><span> |
||||
<a href="/wiki/doku.php/tag:camera?do=showtag&tag=tag%3Acamera">camera</a>, |
||||
<a href="/wiki/doku.php/tag:documentation?do=showtag&tag=tag%3Adocumentation">documentation</a> |
||||
</span></div> |
||||
|
||||
</div> |
||||
<!-- EDIT7 SECTION "ViewPort Settings" [5653-] --> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:multiple_camera_views?do=export_xhtmlbody">view online version</a></em></p> |
@ -1,254 +0,0 @@ |
||||
|
||||
<h3><a>The jME3 Threading Model</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
jME3 is similar to Swing in that for speed and efficiency all changes to the world must be made in a single update thread. This is happening automatically if using Controls and AppSates update metod or simpleUpdate however whenever you pass work to another thread you need to hand the results back to the main jME3 thread before making any changes to the scene graph. |
||||
</p> |
||||
<pre> public void rotateGeography(final Geography goe, final Quaternian rot) { |
||||
mainApp.enqueue(new Callable<Spatial>() { |
||||
|
||||
public Spatial call() throws Exception { |
||||
return geo.rotate(rot); |
||||
} |
||||
|
||||
}); |
||||
}</pre> |
||||
|
||||
<p> |
||||
Note that this example does not fetch the returned value by calling <code>get()</code> on the Future object returned from <code>enqueue()</code>. This means that the example method <code>rotateGeography()</code> will return immediately and will not wait for the rotation to be processed before continuing. |
||||
</p> |
||||
|
||||
<p> |
||||
If the processing thread needs to wait or needs the return value then <code>get()</code> or the other methods in the returned Future object such as <code>isDone()</code> can be used. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT1 SECTION "The jME3 Threading Model" [1-1133] --> |
||||
<h1><a>Multithreading Optimization</a></h1> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
First, make sure you know what <a href="/com/jme3/gde/core/docs/jme3/advanced/application_states.html">Application States</a> and <a href="/com/jme3/gde/core/docs/jme3/advanced/custom_controls.html">Custom Controls</a> are. |
||||
</p> |
||||
|
||||
<p> |
||||
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. |
||||
</p> |
||||
|
||||
<p> |
||||
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. |
||||
</p> |
||||
|
||||
<p> |
||||
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. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT2 SECTION "Multithreading Optimization" [1134-2265] --> |
||||
<h2><a>Java Multithreading</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
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 <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://download.oracle.com/javase/tutorial/essential/concurrency/"><param name="text" value="<html><u>read about the concurrent package more here</u></html>"><param name="textColor" value="blue"></object>, I will give just a short introduction. |
||||
|
||||
</p> |
||||
<ul> |
||||
<li><div> 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 <code>call()</code>.</div> |
||||
</li> |
||||
<li><div> 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. </div> |
||||
</li> |
||||
<li><div> 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.</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT3 SECTION "Java Multithreading" [2266-3338] --> |
||||
<h2><a>Multithreading in jME3</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
So how do we implement multithreading in jME3? |
||||
</p> |
||||
|
||||
<p> |
||||
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. |
||||
</p> |
||||
|
||||
<p> |
||||
To avoid slowdown, we decide to keep the pathfinding operations in the NPC Control, <em>but execute it on another thread</em>. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT4 SECTION "Multithreading in jME3" [3339-4011] --> |
||||
<h3><a>Executor</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
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. |
||||
</p> |
||||
<pre>/* This constructor creates a new executor with a core pool size of 4. */ |
||||
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(4);</pre> |
||||
|
||||
<p> |
||||
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. |
||||
</p> |
||||
|
||||
<p> |
||||
!!! Executor needs to be shut down when the application ends, in order to make the process die properly |
||||
In your simple application you can override the destroy method and shutdown the executor: |
||||
|
||||
</p> |
||||
<pre> @Override |
||||
public void destroy() { |
||||
super.destroy(); |
||||
executor.shutdown(); |
||||
}</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT5 SECTION "Executor" [4012-5087] --> |
||||
<h3><a>Control Class Fields</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
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: |
||||
</p> |
||||
<pre>//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;</pre> |
||||
|
||||
<p> |
||||
Here we also created the Future variable to track the state of this task. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT6 SECTION "Control Class Fields" [5088-5678] --> |
||||
<h3><a>Control Update() Method</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Next let's look at the update() call of the Control where the time-intensive task starts. In our example, the task is the <code>findWay</code> 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 <code>future = executor.submit(findWay);</code>. |
||||
</p> |
||||
<pre>public void update(float tpf) { |
||||
try{ |
||||
//If we have no waylist and not started a callable yet, do so! |
||||
if(wayList == null && future == null){ |
||||
//set the desired location vector, after that we should not modify it anymore |
||||
//because its being accessed on the other thread! |
||||
desiredLocation.set(getGoodNextLocation()); |
||||
//start the callable on the executor |
||||
future = executor.submit(findWay); // Thread starts! |
||||
} |
||||
//If we have started a callable already, we check the status |
||||
else if(future != null){ |
||||
//Get the waylist when its done |
||||
if(future.isDone()){ |
||||
wayList = future.get(); |
||||
future = null; |
||||
} |
||||
else if(future.isCancelled()){ |
||||
//Set future to null. Maybe we succeed next time... |
||||
future = null; |
||||
} |
||||
} |
||||
} |
||||
catch(Exception e){ |
||||
Exceptions.printStackTrace(e); |
||||
} |
||||
if(wayList != null){ |
||||
//.... Success! Let's process the wayList and move the NPC... |
||||
} |
||||
}</pre> |
||||
|
||||
<p> |
||||
Note how this logic makes its decision based on the Future object. |
||||
</p> |
||||
|
||||
<p> |
||||
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. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT7 SECTION "Control Update() Method" [5679-7549] --> |
||||
<h3><a>The Callable</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
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 <code>call()</code>. |
||||
</p> |
||||
|
||||
<p> |
||||
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. |
||||
</p> |
||||
|
||||
<p> |
||||
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: |
||||
|
||||
</p> |
||||
<ul> |
||||
<li><div> Use the execution queue <code>application.enqueue()</code> to create a sub-thread that clones the info. Only disadvantage is, it may be slower. <br/> |
||||
The example below gets the <code>Vector3f location</code> from the scene object <code>mySpatial</code> using this way.</div> |
||||
</li> |
||||
<li><div> 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 <code>application.enqueue()</code>. <br/> |
||||
The following example gets the object <code>Data data = myWorld.getData();</code> using this way.</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
|
||||
These two ways are thread-safe, they don't mess up the game logic, and keep the Callable code readable. |
||||
</p> |
||||
<pre>// A self-contained time-intensive task: |
||||
private Callable<MyWayList> findWay = new Callable<MyWayList>(){ |
||||
public MyWayList call() throws Exception { |
||||
|
||||
//Read or write data from the scene graph -- via the execution queue: |
||||
Vector3f location = application.enqueue(new Callable<Vector3f>() { |
||||
????????public Vector3f call() throws Exception { |
||||
????????????????//we clone the location so we can use the variable safely on our thread |
||||
????????????????return mySpatial.getLocalTranslation().clone(); |
||||
????????} |
||||
}).get(); |
||||
|
||||
// This world class allows safe access via synchronized methods |
||||
Data data = myWorld.getData(); |
||||
|
||||
//... Now process data and find the way ... |
||||
|
||||
return wayList; |
||||
} |
||||
};</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT8 SECTION "The Callable" [7550-9916] --> |
||||
<h2><a>Conclusion</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
The cool thing about this approach is that every entity creates one self-contained Callable for the Executor, and they are all executed in parallel. In theory, you can have one thread per entity without changing anything else but the settings of the executor. |
||||
|
||||
</p> |
||||
<div><span> |
||||
<a href="/wiki/doku.php/tag:loop?do=showtag&tag=tag%3Aloop">loop</a>, |
||||
<a href="/wiki/doku.php/tag:game?do=showtag&tag=tag%3Agame">game</a>, |
||||
<a href="/wiki/doku.php/tag:performance?do=showtag&tag=tag%3Aperformance">performance</a>, |
||||
<a href="/wiki/doku.php/tag:state?do=showtag&tag=tag%3Astate">state</a>, |
||||
<a href="/wiki/doku.php/tag:states?do=showtag&tag=tag%3Astates">states</a>, |
||||
<a href="/wiki/doku.php/tag:documentation?do=showtag&tag=tag%3Adocumentation">documentation</a> |
||||
</span></div> |
||||
|
||||
</div> |
||||
<!-- EDIT9 SECTION "Conclusion" [9917-] --> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:multithreading?do=export_xhtmlbody">view online version</a></em></p> |
@ -1,493 +0,0 @@ |
||||
|
||||
<h1><a>SpiderMonkey: Multi-Player Networking</a></h1> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
This document introduces you to the SpiderMonkey networking <acronym title="Application Programming Interface">API</acronym>. You use this <acronym title="Application Programming Interface">API</acronym> 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: |
||||
|
||||
</p> |
||||
<ul> |
||||
<li><div> The central server (one headless SimpleApplication) coordinates the game in the background.</div> |
||||
</li> |
||||
<li><div> Each player runs a game client (a standard SimpleApplication) and connects to the central server.</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
|
||||
Each Client keeps 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 to share the same game world. Each client then displays the game state to one player from this player's perspective. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT1 SECTION "SpiderMonkey: Multi-Player Networking" [1-841] --> |
||||
<h2><a>SpiderMonkey API Overview</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
The SpiderMonkey <acronym title="Application Programming Interface">API</acronym> 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). |
||||
</p> |
||||
|
||||
<p> |
||||
The SpiderMonkey <acronym title="Application Programming Interface">API</acronym> 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. |
||||
|
||||
</p> |
||||
<div><table> |
||||
<tr> |
||||
<th> Seen from the Client </th><th> </th><th> Seen from the Server </th> |
||||
</tr> |
||||
<tr> |
||||
<td> com.jme3.network.Client </td><td> == </td><td> com.jme3.network.HostedConnection </td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT3 TABLE [1767-1885] --> |
||||
<p> |
||||
|
||||
You can register several types of listeners to be notified of changes. |
||||
</p> |
||||
<ul> |
||||
<li><div> 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.</div> |
||||
</li> |
||||
<li><div> ClientStateListeners inform the Client of changes in its connection state, e.g. when the client gets kicked from the server.</div> |
||||
</li> |
||||
<li><div> ConnectionListeners inform the Server about HostedConnection arrivals and removals, e.g. if a client joins or quits.</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT2 SECTION "SpiderMonkey API Overview" [842-2386] --> |
||||
<h2><a>Client and Server</a></h2> |
||||
<div> |
||||
|
||||
</div> |
||||
<!-- EDIT4 SECTION "Client and Server" [2387-2417] --> |
||||
<h3><a>Creating a Server</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
The game server is a "headless" com.jme3.app.SimpleApplication: |
||||
</p> |
||||
<pre>public class ServerMain extends SimpleApplication { |
||||
public static void main(String[] args) { |
||||
ServerMain app = new ServerMain(); |
||||
app.start(JmeContext.Type.Headless); // headless type for servers! |
||||
} |
||||
}</pre> |
||||
|
||||
<p> |
||||
<p><div>A <code>Headless</code> 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. |
||||
</div></p> |
||||
</p> |
||||
|
||||
<p> |
||||
Create a com.jme3.network.Server in the <code>simpleInitApp()</code> method and specify a communication port, for example 6143. |
||||
</p> |
||||
<pre> public void simpleInitApp() { |
||||
... |
||||
Server myServer = Network.createServer(6143); |
||||
myServer.start(); |
||||
... |
||||
}</pre> |
||||
|
||||
<p> |
||||
When you run this app on a host, the server is ready to accept clients. Let's create a client next. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT5 SECTION "Creating a Server" [2418-3368] --> |
||||
<h3><a>Creating a Client</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
A game client is a standard com.jme3.app.SimpleApplication. |
||||
</p> |
||||
<pre>public class ClientMain extends SimpleApplication { |
||||
public static void main(String[] args) { |
||||
ClientMain app = new ClientMain(); |
||||
app.start(JmeContext.Type.Display); // standard display type |
||||
} |
||||
}</pre> |
||||
|
||||
<p> |
||||
<p><div>A standard SimpleApplication in <code>Display</code> 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. |
||||
</div></p> |
||||
</p> |
||||
|
||||
<p> |
||||
|
||||
Create a com.jme3.network.Client in the <code>simpleInitApp()</code> method and specify the servers IP address, and the same communication port as for the server, here 6143. |
||||
</p> |
||||
<pre>public void simpleInitApp() { |
||||
... |
||||
Client myClient = Network.connectToServer("localhost", 6143); |
||||
myClient.start(); |
||||
...</pre> |
||||
|
||||
<p> |
||||
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. |
||||
</p> |
||||
|
||||
<p> |
||||
When you run this client, it connects to the server. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT6 SECTION "Creating a Client" [3369-4534] --> |
||||
<h3><a>Getting Info About a Client</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
The server refers to a connected client as com.jme3.network.HostedConnection objects. The server can get info about clients as follows: |
||||
|
||||
</p> |
||||
<div><table> |
||||
<tr> |
||||
<th>Accessor</th><th>Purpose</th> |
||||
</tr> |
||||
<tr> |
||||
<td>myServer.getConnections()</td><td>Server gets a collection of all connected HostedConnection objects (all connected clients).</td> |
||||
</tr> |
||||
<tr> |
||||
<td>myServer.getConnections().size()</td><td>Server gets the number of all connected HostedConnection objects (number of clients).</td> |
||||
</tr> |
||||
<tr> |
||||
<td>myServer.getConnection(0)</td><td>Server gets the first (0), second (1), etc, connected HostedConnection object (one client).</td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT8 TABLE [4711-5090] --> |
||||
<p> |
||||
|
||||
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 <code>MyState</code> in the HostedConnection object <code>conn</code>: |
||||
|
||||
</p> |
||||
<div><table> |
||||
<tr> |
||||
<th>Accessor</th><th>Purpose</th> |
||||
</tr> |
||||
<tr> |
||||
<td> conn.setAttribute("MyState", new MyState()); </td><td> Server can change an attribute of the HostedConnection. </td> |
||||
</tr> |
||||
<tr> |
||||
<td> MyState state = conn.getAttribute("MyState")</td><td> Server can read an attribute of the HostedConnection. </td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT9 TABLE [5465-5694] --> |
||||
</div> |
||||
<!-- EDIT7 SECTION "Getting Info About a Client" [4535-5695] --> |
||||
<h2><a>Messaging</a></h2> |
||||
<div> |
||||
|
||||
</div> |
||||
<!-- EDIT10 SECTION "Messaging" [5696-5718] --> |
||||
<h3><a>Creating Message Types</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
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. |
||||
</p> |
||||
<pre>@Serializable |
||||
public class HelloMessage extends AbstractMessage { |
||||
private String hello; // custom message data |
||||
public HelloMessage() {} // empty constructor |
||||
public HelloMessage(String s) { hello = s; } // custom constructor |
||||
}</pre> |
||||
|
||||
<p> |
||||
You must register each message type to the com.jme3.network.serializing.Serializer, in both server and client! |
||||
</p> |
||||
<pre>Serializer.registerClass(HelloMessage.class);</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT11 SECTION "Creating Message Types" [5719-6671] --> |
||||
<h3><a>Responding to Messages</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
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??? <code>messageReceived()</code> method. |
||||
</p> |
||||
|
||||
</div> |
||||
|
||||
<h4><a>ClientListener.java</a></h4> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Create one ClientListener.java and make it extend <code>com.jme3.network.MessageListener</code>. |
||||
|
||||
</p> |
||||
<pre>public class ClientListener implements MessageListener<Client> { |
||||
public void messageReceived(Client source, Message message) { |
||||
if (message instanceof HelloMessage) { |
||||
// do something with the message |
||||
HelloMessage helloMessage = (HelloMessage) message; |
||||
System.out.println("Client #"+source.getId()+" received: '"+helloMessage.getSomething()+"'"); |
||||
} // else... |
||||
}</pre> |
||||
|
||||
<p> |
||||
For each message type, register a client listener to the client. |
||||
</p> |
||||
<pre>myClient.addMessageListener(new ClientListener(), HelloMessage.class);</pre> |
||||
|
||||
</div> |
||||
|
||||
<h4><a>ServerListener.java</a></h4> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Create one ServerListener.java and make it extend <code>com.jme3.network.MessageListener</code>. |
||||
</p> |
||||
<pre>public class ServerListener implements MessageListener<HostedConnection> { |
||||
public void messageReceived(HostedConnection source, Message message) { |
||||
if (message instanceof HelloMessage) { |
||||
// do something with the message |
||||
HelloMessage helloMessage = (HelloMessage) message; |
||||
System.out.println("Server received '" +helloMessage.getSomething() +"' from client #"+source.getId() ); |
||||
} // else.... |
||||
}</pre> |
||||
|
||||
<p> |
||||
For each message type, register a server listener to the server: |
||||
</p> |
||||
<pre>myServer.addMessageListener(new ServerListener(), HelloMessage.class);</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT12 SECTION "Responding to Messages" [6672-8416] --> |
||||
<h3><a>Creating and Sending Messages</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Let's create a new message of type HelloMessage: |
||||
</p> |
||||
<pre>Message message = new HelloMessage("Hello World!");</pre> |
||||
|
||||
<p> |
||||
Now the client can send this message to the server: |
||||
</p> |
||||
<pre>myClient.send(message);</pre> |
||||
|
||||
<p> |
||||
Or the server can broadcast this message to all HostedConnection (clients): |
||||
</p> |
||||
<pre>Message message = new HelloMessage("Welcome!"); |
||||
myServer.broadcast(message);</pre> |
||||
|
||||
<p> |
||||
Or the server can send the message to a specific subset of clients (e.g. to HostedConnection conn1, conn2, and conn3): |
||||
</p> |
||||
<pre>myServer.broadcast( Filters.in( conn1, conn2, conn3 ), message );</pre> |
||||
|
||||
<p> |
||||
Or the server can send the message to all but a few selected clients (e.g. to all HostedConnections but conn4): |
||||
|
||||
</p> |
||||
<pre>myServer.broadcast( Filters.notEqualTo( conn4 ), message );</pre> |
||||
|
||||
<p> |
||||
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 flooding the network with unnecessary broadcasts to all. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT13 SECTION "Creating and Sending Messages" [8417-9506] --> |
||||
<h2><a>Identification and Rejection</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
The ID of the Client and HostedConnection are the same at both ends of a connection. The ID is given out authoritatively by the Server. |
||||
</p> |
||||
<pre>... myClient.getId() ...</pre> |
||||
|
||||
<p> |
||||
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. |
||||
</p> |
||||
|
||||
<p> |
||||
<p><div>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). |
||||
</div></p> |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT14 SECTION "Identification and Rejection" [9507-10424] --> |
||||
<h2><a>Closing Clients and Server Cleanly</a></h2> |
||||
<div> |
||||
|
||||
</div> |
||||
<!-- EDIT15 SECTION "Closing Clients and Server Cleanly" [10425-10471] --> |
||||
<h3><a>Closing a Client</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
You must override the client's destroy() method to close the connection cleanly when the player quits the client: |
||||
</p> |
||||
<pre> @Override |
||||
public void destroy() { |
||||
... // custom code |
||||
myClient.close(); |
||||
super.destroy(); |
||||
}</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT16 SECTION "Closing a Client" [10472-10747] --> |
||||
<h3><a>Closing a Server</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
You must override the server's destroy() method to close the connection when the server quits: |
||||
</p> |
||||
<pre> @Override |
||||
public void destroy() { |
||||
... // custom code |
||||
myServer.close(); |
||||
super.destroy(); |
||||
}</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT17 SECTION "Closing a Server" [10748-11004] --> |
||||
<h3><a>Kicking a Client</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
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) |
||||
</p> |
||||
<pre>conn.close("We kick cheaters.");</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT18 SECTION "Kicking a Client" [11005-11395] --> |
||||
<h2><a>Listening to Connection Notification</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
The server and clients are notified about connection changes. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT19 SECTION "Listening to Connection Notification" [11396-11507] --> |
||||
<h3><a>ClientStateListener</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
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. |
||||
|
||||
</p> |
||||
<div><table> |
||||
<tr> |
||||
<th> ClientStateListener interface method </th><th> Purpose </th> |
||||
</tr> |
||||
<tr> |
||||
<td> public void clientConnected(Client c){} </td><td> Implement here what happens as soon as this client has fully connected to the server. </td> |
||||
</tr> |
||||
<tr> |
||||
<td> public void clientDisconnected(Client c, DisconnectInfo info){} </td><td> Implement here what happens after the server kicks this client. For example, display the DisconnectInfo to the user. </td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT21 TABLE [11750-12119] --> |
||||
<p> |
||||
|
||||
First implement the ClientStateListener interface in the Client class. Then register it to myClient in MyGameClient's simpleInitApp() method: |
||||
</p> |
||||
<pre>myClient.addClientStateListener(this);</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT20 SECTION "ClientStateListener" [11508-12321] --> |
||||
<h3><a>ConnectionListener</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
The com.jme3.network.ConnectionListener notifies the Server whenever new HostedConnections (clients) come and go. The listener notifies the server after the Client connection is fully established (including any internal handshaking). |
||||
|
||||
</p> |
||||
<div><table> |
||||
<tr> |
||||
<th> ConnectionListener interface method </th><th> Purpose </th> |
||||
</tr> |
||||
<tr> |
||||
<td> public void connectionAdded(Server s, HostedConnection c){} </td><td> Implemenent here what happens after a new HostedConnection has joined the Server. </td> |
||||
</tr> |
||||
<tr> |
||||
<td> public void connectionRemoved(Server s, HostedConnection c){} </td><td> Implement here what happens after a HostedConnection has left. E.g. a player has quit the game and the server removes his character. </td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT23 TABLE [12587-12985] --> |
||||
<p> |
||||
|
||||
First implement the ConnectionListener interface in the Server class. Then register it to myServer in MyGameServer's simpleInitApp() method. |
||||
|
||||
</p> |
||||
<pre>myServer.addConnectionListener(this);</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT22 SECTION "ConnectionListener" [12322-13185] --> |
||||
<h2><a>UDP versus TCP</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
SpiderMonkey supports both UDP (unreliable, fast) and TCP (reliable, slow) transport of messages. |
||||
</p> |
||||
<pre>message1.setReliable(true); // TCP |
||||
message2.setReliable(false); // UDP</pre> |
||||
<ul> |
||||
<li><div> Choose reliable and slow transport for messages, if you want to make certain the message is delivered (resent) when lost, and if the order of a series of messages is relevant. E.g. game actions such as "1. wield weapon, 2. attack, 3. dodge".</div> |
||||
</li> |
||||
<li><div> Choose unreliable and fast transport for messages if the next message makes any previously delayed or lost message obsolete and synchronizes the state again. E.g. a series of new locations while walking.</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT24 SECTION "UDP versus TCP" [13186-13856] --> |
||||
<h2><a>Important: Use Multi-Threading</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
<p><div><strong>You cannot modify the scenegraph directly from the network thread.</strong> A common example for such a modification is when you synchronize the player's position in the scene. You have to use Java Multithreading. |
||||
</div></p> |
||||
</p> |
||||
|
||||
<p> |
||||
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. |
||||
</p> |
||||
<pre>app.enqueue(callable);</pre> |
||||
|
||||
<p> |
||||
Learn more about using <a href="/com/jme3/gde/core/docs/jme3/advanced/multithreading.html">multithreading</a> in jME3 here. |
||||
</p> |
||||
|
||||
<p> |
||||
For general advice, see the articles <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="https://developer.valvesoftware.com/wiki/Source_Multiplayer_Networking"><param name="text" value="<html><u>MultiPlayer Networking</u></html>"><param name="textColor" value="blue"></object> and <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="https://developer.valvesoftware.com/wiki/Latency_Compensating_Methods_in_Client/Server_In-game_Protocol_Design_and_Optimization"><param name="text" value="<html><u>Latency Compensating Methods in Client/Server In-game Protocol Design and Optimization</u></html>"><param name="textColor" value="blue"></object> by the Valve Developer Community. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT25 SECTION "Important: Use Multi-Threading" [13857-15003] --> |
||||
<h2><a>Troubleshooting</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
If you have set up a server in your home network, and the game clients cannot reach the server from the outside, it's time to learn about <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://portforward.com/"><param name="text" value="<html><u>port forwarding</u></html>"><param name="textColor" value="blue"></object>. |
||||
</p> |
||||
<div><span> |
||||
<a href="/wiki/doku.php/tag:documentation?do=showtag&tag=tag%3Adocumentation">documentation</a>, |
||||
<a href="/wiki/doku.php/tag:network?do=showtag&tag=tag%3Anetwork">network</a>, |
||||
<a href="/wiki/doku.php/tag:spidermonkey?do=showtag&tag=tag%3Aspidermonkey">spidermonkey</a> |
||||
</span></div> |
||||
|
||||
</div> |
||||
<!-- EDIT26 SECTION "Troubleshooting" [15004-] --> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:networking?do=export_xhtmlbody">view online version</a></em></p> |
Before Width: | Height: | Size: 76 KiB |
Before Width: | Height: | Size: 59 KiB |
Before Width: | Height: | Size: 8.1 KiB |
Before Width: | Height: | Size: 123 KiB |
Before Width: | Height: | Size: 55 KiB |
Before Width: | Height: | Size: 24 KiB |
@ -1,195 +0,0 @@ |
||||
|
||||
<h1><a>Creating JME3 User Interfaces with Nifty GUI</a></h1> |
||||
<div> |
||||
|
||||
<p> |
||||
<img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/nifty-gui-13.png"> |
||||
</p> |
||||
|
||||
<p> |
||||
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 <a href="/com/jme3/gde/core/docs/jme3/advanced/swing_canvas.html">jME3 canvas</a> in a Swing <acronym title="Graphical User Interface">GUI</acronym>, a 3D game typically runs full-screen, or in a window of its own. |
||||
</p> |
||||
|
||||
<p> |
||||
This document introduces you to <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://nifty-gui.lessvoid.com/"><param name="text" value="<html><u>Nifty GUI</u></html>"><param name="textColor" value="blue"></object>, a Java library for building interactive graphical user interfaces (GUIs) for games or similar applications. Nifty <acronym title="Graphical User Interface">GUI</acronym> (the <code>de.lessvoid.nifty</code> package) is well integrated with jME3 through the <code>com.jme3.niftygui</code> package. You define the base <acronym title="Graphical User Interface">GUI</acronym> layout in <acronym title="Extensible Markup Language">XML</acronym>, 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.) |
||||
|
||||
</p> |
||||
<ul> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://vimeo.com/25637085"><param name="text" value="<html><u>Video demo of Nifty GUI 1.3</u></html>"><param name="textColor" value="blue"></object> </div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT1 SECTION "Creating JME3 User Interfaces with Nifty GUI" [1-1159] --> |
||||
<h2><a>Tutorial Overview</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Learn to add a Nifty <acronym title="Graphical User Interface">GUI</acronym> to your jME3 game by going through this multi-part tutorial: |
||||
</p> |
||||
<ol> |
||||
<li><div> <span><a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui.html">Understand the Nifty GUI Concepts</a></span> described on this page.</div> |
||||
</li> |
||||
<li><div> <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_best_practices.html">Browse this short list of Best Practices</a></div> |
||||
</li> |
||||
<li><div> Lay out your graphical user interface:</div> |
||||
<ul> |
||||
<li><div> <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_xml_layout.html">Lay out the GUI in XML</a> ??? or ???</div> |
||||
</li> |
||||
<li><div> <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_java_layout.html">Lay out the GUI in Java</a></div> |
||||
</li> |
||||
</ul> |
||||
</li> |
||||
<li><div> Integrate the <acronym title="Graphical User Interface">GUI</acronym> into the game:</div> |
||||
<ul> |
||||
<li><div> <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_overlay.html">Overlay the User Interface Over the Screen</a> ??? or ???</div> |
||||
</li> |
||||
<li><div> <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_projection.html">Project the User Interface Onto a Texture</a></div> |
||||
</li> |
||||
</ul> |
||||
</li> |
||||
<li><div> <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_java_interaction.html">Interact with the GUI from Java</a></div> |
||||
</li> |
||||
</ol> |
||||
|
||||
</div> |
||||
<!-- EDIT2 SECTION "Tutorial Overview" [1160-1952] --> |
||||
<h2><a>Must Know: Nifty GUI Concepts</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
<img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/nifty-screen-layer-panel.png"> |
||||
</p> |
||||
|
||||
<p> |
||||
Nifty GUIs are made up of the following <strong>elements</strong>: |
||||
|
||||
</p> |
||||
<ul> |
||||
<li><div> A Nifty <acronym title="Graphical User Interface">GUI</acronym> contains one or more <strong>screens</strong>.</div> |
||||
<ul> |
||||
<li><div> Only one screen is visible at a time.</div> |
||||
</li> |
||||
<li><div> Name the first screen <code>start</code>. Name any others whatever you like.</div> |
||||
</li> |
||||
<li><div> Screen are <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_java_interaction.html">controlled by a Java Controller class</a>.</div> |
||||
</li> |
||||
</ul> |
||||
</li> |
||||
<li><div> A screen contains one or more <strong>layers</strong>.</div> |
||||
<ul> |
||||
<li><div> Layers are containers that impose alignment on their contents (vertical, horizontal, or centered)</div> |
||||
</li> |
||||
<li><div> Layers can overlap (z-order), and cannot be nested.</div> |
||||
</li> |
||||
</ul> |
||||
</li> |
||||
<li><div> A layer contains <strong>panels</strong>.</div> |
||||
<ul> |
||||
<li><div> Panels are containers that impose alignment on their contents (vertical, horizontal, or centered)</div> |
||||
</li> |
||||
<li><div> Panels can be nested, and cannot overlap.</div> |
||||
</li> |
||||
</ul> |
||||
</li> |
||||
<li><div> A panel contains <strong>images, text, or controls (buttons, etc)</strong>.</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT3 SECTION "Must Know: Nifty GUI Concepts" [1953-2830] --> |
||||
<h2><a>Resources</a></h2> |
||||
<div> |
||||
<ul> |
||||
<li><div> <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_best_practices.html">Browse this short list of Best Practices before you start</a></div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT4 SECTION "Resources" [2831-2960] --> |
||||
<h3><a>JME-Nifty Sample Code</a></h3> |
||||
<div> |
||||
<ul> |
||||
<li><div> <acronym title="Extensible Markup Language">XML</acronym> examples</div> |
||||
<ul> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/test-data/Interface/Nifty/HelloJme.xml"><param name="text" value="<html><u>HelloJme.xml</u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
</ul> |
||||
</li> |
||||
<li><div> Java examples</div> |
||||
<ul> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/niftygui/TestNiftyGui.java"><param name="text" value="<html><u>TestNiftyGui.java</u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/niftygui/TestNiftyToMesh.java"><param name="text" value="<html><u>TestNiftyToMesh.java</u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
</ul> |
||||
</li> |
||||
<li><div> jME3-ready version of the Nifty <acronym title="Graphical User Interface">GUI</acronym> 1.3 demo (sample code, Java)</div> |
||||
<ul> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://files.seapegasus.org/NiftyGuiDemo.zip"><param name="text" value="<html><u>NiftyGuiDemo.zip</u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
</ul> |
||||
</li> |
||||
<li><div> Find more sample code in the <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://nifty-gui.svn.sourceforge.net/viewvc/nifty-gui/nifty-default-controls-examples/trunk/"><param name="text" value="<html><u>Nifty GUI source repository</u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT5 SECTION "JME-Nifty Sample Code" [2961-3740] --> |
||||
<h3><a>External Documentation</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Learn more from the NiftyGUI page: |
||||
</p> |
||||
<ul> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://sourceforge.net/projects/nifty-gui/files/nifty-gui/1.3.2/nifty-gui-the-manual-1.3.2.pdf/download"><param name="text" value="<html><u>Nifty GUI - the Manual</u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://nifty-gui.sourceforge.net/projects/1.3-SNAPSHOT/nifty/apidocs/index.html"><param name="text" value="<html><u>Nifty 1.3 JavaDoc</u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://nifty-gui.sourceforge.net/projects/1.3-SNAPSHOT/nifty-default-controls/apidocs/"><param name="text" value="<html><u>Nifty 1.3 Controls JavaDoc</u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://jmonkeyengine.org/groups/gui/forum/topic/anyone-succeeded-in-changing-text-in-nifty-programatically/#post-109510"><param name="text" value="<html><u>Forum post: Changing Text in Nifty GUIs programmatically</u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT6 SECTION "External Documentation" [3741-4357] --> |
||||
<h2><a>Next Steps</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Now that you understand the concepts and know where to find more information, learn how to lay out a simple graphical user interface. Typically, you start doing this in <acronym title="Extensible Markup Language">XML</acronym>. |
||||
</p> |
||||
<ul> |
||||
<li><div> <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_xml_layout.html">Lay out the GUI in XML</a> (recommended)</div> |
||||
</li> |
||||
<li><div> <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_java_layout.html">Lay out the GUI in Java</a> (optional)</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT7 SECTION "Next Steps" [4358-4717] --> |
||||
<h2><a>Nifty Logging (Nifty 1.3.1)</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
If you want to disable the nifty log lines, add this code after you created nifty: |
||||
|
||||
</p> |
||||
<pre>Logger.getLogger("de.lessvoid.nifty").setLevel(Level.SEVERE); |
||||
Logger.getLogger("NiftyInputEventHandlingLog").setLevel(Level.SEVERE); </pre> |
||||
<div><span> |
||||
<a href="/wiki/doku.php/tag:gui?do=showtag&tag=tag%3Agui">gui</a>, |
||||
<a href="/wiki/doku.php/tag:documentation?do=showtag&tag=tag%3Adocumentation">documentation</a>, |
||||
<a href="/wiki/doku.php/tag:nifty?do=showtag&tag=tag%3Anifty">nifty</a>, |
||||
<a href="/wiki/doku.php/tag:hud?do=showtag&tag=tag%3Ahud">hud</a> |
||||
</span></div> |
||||
|
||||
</div> |
||||
<!-- EDIT8 SECTION "Nifty Logging (Nifty 1.3.1)" [4718-] --> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:nifty_gui?do=export_xhtmlbody">view online version</a></em></p> |
@ -1,321 +0,0 @@ |
||||
|
||||
<h1><a>Interacting with the GUI from Java</a></h1> |
||||
<div> |
||||
<ol> |
||||
<li><div> <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui.html">Nifty GUI Concepts</a></div> |
||||
</li> |
||||
<li><div> <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_best_practices.html">Nifty GUI Best Practices</a></div> |
||||
</li> |
||||
<li><div> <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_xml_layout.html">Nifty GUI XML Layout</a> or <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_java_layout.html">Nifty GUI Java Layout</a></div> |
||||
</li> |
||||
<li><div> <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_overlay.html">Nifty GUI Overlay</a> or <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_projection.html">Nifty GUI Projection</a></div> |
||||
</li> |
||||
<li><div> <strong>Nifty <acronym title="Graphical User Interface">GUI</acronym> Java Interaction</strong></div> |
||||
</li> |
||||
</ol> |
||||
|
||||
<p> |
||||
|
||||
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 <acronym title="Graphical User Interface">GUI</acronym> 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). |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT1 SECTION "Interacting with the GUI from Java" [1-791] --> |
||||
<h2><a>Connect GUI to Java Controller</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
To let a Nifty screen communicate with the Java application, you register a <code>ScreenController</code> to every NiftyGUI screen. You create a ScreenController by creating a Java class that implements the <code>de.lessvoid.nifty.screen.ScreenController</code> interface and its abtract methods. |
||||
</p> |
||||
|
||||
<p> |
||||
<strong>Pro Tip:</strong> Since you are writing a jME3 application, you can additionally make the ScreenController class extend the <a href="/com/jme3/gde/core/docs/jme3/advanced/application_states.html">AbstractAppState</a> class! This gives the ScreenController access to the application object and to the update loop! |
||||
</p> |
||||
<pre>package tutorial; |
||||
|
||||
import com.jme3.app.Application; |
||||
import com.jme3.app.SimpleApplication; |
||||
import com.jme3.app.state.AbstractAppState; |
||||
import com.jme3.app.state.AppStateManager; |
||||
import de.lessvoid.nifty.Nifty; |
||||
import de.lessvoid.nifty.screen.Screen; |
||||
import de.lessvoid.nifty.screen.ScreenController; |
||||
|
||||
public class MyStartScreen extends AbstractAppState implements ScreenController { |
||||
|
||||
private Nifty nifty; |
||||
private Screen screen; |
||||
private SimpleApplication app; |
||||
|
||||
/** custom methods */ |
||||
|
||||
public MyStartScreen(String data) { |
||||
/** Your custom constructor, can accept arguments */ |
||||
} |
||||
|
||||
/** Nifty GUI ScreenControl methods */ |
||||
|
||||
public void bind(Nifty nifty, Screen screen) { |
||||
this.nifty = nifty; |
||||
this.screen = screen; |
||||
} |
||||
|
||||
public void onStartScreen() { } |
||||
|
||||
public void onEndScreen() { } |
||||
|
||||
/** jME3 AppState methods */ |
||||
|
||||
@Override |
||||
public void initialize(AppStateManager stateManager, Application app) { |
||||
super.initialize(stateManager, app); |
||||
this.app=(SimpleApplication)app; |
||||
} |
||||
|
||||
@Override |
||||
public void update(float tpf) { |
||||
/** jME update loop! */ |
||||
} |
||||
|
||||
}</pre> |
||||
|
||||
<p> |
||||
The name and package of your custom ScreenController class (here <code>tutorial.MyStartScreen</code>) goes into the controller parameter of the respective <acronym title="Extensible Markup Language">XML</acronym> screen it belongs to. For example: |
||||
</p> |
||||
<pre><span><span><nifty></span></span> |
||||
<span><screen id="start" controller="tutorial.MyStartScreen"></span> |
||||
<!-- layer and panel code ... --> |
||||
<span><span></screen></span></span> |
||||
<span><span></nifty></span></span></pre> |
||||
|
||||
<p> |
||||
Or the same in a Java syntax, respectively: |
||||
</p> |
||||
<pre> nifty.addScreen("start", new ScreenBuilder("start") {{ |
||||
controller(new tutorial.MyStartScreen())}});</pre> |
||||
|
||||
<p> |
||||
Now the Java class <code>MyStartScreen</code> and this <acronym title="Graphical User Interface">GUI</acronym> screen (<code>start</code>) are connected. For this example you can also connect the <code>hud</code> screen to MyStartScreen. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT2 SECTION "Connect GUI to Java Controller" [792-3174] --> |
||||
<h2><a>Make GUI and Java Interact</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
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 (<code>public MyStartScreen(GameData data) {}</code>). |
||||
</p> |
||||
|
||||
<p> |
||||
Use any combination of the three following approaches to make Java classes interact with the <acronym title="Graphical User Interface">GUI</acronym>. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT3 SECTION "Make GUI and Java Interact" [3175-3547] --> |
||||
<h3><a>GUI Calls a Void Java Method</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
This is how you respond to an <acronym title="Graphical User Interface">GUI</acronym> interaction such as clicks in <acronym title="Extensible Markup Language">XML</acronym> GUIs: |
||||
</p> |
||||
<ol> |
||||
<li><div> Add <code>visibleToMouse="true"</code> to the parent element!</div> |
||||
</li> |
||||
<li><div> Embed the <code><interact /></code> element into the parent element. </div> |
||||
</li> |
||||
<li><div> Specify the Java methods that you want to call when the users performs certain actions, such as clicking. <br/> |
||||
Example: <code><interact onClick="startGame(hud)" /></code></div> |
||||
</li> |
||||
</ol> |
||||
|
||||
<p> |
||||
|
||||
Or this is how you respond to an <acronym title="Graphical User Interface">GUI</acronym> interaction such as clicks in Java GUIs: |
||||
</p> |
||||
<ol> |
||||
<li><div> Add <code>visibleToMouse(true);</code> to the parent element!</div> |
||||
</li> |
||||
<li><div> Embed one of the <code>interact???()</code> elements into the parent element</div> |
||||
</li> |
||||
<li><div> Specify the Java method that you want to call after the interaction. <br/> |
||||
Example: <code>interactOnClick("startGame(hud)");</code></div> |
||||
</li> |
||||
</ol> |
||||
|
||||
<p> |
||||
|
||||
In the following example, we call the <code>startGame()</code> method when the player clicks the Start button, and <code>quitGame()</code> when the player clicks the Quit button. |
||||
</p> |
||||
<pre> <span><panel id="panel_bottom_left" height="50%" width="50%" valign="center" childLayout="center"></span> |
||||
<span><control name="button" label="Start" id="StartButton" align="center" valign="center" </span> |
||||
<span> visibleToMouse="true" ></span> |
||||
<span><interact onClick="startGame(hud)"/></span> |
||||
<span><span></control></span></span> |
||||
<span><span></panel></span></span> |
||||
|
||||
<span><panel id="panel_bottom_right" height="50%" width="50%" valign="center" childLayout="center"></span> |
||||
<span><control name="button" label="Quit" id="QuitButton" align="center" valign="center" </span> |
||||
<span> visibleToMouse="true" ></span> |
||||
<span><interact onClick="quitGame()"/></span> |
||||
<span><span></control></span></span> |
||||
<span><span></panel></span></span></pre> |
||||
|
||||
<p> |
||||
Or the same in a Java syntax, respectively: |
||||
</p> |
||||
<pre>control(new ButtonBuilder("StartButton", "Start") {{ |
||||
alignCenter(); |
||||
valignCenter(); |
||||
height("50%"); |
||||
width("50%"); |
||||
visibleToMouse(true); |
||||
interactOnClick("startGame(hud)"); |
||||
}}); |
||||
... |
||||
|
||||
control(new ButtonBuilder("QuitButton", "Quit") {{ |
||||
alignCenter(); |
||||
valignCenter(); |
||||
height("50%"); |
||||
width("50%"); |
||||
visibleToMouse(true); |
||||
interactOnClick("quitGame()"); |
||||
}});</pre> |
||||
|
||||
<p> |
||||
Back in the MyStartScreen class, you specify what the <code>startGame()</code> and <code>quitGame()</code> methods do. As you see, you can pass String arguments (here <code>hud</code>) in the method call. You also see that you have access to the app object. |
||||
</p> |
||||
<pre>public class MyStartScreen implements ScreenController { |
||||
... |
||||
|
||||
/** custom methods */ |
||||
public void startGame(String nextScreen) { |
||||
nifty.gotoScreen(nextScreen); // switch to another screen |
||||
// start the game and do some more stuff... |
||||
} |
||||
|
||||
public void quitGame() { |
||||
app.stop(); |
||||
} |
||||
|
||||
... |
||||
}</pre> |
||||
|
||||
<p> |
||||
The startGame() example simply switches the <acronym title="Graphical User Interface">GUI</acronym> to the <code>hud</code> screen when the user clicks Start. Of course, in a real game, you would perform more steps here: Load the game level, switch to in-game input and navigation handling, set a custom <code>running</code> boolean to true, attach custom in-game AppStates ??? and lots more. |
||||
</p> |
||||
|
||||
<p> |
||||
The quitGame() example shows that you have access to the application <code>app</code> object because you made the ScreenController extend AbstractAppState. (If you're creating code from this example, note that you'll need to make sure <code>app</code> is initialized before you can successfully call its methods.) |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT4 SECTION "GUI Calls a Void Java Method" [3548-6724] --> |
||||
<h3><a>GUI Gets Return Value from Java Method</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
When the Nifty <acronym title="Graphical User Interface">GUI</acronym> is initialized, you can get data from Java. In this example, the Java class <code>getPlayerName()</code> in <code>MyStartScreen</code> defines the Text that is displayed in the textfield before the words <code>'s Cool Game</code>. |
||||
</p> |
||||
|
||||
<p> |
||||
First define a Java method in the screen controller, in this example, <code>getPlayerName()</code>. |
||||
</p> |
||||
<pre>public class MySettingsScreen implements ScreenController { |
||||
... |
||||
public String getPlayerName(){ |
||||
return System.getProperty("user.name"); |
||||
} |
||||
}</pre> |
||||
|
||||
<p> |
||||
Nifty uses <code>${CALL.getPlayerName()}</code> to get the return value of the getPlayerName() method from your ScreenController Java class. |
||||
</p> |
||||
<pre><span><text text="${CALL.getPlayerName()}'s Cool Game" font="Interface/Fonts/Default.fnt" width="100%" height="100%" /></span></pre> |
||||
|
||||
<p> |
||||
Or the same in a Java syntax, respectively: |
||||
</p> |
||||
<pre>text(new TextBuilder() {{ |
||||
text("${CALL.getPlayerName()}'s Cool Game"); |
||||
font("Interface/Fonts/Default.fnt"); |
||||
height("100%"); |
||||
width("100%"); |
||||
}});</pre> |
||||
|
||||
<p> |
||||
You can use this for Strings and numeric values (e.g. when you read settings from a file, you display the results in the <acronym title="Graphical User Interface">GUI</acronym>) and also for methods with side effects. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT5 SECTION "GUI Gets Return Value from Java Method" [6725-7912] --> |
||||
<h3><a>Java Modifies Nifty Elements and Events</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
You can also alter the appearance and functions of your nifty elements from Java. Make certain that the element that you want to alter has its <code>id="name"</code> attribute set, so you can identy and address it. |
||||
</p> |
||||
|
||||
<p> |
||||
Here's an example of how to change an image called <code>playerhealth</code>: |
||||
</p> |
||||
<pre>// load or create new image |
||||
NiftyImage img = nifty.getRenderEngine().createImage("Interface/Images/face2.png", false); |
||||
// find old image |
||||
Element niftyElement = nifty.getCurrentScreen().findElementByName("playerhealth"); |
||||
// swap old with new image |
||||
niftyElement.getRenderer(ImageRenderer.class).setImage(img);</pre> |
||||
|
||||
<p> |
||||
The same is valid for other elements, for example a text label "score": |
||||
</p> |
||||
<pre>// find old text |
||||
Element niftyElement = nifty.getCurrentScreen().findElementByName("score"); |
||||
// swap old with new text |
||||
niftyElement.getRenderer(TextRenderer.class).setText("124");</pre> |
||||
|
||||
<p> |
||||
Similarly, to change the onClick() event of an element, create an <code>ElementInteraction</code> object: |
||||
</p> |
||||
<pre>Element niftyElement = nifty.getCurrentScreen().findElementByName("myElement"); |
||||
niftyElement.getElementInteraction().getPrimary().setOnMouseOver(new NiftyMethodInvoker(nifty, "myCustomMethod()", this));</pre> |
||||
|
||||
<p> |
||||
For this to work, there already needs to be a (possibly inactive) <code><interact /></code> tag inside your xml element: |
||||
|
||||
</p> |
||||
<pre><span><interact onClick="doNothing()"/></span></pre> |
||||
|
||||
</div> |
||||
<!-- EDIT6 SECTION "Java Modifies Nifty Elements and Events" [7913-9329] --> |
||||
<h2><a>Next Steps</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
You're done with the basic Nifty <acronym title="Graphical User Interface">GUI</acronym> for jME3 tutorial. You can proceed to advanced topics and learn how add controls and effects: |
||||
</p> |
||||
<ul> |
||||
<li><div> <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_scenarios.html"> Nifty GUI Scenarios</a></div> |
||||
</li> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://sourceforge.net/projects/nifty-gui/files/nifty-gui/nifty-gui-the-manual-v1.0.pdf/download"><param name="text" value="<html><u>Nifty GUI - the Manual</u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
</ul> |
||||
<div><span> |
||||
<a href="/wiki/doku.php/tag:gui?do=showtag&tag=tag%3Agui">gui</a>, |
||||
<a href="/wiki/doku.php/tag:documentation?do=showtag&tag=tag%3Adocumentation">documentation</a>, |
||||
<a href="/wiki/doku.php/tag:input?do=showtag&tag=tag%3Ainput">input</a>, |
||||
<a href="/wiki/doku.php/tag:control?do=showtag&tag=tag%3Acontrol">control</a>, |
||||
<a href="/wiki/doku.php/tag:hud?do=showtag&tag=tag%3Ahud">hud</a>, |
||||
<a href="/wiki/doku.php/tag:nifty?do=showtag&tag=tag%3Anifty">nifty</a> |
||||
</span></div> |
||||
|
||||
</div> |
||||
<!-- EDIT7 SECTION "Next Steps" [9330-] --> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:nifty_gui_java_interaction?do=export_xhtmlbody">view online version</a></em></p> |
@ -1,642 +0,0 @@ |
||||
|
||||
<h1><a>Laying Out the GUI in Java</a></h1> |
||||
<div> |
||||
<ol> |
||||
<li><div> <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui.html">Nifty GUI Concepts</a></div> |
||||
</li> |
||||
<li><div> <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_best_practices.html">Nifty GUI Best Practices</a></div> |
||||
</li> |
||||
<li><div> <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_xml_layout.html">Nifty GUI XML Layout</a> or <strong>Nifty <acronym title="Graphical User Interface">GUI</acronym> Java Layout</strong></div> |
||||
</li> |
||||
<li><div> <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_overlay.html">Nifty GUI Overlay</a> or <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_projection.html">Nifty GUI Projection</a></div> |
||||
</li> |
||||
<li><div> <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_java_interaction.html">Interact with the GUI from Java</a></div> |
||||
</li> |
||||
</ol> |
||||
|
||||
<p> |
||||
|
||||
<strong>Work in progress</strong> You can "draw" the <acronym title="Graphical User Interface">GUI</acronym> to the screen by writing Java code ??? alternatively to using <acronym title="Extensible Markup Language">XML</acronym>. Typically you lay out the static base <acronym title="Graphical User Interface">GUI</acronym> in <acronym title="Extensible Markup Language">XML</acronym>, and use Java commands if you need to change the <acronym title="Graphical User Interface">GUI</acronym> dynamically at runtime. In theory, you can also lay out the whole <acronym title="Graphical User Interface">GUI</acronym> in Java (but we don't cover that here). |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT1 SECTION "Laying Out the GUI in Java" [1-690] --> |
||||
<h2><a>Sample Code</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Sample project |
||||
</p> |
||||
<ul> |
||||
<li><div> <strong>Original Source Code:</strong> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://nifty-gui.svn.sourceforge.net/viewvc/nifty-gui/nifty-default-controls-examples/trunk/src/main/java/de/lessvoid/nifty/examples/"><param name="text" value="<html><u>/nifty-default-controls-examples/trunk/src/main/java/de/lessvoid/nifty/examples/</u></html>"><param name="textColor" value="blue"></object>. <br/> |
||||
</div> |
||||
</li> |
||||
<li><div> <strong>Download demo project:</strong> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://files.seapegasus.org/NiftyGuiDemo.zip"><param name="text" value="<html><u>http://files.seapegasus.org/NiftyGuiDemo.zip</u></html>"><param name="textColor" value="blue"></object> (jme3-ready) <br/> |
||||
The full demo ZIP is based on <code>de.lessvoid.nifty.examples.controls.ControlsDemo.java</code>.</div> |
||||
<ol> |
||||
<li><div> The demo is a SimpleApplication-based game (use e.g. the BasicGame template in the jMonkeyEngine <acronym title="Software Development Kit">SDK</acronym>).</div> |
||||
</li> |
||||
<li><div> Copy images and sound files into your project's <code>assets/Interface/</code> directory. (In this example, I copied them from <code>nifty-default-controls-examples/trunk/src/main/resources/</code> to <code>assets/Interface/</code>).</div> |
||||
</li> |
||||
<li><div> Make sure to use paths relative to your project's <code>assets/</code> directory.</div> |
||||
<ul> |
||||
<li><div> E.g. for .fnt/.png/.jpg files use <code>filename("Interface/yang.png");</code> ( not <code>filename("yang.png");</code>).</div> |
||||
</li> |
||||
<li><div> E.g. for .wav/.ogg files use <code>filename("Interface/sounds/gong.wav");</code> (not <code>filename("sounds/gong.wav");</code>).</div> |
||||
</li> |
||||
</ul> |
||||
</li> |
||||
</ol> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
|
||||
Just so you get a quick picture what Nifty <acronym title="Graphical User Interface">GUI</acronym>'s Java Syntax looks like, here is the most basic example. It creates a screen with a layer and a panel that contains a button. |
||||
</p> |
||||
<pre>package mygame; |
||||
|
||||
import com.jme3.app.SimpleApplication; |
||||
import com.jme3.niftygui.NiftyJmeDisplay; |
||||
import de.lessvoid.nifty.Nifty; |
||||
import de.lessvoid.nifty.builder.ScreenBuilder; |
||||
import de.lessvoid.nifty.builder.LayerBuilder; |
||||
import de.lessvoid.nifty.builder.PanelBuilder; |
||||
import de.lessvoid.nifty.controls.button.builder.ButtonBuilder; |
||||
import de.lessvoid.nifty.screen.DefaultScreenController; |
||||
|
||||
<span>/** |
||||
* @author iamcreasy |
||||
*/</span> |
||||
public class Main extends SimpleApplication { |
||||
|
||||
public static void main(String[] args) { |
||||
Main app = new Main(); |
||||
app.start(); |
||||
} |
||||
|
||||
@Override |
||||
public void simpleInitApp() { |
||||
NiftyJmeDisplay niftyDisplay = new NiftyJmeDisplay( |
||||
assetManager, inputManager, audioRenderer, guiViewPort); |
||||
Nifty nifty = niftyDisplay.getNifty(); |
||||
guiViewPort.addProcessor(niftyDisplay); |
||||
flyCam.setDragToRotate(true); |
||||
|
||||
nifty.loadStyleFile("nifty-default-styles.xml"); |
||||
nifty.loadControlFile("nifty-default-controls.xml"); |
||||
|
||||
// <screen> |
||||
nifty.addScreen("Screen_ID", new ScreenBuilder("Hello Nifty Screen"){{ |
||||
controller(new DefaultScreenController()); // Screen properties |
||||
|
||||
// <layer> |
||||
layer(new LayerBuilder("Layer_ID") {{ |
||||
childLayoutVertical(); // layer properties, add more... |
||||
|
||||
// <panel> |
||||
panel(new PanelBuilder("Panel_ID") {{ |
||||
childLayoutCenter(); // panel properties, add more... |
||||
|
||||
// GUI elements |
||||
control(new ButtonBuilder("Button_ID", "Hello Nifty"){{ |
||||
alignCenter(); |
||||
valignCenter(); |
||||
height("5%"); |
||||
width("15%"); |
||||
}}); |
||||
|
||||
//.. add more GUI elements here |
||||
|
||||
}}); |
||||
// </panel> |
||||
}}); |
||||
// </layer> |
||||
}}.build(nifty)); |
||||
// </screen> |
||||
|
||||
nifty.gotoScreen("Screen_ID"); // start the screen |
||||
} |
||||
}</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT2 SECTION "Sample Code" [691-3958] --> |
||||
<h2><a>Implement Your GUI Layout</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
<img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/gui-layout-draft.png"> |
||||
</p> |
||||
|
||||
<p> |
||||
In this tutorial, you recreate the same screen as in the Nifty <acronym title="Graphical User Interface">GUI</acronym> <acronym title="Extensible Markup Language">XML</acronym> example. |
||||
</p> |
||||
|
||||
<p> |
||||
Create an Screen.Java file in the <code>assets/Interfaces/</code> directory of your project. One Java 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). |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT3 SECTION "Implement Your GUI Layout" [3959-4495] --> |
||||
<h3><a>Make Screens</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
The following minimal Java file contains a start screen and a HUD screen. (Neither has been defined yet.) |
||||
</p> |
||||
<pre>nifty.addScreen("start", new ScreenBuilder("start"){{ |
||||
controller(new DefaultScreenController()); |
||||
// <!-- ... --> |
||||
}}.build(nifty)); |
||||
|
||||
nifty.addScreen("hud", new ScreenBuilder("hud"){{ |
||||
controller(new DefaultScreenController()); |
||||
// <!-- ... --> |
||||
}}.build(nifty));</pre> |
||||
|
||||
<p> |
||||
Every Nifty <acronym title="Graphical User Interface">GUI</acronym> must have a start screen. The others (in this example, the HUD screen) are optional. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT4 SECTION "Make Screens" [4496-5030] --> |
||||
<h3><a>Make Layers</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
The following Java code shows how we add layers to the start screen and HUD screen: |
||||
</p> |
||||
<pre>nifty.addScreen("start", new ScreenBuilder("start"){{ |
||||
controller(new DefaultScreenController()); |
||||
|
||||
// layer added |
||||
layer(new LayerBuilder("background") {{ |
||||
childLayoutCenter(); |
||||
backgroundColor("#000f"); |
||||
|
||||
// <!-- ... --> |
||||
}}); |
||||
|
||||
layer(new LayerBuilder("foreground") {{ |
||||
childLayoutVertical(); |
||||
backgroundColor("#0000"); |
||||
|
||||
// <!-- ... --> |
||||
}}); |
||||
// layer added |
||||
|
||||
}}.build(nifty));</pre> |
||||
|
||||
<p> |
||||
Repeat the same, but use |
||||
</p> |
||||
<pre>nifty.addScreen("hud", new ScreenBuilder("hud"){{</pre> |
||||
|
||||
<p> |
||||
for the HUD screen. |
||||
</p> |
||||
|
||||
<p> |
||||
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. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT5 SECTION "Make Layers" [5031-5968] --> |
||||
<h3><a>Make Panels</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
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 <code>start</code> screen: |
||||
</p> |
||||
<pre> nifty.addScreen("start", new ScreenBuilder("start") {{ |
||||
controller(new DefaultScreenController()); |
||||
layer(new LayerBuilder("background") {{ |
||||
childLayoutCenter(); |
||||
backgroundColor("#000f"); |
||||
// <!-- ... --> |
||||
}}); |
||||
|
||||
layer(new LayerBuilder("foreground") {{ |
||||
childLayoutVertical(); |
||||
backgroundColor("#0000"); |
||||
|
||||
// panel added |
||||
panel(new PanelBuilder("panel_top") {{ |
||||
childLayoutCenter(); |
||||
alignCenter(); |
||||
backgroundColor("#f008"); |
||||
height("25%"); |
||||
width("75%"); |
||||
}}); |
||||
|
||||
panel(new PanelBuilder("panel_mid") {{ |
||||
childLayoutCenter(); |
||||
alignCenter(); |
||||
backgroundColor("#0f08"); |
||||
height("50%"); |
||||
width("75%"); |
||||
}}); |
||||
|
||||
panel(new PanelBuilder("panel_bottom") {{ |
||||
childLayoutHorizontal(); |
||||
alignCenter(); |
||||
backgroundColor("#00f8"); |
||||
height("25%"); |
||||
width("75%"); |
||||
|
||||
panel(new PanelBuilder("panel_bottom_left") {{ |
||||
childLayoutCenter(); |
||||
valignCenter(); |
||||
backgroundColor("#44f8"); |
||||
height("50%"); |
||||
width("50%"); |
||||
}}); |
||||
|
||||
panel(new PanelBuilder("panel_bottom_right") {{ |
||||
childLayoutCenter(); |
||||
valignCenter(); |
||||
backgroundColor("#88f8"); |
||||
height("50%"); |
||||
width("50%"); |
||||
}}); |
||||
}}); // panel added |
||||
}}); |
||||
|
||||
}}.build(nifty));</pre> |
||||
|
||||
<p> |
||||
The following panels go into in the <code>hud</code> screen: |
||||
</p> |
||||
<pre> nifty.addScreen("hud", new ScreenBuilder("hud") {{ |
||||
controller(new DefaultScreenController()); |
||||
|
||||
layer(new LayerBuilder("background") {{ |
||||
childLayoutCenter(); |
||||
backgroundColor("#000f"); |
||||
// <!-- ... --> |
||||
}}); |
||||
|
||||
layer(new LayerBuilder("foreground") {{ |
||||
childLayoutHorizontal(); |
||||
backgroundColor("#0000"); |
||||
|
||||
// panel added |
||||
panel(new PanelBuilder("panel_left") {{ |
||||
childLayoutVertical(); |
||||
backgroundColor("#0f08"); |
||||
height("100%"); |
||||
width("80%"); |
||||
// <!-- spacer --> |
||||
}}); |
||||
|
||||
panel(new PanelBuilder("panel_right") {{ |
||||
childLayoutVertical(); |
||||
backgroundColor("#00f8"); |
||||
height("100%"); |
||||
width("20%"); |
||||
|
||||
panel(new PanelBuilder("panel_top_right1") {{ |
||||
childLayoutCenter(); |
||||
backgroundColor("#00f8"); |
||||
height("15%"); |
||||
width("100%"); |
||||
}}); |
||||
|
||||
panel(new PanelBuilder("panel_top_right2") {{ |
||||
childLayoutCenter(); |
||||
backgroundColor("#44f8"); |
||||
height("15%"); |
||||
width("100%"); |
||||
}}); |
||||
|
||||
panel(new PanelBuilder("panel_bot_right") {{ |
||||
childLayoutCenter(); |
||||
valignCenter(); |
||||
backgroundColor("#88f8"); |
||||
height("70%"); |
||||
width("100%"); |
||||
}}); |
||||
}}); // panel added |
||||
}}); |
||||
}}.build(nifty));</pre> |
||||
|
||||
<p> |
||||
Try the sample. Remember to activate a screen using <code>nifty.gotoScreen("start");</code> or <code>hud</code> respectively. |
||||
The result should look as follows: |
||||
</p> |
||||
|
||||
<p> |
||||
<img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/nifty-gui-panels.png"> |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT6 SECTION "Make Panels" [5969-9926] --> |
||||
<h2><a>Adding Content to Panels</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
See also <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://sourceforge.net/apps/mediawiki/nifty-gui/index.php?title=Layout_Introduction"><param name="text" value="<html><u>Layout Introduction</u></html>"><param name="textColor" value="blue"></object> on the Nifty <acronym title="Graphical User Interface">GUI</acronym> site. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT7 SECTION "Adding Content to Panels" [9927-10105] --> |
||||
<h3><a>Add Images</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
The start-background.png image is a fullscreen background picture. In the <code>start</code> screen, add the following image element: |
||||
|
||||
</p> |
||||
<pre> nifty.addScreen("start", new ScreenBuilder("start") {{ |
||||
controller(new DefaultScreenController()); |
||||
layer(new LayerBuilder("background") {{ |
||||
childLayoutCenter(); |
||||
backgroundColor("#000f"); |
||||
|
||||
// add image |
||||
image(new ImageBuilder() {{ |
||||
filename("Interface/tutorial/start-background.png"); |
||||
}}); |
||||
|
||||
}});</pre> |
||||
|
||||
<p> |
||||
The hud-frame.png image is a transparent frame that we use as HUD decoration. In the <code>hud</code> screen, add the following image element: |
||||
|
||||
</p> |
||||
<pre> nifty.addScreen("hud", new ScreenBuilder("hud") {{ |
||||
controller(new DefaultScreenController()); |
||||
|
||||
layer(new LayerBuilder("background") {{ |
||||
childLayoutCenter(); |
||||
backgroundColor("#000f"); |
||||
|
||||
// add image |
||||
image(new ImageBuilder() {{ |
||||
filename("Interface/tutorial/hud-frame.png"); |
||||
}}); |
||||
|
||||
}});</pre> |
||||
|
||||
<p> |
||||
The face1.png image is an image that you want to use as a status icon. |
||||
In the <code>hud</code> screen's <code>foreground</code> layer, add the following image element: |
||||
|
||||
</p> |
||||
<pre> panel(new PanelBuilder("panel_top_right2") {{ |
||||
childLayoutCenter(); |
||||
backgroundColor("#44f8"); |
||||
height("15%"); |
||||
width("100%"); |
||||
|
||||
// add image |
||||
image(new ImageBuilder() {{ |
||||
filename("Interface/tutorial/face1.png"); |
||||
valignCenter(); |
||||
alignCenter(); |
||||
height("50%"); |
||||
width("30%"); |
||||
}}); |
||||
|
||||
}});</pre> |
||||
|
||||
<p> |
||||
|
||||
This image is scaled to use 50% of the height and 30% of the width of its container. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT8 SECTION "Add Images" [10106-12093] --> |
||||
<h3><a>Add Static Text</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
The game title is a typical example of static text. In the <code>start</code> screen, add the following text element: |
||||
|
||||
</p> |
||||
<pre> // panel added |
||||
panel(new PanelBuilder("panel_top") {{ |
||||
childLayoutCenter(); |
||||
alignCenter(); |
||||
backgroundColor("#f008"); |
||||
height("25%"); |
||||
width("75%"); |
||||
|
||||
// add text |
||||
text(new TextBuilder() {{ |
||||
text("My Cool Game"); |
||||
font("Interface/Fonts/Default.fnt"); |
||||
height("100%"); |
||||
width("100%"); |
||||
}}); |
||||
|
||||
}});</pre> |
||||
|
||||
<p> |
||||
For longer pieces of static text, such as an introduction, you can use wrap="true". Add the following text element to the <code>Start screen</code>: |
||||
</p> |
||||
<pre> panel(new PanelBuilder("panel_mid") {{ |
||||
childLayoutCenter(); |
||||
alignCenter(); |
||||
backgroundColor("#0f08"); |
||||
height("50%"); |
||||
width("75%"); |
||||
// add text |
||||
text(new TextBuilder() {{ |
||||
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"); |
||||
wrap(true); |
||||
height("100%"); |
||||
width("100%"); |
||||
}}); |
||||
|
||||
}});</pre> |
||||
|
||||
<p> |
||||
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 <code>assets/Interface</code> directory. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT9 SECTION "Add Static Text" [12094-13843] --> |
||||
<h3><a>Add Controls</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Before you can use any control, you must load a Control Definition first. Add the following two lines <em>before</em> your screen definitions: |
||||
</p> |
||||
<pre> nifty.loadStyleFile("nifty-default-styles.xml"); |
||||
nifty.loadControlFile("nifty-default-controls.xml");</pre> |
||||
|
||||
</div> |
||||
|
||||
<h4><a>Label Control</a></h4> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Use label controls for text that you want to edit dynamically from Java. One example for this is the score display. |
||||
In the <code>hud</code> screen's <code>foreground</code> layer, add the following text element: |
||||
</p> |
||||
<pre> panel(new PanelBuilder("panel_top_right1") {{ |
||||
childLayoutCenter(); |
||||
backgroundColor("#00f8"); |
||||
height("15%"); |
||||
width("100%"); |
||||
|
||||
control(new LabelBuilder(){{ |
||||
color("#000"); |
||||
text("123"); |
||||
width("100%"); |
||||
height("100%"); |
||||
}});</pre> |
||||
|
||||
<p> |
||||
Note that the width and height do not scale the bitmap font, but 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). |
||||
</p> |
||||
|
||||
</div> |
||||
|
||||
<h4><a>Button Control</a></h4> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Our <acronym title="Graphical User Interface">GUI</acronym> plan asks for two buttons on the start screen. You add the Start and Quit buttons to the bottom panel of the <code>start</code> screen using the <code><control></code> element: |
||||
</p> |
||||
<pre> panel(new PanelBuilder("panel_bottom_left") {{ |
||||
childLayoutCenter(); |
||||
valignCenter(); |
||||
backgroundColor("#44f8"); |
||||
height("50%"); |
||||
width("50%"); |
||||
|
||||
// add control |
||||
control(new ButtonBuilder("StartButton", "Start") {{ |
||||
alignCenter(); |
||||
valignCenter(); |
||||
height("50%"); |
||||
width("50%"); |
||||
}}); |
||||
|
||||
}}); |
||||
|
||||
panel(new PanelBuilder("panel_bottom_right") {{ |
||||
childLayoutCenter(); |
||||
valignCenter(); |
||||
backgroundColor("#88f8"); |
||||
height("50%"); |
||||
width("50%"); |
||||
|
||||
// add control |
||||
control(new ButtonBuilder("QuitButton", "Quit") {{ |
||||
alignCenter(); |
||||
valignCenter(); |
||||
height("50%"); |
||||
width("50%"); |
||||
}}); |
||||
|
||||
}});</pre> |
||||
|
||||
<p> |
||||
Note that these controls don't do anything yet ??? we'll get to that soon. |
||||
</p> |
||||
|
||||
</div> |
||||
|
||||
<h4><a>Other Controls</a></h4> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Nifty additionally offers many customizable controls such as check boxes, text fields, menus, chats, tabs, ??? See also <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://sourceforge.net/apps/mediawiki/nifty-gui/index.php?title=Elements"><param name="text" value="<html><u>Elements</u></html>"><param name="textColor" value="blue"></object> on the Nifty <acronym title="Graphical User Interface">GUI</acronym> site. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT10 SECTION "Add Controls" [13844-16777] --> |
||||
<h2><a>Intermediate Result</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
When you preview this code in the jMonkeyEngine <acronym title="Software Development Kit">SDK</acronym>, our tutorial demo should looks as follows: A start screen with two buttons, and a game screen with a simple HUD frame and a blue cube (which stands for any jME3 game content). |
||||
</p> |
||||
|
||||
<p> |
||||
<strong>Tip:</strong> Remove all lines that set background colors, you only needed them to see the arrangement. |
||||
</p> |
||||
|
||||
<p> |
||||
<img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/nifty-gui-simple-demo.png"> |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT11 SECTION "Intermediate Result" [16778-17190] --> |
||||
<h2><a>Nifty Java Settings</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Before initializing the nifty screens, you set up properties and register media. |
||||
</p> |
||||
<div><table> |
||||
<tr> |
||||
<th> Nifty Method </th><th> Description </th> |
||||
</tr> |
||||
<tr> |
||||
<td> registerSound("mysound", "Interface/abc.wav"); </td><td> </td> |
||||
</tr> |
||||
<tr> |
||||
<td> registerMusic("mymusic", "Interface/xyz.ogg"); </td><td> </td> |
||||
</tr> |
||||
<tr> |
||||
<td> registerMouseCursor("mypointer", "Interface/abc.png", 5, 4); </td><td> </td> |
||||
</tr> |
||||
<tr> |
||||
<td> registerEffect(?); </td><td> ? </td> |
||||
</tr> |
||||
<tr> |
||||
<td> setDebugOptionPanelColors(true);</td><td> Highlight all panels, makes it easier to arrange them. </td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT13 TABLE [17305-17628] --> |
||||
<p> |
||||
|
||||
Example: |
||||
</p> |
||||
<pre>nifty.registerMouseCursor("hand", "Interface/mouse-cursor-hand.png", 5, 4);</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT12 SECTION "Nifty Java Settings" [17191-17733] --> |
||||
<h2><a>Next Steps</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Integrate the <acronym title="Graphical User Interface">GUI</acronym> into the game. Typically, you will overlay the <acronym title="Graphical User Interface">GUI</acronym>. |
||||
</p> |
||||
<ul> |
||||
<li><div> <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_overlay.html">Nifty GUI Overlay</a> (recommended)</div> |
||||
</li> |
||||
<li><div> <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_projection.html">Nifty GUI Projection</a> (optional)</div> |
||||
</li> |
||||
</ul> |
||||
<div><span> |
||||
<a href="/wiki/doku.php/tag:gui?do=showtag&tag=tag%3Agui">gui</a>, |
||||
<a href="/wiki/doku.php/tag:documentation?do=showtag&tag=tag%3Adocumentation">documentation</a>, |
||||
<a href="/wiki/doku.php/tag:nifty?do=showtag&tag=tag%3Anifty">nifty</a>, |
||||
<a href="/wiki/doku.php/tag:hud?do=showtag&tag=tag%3Ahud">hud</a> |
||||
</span></div> |
||||
|
||||
</div> |
||||
<!-- EDIT14 SECTION "Next Steps" [17734-] --> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:nifty_gui_java_layout?do=export_xhtmlbody">view online version</a></em></p> |
@ -1,92 +0,0 @@ |
||||
|
||||
<h1><a>Integrating Nifty GUI: Overlay</a></h1> |
||||
<div> |
||||
<ol> |
||||
<li><div> <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui.html">Nifty GUI Concepts</a></div> |
||||
</li> |
||||
<li><div> <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_best_practices.html">Nifty GUI Best Practices</a></div> |
||||
</li> |
||||
<li><div> <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_xml_layout.html">Nifty GUI XML Layout</a> or <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_java_layout.html">Nifty GUI Java Layout</a></div> |
||||
</li> |
||||
<li><div> <strong>Nifty <acronym title="Graphical User Interface">GUI</acronym> Overlay</strong> or <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_projection.html">Nifty GUI Projection</a></div> |
||||
</li> |
||||
<li><div> <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_java_interaction.html">Interact with the GUI from Java</a></div> |
||||
</li> |
||||
</ol> |
||||
|
||||
<p> |
||||
|
||||
<img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/nifty-gui-example.png"> |
||||
</p> |
||||
|
||||
<p> |
||||
Typically, you define a key (for example escape) that switches the <acronym title="Graphical User Interface">GUI</acronym> on and off. The <acronym title="Graphical User Interface">GUI</acronym> can be a StartScreen, OptionsScreen, CharacterCreationScreen, etc. While the <acronym title="Graphical User Interface">GUI</acronym> is up, you pause the running game, and then overlay the <acronym title="Graphical User Interface">GUI</acronym>. 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 <acronym title="Graphical User Interface">GUI</acronym>. |
||||
</p> |
||||
|
||||
<p> |
||||
You can also <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_projection.html">project</a> the <acronym title="Graphical User Interface">GUI</acronym> 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. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT1 SECTION "Integrating Nifty GUI: Overlay" [1-1043] --> |
||||
<h2><a>Sample Code</a></h2> |
||||
<div> |
||||
<ul> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/niftygui/TestNiftyGui.java"><param name="text" value="<html><u>TestNiftyGui.java</u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT2 SECTION "Sample Code" [1044-1206] --> |
||||
<h2><a>Overlaying the User Interface Over the Screen</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
This code shows you how to overlay anything on the screen with the <acronym title="Graphical User Interface">GUI</acronym>. This is the most common usecase. |
||||
</p> |
||||
<pre>NiftyJmeDisplay niftyDisplay = new NiftyJmeDisplay( |
||||
assetManager, inputManager, audioRenderer, guiViewPort); |
||||
/** Create a new NiftyGUI object */ |
||||
Nifty nifty = niftyDisplay.getNifty(); |
||||
/** Read your XML and initialize your custom ScreenController */ |
||||
nifty.fromXml("Interface/tutorial/step2/screen.xml", "start"); |
||||
// nifty.fromXml("Interface/helloworld.xml", "start", new MySettingsScreen(data)); |
||||
// attach the Nifty display to the gui view port as a processor |
||||
guiViewPort.addProcessor(niftyDisplay); |
||||
// disable the fly cam |
||||
flyCam.setDragToRotate(true);</pre> |
||||
|
||||
<p> |
||||
Currently you do not have a ScreenController ??? we will create one in the next exercise. As soon as you have a screen controller, you will use the commented variant of the <acronym title="Extensible Markup Language">XML</acronym> loading method: |
||||
</p> |
||||
<pre>nifty.fromXml("Interface/helloworld.xml", "start", new MySettingsScreen());</pre> |
||||
|
||||
<p> |
||||
The <code>MySettingsScreen</code> class is a custom de.lessvoid.nifty.screen.ScreenController in which you will implement your <acronym title="Graphical User Interface">GUI</acronym> behaviour. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT3 SECTION "Overlaying the User Interface Over the Screen" [1207-2372] --> |
||||
<h2><a>Next Steps</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Now that you have layed out and integrated the <acronym title="Graphical User Interface">GUI</acronym> in your app, you want to respond to user input and display the current game. Time to create a ScreenController! |
||||
</p> |
||||
<ul> |
||||
<li><div> <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_java_interaction.html">Interact with the GUI from Java</a></div> |
||||
</li> |
||||
</ul> |
||||
<div><span> |
||||
<a href="/wiki/doku.php/tag:gui?do=showtag&tag=tag%3Agui">gui</a>, |
||||
<a href="/wiki/doku.php/tag:documentation?do=showtag&tag=tag%3Adocumentation">documentation</a>, |
||||
<a href="/wiki/doku.php/tag:nifty?do=showtag&tag=tag%3Anifty">nifty</a>, |
||||
<a href="/wiki/doku.php/tag:hud?do=showtag&tag=tag%3Ahud">hud</a> |
||||
</span></div> |
||||
|
||||
</div> |
||||
<!-- EDIT4 SECTION "Next Steps" [2373-] --> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:nifty_gui_overlay?do=export_xhtmlbody">view online version</a></em></p> |
@ -1,94 +0,0 @@ |
||||
|
||||
<h1><a>Nifty GUI: Create a PopUp Menu</a></h1> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Even though you create and populate the popup menu in Java, you still need a "placeholder" in your <acronym title="Extensible Markup Language">XML</acronym> file. |
||||
The popup element needs to be placed <em>outside</em> of any screen! |
||||
</p> |
||||
<pre><span><useControls filename="nifty-default-controls.xml"/></span> |
||||
... |
||||
<span><popup id="niftyPopupMenu" childLayout="absolute-inside"</span> |
||||
<span> controller="ControllerOfYourChoice" width="10%"></span> |
||||
<span><interact onClick="closePopup()" onSecondaryClick="closePopup()" onTertiaryClick="closePopup()" /></span> |
||||
<span><control id="#menu" name="niftyMenu" /></span> |
||||
<span><span></popup></span></span> |
||||
...</pre> |
||||
|
||||
<p> |
||||
A brief explanation of some the attributes above: |
||||
</p> |
||||
<ul> |
||||
<li><div> The popup id is used within your Java code so that nifty knows which popup placeholder to create.</div> |
||||
</li> |
||||
<li><div> The Controller tells Nifty which Java class handles MenuItemActivatedEvent.</div> |
||||
</li> |
||||
<li><div> The on(Secondary/Tertiary)Click tells Nifty to close the popup if the user clicks anywhere except on the menu items (in this example; you have to define the closePopup()-method yourself, in the screen controller)</div> |
||||
</li> |
||||
<li><div> The control id is used by the Java class to define a control type (i.e. Menu)</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
|
||||
The Java code within your defined ScreenController implementation: |
||||
</p> |
||||
<pre>private Element popup; |
||||
... |
||||
public void createMyPopupMenu(){ |
||||
popup = nifty.createPopup("niftyPopupMenu"); |
||||
Menu myMenu = popup.findNiftyControl("#menu", Menu.class); |
||||
myMenu.setWidth(new SizeValue("100px")); // must be set |
||||
myMenu.addMenuItem("Click me!", "menuItemIcon.png", |
||||
new menuItem("menuItemid", "blah blah")); // menuItem is a custom class |
||||
nifty.subscribe( |
||||
nifty.getCurrentScreen(), |
||||
myMenu.getId(), |
||||
MenuItemActivatedEvent.class, |
||||
new MenuItemActivatedEventSubscriber()); |
||||
} |
||||
|
||||
public void showMenu() { // the method to trigger the menu |
||||
// If this is a menu that is going to be used many times, then |
||||
// call this in your constructor rather than here |
||||
createMyPopupMenu() |
||||
// call the popup to screen of your choice: |
||||
nifty.showPopup(nifty.getCurrentScreen(), popup.getId(), null); |
||||
} |
||||
|
||||
private class menuItem { |
||||
public String id; |
||||
public String name; |
||||
public menuItem(String id, String name){ |
||||
this.id= id; |
||||
this.name = name; |
||||
} |
||||
}</pre> |
||||
<ul> |
||||
<li><div> The createMyPopupMenu() method creates the menu with set width so that you can populate it.</div> |
||||
</li> |
||||
<li><div> The showMenu() method is called by something to trigger the menu (i.e. could be a Key or some other method).</div> |
||||
</li> |
||||
<li><div> Note: if you want to be able to access the popup via your id, use createPopupWithId(id, id) instead.</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
|
||||
To handle menu item events (i.e. calling a method when you click on a menu item), you register (subscribe) a EventTopicSubscriber<MenuItemActivatedEvent> class implementation to a nifty screen and element. |
||||
</p> |
||||
<pre> private class MenuItemActivatedEventSubscriber |
||||
implements EventTopicSubscriber<MenuItemActivatedEvent> { |
||||
|
||||
@Override |
||||
public void onEvent(final String id, final MenuItemActivatedEvent event) { |
||||
menuItem item = (menuItem) event.getItem(); |
||||
if ("menuItemid".equals(item.id)) { |
||||
//do something !!! |
||||
} |
||||
} |
||||
};</pre> |
||||
|
||||
</div> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:nifty_gui_popup_menu?do=export_xhtmlbody">view online version</a></em></p> |
@ -1,111 +0,0 @@ |
||||
|
||||
<h1><a>Integrating Nifty GUI: Projection</a></h1> |
||||
<div> |
||||
<ol> |
||||
<li><div> <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui.html">Nifty GUI Concepts</a></div> |
||||
</li> |
||||
<li><div> <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_best_practices.html">Nifty GUI Best Practices</a></div> |
||||
</li> |
||||
<li><div> <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_xml_layout.html">Nifty GUI XML Layout</a> or <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_java_layout.html">Nifty GUI Java Layout</a></div> |
||||
</li> |
||||
<li><div> <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_overlay.html">Nifty GUI Overlay</a> or <strong>Nifty <acronym title="Graphical User Interface">GUI</acronym> Projection</strong></div> |
||||
</li> |
||||
<li><div> <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_java_interaction.html">Interact with the GUI from Java</a></div> |
||||
</li> |
||||
</ol> |
||||
|
||||
<p> |
||||
|
||||
<img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/nifty-gui.png"> |
||||
</p> |
||||
|
||||
<p> |
||||
Typically you define a key (for example escape) to switch the <acronym title="Graphical User Interface">GUI</acronym> on and off. Then you <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_overlay.html">overlay</a> the running game with the <acronym title="Graphical User Interface">GUI</acronym> (you will most likely pause the game then). |
||||
</p> |
||||
|
||||
<p> |
||||
Alternatively, you can also project the <acronym title="Graphical User Interface">GUI</acronym> 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 <acronym title="Graphical User Interface">GUI</acronym> by keyboard, or programmatically. You can select input fields using the arrow keys, and trigger actions using the return key. |
||||
</p> |
||||
|
||||
<p> |
||||
This <acronym title="Graphical User Interface">GUI</acronym> projection variant is less commonly used than the <acronym title="Graphical User Interface">GUI</acronym> overlay variant. Usecases for <acronym title="Graphical User Interface">GUI</acronym> projection are, for example, a player avatar using an in-game computer screen. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT1 SECTION "Integrating Nifty GUI: Projection" [1-1192] --> |
||||
<h2><a>Sample Code</a></h2> |
||||
<div> |
||||
<ul> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/niftygui/TestNiftyToMesh.java"><param name="text" value="<html><u>TestNiftyToMesh.java</u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT2 SECTION "Sample Code" [1193-1360] --> |
||||
<h2><a>Projecting the User Interface Onto a Texture</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
You can project the Nifty <acronym title="Graphical User Interface">GUI</acronym> onto a texture, load the texture into a material, and assign it to a Geometry (Quads or Boxes are best). |
||||
</p> |
||||
<pre>/** 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 */ |
||||
NiftyJmeDisplay niftyDisplay = new NiftyJmeDisplay( |
||||
assetManager, inputManager, audioRenderer, niftyView); |
||||
/** Create a new NiftyGUI object */ |
||||
Nifty nifty = niftyDisplay.getNifty(); |
||||
/** Read your XML and initialize your custom ScreenController */ |
||||
nifty.fromXml("Interface/helloworld.xml", "start", new MySettingsScreen(data)); |
||||
|
||||
/** Prepare a framebuffer for the texture niftytex */ |
||||
niftyView.addProcessor(niftyDisplay); |
||||
FrameBuffer fb = new FrameBuffer(1024, 768, 0); |
||||
fb.setDepthBuffer(Format.Depth); |
||||
Texture2D niftytex = new Texture2D(1024, 768, Format.RGB8); |
||||
fb.setColorTexture(niftytex); |
||||
niftyView.setClearEnabled(true); |
||||
niftyView.setOutputFrameBuffer(fb); |
||||
|
||||
/** This is the 3D cube we project the GUI on */ |
||||
Box b = new Box(Vector3f.ZERO, 1, 1, 1); |
||||
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);</pre> |
||||
|
||||
<p> |
||||
The MySettingsScreen class is a custom de.lessvoid.nifty.screen.ScreenController in which you implement your <acronym title="Graphical User Interface">GUI</acronym> behaviour. The variable <code>data</code> contains an object that you use to exchange state info with the game. See <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_java_interaction.html">Nifty GUI Java Interaction</a> for details on how to create this class. |
||||
</p> |
||||
|
||||
<p> |
||||
Run the code sample. You select buttons on this <acronym title="Graphical User Interface">GUI</acronym> with the arrow keys and then press return. Note that clicking on the texture will not work! |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT3 SECTION "Projecting the User Interface Onto a Texture" [1361-3239] --> |
||||
<h2><a>Next Steps</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Now that you have layed out and integrated the <acronym title="Graphical User Interface">GUI</acronym> in your app, you want to respond to user input and display the current game. |
||||
</p> |
||||
<ul> |
||||
<li><div> <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_java_interaction.html">Interact with the GUI from Java</a></div> |
||||
</li> |
||||
</ul> |
||||
<div><span> |
||||
<a href="/wiki/doku.php/tag:gui?do=showtag&tag=tag%3Agui">gui</a>, |
||||
<a href="/wiki/doku.php/tag:documentation?do=showtag&tag=tag%3Adocumentation">documentation</a>, |
||||
<a href="/wiki/doku.php/tag:nifty?do=showtag&tag=tag%3Anifty">nifty</a>, |
||||
<a href="/wiki/doku.php/tag:hud?do=showtag&tag=tag%3Ahud">hud</a>, |
||||
<a href="/wiki/doku.php/tag:texture?do=showtag&tag=tag%3Atexture">texture</a> |
||||
</span></div> |
||||
|
||||
</div> |
||||
<!-- EDIT4 SECTION "Next Steps" [3240-] --> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:nifty_gui_projection?do=export_xhtmlbody">view online version</a></em></p> |
@ -1,349 +0,0 @@ |
||||
|
||||
<h1><a>Nifty GUI 1.3 - Usecase Scenarios</a></h1> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
This document contains typical NiftyGUI usecase scenarios, such as adding effects, game states, and creating typical game screens. |
||||
</p> |
||||
|
||||
<p> |
||||
Requirements: These tips assume that you have read and understood the <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui.html">Creating JME3 User Interfaces with Nifty GUI</a> tutorial, and have already laid out a basic <acronym title="Graphical User Interface">GUI</acronym> that interacts with your JME3 application. Here you learn how you integrate the <acronym title="Graphical User Interface">GUI</acronym> better, and add effects and advanced controls. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT1 SECTION "Nifty GUI 1.3 - Usecase Scenarios" [1-506] --> |
||||
<h2><a>Switch Game States</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
In a JME game, you typically have three game states: |
||||
</p> |
||||
<ol> |
||||
<li><div> Stopped: The game is stopped, a StartScreen is displayed. </div> |
||||
</li> |
||||
<li><div> Running: The game is running, the in-game HudScreen is displayed. </div> |
||||
</li> |
||||
<li><div> Paused: The game is paused, a PausedScreen is displayed.</div> |
||||
</li> |
||||
</ol> |
||||
|
||||
<p> |
||||
|
||||
(Aside: Additionally, the Stopped state often contains a LoadScreen, LogonScreen, OptionsScreen, CharacterCreationScreen, HighScoreScreen, CreditsScreen, etc. Some games let you access the OptionsScreen in the Paused state as well. The Running state can also contain an InventoryScreen, ItemShopScreen, StatsScreen, SkillScreen, etc.) |
||||
</p> |
||||
|
||||
<p> |
||||
In JME, game states are implemented as custom <a href="/com/jme3/gde/core/docs/jme3/advanced/application_states.html">AppState</a> objects. Write each AppState so it brings its own input mappings, rootNode content, update loop behaviour, etc with it. |
||||
</p> |
||||
<ol> |
||||
<li><div> Stopped: StartScreen AppState + GuiInputs AppState</div> |
||||
</li> |
||||
<li><div> Paused: PausedScreen AppState + GuiInputs AppState</div> |
||||
</li> |
||||
<li><div> Running: HudScreen AppState + InGameInputs AppState + BulletAppState (jme physics), ???</div> |
||||
</li> |
||||
</ol> |
||||
|
||||
<p> |
||||
|
||||
When the player switches between game states, you detach one set of AppStates, and attach another. For example, when the player pauses the running game, you use a boolean switch to pause the game loop and deactivate the game inputs (shooting, navigation). The screen is overlayed with a PausedScreen, which contains a visible mouse pointer and a Continue button. When the player clicks Continue, the mouse pointer is deactivated, the in-game input and navigational mappings are activated, and the game loop continues. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT2 SECTION "Switch Game States" [507-2043] --> |
||||
<h2><a>Get Access to Application and Update Loop</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Since you are writing a jME3 application, you can additionally make any ScreenController class extend the <a href="/com/jme3/gde/core/docs/jme3/advanced/application_states.html">AbstractAppState</a> class. |
||||
This gives the ScreenController access to the application object and to the update loop! |
||||
</p> |
||||
<pre>public class StartScreenState extends AbstractAppState { |
||||
|
||||
private ViewPort viewPort; |
||||
private Node rootNode; |
||||
private Node guiNode; |
||||
private AssetManager assetManager; |
||||
private Node localRootNode = new Node("Start Screen RootNode"); |
||||
private Node localGuiNode = new Node("Start Screen GuiNode"); |
||||
private final ColorRGBA backgroundColor = ColorRGBA.Gray; |
||||
|
||||
public StartScreenState(SimpleApplication app){ |
||||
this.rootNode = app.getRootNode(); |
||||
this.viewPort = app.getViewPort(); |
||||
this.guiNode = app.getGuiNode(); |
||||
this.assetManager = app.getAssetManager(); |
||||
} |
||||
|
||||
@Override |
||||
public void initialize(AppStateManager stateManager, Application app) { |
||||
super.initialize(stateManager, app); |
||||
/** init the screen */ |
||||
} |
||||
|
||||
@Override |
||||
public void update(float tpf) { |
||||
/** any main loop action happens here */ |
||||
} |
||||
|
||||
@Override |
||||
public void stateAttached(AppStateManager stateManager) { |
||||
rootNode.attachChild(localRootNode); |
||||
guiNode.attachChild(localGuiNode); |
||||
viewPort.setBackgroundColor(backgroundColor); |
||||
} |
||||
|
||||
@Override |
||||
public void stateDetached(AppStateManager stateManager) { |
||||
rootNode.detachChild(localRootNode); |
||||
guiNode.detachChild(localGuiNode); |
||||
} |
||||
|
||||
}</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT3 SECTION "Get Access to Application and Update Loop" [2044-3599] --> |
||||
<h2><a>Know Your Variables</a></h2> |
||||
<div> |
||||
<div><table> |
||||
<tr> |
||||
<th>Variable</th><th>Description</th> |
||||
</tr> |
||||
<tr> |
||||
<td>${CALL.myMethod()} </td><td> Calls a method in the current ScreenController and gets the method's return String. The method can also be void and have a side effect, e.g. play a sound etc.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>${ENV.HOME}</td><td> Returns the path to user's home directory.</td> |
||||
</tr> |
||||
<tr> |
||||
<td>${ENV.key} </td><td> Looks up <code>key</code> in the environment variables. Use it like Java's System.getEnv("key").</td> |
||||
</tr> |
||||
<tr> |
||||
<td>${PROP.key}</td><td> looks up <code>key</code> in the Nifty properties. Use Nifty.setGlobalproperties(properties) and Nifty.getGlobalproperties("key"). Or SystemGetProperties(key);</td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT5 TABLE [3632-4163] --> |
||||
<p> |
||||
|
||||
See also: <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://sourceforge.net/apps/mediawiki/nifty-gui/index.php?title=MarkUp"><param name="text" value="<html><u>http://sourceforge.net/apps/mediawiki/nifty-gui/index.php?title=MarkUp</u></html>"><param name="textColor" value="blue"></object> |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT4 SECTION "Know Your Variables" [3600-4246] --> |
||||
<h2><a>Use ScreenControllers for Mutally Exclusive Functionality</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Technically you are free to create one ScreenController class for each screen, or reuse the same ScreenController for all or some of them. In the end it may be best to create individual ScreenControllers for functionality that is mutually exclusive. |
||||
</p> |
||||
|
||||
<p> |
||||
For example, create a <code>MyHudScreen.java</code> for the <code>hud</code> screen, and a <code>MyStartScreen.java</code> for the <code>start</code> screen. |
||||
</p> |
||||
<ul> |
||||
<li><div> Include all user interface methods that are needed during the game (while the HUD is up) in <code>MyHudScreen.java</code>. Then make this class control all screens that can be up during the game (the HUD screen, a MiniMap screen, an Inventory screen, an Abilities or Skills screen, etc). All these screens possibly share data (game data, player data), so it makes sense to control them all with methods of the same <code>MyHudScreen.java</code> class.</div> |
||||
</li> |
||||
<li><div> The start screen, however, is mostly independent of the running game. Include all user interface methods that are needed outside the game (while you are on the start screen) in <code>MyStartScreen.java</code>. Then make this class control all screens that can be up outside the game (the Start screen, a Settings/Options screen, a HighScore screen, etc). All these classes need to read and write saved game data, so it makes sense to control them all with methods of the same <code>MyStartScreen.java</code> class.</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT6 SECTION "Use ScreenControllers for Mutally Exclusive Functionality" [4247-5629] --> |
||||
<h2><a>Create a "Loading..." Screen</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Get the full <a href="/com/jme3/gde/core/docs/jme3/advanced/loading_screen.html">Loading Screen</a> tutorial here. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT7 SECTION "Create a Loading... Screen" [5630-5734] --> |
||||
<h2><a>Create a Popup Menu</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Get the full <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_popup_menu.html">Nifty GUI PopUp Menu</a> tutorial here. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT8 SECTION "Create a Popup Menu" [5735-5837] --> |
||||
<h2><a>Add Visual Effects</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
You can register effects to screen elements. |
||||
</p> |
||||
<ul> |
||||
<li><div> Respond to element events such as onStartScreen, onEndScreen, onHover, onFocus, onActive,</div> |
||||
</li> |
||||
<li><div> Trigger effects that change movement, blending, size, color, fading, and much more.</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
|
||||
Here is an example that moves a panel when the startScreen opens. You place an < effect > tag inside the element that you want to be affected. |
||||
</p> |
||||
<pre><span><panel height="25%" width="35%" ...></span> |
||||
<span><span><effect></span></span> |
||||
<span><onStartScreen name="move" mode="in" direction="top" length="300" startDelay="0" inherit="true"/></span> |
||||
<span><span></effect></span></span> |
||||
<span><span></panel></span></span></pre> |
||||
|
||||
<p> |
||||
Learn more from the NiftyGUI page: |
||||
</p> |
||||
<ul> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://sourceforge.net/apps/mediawiki/nifty-gui/index.php?title=Effects"><param name="text" value="<html><u>http://sourceforge.net/apps/mediawiki/nifty-gui/index.php?title=Effects</u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT9 SECTION "Add Visual Effects" [5838-6550] --> |
||||
<h2><a>Add Sound Effects</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Playing sounds using Nifty is also possible with a <code>playSound</code> effect as trigger. Remember to first register the sound that you want to play: |
||||
</p> |
||||
<pre><span><registerSound id="myclick" filename="Interface/sounds/ButtonClick.ogg" /></span> |
||||
... |
||||
<span><span><label></span></span> |
||||
<span><span><effect></span></span> |
||||
<span><onClick name="playSound" sound="myclick"/></span> |
||||
<span><span></effect></span></span> |
||||
<span><span></label></span></span></pre> |
||||
|
||||
</div> |
||||
<!-- EDIT10 SECTION "Add Sound Effects" [6551-6913] --> |
||||
<h2><a>Pass ClickLoc From Nifty to Java</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
After a mouse click, you may want to record the 2D clickLoc and send this info to your Java application. Typical ScreenController methods however only have a String argument. You'd have to convert the String to ints. |
||||
</p> |
||||
|
||||
<p> |
||||
To pass the clickLoc as two ints, you can use the special <code>(int x, int y)</code> syntax in the ScreenController: |
||||
|
||||
</p> |
||||
<pre> public void clicked(int x, int y) { |
||||
// here you can use the x and y of the clickLoc |
||||
}</pre> |
||||
|
||||
<p> |
||||
|
||||
In the Nifty <acronym title="Graphical User Interface">GUI</acronym> screen code (e.g. <acronym title="Extensible Markup Language">XML</acronym> file) you must call the <code>(int x, int y)</code> method <em>without</em> any parameters! |
||||
|
||||
</p> |
||||
<pre><span><interact onClick="clicked()"/></span> </pre> |
||||
|
||||
<p> |
||||
|
||||
You can name the method (here <code>clicked</code>) what ever you like, as long as you keep the argument syntax. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT11 SECTION "Pass ClickLoc From Nifty to Java" [6914-7675] --> |
||||
<h2><a>Load Several XML Files</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
The basic Nifty <acronym title="Graphical User Interface">GUI</acronym> example showed how to use the <code>nifty.fromXML()</code> method to load one <acronym title="Extensible Markup Language">XML</acronym> file containing all Nifty <acronym title="Graphical User Interface">GUI</acronym> screens. |
||||
The following code sample shows how you can load several <acronym title="Extensible Markup Language">XML</acronym> files into one nifty object. Loading several files with <code>nifty.addXml()</code> allows you to split up each screen into one <acronym title="Extensible Markup Language">XML</acronym> file, instead of all into one hard-to-read <acronym title="Extensible Markup Language">XML</acronym> file. |
||||
</p> |
||||
<pre>NiftyJmeDisplay niftyDisplay = new NiftyJmeDisplay(assetManager, inputManager, audioRenderer, viewPort); |
||||
Nifty nifty = niftyDisplay.getNifty(); |
||||
nifty.addXml("Interface/Screens/OptionsScreen.xml"); |
||||
nifty.addXml("Interface/Screens/StartScreen.xml"); |
||||
nifty.gotoScreen("startScreen"); |
||||
StartScreenControl screenControl = (StartScreenControl) nifty.getScreen("startScreen").getScreenController(); |
||||
OptionsScreenControl optionsControl = (OptionsScreenControl) nifty.getScreen("optionsScreen").getScreenController(); |
||||
stateManager.attach(screenControl); |
||||
stateManager.attach(optionsControl); |
||||
guiViewPort.addProcessor(niftyDisplay);</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT12 SECTION "Load Several XML Files" [7676-8724] --> |
||||
<h2><a>Register additional explicit screen controllers</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
In addition to the <code>nifty.addXml()</code> methods to attach many nifty <acronym title="Extensible Markup Language">XML</acronym> files, there exists a <code>nifty.registerScreenController()</code> method to explicitly attach more screen controllers. |
||||
</p> |
||||
|
||||
<p> |
||||
The following code sample shows how you can explicitly attach several screen controllers before adding the <acronym title="Extensible Markup Language">XML</acronym> file to nifty, which would otherwise cause nifty to implicitly instantiate the screen controller class. |
||||
</p> |
||||
<pre>NiftyJmeDisplay niftyDisplay = new NiftyJmeDisplay(assetManager, inputManager, audioRenderer, viewPort); |
||||
Nifty nifty = niftyDisplay.getNifty(); |
||||
|
||||
nifty.registerScreenController(new OptionsScreenController(randomConstructorArgument)); |
||||
nifty.addXml("Interface/Screens/OptionsScreen.xml");</pre> |
||||
|
||||
</div> |
||||
<!-- EDIT13 SECTION "Register additional explicit screen controllers" [8725-9493] --> |
||||
<h2><a>Design Your Own Styles</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
By default, your Nifty <acronym title="Extensible Markup Language">XML</acronym> screens use the built.in styles: |
||||
</p> |
||||
<pre> <span><useStyles filename="nifty-default-styles.xml" /></span> </pre> |
||||
|
||||
<p> |
||||
But you can switch to a set of custom styles in your game project's asset directory like this: |
||||
</p> |
||||
<pre> <span><useStyles filename="Interface/Styles/myCustomStyles.xml" /></span> </pre> |
||||
|
||||
<p> |
||||
Inside myCustomStyles.xml you define styles like this: |
||||
</p> |
||||
<pre><span><?xml version="1.0" encoding="UTF-8"?></span> |
||||
<span><span><nifty-styles></span></span> |
||||
<span><useStyles filename="Interface/Styles/Font/myCustomFontStyle.xml" /></span> |
||||
<span><useStyles filename="Interface/Styles/Button/myCustomButtonStyle.xml" /></span> |
||||
<span><useStyles filename="Interface/Styles/Label/myCustomLabelStyle.xml" /></span> |
||||
... |
||||
<span><span></nifty-styles></span></span></pre> |
||||
|
||||
<p> |
||||
Learn more about how to create styles by looking at the <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://sourceforge.net/apps/mediawiki/nifty-gui/index.php?title=Build_from_Source"><param name="text" value="<html><u>Nifty GUI source code</u></html>"><param name="textColor" value="blue"></object> for ???nifty-style-black???. Copy it as a template and change it to create your own style. |
||||
|
||||
</p> |
||||
<hr/> |
||||
|
||||
<p> |
||||
Learn more from the NiftyGUI page: |
||||
</p> |
||||
<ul> |
||||
<li><div> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://sourceforge.net/apps/mediawiki/nifty-gui/index.php?title=Effects"><param name="text" value="<html><u>http://sourceforge.net/apps/mediawiki/nifty-gui/index.php?title=Effects</u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
</ul> |
||||
<div><span> |
||||
<a href="/wiki/doku.php/tag:gui?do=showtag&tag=tag%3Agui">gui</a>, |
||||
<a href="/wiki/doku.php/tag:documentation?do=showtag&tag=tag%3Adocumentation">documentation</a>, |
||||
<a href="/wiki/doku.php/tag:nifty?do=showtag&tag=tag%3Anifty">nifty</a>, |
||||
<a href="/wiki/doku.php/tag:hud?do=showtag&tag=tag%3Ahud">hud</a>, |
||||
<a href="/wiki/doku.php/tag:click?do=showtag&tag=tag%3Aclick">click</a>, |
||||
<a href="/wiki/doku.php/tag:state?do=showtag&tag=tag%3Astate">state</a>, |
||||
<a href="/wiki/doku.php/tag:states?do=showtag&tag=tag%3Astates">states</a>, |
||||
<a href="/wiki/doku.php/tag:sound?do=showtag&tag=tag%3Asound">sound</a>, |
||||
<a href="/wiki/doku.php/tag:effect?do=showtag&tag=tag%3Aeffect">effect</a> |
||||
</span></div> |
||||
|
||||
</div> |
||||
<!-- EDIT14 SECTION "Design Your Own Styles" [9494-] --> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:nifty_gui_scenarios?do=export_xhtmlbody">view online version</a></em></p> |
@ -1,391 +0,0 @@ |
||||
|
||||
<h1><a>Laying out the GUI in XML</a></h1> |
||||
<div> |
||||
<ol> |
||||
<li><div> <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui.html">Nifty GUI Concepts</a></div> |
||||
</li> |
||||
<li><div> <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_best_practices.html">Nifty GUI Best Practices</a></div> |
||||
</li> |
||||
<li><div> <strong>Nifty <acronym title="Graphical User Interface">GUI</acronym> <acronym title="Extensible Markup Language">XML</acronym> Layout</strong> or <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_java_layout.html">Nifty GUI Java Layout</a></div> |
||||
</li> |
||||
<li><div> <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_overlay.html">Nifty GUI Overlay</a> or <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_projection.html">Nifty GUI Projection</a></div> |
||||
</li> |
||||
<li><div> <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_java_interaction.html">Interact with the GUI from Java</a></div> |
||||
</li> |
||||
</ol> |
||||
|
||||
<p> |
||||
|
||||
You can "draw" the <acronym title="Graphical User Interface">GUI</acronym> to the screen by writing <acronym title="Extensible Markup Language">XML</acronym> code (alternatively you can also use Java). |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT1 SECTION "Laying out the GUI in XML" [1-478] --> |
||||
<h2><a>Plan Your GUI Layout</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
<img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/gui-layout-draft.png"> |
||||
</p> |
||||
|
||||
<p> |
||||
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 <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://en.wikipedia.org/wiki/HUD_%28video_gaming%29"><param name="text" value="<html><u>HUD</u></html>"><param name="textColor" value="blue"></object> that displays info during the game. Before writing code, you plan the <acronym title="Graphical User Interface">GUI</acronym> layout, either on paper or in a graphic application. |
||||
</p> |
||||
|
||||
<p> |
||||
The StartScreen contains: |
||||
</p> |
||||
<ul> |
||||
<li><div> The background layer has a centered layout and contains an image.</div> |
||||
</li> |
||||
<li><div> The top layer has a vertical layout, containing 3 panels: </div> |
||||
<ul> |
||||
<li><div> The top panel contains a label with the game title, </div> |
||||
</li> |
||||
<li><div> The middle panel contains a text field with the game description. </div> |
||||
</li> |
||||
<li><div> The bottom panel has a horizontal layout and contains two more panels:</div> |
||||
<ul> |
||||
<li><div> The left panel contains a Start button.</div> |
||||
</li> |
||||
<li><div> The right panel contains a Quit button.</div> |
||||
</li> |
||||
</ul> |
||||
</li> |
||||
</ul> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
|
||||
The HUD contains: |
||||
</p> |
||||
<ul> |
||||
<li><div> The background layer has a centered layout, and contains the partially transparent HUD image.</div> |
||||
</li> |
||||
<li><div> The top layer has a horizontal layout, containing 2 panels: </div> |
||||
<ul> |
||||
<li><div> The left panel as transparent spacer.</div> |
||||
</li> |
||||
<li><div> The right panel has a vertical layout containing 2 panels, a label and an image.</div> |
||||
</li> |
||||
</ul> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT2 SECTION "Plan Your GUI Layout" [479-1663] --> |
||||
<h2><a>Implement Your GUI Layout</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
<img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/nifty-screen-layer-panel.png"> |
||||
</p> |
||||
|
||||
<p> |
||||
Create an empty screen.xml file in the <code>assets/Interfaces/</code> directory of your project. One <acronym title="Extensible Markup Language">XML</acronym> 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). |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT3 SECTION "Implement Your GUI Layout" [1664-2139] --> |
||||
<h3><a>Make Screens</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
The following minimal <acronym title="Extensible Markup Language">XML</acronym> file contains a start screen and a HUD screen. (Neither has been defined yet.) |
||||
</p> |
||||
<pre><span><?xml version="1.0" encoding="UTF-8"?></span> |
||||
<span><nifty xmlns="http://nifty-gui.sourceforge.net/nifty-1.3.xsd"</span> |
||||
<span> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"</span> |
||||
<span> xsi:schemaLocation="http://nifty-gui.sourceforge.net/nifty-1.3.xsd http://nifty-gui.sourceforge.net/nifty-1.3.xsd"></span> |
||||
<span><screen id="start"></span> |
||||
<!-- ... --> |
||||
<span><span></screen></span></span> |
||||
<span><screen id="hud"></span> |
||||
<!-- ... --> |
||||
<span><span></screen></span></span> |
||||
<span><span></nifty></span></span></pre> |
||||
|
||||
<p> |
||||
Every Nifty <acronym title="Graphical User Interface">GUI</acronym> must have a start screen. The others (in this example, the HUD screen) are optional. |
||||
</p> |
||||
|
||||
<p> |
||||
<strong>Note:</strong> In the following examples, the <acronym title="Extensible Markup Language">XML</acronym> schema header is abbreviated to just <code><nifty></code>. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT4 SECTION "Make Screens" [2140-2872] --> |
||||
<h3><a>Make Layers</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
The following minimal <acronym title="Extensible Markup Language">XML</acronym> file shows how we added layers to the start screen and HUD screen: |
||||
</p> |
||||
<pre><span><span><nifty></span></span> |
||||
<span><screen id="start"></span> |
||||
<span><layer id="background" backgroundColor="#000f"></span> |
||||
<!-- ... --> |
||||
<span><span></layer></span></span> |
||||
<span><layer id="foreground" backgroundColor="#0000" childLayout="vertical"></span> |
||||
<!-- ... --> |
||||
<span><span></layer></span></span> |
||||
<span><span></screen></span></span> |
||||
<span><screen id="hud"></span> |
||||
<span><layer id="background" backgroundColor="#000f"></span> |
||||
<!-- ... --> |
||||
<span><span></layer></span></span> |
||||
<span><layer id="foreground" backgroundColor="#0000" childLayout="horizontal"></span> |
||||
<!-- ... --> |
||||
<span><span></layer></span></span> |
||||
<span><span></screen></span></span> |
||||
<span><span></nifty></span></span></pre> |
||||
|
||||
<p> |
||||
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. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT5 SECTION "Make Layers" [2873-3646] --> |
||||
<h3><a>Make Panels</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
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 <code>start</code> screen's <code>foreground</code> layer: |
||||
</p> |
||||
<pre> <span><panel id="panel_top" height="25%" width="75%" align="center" childLayout="center"</span> |
||||
<span> backgroundColor="#f008"></span> |
||||
<span><span></panel></span></span> |
||||
<span><panel id="panel_mid" height="50%" width="75%" align="center" childLayout="center"</span> |
||||
<span> backgroundColor="#0f08"></span> |
||||
<span><span></panel></span></span> |
||||
<span><panel id="panel_bottom" height="25%" width="75%" align="center" childLayout="horizontal"</span> |
||||
<span> backgroundColor="#00f8"></span> |
||||
<span><panel id="panel_bottom_left" height="50%" width="50%" valign="center" childLayout="center" </span> |
||||
<span> backgroundColor="#44f8"></span> |
||||
<span><span></panel></span></span> |
||||
<span><panel id="panel_bottom_right" height="50%" width="50%" valign="center" childLayout="center"</span> |
||||
<span> backgroundColor="#88f8"></span> |
||||
<span><span></panel></span></span> |
||||
<span><span></panel></span></span></pre> |
||||
|
||||
<p> |
||||
The following panels go into in the <code>hud</code> screen's <code>foreground</code> layer: |
||||
</p> |
||||
<pre> <span><panel id="panel_left" width="80%" height="100%" childLayout="vertical" </span> |
||||
<span> backgroundColor="#0f08"></span> |
||||
<!-- spacer --> |
||||
<span><span></panel></span></span> |
||||
<span><panel id="panel_right" width="20%" height="100%" childLayout="vertical" </span> |
||||
<span> backgroundColor="#00f8" ></span> |
||||
<span><panel id="panel_top_right1" width="100%" height="15%" childLayout="center"</span> |
||||
<span> backgroundColor="#00f8"></span> |
||||
<span><span></panel></span></span> |
||||
<span><panel id="panel_top_right2" width="100%" height="15%" childLayout="center"</span> |
||||
<span> backgroundColor="#44f8"></span> |
||||
<span><span></panel></span></span> |
||||
<span><panel id="panel_bot_right" width="100%" height="70%" valign="center"</span> |
||||
<span> backgroundColor="#88f8"></span> |
||||
<span><span></panel></span></span> |
||||
<span><span></panel></span></span></pre> |
||||
|
||||
<p> |
||||
The result should look as follows: |
||||
</p> |
||||
|
||||
<p> |
||||
<img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/nifty-gui-panels.png"> |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT6 SECTION "Make Panels" [3647-5529] --> |
||||
<h2><a>Adding Content to Panels</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
See also <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://sourceforge.net/apps/mediawiki/nifty-gui/index.php?title=Layout_Introduction"><param name="text" value="<html><u>Layout Introduction</u></html>"><param name="textColor" value="blue"></object> on the Nifty <acronym title="Graphical User Interface">GUI</acronym> site. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT7 SECTION "Adding Content to Panels" [5530-5708] --> |
||||
<h3><a>Add Images</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
The start-background.png image is a fullscreen background picture. In the <code>start</code> screen, add the following image element: |
||||
|
||||
</p> |
||||
<pre> <span><layer id="background" childLayout="center"></span> |
||||
<span><image filename="Interface/tutorial/step2/start-background.png"><span></image></span></span> |
||||
<span><span></layer></span></span></pre> |
||||
|
||||
<p> |
||||
The hud-frame.png image is a transparent frame that we use as HUD decoration. In the <code>hud</code> screen, add the following image element: |
||||
|
||||
</p> |
||||
<pre> <span><layer id="background" childLayout="center"></span> |
||||
<span><image filename="Interface/tutorial/step2/hud-frame.png"><span></image></span></span> |
||||
<span><span></layer></span></span></pre> |
||||
|
||||
<p> |
||||
In order to make the hud-frame.png independent of the screen resolution you are using, you could use the <code>imageMode</code> attribute on the image element <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://sourceforge.net/apps/mediawiki/nifty-gui/index.php?title=Resizable_Images_(ImageMode%3Dresize)_explained"><param name="text" value="<html><u> Resizable Images (ImageMode=resize) explained</u></html>"><param name="textColor" value="blue"></object> |
||||
</p> |
||||
<pre> <span><layer id="background" childLayout="center"></span> |
||||
<span><image filename="Interface/tutorial/step2/hud-frame.png" imageMode="resize:40,490,110,170,40,560,40,270,40,560,40,40" width="100%" height="100%"/></span> |
||||
<span><span></layer></span></span></pre> |
||||
|
||||
<p> |
||||
The face1.png image is an image that you want to use as a status icon. |
||||
In the <code>hud</code> screen's <code>foreground</code> layer, add the following image element: |
||||
|
||||
</p> |
||||
<pre> <span><panel id="panel_bottom_left" height="75%" width="20%" valign="center" childLayout="center"></span> |
||||
<span><image filename="Interface/tutorial/step2/face1.png" </span> |
||||
<span> valign="center" align="center" height="50%" width="30%" ></span> |
||||
<span><span></image></span></span> |
||||
<span><span></panel></span></span></pre> |
||||
|
||||
<p> |
||||
|
||||
This image is scaled to use 50% of the height and 30% of the width of its container. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT8 SECTION "Add Images" [5709-7395] --> |
||||
<h3><a>Add Static Text</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
The game title is a typical example of static text. In the <code>start</code> screen, add the following text element: |
||||
|
||||
</p> |
||||
<pre> <span><panel id="panel_top" height="25%" width="75%" align="center" childLayout="center"></span> |
||||
<span><text text="My Cool Game" font="Interface/Fonts/Default.fnt" width="100%" height="100%" /></span> |
||||
<span><span></panel></span></span></pre> |
||||
|
||||
<p> |
||||
For longer pieces of static text, such as an introduction, you can use wrap="true". Add the following text element to the <code>Start screen</code>: |
||||
</p> |
||||
<pre> <span><panel id="panel_mid" height="50%" width="75%" align="center" childLayout="center"></span> |
||||
<span><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. ..." </span> |
||||
<span> font="Interface/Fonts/Default.fnt" width="100%" height="100%" wrap="true" /></span> |
||||
<span><span></panel></span></span></pre> |
||||
|
||||
<p> |
||||
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 <code>assets/Interface</code> directory. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT9 SECTION "Add Static Text" [7396-8476] --> |
||||
<h3><a>Add Controls</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Before you can use any control, you must load a Control Definition first. Add the following two lines <em>before</em> your screen definitions: |
||||
</p> |
||||
<pre> <span><useControls filename="nifty-default-controls.xml" /></span> |
||||
<span><useStyles filename="nifty-default-styles.xml" /></span></pre> |
||||
|
||||
</div> |
||||
|
||||
<h4><a>Label Control</a></h4> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Use label controls for text that you want to edit dynamically from Java. One example for this is the score display. |
||||
In the <code>hud</code> screen's <code>foreground</code> layer, add the following text element: |
||||
</p> |
||||
<pre> <span><panel id="panel_top_right" height="100%" width="15%" childLayout="center"></span> |
||||
<span><control name="label" color="#000" text="123" width="100%" height="100%" /></span> |
||||
<span><span></panel></span></span></pre> |
||||
|
||||
<p> |
||||
Note that the width and height do not scale the bitmap font, but indirectly make certain it is centered. If you want a different size for the font, you need to provide an extra bitmap font (they come with fixed sizes and don't scale well). |
||||
</p> |
||||
|
||||
</div> |
||||
|
||||
<h4><a>Button Control</a></h4> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Our <acronym title="Graphical User Interface">GUI</acronym> plan asks for two buttons on the start screen. You add the Start and Quit buttons to the bottom panel of the <code>start</code> screen using the <code><control></code> element: |
||||
</p> |
||||
<pre> <span><panel id="panel_bottom_left" height="50%" width="50%" valign="center" childLayout="center"></span> |
||||
<span><control name="button" label="Start" id="StartButton" align="center" valign="center"></span> |
||||
<span><span></control></span></span> |
||||
<span><span></panel></span></span> |
||||
<span><panel id="panel_bottom_right" height="50%" width="50%" valign="center" childLayout="center"></span> |
||||
<span><control name="button" label="Quit" id="QuitButton" align="center" valign="center"></span> |
||||
<span><span></control></span></span> |
||||
<span><span></panel></span></span></pre> |
||||
|
||||
<p> |
||||
Note that these controls don't do anything yet ??? we'll get to that soon. |
||||
</p> |
||||
|
||||
</div> |
||||
|
||||
<h4><a>Other Controls</a></h4> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Nifty additionally offers many customizable controls such as check boxes, text fields, menus, chats, tabs, ??? See also <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://sourceforge.net/apps/mediawiki/nifty-gui/index.php?title=Elements"><param name="text" value="<html><u>Elements</u></html>"><param name="textColor" value="blue"></object> on the Nifty <acronym title="Graphical User Interface">GUI</acronym> site. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT10 SECTION "Add Controls" [8477-10445] --> |
||||
<h2><a>Intermediate Result</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
When you preview this code in the jMonkeyEngine <acronym title="Software Development Kit">SDK</acronym>, our tutorial demo should looks as follows: A start screen with two buttons, and a game screen with a simple HUD frame and a blue cube (which stands for any jME3 game content). |
||||
</p> |
||||
|
||||
<p> |
||||
<img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/nifty-gui-simple-demo.png"> |
||||
</p> |
||||
|
||||
<p> |
||||
Compare this result with the layout draft above. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT11 SECTION "Intermediate Result" [10446-10806] --> |
||||
<h2><a>Next Steps</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Integrate the <acronym title="Graphical User Interface">GUI</acronym> into the game. Typically, you will overlay the <acronym title="Graphical User Interface">GUI</acronym>. |
||||
</p> |
||||
<ul> |
||||
<li><div> <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_overlay.html">Nifty GUI Overlay</a> (recommended)</div> |
||||
</li> |
||||
<li><div> <a href="/com/jme3/gde/core/docs/jme3/advanced/nifty_gui_projection.html">Nifty GUI Projection</a> (optional)</div> |
||||
</li> |
||||
</ul> |
||||
<div><span> |
||||
<a href="/wiki/doku.php/tag:gui?do=showtag&tag=tag%3Agui">gui</a>, |
||||
<a href="/wiki/doku.php/tag:documentation?do=showtag&tag=tag%3Adocumentation">documentation</a>, |
||||
<a href="/wiki/doku.php/tag:nifty?do=showtag&tag=tag%3Anifty">nifty</a>, |
||||
<a href="/wiki/doku.php/tag:hud?do=showtag&tag=tag%3Ahud">hud</a> |
||||
</span></div> |
||||
|
||||
</div> |
||||
<!-- EDIT12 SECTION "Next Steps" [10807-] --> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:nifty_gui_xml_layout?do=export_xhtmlbody">view online version</a></em></p> |
Before Width: | Height: | Size: 126 KiB |
Before Width: | Height: | Size: 9.7 KiB |
Before Width: | Height: | Size: 57 KiB |
Before Width: | Height: | Size: 65 KiB |
@ -1,75 +0,0 @@ |
||||
|
||||
<h1><a>Working Blender and OgreXML Versions</a></h1> |
||||
<div> |
||||
|
||||
<p> |
||||
Here you can find working combinations of Blender and the OgreXML exporter, with any tips or bugs associated with each. |
||||
|
||||
</p> |
||||
<div><table> |
||||
<tr> |
||||
<th> Blender Version </th><th> OgreXML Exporter Version </th><th> Notes </th> |
||||
</tr> |
||||
<tr> |
||||
<td> 2.6.3 </td><td> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/blender2ogre/downloads/list"><param name="text" value="<html><u>0.5.8</u></html>"><param name="textColor" value="blue"></object> </td><td> Root bone, no transforms on object, no envelopes </td> |
||||
</tr> |
||||
<tr> |
||||
<td> 2.6.2 </td><td> <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/blender2ogre/downloads/list"><param name="text" value="<html><u>0.5.5</u></html>"><param name="textColor" value="blue"></object> </td><td> Root bone, no transforms on object, no envelopes </td> |
||||
</tr> |
||||
<tr> |
||||
<td> 2.6.1 </td><td> ? </td><td> </td> |
||||
</tr> |
||||
<tr> |
||||
<td> 2.6.0 </td><td> ? </td><td> </td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT2 TABLE [173-518] --> |
||||
</div> |
||||
<!-- EDIT1 SECTION "Working Blender and OgreXML Versions" [1-519] --> |
||||
<h1><a>Tips</a></h1> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
Tips for exporting animations through OgreXML correctly: |
||||
</p> |
||||
<ul> |
||||
<li><div> apply all transformations</div> |
||||
</li> |
||||
<li><div> armature should have 0,0,0 transformation (loc,rot,scale)</div> |
||||
</li> |
||||
<li><div> model object should have 0,0,0 transformation (loc,rot,scale)</div> |
||||
</li> |
||||
<li><div> root bone should have 0,0,0 transformation (loc,rot,scale)</div> |
||||
</li> |
||||
<li><div> no envelopes</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
|
||||
Test Character - <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://dl.dropbox.com/u/26887202/123/jme_blender/characterOgre26.zip"><param name="text" value="<html><u>http://dl.dropbox.com/u/26887202/123/jme_blender/characterOgre26.zip</u></html>"><param name="textColor" value="blue"></object> |
||||
</p> |
||||
|
||||
<p> |
||||
<img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/ogre_solved.jpg"> |
||||
<img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/ogre_solved2.png"> |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT3 SECTION "Tips" [520-996] --> |
||||
<h1><a>Troubleshooting</a></h1> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
<strong>Q:</strong> <em>My animation is stretched.</em> |
||||
</p> |
||||
|
||||
<p> |
||||
<strong>A:</strong> Use the exporting tips provided above |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT4 SECTION "Troubleshooting" [997-] --> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:ogrecompatibility?do=export_xhtmlbody">view online version</a></em></p> |
Before Width: | Height: | Size: 10 KiB |
@ -1,196 +0,0 @@ |
||||
|
||||
<h1><a>Open Game Finder</a></h1> |
||||
<div> |
||||
|
||||
<p> |
||||
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. |
||||
</p> |
||||
<ul> |
||||
<li><div> Homepage: <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/open-game-finder/"><param name="text" value="<html><u>http://code.google.com/p/open-game-finder/</u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
<li><div> Documentation: <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/open-game-finder/w/list"><param name="text" value="<html><u>http://code.google.com/p/open-game-finder/w/list</u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
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 <acronym title="Graphical User Interface">GUI</acronym> plugin. |
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT1 SECTION "Open Game Finder" [1-629] --> |
||||
<h2><a>Installation</a></h2> |
||||
<div> |
||||
<ol> |
||||
<li><div> Go to <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/open-game-finder/downloads/list"><param name="text" value="<html><u>http://code.google.com/p/open-game-finder/downloads/list</u></html>"><param name="textColor" value="blue"></object></div> |
||||
</li> |
||||
<li><div> Download Client-1.0-bin.zip and Server-1.0-bin.zip</div> |
||||
</li> |
||||
<li><div> Unzip the two files to, for example, your jMonkeyProjects directory.</div> |
||||
</li> |
||||
</ol> |
||||
|
||||
</div> |
||||
<!-- EDIT2 SECTION "Installation" [630-849] --> |
||||
<h2><a>Setting up the Database</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
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. |
||||
</p> |
||||
<ul> |
||||
<li><div> On Windows, use installServer.bat to create a new database from scratch. On Mac <acronym title="Operating System">OS</acronym> or Linux, run <code>java -jar lib/Server-0.1.jar install</code> in the Terminal.</div> |
||||
</li> |
||||
<li><div> On Windows, use updateServer.bat to update the difference between the current state of the database and the way it should be. On Mac <acronym title="Operating System">OS</acronym> and Linux, run <code>java -jar lib/Server-0.1.jar update</code> in the Terminal. <br/> |
||||
<strong>This new feature is currently untested.</strong></div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT3 SECTION "Setting up the Database" [850-1523] --> |
||||
<h2><a>Running the server</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
Change into the OGF-Server directory and run the server: |
||||
</p> |
||||
<ul> |
||||
<li><div> On Windows: Run startServer.bat</div> |
||||
</li> |
||||
<li><div> On Linux and MacOS X: Run <code>java -jar lib/Server-1.0.jar</code> in the Terminal.</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
The server is now running and ready to accept connections. <br/> |
||||
|
||||
<strong>Note:</strong> In the alpha release, the server runs on localhost. In the final release, you will be able to configure the host! |
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT4 SECTION "Running the server" [1524-1913] --> |
||||
<h2><a>Running the client</a></h2> |
||||
<div> |
||||
<ol> |
||||
<li><div> Change into the OGF-Client directory and run the client:</div> |
||||
<ul> |
||||
<li><div> On Windows: Run startClient.bat</div> |
||||
</li> |
||||
<li><div> On Linux and MacOS X: Run <code>java -jar lib/Client-1.0.jar</code> in the Terminal.</div> |
||||
</li> |
||||
</ul> |
||||
</li> |
||||
<li><div> If a Display Settings window appears, you can keep the defaults and click OK.</div> |
||||
</li> |
||||
</ol> |
||||
|
||||
<p> |
||||
A client is now running, connects to the server, and displays a registration/login window. |
||||
<img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/open-game-finder-1.png"> |
||||
<strong>Note:</strong> You can run several clients on localhost for testing. |
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT5 SECTION "Running the client" [1914-2406] --> |
||||
<h3><a>Client: 1. Registration</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
If clients use OGF for the first time, they need to register. |
||||
On the main screen of the client: |
||||
</p> |
||||
<ol> |
||||
<li><div> Click Register</div> |
||||
</li> |
||||
<li><div> Choose a user name and password (repeat the password).</div> |
||||
</li> |
||||
<li><div> Select an Avatar image.</div> |
||||
</li> |
||||
<li><div> Click register to complete the registration.</div> |
||||
</li> |
||||
</ol> |
||||
|
||||
<p> |
||||
The client registers the account and opens the chat window directly. |
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT6 SECTION "Client: 1. Registration" [2407-2760] --> |
||||
<h3><a>Client: 2. Login</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
If returning clients are already registered to an OGF server, they can log in. |
||||
On the main screen of the client: |
||||
</p> |
||||
<ol> |
||||
<li><div> Enter a user name and password that you previously registered.</div> |
||||
</li> |
||||
<li><div> Click Login</div> |
||||
</li> |
||||
</ol> |
||||
|
||||
<p> |
||||
The client logs you in and opens the chat window. |
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT7 SECTION "Client: 2. Login" [2761-3033] --> |
||||
<h3><a>Client: 3. Chat</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
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. |
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT8 SECTION "Client: 3. Chat" [3034-3213] --> |
||||
<h2><a>Connecting to a Game</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
Q: I want to gather players using the OGF client to connect to the game server. How do I start my multiplayer game? <br/> |
||||
|
||||
A: The following sample code demos the typical use case: <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/open-game-finder/source/browse/OGF/TRUNK/Client/src/main/java/com/ractoc/opengamefinder/client/OGFClientStartup.java"><param name="text" value="<html><u>OGFClientStartup.java</u></html>"><param name="textColor" value="blue"></object> |
||||
<br/> |
||||
|
||||
In a JME3 Application's init method: |
||||
</p> |
||||
<ol> |
||||
<li><div> Create a com.ractoc.opengamefinder.client.GUIContainer object.</div> |
||||
</li> |
||||
<li><div> Create a game instance using the GUIContainer (via a ClientFactory).</div> |
||||
</li> |
||||
<li><div> Check the com.ractoc.pffj.api.BasePluginMessageResult for success or failure.</div> |
||||
</li> |
||||
</ol> |
||||
|
||||
<p> |
||||
After this, continue writing your JME3 init method. |
||||
|
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT9 SECTION "Connecting to a Game" [3214-3904] --> |
||||
<h2><a>Configuration</a></h2> |
||||
<div> |
||||
<ul> |
||||
<li><div> Q: How can I offer more avatars to choose from? <br/> |
||||
A: Save the image files in the path <code>jMonkeyProjects/OGF-Client-1.0-bin/OGF/resources/avatars/</code></div> |
||||
</li> |
||||
<li><div> Q: How do I configure servers addresses? <br/> |
||||
A: TBD</div> |
||||
</li> |
||||
</ul> |
||||
<div><span> |
||||
<a href="/wiki/doku.php/tag:network?do=showtag&tag=tag%3Anetwork">network</a> |
||||
</span></div> |
||||
|
||||
</div> |
||||
<!-- EDIT10 SECTION "Configuration" [3905-] --> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:open_game_finder?do=export_xhtmlbody">view online version</a></em></p> |
Before Width: | Height: | Size: 183 KiB |
Before Width: | Height: | Size: 182 KiB |
Before Width: | Height: | Size: 18 KiB |
@ -1,241 +0,0 @@ |
||||
|
||||
<h1><a>Particle Emmitter Settings</a></h1> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
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 <em>just right</em>, and it's worth exploring the expressiveness of the options described below. |
||||
</p> |
||||
|
||||
<p> |
||||
<p><div>Use the <a href="/com/jme3/gde/core/docs/sdk/scene_explorer.html">Scene Explorer</a> in the <a href="/com/jme3/gde/core/docs/sdk.html">SDK</a> to design and preview effects. |
||||
</div></p> |
||||
</p> |
||||
|
||||
<p> |
||||
<img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/explosion-5.png"> <img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/particle.png"> <img src="nbdocs:/com/jme3/gde/core/docs/jme3/beginner/beginner-effect-fire.png"> <img src="nbdocs:/com/jme3/gde/core/docs/jme3/advanced/butterfly-particle-emitter.png"> |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT1 SECTION "Particle Emmitter Settings" [1-844] --> |
||||
<h2><a>Create an Emitter</a></h2> |
||||
<div> |
||||
<ol> |
||||
<li><div> Create one emitter for each effect: <pre>ParticleEmitter explosion = new ParticleEmitter( |
||||
"My explosion effect", ParticleMesh.Type.Triangle, 30);</pre> |
||||
</div> |
||||
</li> |
||||
<li><div> Attach the emitter to the rootNode and position it in the scene: <pre>rootNode.attachChild(explosion); |
||||
explosion.setLocalTranslation(bomb.getLocalTranslation());</pre> |
||||
</div> |
||||
</li> |
||||
<li><div> Trigger the effect by calling <pre>explosion.emitAllParticles()</pre> |
||||
</div> |
||||
</li> |
||||
<li><div> End the effect by calling <pre>explosion.killAllParticles()</pre> |
||||
</div> |
||||
</li> |
||||
</ol> |
||||
|
||||
<p> |
||||
Choose one of the following mesh shapes |
||||
</p> |
||||
<ul> |
||||
<li><div> ParticleMesh.Type.Triangle</div> |
||||
</li> |
||||
<li><div> ParticleMesh.Type.Point</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
</div> |
||||
<!-- EDIT2 SECTION "Create an Emitter" [845-1473] --> |
||||
<h2><a>Configure Parameters</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
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. |
||||
</p> |
||||
<div><table> |
||||
<tr> |
||||
<th> Parameter </th><th> Method </th><th> Default </th><th> Description </th> |
||||
</tr> |
||||
<tr> |
||||
<td> number </td><td> <code>setNumParticles()</code> </td><td> </td><td> The maximum number of particles visible at the same time. Specified by user in constructor. </td> |
||||
</tr> |
||||
<tr> |
||||
<td> emission rate </td><td> <code>setParticlesPerSec()</code> </td><td> 20 </td><td> Density of the effect, how many new particles are emitted per second. <br/> |
||||
Set to zero to control the start/end of the effect. <br/> |
||||
Set to a number for a constantly running effect. </td> |
||||
</tr> |
||||
<tr> |
||||
<td> size </td><td> <code>setStartSize()</code>, <code>setEndSize()</code> </td><td> 0.2f, 2f </td><td> The radius of the scaled sprite image. Set both to same value for constant size effect. <br/> |
||||
Set to different values for shrink/grow effect. </td> |
||||
</tr> |
||||
<tr> |
||||
<td> color </td><td> <code>setStartColor()</code>, <code>setEndColor()</code> </td><td> gray </td><td> Controls how the opaque (non-black) parts of the texture are colorized. <br/> |
||||
Set both to the same color for single-colored effects (e.g. fog, debris). <br/> |
||||
Set both to different colors for a gradient effect (e.g. fire). </td> |
||||
</tr> |
||||
<tr> |
||||
<td> direction/velocity </td><td> <code>getParticleInfluencer(). setInitialVelocity(initialVelocity)</code> </td><td> Vector3f(0,0,0) </td><td> A vector specifying the initial direction and speed of particles. The longer the vector, the faster. </td> |
||||
</tr> |
||||
<tr> |
||||
<td> fanning out </td><td> <code>getParticleInfluencer(). setVelocityVariation(variation)</code> </td><td> 0.2f </td><td> How much the direction (<code>setInitialVelocity()</code>) can vary among particles. Use a value between 1 and 0 to create a directed swarm-like cloud of particles. <br/> |
||||
1 = Maximum variation, particles emit in random 360?? directions (e.g. explosion, butterflies). <br/> |
||||
0.5f = particles are emitted within 180?? of the initial direction. <br/> |
||||
0 = No variation, particles fly in a straight line in direction of start velocity (e.g. lasergun blasts). </td> |
||||
</tr> |
||||
<tr> |
||||
<td> direction <br/> |
||||
(pick one)</td><td> <code>setFacingVelocity()</code> </td><td> false </td><td> true = Flying particles pitch in the direction they're flying (e.g. missiles). <br/> |
||||
false = Particles keep flying rotated the way they started (e.g. debris). </td> |
||||
</tr> |
||||
<tr> |
||||
<td> direction <br/> |
||||
(pick one)</td><td> <code>setFaceNormal()</code> </td><td> Vector3f.NAN </td><td> Vector3f = Flying particles face in the given direction (e.g. horizontal shockwave faces up = Vector3f.UNIT_Y). <br/> |
||||
Vector3f.NAN = Flying particles face the camera. </td> |
||||
</tr> |
||||
<tr> |
||||
<td> lifetime </td><td> <code>setLowLife()</code>, <code>setHighLife()</code> </td><td> 3f, 7f </td><td> The time period before a particle fades is set to a random value between minimum and maximum; minimum must be smaller than maximum. A minimum < 1f makes the effect more busy, a higher minimum looks more steady. Use a maximum < 1f for short bursts, and higher maxima for long lasting swarms or smoke. Set maximum and minimum to similar values to create an evenly spaced effect (e.g. fountain), set the to very different values to create a distorted effect (e.g. fire with individual long flames). </td> |
||||
</tr> |
||||
<tr> |
||||
<td> spinning </td><td> <code>setRotateSpeed()</code> </td><td> 0f </td><td> 0 = Flying particles don't spin while flying (e.g. smoke, insects, controlled projectiles). <br/> |
||||
> 0 = How fast particle spins while flying (e.g. debris, shuriken, missiles out of control). </td> |
||||
</tr> |
||||
<tr> |
||||
<td> rotation </td><td> <code>setRandomAngle()</code> </td><td> false </td><td> true = The particle sprite is rotated at a random angle when it is emitted (e.g. explosion, debris). <br/> |
||||
false = Particles fly straight like you drew them in the sprite texture (e.g. insects). </td> |
||||
</tr> |
||||
<tr> |
||||
<td> gravity </td><td> <code>setGravity()</code> </td><td> Vector3f(0.0f,0.1f,0.0f) </td><td> Particles fall in the direction of the vector (e.g. debris, sparks). <br/> |
||||
(0,0,0) = Particles keep flying in start direction (e.g. flames, zero-gravity explosion.) </td> |
||||
</tr> |
||||
<tr> |
||||
<td> start area </td><td><code>setShape(new EmitterSphereShape( Vector3f.ZERO, 2f));</code></td><td>EmitterPointShape()</td><td>By default, particles are emitted from the emitters location (a point). You can increase the emitter shape to occupy a sphere, so that the start point of new particles can be anywhere inside the sphere, which makes the effect a bit more irregular.</td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT4 TABLE [1638-5412] --> |
||||
<p> |
||||
Build up you effect by specifying one parameter after the other. If you change several parameters at the same time, it's difficult to tell which of the values caused which outcome. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT3 SECTION "Configure Parameters" [1474-5594] --> |
||||
<h2><a>Create an Effect Material</a></h2> |
||||
<div> |
||||
|
||||
<p> |
||||
|
||||
<img src="/wiki/lib/exe/fetch.php"> |
||||
</p> |
||||
|
||||
<p> |
||||
Use the common Particle.j3md Material Definition and a texture to specify the shape of the particles. The shape is defined by the texture you provide and can be anything ??? debris, flames, smoke, mosquitoes, leaves, butterflies??? be creative. |
||||
</p> |
||||
<pre> Material flash_mat = new Material( |
||||
assetManager, "Common/MatDefs/Misc/Particle.j3md"); |
||||
flash_mat.setTexture("Texture", |
||||
assetManager.loadTexture("Effects/Explosion/flash.png")); |
||||
flash.setMaterial(flash_mat); |
||||
flash.setImagesX(2); // columns |
||||
flash.setImagesY(2); // rows |
||||
flash.setSelectRandomImage(true);</pre> |
||||
|
||||
<p> |
||||
The effect texture can be one image, or contain a sprite animation ??? a series of slightly different pictures in equally spaced rows and columns. If you choose the sprite animation: |
||||
</p> |
||||
<ul> |
||||
<li><div> Specify the number of rows and columns using setImagesX(2) and setImagesY().</div> |
||||
</li> |
||||
<li><div> Specify whether you want to play the sprite series in order (animation), or at random (explosion, flame), by setting setSelectRandomImage() true or false.</div> |
||||
</li> |
||||
</ul> |
||||
|
||||
<p> |
||||
|
||||
<strong>Examples:</strong> Have a look at the following default textures and you will see how you can create your own sprite textures after the same fashion. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT5 SECTION "Create an Effect Material" [5595-6915] --> |
||||
<h3><a>Default Particle Textures</a></h3> |
||||
<div> |
||||
|
||||
<p> |
||||
The Material is used together with grayscale texture: The black parts will be transparent and the white parts will be opaque (colored). |
||||
The following effect textures are available by default from <code>test-data.jar</code>. You can also load your own textures from your assets directory. |
||||
</p> |
||||
<div><table> |
||||
<tr> |
||||
<th> Texture Path </th><th> Dimension </th><th> Preview </th> |
||||
</tr> |
||||
<tr> |
||||
<td> Effects/Explosion/Debris.png </td><td> 3*3 </td><td> <img src="/wiki/lib/exe/fetch.php"> </td> |
||||
</tr> |
||||
<tr> |
||||
<td> Effects/Explosion/flame.png </td><td> 2*2 </td><td> <img src="/wiki/lib/exe/fetch.php"> </td> |
||||
</tr> |
||||
<tr> |
||||
<td> Effects/Explosion/flash.png </td><td> 2*2 </td><td> <img src="/wiki/lib/exe/fetch.php"> </td> |
||||
</tr> |
||||
<tr> |
||||
<td> Effects/Explosion/roundspark.png </td><td> 1*1 </td><td> <img src="/wiki/lib/exe/fetch.php"> </td> |
||||
</tr> |
||||
<tr> |
||||
<td> Effects/Explosion/shockwave.png </td><td> 1*1 </td><td> <img src="/wiki/lib/exe/fetch.php"> </td> |
||||
</tr> |
||||
<tr> |
||||
<td> Effects/Explosion/smoketrail.png </td><td> 1*3 </td><td> <img src="/wiki/lib/exe/fetch.php"> </td> |
||||
</tr> |
||||
<tr> |
||||
<td> Effects/Explosion/spark.png </td><td> 1*1 </td><td> <img src="/wiki/lib/exe/fetch.php"> </td> |
||||
</tr> |
||||
<tr> |
||||
<td> Effects/Smoke/Smoke.png </td><td> 1*15 </td><td> <img src="/wiki/lib/exe/fetch.php"> </td> |
||||
</tr> |
||||
</table></div> |
||||
<!-- EDIT7 TABLE [7231-8476] --> |
||||
<p> |
||||
|
||||
<strong>Tip:</strong> Use the <code>setStartColor()</code>/<code>setEndColor()</code> settings described above to colorize the white and gray parts of textures. |
||||
</p> |
||||
|
||||
</div> |
||||
<!-- EDIT6 SECTION "Default Particle Textures" [6916-8608] --> |
||||
<h2><a>Usage Example</a></h2> |
||||
<div> |
||||
<pre> ParticleEmitter fire = new ParticleEmitter("Emitter", ParticleMesh.Type.Triangle, 30); |
||||
Material mat_red = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md"); |
||||
mat_red.setTexture("Texture", assetManager.loadTexture("Effects/Explosion/flame.png")); |
||||
fire.setMaterial(mat_red); |
||||
fire.setImagesX(2); 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 |
||||
fire.getParticleInfluencer().setInitialVelocity(new Vector3f(0,2,0)); |
||||
fire.setStartSize(1.5f); |
||||
fire.setEndSize(0.1f); |
||||
fire.setGravity(0,0,0); |
||||
fire.setLowLife(0.5f); |
||||
fire.setHighLife(3f); |
||||
fire.getParticleInfluencer().setVelocityVariation(0.3f); |
||||
rootNode.attachChild(fire);</pre> |
||||
|
||||
<p> |
||||
|
||||
Browse the full source code of all <object classid="java:org.netbeans.modules.javahelp.BrowserDisplayer"><param name="content" value="http://code.google.com/p/jmonkeyengine/source/browse/#svn%2Ftrunk%2Fengine%2Fsrc%2Ftest%2Fjme3test%2Feffect"><param name="text" value="<html><u>effect examples</u></html>"><param name="textColor" value="blue"></object> here. |
||||
</p> |
||||
<hr/> |
||||
|
||||
<p> |
||||
|
||||
See also: <a href="/com/jme3/gde/core/docs/jme3/advanced/effects_overview.html">Effects Overview</a> |
||||
</p> |
||||
<div><span> |
||||
<a href="/wiki/doku.php/tag:documentation?do=showtag&tag=tag%3Adocumentation">documentation</a>, |
||||
<a href="/wiki/doku.php/tag:effect?do=showtag&tag=tag%3Aeffect">effect</a> |
||||
</span></div> |
||||
|
||||
</div> |
||||
<!-- EDIT8 SECTION "Usage Example" [8609-] --> |
||||
<p><em><a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:particle_emitters?do=export_xhtmlbody">view online version</a></em></p> |