package edu.ups.gamedev.game;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.UnknownHostException;
import com.jme.image.Texture;
import com.jme.input.AbsoluteMouse;
import com.jme.input.InputHandler;
import com.jme.input.KeyBindingManager;
import com.jme.input.KeyInput;
import com.jme.input.MouseInput;
import com.jme.light.DirectionalLight;
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.SceneElement;
import com.jme.scene.Text;
import com.jme.scene.state.AlphaState;
import com.jme.scene.state.CullState;
import com.jme.scene.state.LightState;
import com.jme.scene.state.TextureState;
import com.jme.scene.state.WireframeState;
import com.jme.scene.state.ZBufferState;
import com.jme.system.DisplaySystem;
import com.jme.system.GameSettings;
import com.jme.util.TextureManager;
import com.jme.util.Timer;
import com.jmex.game.state.GameState;
import com.jmex.physics.PhysicsDebugger;
import com.jmex.physics.StaticPhysicsNode;
import com.jmex.physics.material.Material;
import com.jmex.terrain.TerrainPage;
import edu.ups.gamedev.net.Client;
import edu.ups.gamedev.net.NetworkCommon;
import edu.ups.gamedev.net.NetworkConstants;
import edu.ups.gamedev.net.Server;
import edu.ups.gamedev.player.MouseLookCamera;
import edu.ups.gamedev.player.Player;
import edu.ups.gamedev.player.Tank;
import edu.ups.gamedev.player.TankController;
import edu.ups.gamedev.player.TankInputHandler;
import edu.ups.gamedev.terrain.Level;
import edu.ups.gamedev.weapons.CannonFireable;
import edu.ups.gamedev.weapons.KineticWarhead;
import edu.ups.gamedev.weapons.MissileFireable;
import edu.ups.gamedev.weapons.TeapotPlacingWarhead;
import edu.ups.gamedev.weapons.Weapon;
public class TankGameState extends GameState {
public final Vector3f UP = new Vector3f(0,1,0);
protected float nearFrustrum = 1;
protected float farFrustrum = 10000;
// global objects
protected Node root;
protected Player player;
protected MouseLookCamera chaseCam;
protected TerrainPage terrain;
protected InputHandler input;
protected AbsoluteMouse mouse;
protected WireframeState wireState;
protected boolean showPhysics = false;
// hud
protected Node hud;
protected Text fps;
//network
protected NetworkCommon net;
protected boolean isServer;
protected InetAddress address;
// local convenience references to static resources
protected DisplaySystem display;
protected Renderer renderer;
protected GameSettings settings;
protected Timer timer;
public TankGameState(boolean isServer, InetAddress address) {
root = new Node("root");
this.isServer = isServer;
this.address = address;
}
/**
* Create the chase camera and assign a tank to it.
*
*/
protected void buildCamera() {
Camera cam = renderer.getCamera();
// initialize the perspective
cam.setFrustumPerspective(60.0f, (float) display.getWidth()
/ (float) display.getHeight(), nearFrustrum, farFrustrum);
cam.update();
// initialize the control scheme
chaseCam = new MouseLookCamera(cam, player.getControlledObject(), root,
15, 0, 0);
}
/**
* Build the HUD.
*
* @throws MalformedURLException
*/
protected void buildHud() {
// BLATANTLY stolen from SimpleGame
// -- FPS DISPLAY
// First setup alpha state
/* This allows correct blending of text and what is already rendered below it */
AlphaState as1 = display.getRenderer().createAlphaState();
as1.setBlendEnabled(true);
as1.setSrcFunction(AlphaState.SB_SRC_ALPHA);
as1.setDstFunction(AlphaState.DB_ONE);
as1.setTestEnabled(true);
as1.setTestFunction(AlphaState.TF_GREATER);
as1.setEnabled(true);
// Now setup font texture
TextureState font = display.getRenderer().createTextureState();
/* The texture is loaded from fontLocation */
font.setTexture(TextureManager.loadTexture(TankGameState.class
.getClassLoader().getResource("com/jme/app/defaultfont.tga"),
Texture.MM_LINEAR, Texture.FM_LINEAR));
font.setEnabled(true);
// Then our font Text object.
/** This is what will actually have the text at the bottom. */
fps = new Text("FPS label", "");
fps.setCullMode(SceneElement.CULL_NEVER);
fps.setTextureCombineMode(TextureState.REPLACE);
// Finally, a stand alone node (not attached to root on purpose)
hud = new Node("HUD");
hud.attachChild(fps);
hud.setRenderState(font);
hud.setRenderState(as1);
hud.setCullMode(SceneElement.CULL_NEVER);
}
/**
* Create an InputHandler and handle the mouse.
*/
protected void buildInput() {
// TODO this is sort of messy and out of order, TankInputHandler should be handled when creating tanks, or something
input = new TankInputHandler((Tank) player.getControlledObject());
// Create a new mouse. Restrict its movements to the display screen.
mouse = new AbsoluteMouse("mouse", display.getWidth(), display
.getHeight());
// Center the mouse to begin with
MouseInput.get().setCursorPosition(display.getWidth() / 2,
display.getHeight() / 2);
// Assign the mouse to an input handler
mouse.registerWithInputHandler(input);
}
/**
* Loads user input keys into the KeyBindingManager.
*
*/
protected void buildKeys() {
// TODO set control keys. Eventually this should be done via some user-configurable file.
KeyBindingManager.getKeyBindingManager().set("exit",
KeyInput.KEY_ESCAPE);
// stolen from SimpleGame
/* Assign key T to action "toggle_wire". */
KeyBindingManager.getKeyBindingManager().set("toggle_wire",
KeyInput.KEY_T);
KeyBindingManager.getKeyBindingManager().set("toggle_physics",
KeyInput.KEY_V);
}
/**
* Assemble the lighting.
*
*/
protected void buildLighting() {
// Set up a basic, default light.
DirectionalLight light = new DirectionalLight();
light.setDiffuse(new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f));
light.setAmbient(new ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f));
light.setDirection(new Vector3f(1, -1, 0).normalize());
light.setEnabled(true);
// Attach the light to a lightState and the lightState to root.
LightState lightState = display.getRenderer().createLightState();
lightState.setEnabled(true);
lightState.attach(light);
root.setRenderState(lightState);
}
protected void buildNetwork() {
// initialize the network connection based on which option the user selected
if (isServer) {
try {
net = new Server();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// try {
// new ChatServer((Server)net);
// } catch (Exception e) {
// //TODO
// }
} else {
try {
net = new Client(address);
((Client) net).connectToServer();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// try {
// new ChatClient((Client)net);
// } catch (Exception e) {
// //TODO
// }
}
}
/**
* Create a <code>Player</code> and give the player a <code>Tank</code>.
*
*/
protected void buildPlayer() {
// TODO abstract player and tank creation
// create player and tank
Tank playerTank = createTank(Tank.LIGHT_TANK);
player = new Player("Player", playerTank);
// attach everything
root.attachChild(playerTank);
playerTank.setLocalTranslation(10, 200, 10);
playerTank.setPrimaryWeapon(new Weapon(CannonFireable.class, new TeapotPlacingWarhead(), .2f));
playerTank.setSecondaryWeapon(new Weapon(MissileFireable.class, new KineticWarhead(), .2f));
playerTank.addController(new TankController(playerTank));
//register the player
try {
net.register(player.getControlledObject(), NetworkConstants.TANK);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Load in the terrain.
*
*/
protected void buildTerrain() {
// TODO abstract terrain creation and loading
try {
Level level = new Level(new File("resources/mapOne"));
terrain = level.getMap().getTerrain();
StaticPhysicsNode staticNode = TankGame.PHYSICS.getPhysicsSpace().createStaticNode();
root.attachChild(staticNode);
staticNode.attachChild(terrain);
staticNode.generatePhysicsGeometry(true);
staticNode.setMaterial(Material.WOOD);
} catch (FileNotFoundException fnfe) {
ErrorHandler.log(fnfe.getMessage());
ErrorHandler.exit();
} catch (IOException ioe) {
ErrorHandler.log(ioe.getMessage());
ErrorHandler.exit();
}
}
public void respawn(){
buildPlayer();
buildCamera();
buildInput();
}
@Override
public void cleanup() {
net.kill();
}
/**
* Create a new Tank of type tankType.
*
* @param tankType
* @return
*/
protected Tank createTank(String tankType) {
Tank tank = null;
try {
tank = new Tank(tankType);
} catch (MalformedURLException murle) {
ErrorHandler.log("Could not load resource " + tankType);
ErrorHandler.exit();
}
return tank;
}
/**
* Return the <code>MouseLookCamera</code> used by this TankGameState.
*
* @return
*/
public MouseLookCamera getCamera() {
return chaseCam;
}
public InputHandler getInput() {
return input;
}
public NetworkCommon getNetwork() {
return net;
}
// /**
// * Get the <code>PhysicsSpace</code> associate with this TankGameState.
// *
// * @return
// */
// public PhysicsSpace getPhysicsSpace() {
// return physicsSpace;
// }
/**
* Retrieve the root <code>Node</code> of this TankGameState.
*
* @return root node
*/
public Node getRoot() {
return root;
}
/**
* Returns the <code>TerrainPage</code> associated with this TankGameState.
*
* @return terrain
*/
public TerrainPage getTerrain() {
return terrain;
}
/**
* Handles user input as described by the KeyBindingManager.
*
*/
protected void handleKeys() {
// handle exiting
if (KeyBindingManager.getKeyBindingManager().isValidCommand("exit")) {
setActive(false);
TankGame.GAME.shutdown();
}
// stolen form SimpleGame
if (KeyBindingManager.getKeyBindingManager().isValidCommand(
"toggle_wire", false)) {
wireState.setEnabled(!wireState.isEnabled());
root.updateRenderState();
}
if (KeyBindingManager.getKeyBindingManager().isValidCommand(
"toggle_physics", false)) {
showPhysics = !showPhysics;
}
}
/**
* Initialize this GameState.
*
*/
public void init() {
// bind static resources to local variables
display = TankGame.GAME.getDisplay();
renderer = display.getRenderer();
settings = TankGame.GAME.getSettings();
timer = Timer.getTimer();
// init locals
//root = new Node("root");
// physicsSpace.setDirectionalGravity(new Vector3f(0f,-9.8f,0f));
// build statements
buildKeys();
buildTerrain();
buildNetwork();
buildPlayer();
buildCamera();
buildInput();
buildLighting();
buildHud();
// create wireframe state
wireState = display.getRenderer().createWireframeState();
wireState.setEnabled(false);
root.setRenderState(wireState);
// set culling on nonfacing triangles
CullState cs = display.getRenderer().createCullState();
cs.setCullMode(CullState.CS_BACK);
root.setRenderState(cs);
// enable the depth buffer
ZBufferState buf = display.getRenderer().createZBufferState();
buf.setEnabled(true);
buf.setFunction(ZBufferState.CF_LEQUAL);
root.setRenderState(buf);
// enable statistics gathering
renderer.enableStatistics(true);
// update the tree
root.updateGeometricState(0.0f, true);
root.updateRenderState();
hud.updateGeometricState(0.0f, true);
hud.updateRenderState();
}
@Override
public void render(float arg0) {
// Clear the screen
display.getRenderer().clearStatistics();
display.getRenderer().clearBuffers();
try {
display.getRenderer().draw(root);
} catch (Exception e) {
e.printStackTrace();
}
display.getRenderer().draw(hud);
if (showPhysics) PhysicsDebugger.drawPhysics(TankGame.PHYSICS.getPhysicsSpace(), renderer);
}
@Override
public void update(float interpolation) {
handleKeys();
// FPS stuff
fps.print("FPS: " + (int) timer.getFrameRate() + " - "
+ renderer.getStatistics());
// other updates
input.update(interpolation);
chaseCam.update();
root.updateGeometricState(interpolation, true);
}
}