/*
* Copyright (C) 2008 The Fysix Team
*
* This file is part of Fysix.
*
* Fysix is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* Fysix is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Fysix; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package net.sf.fysix;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;
import java.awt.geom.Ellipse2D;
import java.io.File;
import java.util.Collections;
import java.util.List;
import net.sf.fysix.engine.Engine;
import net.sf.fysix.input.InputAction;
import net.sf.fysix.input.InputHandler;
import net.sf.fysix.leveleditor.presentation.renderer.ShapeEditorDisplay;
import net.sf.fysix.leveleditor.tool.level.subtool.draw.DrawSettings;
import net.sf.fysix.leveleditor.tool.level.subtool.draw.ShapeMapObject;
import net.sf.fysix.leveleditor.tool.position.WorldPos;
import net.sf.fysix.math.Vector2d;
import net.sf.fysix.object.ShapeData;
import net.sf.fysix.object.ShapeHandler;
import net.sf.fysix.player.PlayerHandler;
import net.sf.fysix.presentation.renderer.HeadUpDisplay;
import net.sf.fysix.presentation.renderer.ProgressBar;
import net.sf.fysix.presentation.renderer.Renderer;
import net.sf.fysix.presentation.renderer.WorldDisplay;
import net.sf.fysix.presentation.renderer.Renderer.Part;
import net.sf.fysix.presentation.view.GroundView;
import net.sf.fysix.world.Planet;
import net.sf.fysix.world.TestPlanetEnvironment;
import net.sf.fysix.world.World;
import net.sf.fysix.world.WorldObject;
import net.sf.fysix.world.WorldObject.TypeE;
public class Main implements Runnable {
private static final long NANOS_PER_SEC = 1000000000L;
private static final long NANOS_PER_MILLI = 1000000L;
/**
* @param args
*/
public static void main(String[] args) {
Main main = new Main();
main.run();
}
private Renderer renderer;
private Engine engine;
private World world;
private int tickRate;
private WorldDisplay worldDisplay1;
private WorldDisplay worldDisplay2;
private PlayerHandler player1;
private PlayerHandler player2;
private HeadUpDisplay hud1;
private HeadUpDisplay hud2;
private InputHandler input1 = new InputHandler();
private InputHandler input2 = new InputHandler();
private InputHandler ctrlInput = new InputHandler();
private ProgressBar pb1;
private ProgressBar pb2;
private TestPlanetEnvironment testPlanetEnvironment; // TODO : Test
private ShapeEditorDisplay editorDisplay;
private double scaleCtrl = 2.0;
// TODO: Change false to disable/true to enable
private boolean levelEditor = true;
// Main
public Main() {
renderer = new Renderer();
engine = new Engine();
world = World.getInstance();
worldDisplay1 = new WorldDisplay();
worldDisplay2 = new WorldDisplay();
hud1 = new HeadUpDisplay();
hud2 = new HeadUpDisplay();
pb1 = new ProgressBar();
pb2 = new ProgressBar();
if(levelEditor == true){
editorDisplay = new ShapeEditorDisplay();
}
input1.mapKey(KeyEvent.VK_ALT, InputAction.FORWARD);
input1.mapKey(KeyEvent.VK_E, InputAction.BACKWARD);
input1.mapKey(KeyEvent.VK_A, InputAction.ROTATE_LEFT);
input1.mapKey(KeyEvent.VK_S, InputAction.ROTATE_RIGHT);
input1.mapKey(KeyEvent.VK_Z, InputAction.STRAFE_LEFT);
input1.mapKey(KeyEvent.VK_X, InputAction.STRAFE_RIGHT);
input1.mapKey(KeyEvent.VK_D, InputAction.SHOOT);
input2.mapKey(KeyEvent.VK_SPACE, InputAction.FORWARD);
input2.mapKey(KeyEvent.VK_O, InputAction.BACKWARD);
input2.mapKey(KeyEvent.VK_J, InputAction.ROTATE_LEFT);
input2.mapKey(KeyEvent.VK_K, InputAction.ROTATE_RIGHT);
input2.mapKey(KeyEvent.VK_N, InputAction.STRAFE_LEFT);
input2.mapKey(KeyEvent.VK_M, InputAction.STRAFE_RIGHT);
input2.mapKey(KeyEvent.VK_L, InputAction.SHOOT);
ctrlInput.mapKey(KeyEvent.VK_ESCAPE, InputAction.QUIT);
ctrlInput.mapKey(KeyEvent.VK_F1, InputAction.ZOOM_IN);
ctrlInput.mapKey(KeyEvent.VK_F2, InputAction.ZOOM_OUT);
if(levelEditor == true){
ctrlInput.mapKey(KeyEvent.VK_UP, InputAction.PAN_UP);
ctrlInput.mapKey(KeyEvent.VK_DOWN, InputAction.PAN_DOWN);
ctrlInput.mapKey(KeyEvent.VK_LEFT, InputAction.PAN_LEFT);
ctrlInput.mapKey(KeyEvent.VK_RIGHT, InputAction.PAN_RIGHT);
}
renderer.addKeyListener(input1);
renderer.addKeyListener(input2);
renderer.addKeyListener(ctrlInput);
if(levelEditor == true){
renderer.addMouseListener(editorDisplay.getMouseListener());
renderer.addMouseMotionListener(editorDisplay.getMouseMotionListener());
}
ShapeHandler sh = new ShapeHandler();
sh.loadShapes(new File("config\\shapes.xml"));
player1 = new PlayerHandler(input1, sh.getShapeByName("classic"));
player1.enterCreate(world, new Vector2d(0, 0));
player1.enterInit(world);
player1.enterPlayActive(world);
hud1.setPlayerShip(player1);
pb1.setPlayerShip(player1);
player2 = new PlayerHandler(input2, sh.getShapeByName("modified"));
player2.enterCreate(world, new Vector2d(0, -400));
player2.enterInit(world);
player2.enterPlayActive(world);
hud2.setPlayerShip(player2);
pb2.setPlayerShip(player2);
//planet = new Planet(60, AbstractWorldObject.TTL_INFINITE, TypeE.OBJECT_ALIVE);
testPlanetEnvironment = new TestPlanetEnvironment(new Vector2d(300, 0)); // TODO : Test
//planet.setPosition(new Vector2d(300, 0));
//world.addObject(planet, false);
// MAP/LEVEL
if(levelEditor == false){
ShapeHandler levelLoader = new ShapeHandler();
levelLoader.loadShapes(new File("config\\level.xml"));
List<ShapeData> groundShapes = levelLoader.getShapes();
for (ShapeData sd : Collections.unmodifiableCollection(groundShapes)){
// System.out.println("SHAPE : len = " + sd.x.length);
Polygon pShape = new Polygon();
for(int vx=0;vx<sd.x.length;vx++){
pShape.addPoint(sd.x[vx]-500, sd.y[vx]-500); // TODO: FIX SIZE TO MAP!!!
// System.out.println("SHAPE : x = " + (sd.x[vx]-10000) + " , y = " + + (sd.y[vx]-10000));
}
world.addGround(pShape, 0.5);
}
world.addGround(new Ellipse2D.Float(-60+300, -60, 60*2, 60*2), 1.0);
world.addGround(new Polygon(new int[] { -200, 200, 0}, new int[] { 200, 200, 300 }, 3), 0.5);
}
world.setGroundView(new GroundView(world));
world.addEnvironment(testPlanetEnvironment); // TODO : Test
//world.addEnvironment(new TestEnvironment()); // TOTAL MAP/LEVEL GRAVITY
worldDisplay1.setWorld(world);
worldDisplay2.setWorld(world);
if(levelEditor == false){
renderer.addDisplay(worldDisplay1, Part.LEFT);
renderer.addDisplay(worldDisplay2, Part.RIGHT);
renderer.addDisplay(hud1, Part.LEFT);
renderer.addDisplay(hud2, Part.RIGHT);
renderer.addDisplay(pb1, Part.LEFT);
renderer.addDisplay(pb2, Part.RIGHT);
} else {
renderer.addDisplay(editorDisplay, Part.FULL);
}
engine.setWorld(world);
tickRate = 30;
}
private int panX = 0;
private int panY = 0;
public void run() {
long nextTick = System.nanoTime() + NANOS_PER_SEC / tickRate;
long dropMask = 0;
// This loop tries to keep a constant tick rate dropping rendered frames if the computer is too slow.
// It is important to keep the physics engine delta time constant so the calculations are the same
// regardless of computer speed. More so in network games.
while (true) {
long delta = nextTick - System.nanoTime();
if (delta > 0) {
// Render one frame
long start = System.nanoTime();
renderer.renderFrame(scaleCtrl);
hud1.setRenderTime(System.nanoTime() - start);
hud2.setRenderTime(System.nanoTime() - start);
} else {
// No time to render frame, skip frame
dropMask |= 1;
}
hud1.setFps((double) tickRate * (Long.SIZE - Long.bitCount(dropMask)) / Long.SIZE);
hud2.setFps((double) tickRate * (Long.SIZE - Long.bitCount(dropMask)) / Long.SIZE);
dropMask <<= 1;
delta = nextTick - System.nanoTime();
while (delta > 0) {
// Fast computer so we can sleep for a while
try {
Thread.sleep(delta / NANOS_PER_MILLI, (int) (delta % NANOS_PER_MILLI));
} catch (InterruptedException e) {
e.printStackTrace();
}
delta = nextTick - System.nanoTime();
}
// Handle any events from one shot input here, e.g. hitting 'shoot'.
// Continuous input, e.g. holding down 'accelerate', is not handled by event.
// It is handled by checking if the key is down when calculating the accelerating force.
//
// PLAYER 1
//
int shots = input1.checkEvent(InputAction.SHOOT);
if (shots > 0) {
WorldObject bullet = new Planet(2,50, TypeE.WEAPON_SHOT_MINE);
Vector2d dir = new Vector2d(Math.cos(player1.getWorldObject().getRotation()), Math.sin(player1.getWorldObject().getRotation()));
Vector2d pos = player1.getWorldObject().getPosition();
pos.addScaled(16, dir);
bullet.setPosition(pos);
dir.scale(1000000);
//bullet.setVelocity(dir);
world.addObject(bullet, true);
bullet.applyImpulse(dir);
//dir.scale(-1);
//playerShip.applyImpulse(dir);
}
//
// PLAYER 2
//
shots = input2.checkEvent(InputAction.SHOOT);
if (shots > 0) {
WorldObject bullet = new Planet(2,50, TypeE.WEAPON_SHOT_MINE);
Vector2d dir = new Vector2d(Math.cos(player2.getWorldObject().getRotation()), Math.sin(player2.getWorldObject().getRotation()));
Vector2d pos = player2.getWorldObject().getPosition();
pos.addScaled(16, dir);
bullet.setPosition(pos);
dir.scale(1000000);
//bullet.setVelocity(dir);
world.addObject(bullet, true);
bullet.applyImpulse(dir);
}
// Advance the game time by one tick
engine.tick(1.0 / tickRate);
nextTick += NANOS_PER_SEC / tickRate;
if(levelEditor == false){
worldDisplay1.scrollTo(player1.getWorldObject().getPosition(), 1.0 / tickRate);
worldDisplay2.scrollTo(player2.getWorldObject().getPosition(), 1.0 / tickRate);
} else {
worldDisplay1.scrollTo(new Vector2d(panX, panY), 1.0 / tickRate);
}
// InputControl
if(ctrlInput.checkEvent(InputAction.QUIT) > 0){
System.exit(0);
}
if(ctrlInput.checkEvent(InputAction.ZOOM_IN) > 0){
if(scaleCtrl>0.001){
scaleCtrl *= 0.4;
}
}
if(ctrlInput.checkEvent(InputAction.ZOOM_OUT) > 0){
if(scaleCtrl<1000.0){
scaleCtrl /= 0.4;
}
}
if(levelEditor == true){
if(ctrlInput.checkEvent(InputAction.PAN_UP) > 0){
panY -= 100;
System.out.println("PAN_UP => X : " + panX + " , Y: " + panY);
}
if(ctrlInput.checkEvent(InputAction.PAN_DOWN) > 0){
panY += 100;
System.out.println("PAN_DOWN => X : " + panX + " , Y: " + panY);
}
if(ctrlInput.checkEvent(InputAction.PAN_LEFT) > 0){
panX -= 100;
System.out.println("PAN_LEFT => X : " + panX + " , Y: " + panY);
}
if(ctrlInput.checkEvent(InputAction.PAN_RIGHT) > 0){
panX += 100;
System.out.println("PAN_RIGHT => X : " + panX + " , Y: " + panY);
}
editorDisplay.setScreenState(scaleCtrl, panX, panY, renderer.getScreenSize().width, renderer.getScreenSize().height);
}
}
}
}