| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153 |
- <!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge"><![endif]--><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="Asciidoctor 1.5.4"><title>Application States</title><link rel="stylesheet" href="./asciidoctor.css">
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.5.0/css/font-awesome.min.css">
- <link rel="stylesheet" href="./coderay-asciidoctor.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/docsearch.js/2/docsearch.min.css"><link rel="stylesheet" href="/home/travis/build/jMonkeyEngine/wiki/build/asciidoc/html5/jme3/advanced/twemoji-awesome.css"></head><body class="article toc2 toc-left"><div id="header"><div id="toolbar"><a href="https://github.com/jMonkeyEngine/wiki/edit/master/src/docs/asciidoc/jme3/advanced/application_states.adoc"><i class="fa fa-pencil-square" aria-hidden="true"></i></a><a href="https://github.com/jMonkeyEngine/wiki/new/master/src/docs/asciidoc/jme3/advanced/"><i class="fa fa-plus-square" aria-hidden="true"></i></a><input dir="auto" style="position: relative; vertical-align: top;" spellcheck="false" autocomplete="off" class="searchbox__input aa-input" id="doc-search" name="search" placeholder="Search in the doc" required="required" type="search"></div><h1>Application States</h1><div class="details"><span class="author" id="author"></span><br><span id="revnumber">version ,</span> <span id="revdate">2016/03/17 20:48</span></div><div id="toc" class="toc2"><div id="toctitle">Table of Contents</div><ul class="sectlevel1"><li><a href="#overview">Overview</a><ul class="sectlevel2"><li><a href="#use-case-examples">Use Case Examples</a></li><li><a href="#supported-features">Supported Features</a></li><li><a href="#usage">Usage</a></li><li><a href="#code-samples">Code Samples</a></li></ul></li><li><a href="#appstate">AppState</a></li><li><a href="#abstractappstate">AbstractAppState</a></li><li><a href="#baseappstate">BaseAppState</a></li><li><a href="#pausing-and-unpausing">Pausing and Unpausing</a></li><li><a href="#appstatemanager">AppStateManager</a></li><li><a href="#best-practices">Best Practices</a><ul class="sectlevel2"><li><a href="#communication-among-appstates">Communication Among AppStates</a></li><li><a href="#initialize-familiar-class-fields">Initialize Familiar Class Fields</a></li></ul></li></ul></div></div><div id="content"><div id="preamble"><div class="sectionbody"><div class="paragraph"><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="../../jme3/advanced/custom_controls.html">Custom Controls</a> instead. Controls and AppStates can be used together.)</p></div></div></div>
- <div class="sect2"><h3 id="overview">Overview</h3><div class="sect2"><h3 id="use-case-examples">Use Case Examples</h3><div class="paragraph"><p>There are situations during your game development where you think:</p></div>
- <div class="ulist"><ul><li><p>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?</p></li><li><p>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?</p></li><li><p>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?</p></li><li><p>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?</p></li><li><p>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?</p></li></ul></div>
- <div class="paragraph"><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></div>
- <div class="ulist"><ul><li><p>a subset of class fields, functions, methods (game state data and accessors),</p></li><li><p>a subset of <abbr title="Graphical User Interface">GUI</abbr> elements and their listeners,</p></li><li><p>a subset of input handlers and mappings,</p></li><li><p>a subset of nodes that you load and attach to the rootNode,</p></li><li><p>a subset of conditional actions that you branch to in the simpleUpdate() loop,</p></li><li><p>a subset of other AppStates and Controls</p></li><li><p>… or combinations thereof.</p></li></ul></div></div>
- <div class="sect2"><h3 id="supported-features">Supported Features</h3><div class="paragraph"><p>Each AppState lets you define what happens to it in the following situations:</p></div>
- <div class="ulist"><ul><li><p><strong>The AppState is initialized:</strong> You load and initialize game data, InputHandlers, AppStates and Controls and attach nodes.<br>
- The AppState executes its own simpleInitApp() method when it is attached, so to speak.</p></li><li><p><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.</p></li><li><p><strong>While the AppState is running/paused:</strong> You can poll isEnabled() to define paused and unpaused game behaviour in the update() loop. In update(), you poll and modify the game state, modify the scene graph, and trigger events. Test if <code>!isEnabled()</code>, and 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).</p></li><li><p><strong>The AppState has been disabled (paused):</strong> This toggles a boolean isEnabled() to false. Here you switch all objects to their specific “paused” behaviour.</p></li><li><p><strong>The AppState is cleaned up:</strong> Here you decide what happens when the AppState is detached. Save this AppState’s game state, unregister Controls and InputHandlers, detach related AppStates, detach nodes from the rootNode, etc.</p></li></ul></div>
- <div class="admonitionblock tip"><table><tr><td class="icon"><i class="fa icon-tip" title="Tip"></i></td><td class="content"><div class="paragraph"><p>AppStates are extremely handy to swap out, or pause/unpause whole sets of other AppStates. For example, an InGameState (loads in-game <abbr title="Graphical User Interface">GUI</abbr>, 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 <abbr title="Graphical User Interface">GUI</abbr>, switches to click-to-select input mappings).</p></div></td></tr></table></div></div>
- <div class="sect2"><h3 id="usage">Usage</h3><div class="paragraph"><p>To implement game logic:</p></div>
- <div class="olist arabic"><ol class="arabic"><li><p>Create one AbstractAppState instance for each set of game mechanics.</p></li><li><p>Implement game behaviour in the AppState’s update() method.</p><div class="ulist"><ul><li><p>You can pass custom data as arguments in the constructor.</p></li><li><p>The AppState has access to everything inside the app’s scope via the Application <code>app</code> object.</p></li></ul></div></li><li><p>Create and attach the AppState to the AppStateManager (<code>stateManager.attach(myAppState);</code>) and initialize it.</p></li><li><p>Enable and disable (unpause and pause) the AppStates that you need during the game.</p></li><li><p>Detach the AppState from the AppStateManager (<code>stateManager.detach(myAppState);</code>) and clean it up.</p></li></ol></div>
- <div class="paragraph"><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></div>
- <div class="sect2"><h3 id="code-samples">Code Samples</h3><div class="paragraph"><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></div>
- <div class="ulist"><ul><li><p><a href="https://github.com/jMonkeyEngine/jmonkeyengine/blob/master/jme3-bullet/src/common/java/com/jme3/bullet/BulletAppState.java">BulletAppState</a> controls physical behaviour in PhysicsControl’ed Spatials.</p></li><li><p><a href="https://github.com/jMonkeyEngine/jmonkeyengine/blob/master/jme3-examples/src/main/java/jme3test/app/state/TestAppStates.java">TestAppStates.java</a> an example of a custom AppState</p><div class="ulist"><ul><li><p><a href="https://github.com/jMonkeyEngine/jmonkeyengine/blob/master/jme3-examples/src/main/java/jme3test/app/state/RootNodeState.java">RootNodeState.java</a></p></li></ul></div></li></ul></div></div></div>
- <div class="sect1"><h2 id="appstate">AppState</h2><div class="sectionbody"><div class="paragraph"><p>The AppState interface lets you initialize sets of objects, and hook a set of continuously executing code into the main loop.</p></div>
- <table class="tableblock frame-all grid-all spread"><colgroup><col style="width: 25%;"><col style="width: 75%;"></colgroup><thead><tr><th class="tableblock halign-left valign-top">AppState Method</th><th class="tableblock halign-left valign-top">Usage</th></tr></thead><tbody><tr><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>initialize(asm,app)</p></div></div></td><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>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:</p></div>
- <div class="listingblock"><div class="content"><pre class="CodeRay highlight"><code data-lang="java"><span class="local-variable">super</span>.initialize(stateManager, app);
- <span class="local-variable">this</span>.app = (SimpleApplication) app;</code></pre></div></div></div></td></tr><tr><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>cleanup()</p></div></div></td><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>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).</p></div></div></td></tr><tr><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>update(float tpf)</p></div></div></td><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>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.</p></div></div></td></tr><tr><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>isInitialized()</p></div></div></td><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>Your implementations of this interface should return the correct respective boolean value. (See AbstractAppState)</p></div></div></td></tr><tr><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>setEnabled(true)<br>
- setEnabled(false)</p></div></div></td><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>Temporarily enables or disables an AppState. (See AbstractAppState)</p></div></div></td></tr><tr><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>isEnabled()</p></div></div></td><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>Test whether AppState is enabled or disabled. Your implementation should consider the boolean. (See AbstractAppState)</p></div></div></td></tr><tr><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>stateAttached(asm)<br>
- stateDetached(asm)</p></div></div></td><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>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.)</p></div></div></td></tr><tr><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>render(RenderManager rm)</p></div></div></td><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>Renders the state, plus your optional customizations. (Typically not used.)</p></div></div></td></tr><tr><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>postRender()</p></div></div></td><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>Called after all rendering commands are flushed, including your optional customizations. (Typically not used.)</p></div></div></td></tr></tbody></table></div></div>
- <div class="sect1"><h2 id="abstractappstate">AbstractAppState</h2><div class="sectionbody"><div class="paragraph"><p>The <a href="https://github.com/jMonkeyEngine/jmonkeyengine/blob/master/jme3-core/src/main/java/com/jme3/app/state/AbstractAppState.java">AbstractAppState</a> class already implements some common methods (<code>isInitialized(), setEnabled(), isEnabled()</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></div>
- <div class="paragraph"><p>Definition:</p></div>
- <div class="listingblock"><div class="content"><pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">class</span> <span class="class">MyAppState</span> <span class="directive">extends</span> AbstractAppState {
- <span class="directive">private</span> SimpleApplication app;
- <span class="directive">private</span> Node x = <span class="keyword">new</span> Node(<span class="string"><span class="delimiter">"</span><span class="content">x</span><span class="delimiter">"</span></span>); <span class="comment">// some custom class fields...</span>
- <span class="directive">public</span> Node getX(){ <span class="keyword">return</span> x; } <span class="comment">// some custom methods...</span>
- <span class="annotation">@Override</span>
- <span class="directive">public</span> <span class="type">void</span> initialize(AppStateManager stateManager, Application app) {
- <span class="local-variable">super</span>.initialize(stateManager, app);
- <span class="local-variable">this</span>.app = (SimpleApplication)app; <span class="comment">// cast to a more specific class</span>
- <span class="comment">// init stuff that is independent of whether state is PAUSED or RUNNING</span>
- <span class="local-variable">this</span>.app.getRootNode().attachChild(getX()); <span class="comment">// modify scene graph...</span>
- <span class="local-variable">this</span>.app.doSomething(); <span class="comment">// call custom methods...</span>
- }
- <span class="annotation">@Override</span>
- <span class="directive">public</span> <span class="type">void</span> cleanup() {
- <span class="local-variable">super</span>.cleanup();
- <span class="comment">// unregister all my listeners, detach all my nodes, etc...</span>
- <span class="local-variable">this</span>.app.getRootNode().detachChild(getX()); <span class="comment">// modify scene graph...</span>
- <span class="local-variable">this</span>.app.doSomethingElse(); <span class="comment">// call custom methods...</span>
- }
- <span class="annotation">@Override</span>
- <span class="directive">public</span> <span class="type">void</span> setEnabled(<span class="type">boolean</span> enabled) {
- <span class="comment">// Pause and unpause</span>
- <span class="local-variable">super</span>.setEnabled(enabled);
- <span class="keyword">if</span>(enabled){
- <span class="comment">// init stuff that is in use while this state is RUNNING</span>
- <span class="local-variable">this</span>.app.getRootNode().attachChild(getX()); <span class="comment">// modify scene graph...</span>
- <span class="local-variable">this</span>.app.doSomethingElse(); <span class="comment">// call custom methods...</span>
- } <span class="keyword">else</span> {
- <span class="comment">// take away everything not needed while this state is PAUSED</span>
- ...
- }
- }
- <span class="comment">// Note that update is only called while the state is both attached and enabled.</span>
- <span class="annotation">@Override</span>
- <span class="directive">public</span> <span class="type">void</span> update(<span class="type">float</span> tpf) {
- <span class="comment">// do the following while game is RUNNING</span>
- <span class="local-variable">this</span>.app.getRootNode().getChild(<span class="string"><span class="delimiter">"</span><span class="content">blah</span><span class="delimiter">"</span></span>).scale(tpf); <span class="comment">// modify scene graph...</span>
- x.setUserData(...); <span class="comment">// call some methods...</span>
- }
- }</code></pre></div></div></div></div>
- <div class="sect1"><h2 id="baseappstate">BaseAppState</h2><div class="sectionbody"><div class="paragraph"><p>A new <a href="https://javadoc.jmonkeyengine.org/v3.3.0-beta1/com/jme3/app/state/BaseAppState.html">BaseAppState</a> class was introduced as part of the <a href="https://hub.jmonkeyengine.org/t/jmonkeyengine-3-1-alpha-4-released/35478">updates</a> being made to the AppState interface. AbstractAppState is the most minimal of the minimal implementations of the AppState interface. You essentially still need to do everything yourself, including getting the funky enable/disable/initialized/terminate logic right. Now you just extend BaseAppState and you get onEnable() and onDisable() already worked out for you.</p></div>
- <div class="paragraph"><p>Definition:</p></div>
- <div class="listingblock"><div class="content"><pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">class</span> <span class="class">MyBaseAppState</span> <span class="directive">extends</span> BaseAppState {<span class="error"> </span><span class="error"> </span><span class="error"> </span> <span class="error"> </span><span class="error"> </span><span class="error"> </span>
- <span class="annotation">@Override</span><span class="error"> </span><span class="error"> </span><span class="error"> </span>
- <span class="directive">protected</span> <span class="type">void</span> initialize(Application app) {<span class="error"> </span><span class="error"> </span><span class="error"> </span><span class="error"> </span><span class="error"> </span><span class="error"> </span><span class="error"> </span>
- <span class="comment">//It is technically safe to do all initialization and cleanup in the </span>
- <span class="comment">//onEnable()/onDisable() methods. Choosing to use initialize() and </span>
- <span class="comment">//cleanup() for this is a matter of performance specifics for the </span>
- <span class="comment">//implementor. </span>
- <span class="comment">//TODO: initialize your AppState, e.g. attach spatials to rootNode </span>
- }
- <span class="annotation">@Override</span><span class="error"> </span><span class="error"> </span><span class="error"> </span>
- <span class="directive">protected</span> <span class="type">void</span> cleanup(Application app) {<span class="error"> </span><span class="error"> </span><span class="error"> </span><span class="error"> </span><span class="error"> </span><span class="error"> </span><span class="error"> </span>
- <span class="comment">//TODO: clean up what you initialized in the initialize method, </span>
- <span class="comment">//e.g. remove all spatials from rootNode </span>
- }
- <span class="error"> </span> <span class="comment">//onEnable()/onDisable() can be used for managing things that should </span>
- <span class="comment">//only exist while the state is enabled. Prime examples would be scene </span>
- <span class="comment">//graph attachment or input listener attachment. </span>
- <span class="annotation">@Override</span><span class="error"> </span><span class="error"> </span><span class="error"> </span>
- <span class="directive">protected</span> <span class="type">void</span> onEnable() {<span class="error"> </span><span class="error"> </span><span class="error"> </span><span class="error"> </span><span class="error"> </span><span class="error"> </span><span class="error"> </span>
- <span class="comment">//Called when the state is fully enabled, ie: is attached and </span>
- <span class="comment">//isEnabled() is true or when the setEnabled() status changes after the </span>
- <span class="comment">//state is attached. </span>
- }
- <span class="error"> </span> <span class="error"> </span>
- <span class="error"> </span> <span class="annotation">@Override</span><span class="error"> </span><span class="error"> </span><span class="error"> </span>
- <span class="directive">protected</span> <span class="type">void</span> onDisable() {<span class="error"> </span><span class="error"> </span><span class="error"> </span><span class="error"> </span><span class="error"> </span><span class="error"> </span><span class="error"> </span>
- <span class="comment">//Called when the state was previously enabled but is now disabled </span>
- <span class="comment">//either because setEnabled(false) was called or the state is being </span>
- <span class="comment">//cleaned up. </span>
- }<span class="error"> </span><span class="error"> </span><span class="error"> </span> <span class="error"> </span><span class="error"> </span><span class="error"> </span>
- <span class="annotation">@Override</span><span class="error"> </span><span class="error"> </span><span class="error"> </span>
- <span class="directive">public</span> <span class="type">void</span> update(<span class="type">float</span> tpf) {<span class="error"> </span><span class="error"> </span><span class="error"> </span><span class="error"> </span><span class="error"> </span><span class="error"> </span><span class="error"> </span>
- <span class="comment">//TODO: implement behavior during runtime </span>
- }
- <span class="error"> </span> <span class="error"> </span>
- }</code></pre></div></div>
- <div class="paragraph"><p>Notable BaseAppState changes are as follows:</p></div>
- <div class="ulist"><ul><li><p>You no longer need to call super.initialize(stateManager, app) because it is now called by BaseAppState upon initialization for you.</p></li><li><p>You no longer have to cast SimpleApplication to have access to AssetManager, AppStateManager, and you can even get a State directly. The getters getApplication(), getAssetManager(), getState(type) and their methods are available to you immediately. However, you still have to cast SimpleApplication to get rootNode.</p></li><li><p>You no longer call super during cleanup, its done for you now.</p></li><li><p>It’s now safe to do all initialization and cleanup in the onEnable()/onDisable() methods.</p></li><li><p>Cleanup and setEnabled now have logging built in.</p></li></ul></div>
- <div class="paragraph"><p>You use BaseAppState as you would AbstractAppState, other than mentioned above, and which one you use is entirely up to you. However, BaseAppState makes your life easier and is the recommended one to use now.</p></div>
- <div class="paragraph"><p>See <a href="https://javadoc.jmonkeyengine.org/v3.3.0-beta1/com/jme3/app/state/BaseAppState.html">BaseAppState</a> for more information.</p></div></div></div>
- <div class="sect1"><h2 id="pausing-and-unpausing">Pausing and Unpausing</h2><div class="sectionbody"><div class="paragraph"><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></div></div>
- <div class="sect1"><h2 id="appstatemanager">AppStateManager</h2><div class="sectionbody"><div class="paragraph"><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 class="tableblock frame-all grid-all spread"><colgroup><col style="width: 50%;"><col style="width: 50%;"></colgroup><thead><tr><th class="tableblock halign-left valign-top">AppStateManager Method</th><th class="tableblock halign-left valign-top">Usage</th></tr></thead><tbody><tr><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>hasState(myState)</p></div></div></td><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>Is AppState object 'myState' attached?</p></div></div></td></tr><tr><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>getState(MyAppState.class)</p></div></div></td><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>Returns the first attached state that is an instance of a subclass of <code>MyAppState.class</code>.</p></div></div></td></tr></tbody></table>
- <div class="paragraph"><p>The AppStateManager’s <code>render(), postRender(), cleanup()</code> methods are internal, ignore them, users never call them directly.</p></div>
- <div class="ulist"><ul><li><p>If a detached AppState is attached then initialize() will be called on the following render pass.</p></li><li><p>If an attached AppState is detached then cleanup() will be called on the following render pass.</p></li><li><p>If you attach an already-attached AppState then the second attach is a no-op and will return false.</p></li><li><p>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.</p></li><li><p>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.</p></li></ul></div></div></div>
- <div class="sect2"><h3 id="best-practices">Best Practices</h3><div class="sect2"><h3 id="communication-among-appstates">Communication Among AppStates</h3><div class="paragraph"><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></div>
- <div class="paragraph"><p>You can use custom accessors to get data from AppStates, to set data in AppStates, or to trigger methods in AppStates.</p></div>
- <div class="listingblock"><div class="content"><pre class="CodeRay highlight"><code data-lang="java"><span class="local-variable">this</span>.app.getStateManager().getState(MyAppState.class).doSomeCustomStuffInThisState();</code></pre></div></div></div>
- <div class="sect2"><h3 id="initialize-familiar-class-fields">Initialize Familiar Class Fields</h3><div class="paragraph"><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></div>
- <div class="listingblock"><div class="content"><pre class="CodeRay highlight"><code data-lang="java"><span class="directive">private</span> SimpleApplication app;
- <span class="directive">private</span> Node rootNode;
- <span class="directive">private</span> AssetManager assetManager;
- <span class="directive">private</span> AppStateManager stateManager;
- <span class="directive">private</span> InputManager inputManager;
- <span class="directive">private</span> ViewPort viewPort;
- <span class="directive">private</span> BulletAppState physics;
- <span class="directive">public</span> <span class="type">class</span> <span class="class">MyAppState</span> <span class="directive">extends</span> AbstractAppState {
- <span class="annotation">@Override</span>
- <span class="directive">public</span> <span class="type">void</span> initialize(AppStateManager stateManager, Application app) {
- <span class="local-variable">super</span>.initialize(stateManager, app);
- <span class="local-variable">this</span>.app = (SimpleApplication) app; <span class="comment">// can cast Application to something more specific</span>
- <span class="local-variable">this</span>.rootNode = <span class="local-variable">this</span>.app.getRootNode();
- <span class="local-variable">this</span>.assetManager = <span class="local-variable">this</span>.app.getAssetManager();
- <span class="local-variable">this</span>.stateManager = <span class="local-variable">this</span>.app.getStateManager();
- <span class="local-variable">this</span>.inputManager = <span class="local-variable">this</span>.app.getInputManager();
- <span class="local-variable">this</span>.viewPort = <span class="local-variable">this</span>.app.getViewPort();
- <span class="local-variable">this</span>.physics = <span class="local-variable">this</span>.stateManager.getState(BulletAppState.class);
- }
- }</code></pre></div></div></div></div></div><div id="footer"><div id="footer-text">Version <br>Last updated 2019-12-20 23:30:51 +00:00</div></div><script type="text/javascript" src="https://cdn.jsdelivr.net/docsearch.js/2/docsearch.min.js"></script><script>docsearch({
- apiKey: 'a736b6d93de805e26ec2f49b55013fbd',
- indexName: 'jmonkeyengine',
- inputSelector: '#doc-search',
- debug: false // Set debug to true if you want to inspect the dropdown
- });</script></body></html>
|