📄 basesimplegame.java
字号:
/*
* Copyright (c) 2003-2009 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.
*/
// $Id: BaseSimpleGame.java 4091 2009-01-21 19:01:20Z joshua.j.ellen $
package com.jme.app;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.jme.input.FirstPersonHandler;
import com.jme.input.InputHandler;
import com.jme.input.KeyBindingManager;
import com.jme.input.KeyInput;
import com.jme.input.MouseInput;
import com.jme.input.joystick.JoystickInput;
import com.jme.light.PointLight;
import com.jme.math.Vector3f;
import com.jme.renderer.Camera;
import com.jme.renderer.ColorRGBA;
import com.jme.renderer.Renderer;
import com.jme.scene.Node;
import com.jme.scene.Spatial;
import com.jme.scene.Text;
import com.jme.scene.Spatial.CullHint;
import com.jme.scene.shape.Quad;
import com.jme.scene.state.LightState;
import com.jme.scene.state.WireframeState;
import com.jme.scene.state.ZBufferState;
import com.jme.system.DisplaySystem;
import com.jme.system.JmeException;
import com.jme.util.Debug;
import com.jme.util.GameTaskQueue;
import com.jme.util.GameTaskQueueManager;
import com.jme.util.TextureManager;
import com.jme.util.Timer;
import com.jme.util.geom.Debugger;
import com.jme.util.stat.StatCollector;
import com.jme.util.stat.StatType;
import com.jme.util.stat.graph.DefColorFadeController;
import com.jme.util.stat.graph.GraphFactory;
import com.jme.util.stat.graph.LineGrapher;
import com.jme.util.stat.graph.TabledLabelGrapher;
/**
* A game implementation that handles numerous common tasks.
* <p>
* This class implements all of the abstract methods and provides some default
* input handlers and code to report on memory usage and to display simple
* performance metrics on the screen.
* <p>
* All that is required to use this class is to build your scene graph (in
* {@link #simpleInitGame()}) and add it to the {@link #rootNode}.
* <p>
* A light state is provided with a single point light, (you can easily add
* more by accessing the {@link #lightState} field) and there is an FPS and
* statistics display. The depth buffer compare function is automatically set
* to {@code CF_LEQUAL}. Wireframe mode and the lights may be toggled via T
* and L respectively.
* <p>
* Note that this class does <strong>not</strong> automatically render the
* root node, you need to do this yourself by overriding {@link #simpleRender()}.
* If you need to update your game state then a corresponding
* {@link #simpleUpdate()} hook is also provided.
*
* @author Joshua Slack, (javadoc by cep21)
* @version $Revision: 4091 $, $Date: 2009-01-22 03:01:20 +0800 (星期四, 22 一月 2009) $
*/
public abstract class BaseSimpleGame extends BaseGame {
private static final Logger logger = Logger.getLogger(BaseSimpleGame.class
.getName());
/**
* The camera that we see through.
*/
protected Camera cam;
/**
* The root of our normal scene graph.
*/
protected Node rootNode;
/**
* Handles our mouse/keyboard input.
*/
protected InputHandler input;
/**
* High resolution timer for jME.
*/
protected Timer timer;
/**
* The root node for our stats and text.
*/
protected Node statNode;
/**
* The root node for our stats graphs.
*/
protected Node graphNode;
/**
* Alpha bits to use for the renderer. Any changes must be made prior to call of start().
*/
protected int alphaBits = 0;
/**
* Depth bits to use for the renderer. Any changes must be made prior to call of start().
*/
protected int depthBits = 8;
/**
* Stencil bits to use for the renderer. Any changes must be made prior to call of start().
*/
protected int stencilBits = 0;
/**
* Number of samples to use for the multisample buffer. Any changes must be made prior to call of start().
*/
protected int samples = 0;
/**
* Simply an easy way to get at timer.getTimePerFrame(). Also saves math cycles since
* you don't call getTimePerFrame more than once per frame.
*/
protected float tpf;
/**
* True if the renderer should display the depth buffer.
*/
protected boolean showDepth = false;
/**
* True if the renderer should display bounds.
*/
protected boolean showBounds = false;
/**
* True if the renderer should display normals.
*/
protected boolean showNormals = false;
/**
* True if the we should show the stats graphs.
*/
protected boolean showGraphs = false;
/**
* A wirestate to turn on and off for the rootNode
*/
protected WireframeState wireState;
/**
* A lightstate to turn on and off for the rootNode
*/
protected LightState lightState;
/**
* boolean for toggling the simpleUpdate and geometric update parts of the
* game loop on and off.
*/
protected boolean pause;
private TabledLabelGrapher tgrapher;
// private TimedAreaGrapher lgrapher;
private LineGrapher lgrapher;
private Quad lineGraph, labGraph;
public BaseSimpleGame() {
System.setProperty("jme.stats", "set");
}
/**
* Updates the timer, sets tpf, updates the input and updates the fps
* string. Also checks keys for toggling pause, bounds, normals, lights,
* wire etc.
*
* @param interpolation unused in this implementation
* @see AbstractGame#update(float interpolation)
*/
protected void update( float interpolation ) {
/** Recalculate the framerate. */
timer.update();
/** Update tpf to time per frame according to the Timer. */
tpf = timer.getTimePerFrame();
/** Check for key/mouse updates. */
updateInput();
/** update stats, if enabled. */
if (Debug.stats) {
StatCollector.update();
}
// Execute updateQueue item
GameTaskQueueManager.getManager().getQueue(GameTaskQueue.UPDATE).execute();
/** If toggle_pause is a valid command (via key p), change pause. */
if ( KeyBindingManager.getKeyBindingManager().isValidCommand(
"toggle_pause", false ) ) {
pause = !pause;
}
/** If step is a valid command (via key ADD), update scenegraph one unit. */
if ( KeyBindingManager.getKeyBindingManager().isValidCommand(
"step", true ) ) {
simpleUpdate();
rootNode.updateGeometricState(tpf, true);
}
/** If toggle_wire is a valid command (via key T), change wirestates. */
if ( KeyBindingManager.getKeyBindingManager().isValidCommand(
"toggle_wire", false ) ) {
wireState.setEnabled( !wireState.isEnabled() );
rootNode.updateRenderState();
}
/** If toggle_lights is a valid command (via key L), change lightstate. */
if ( KeyBindingManager.getKeyBindingManager().isValidCommand(
"toggle_lights", false ) ) {
lightState.setEnabled( !lightState.isEnabled() );
rootNode.updateRenderState();
}
/** If toggle_bounds is a valid command (via key B), change bounds. */
if ( KeyBindingManager.getKeyBindingManager().isValidCommand(
"toggle_bounds", false ) ) {
showBounds = !showBounds;
}
/** If toggle_depth is a valid command (via key F3), change depth. */
if ( KeyBindingManager.getKeyBindingManager().isValidCommand(
"toggle_depth", false ) ) {
showDepth = !showDepth;
}
if (Debug.stats) {
/** handle toggle_stats command (key F4) */
if ( KeyBindingManager.getKeyBindingManager().isValidCommand(
"toggle_stats", false ) ) {
showGraphs = !showGraphs;
Debug.updateGraphs = showGraphs;
labGraph.clearControllers();
lineGraph.clearControllers();
labGraph.addController(new DefColorFadeController(labGraph, showGraphs ? .6f : 0f, showGraphs ? .5f : -.5f));
lineGraph.addController(new DefColorFadeController(lineGraph, showGraphs ? .6f : 0f, showGraphs ? .5f : -.5f));
}
}
if ( KeyBindingManager.getKeyBindingManager().isValidCommand(
"toggle_normals", false ) ) {
showNormals = !showNormals;
}
/** If camera_out is a valid command (via key C), show camera location. */
if ( KeyBindingManager.getKeyBindingManager().isValidCommand(
"camera_out", false ) ) {
logger.info( "Camera at: "
+ display.getRenderer().getCamera().getLocation() );
}
if ( KeyBindingManager.getKeyBindingManager().isValidCommand(
"screen_shot", false ) ) {
display.getRenderer().takeScreenShot( "SimpleGameScreenShot" );
}
if ( KeyBindingManager.getKeyBindingManager().isValidCommand(
"parallel_projection", false ) ) {
if ( cam.isParallelProjection() ) {
cameraPerspective();
}
else {
cameraParallel();
}
}
if ( KeyBindingManager.getKeyBindingManager().isValidCommand(
"mem_report", false ) ) {
long totMem = Runtime.getRuntime().totalMemory();
long freeMem = Runtime.getRuntime().freeMemory();
long maxMem = Runtime.getRuntime().maxMemory();
logger.info("|*|*| Memory Stats |*|*|");
logger.info("Total memory: "+(totMem>>10)+" kb");
logger.info("Free memory: "+(freeMem>>10)+" kb");
logger.info("Max memory: "+(maxMem>>10)+" kb");
}
if ( KeyBindingManager.getKeyBindingManager().isValidCommand( "exit",
false ) ) {
finish();
}
}
/**
* Check for key/mouse updates. Allow overriding this method to skip update in subclasses.
*/
protected void updateInput() {
input.update( tpf );
}
/**
* Clears stats, the buffers and renders bounds and normals if on.
*
* @param interpolation unused in this implementation
* @see AbstractGame#render(float interpolation)
*/
protected void render( float interpolation ) {
Renderer r = display.getRenderer();
/** Clears the previously rendered information. */
r.clearBuffers();
// Execute renderQueue item
GameTaskQueueManager.getManager().getQueue(GameTaskQueue.RENDER).execute();
}
protected void doDebug(Renderer r) {
/**
* If showing bounds, draw rootNode's bounds, and the bounds of all its
* children.
*/
if ( showBounds ) {
Debugger.drawBounds( rootNode, r, true );
}
if ( showNormals ) {
Debugger.drawNormals( rootNode, r );
Debugger.drawTangents( rootNode, r );
}
}
/**
* Creates display, sets up camera, and binds keys. Called in
* BaseGame.start() directly after the dialog box.
*
* @see AbstractGame#initSystem()
*/
protected void initSystem() throws JmeException {
logger.info(getVersion());
try {
/**
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -