package org.group20.sunstruck;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Iterator;
import org.group20.sunstruck.behavior.Behavior;
import org.group20.sunstruck.gameobject.Boss;
import org.group20.sunstruck.gameobject.GameObject;
import org.group20.sunstruck.gameobject.GameObjectFactory;
import org.group20.sunstruck.gameobject.Player;
import org.group20.sunstruck.gui.GUI;
import org.group20.sunstruck.input.Input;
import org.group20.sunstruck.interfaces.GameInterface;
import org.group20.sunstruck.world.map.MapGenerator;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
import com.badlogic.gdx.physics.box2d.Contact;
import com.badlogic.gdx.physics.box2d.ContactListener;
import com.badlogic.gdx.physics.box2d.World;
public class Game implements GameInterface, ContactListener {
public static final FileHandle PLAYER_FILE = Gdx.files
.external("player.dat");
public static boolean DEBUG = false;
public static TextureAtlas textureAtlas = new TextureAtlas(
Gdx.files.internal("data/pack"));
private float updateRate = 1.0f; // physics update rate
private float totalTime;
private Vector2 initGravity = new Vector2(0, 0);
private DIFFICULTIES difficulty;
private GameObjectFactory goFactory;
private MapGenerator map = new MapGenerator();
private Player player;
private Shop shop;
private World world;
private Input input;
private GUI gui;
private Menu menu;
private ArrayList<Body> destroyedBodiesList = new ArrayList<Body>();
private float time;
private boolean bossMode = false;
private boolean bossAlive = false;
private float bossTimer = 0;
private int bossCount = 1;
private int bossInterval = 50000; // playerScore >
// bossInterval*bossCount =>
// spawn boss
private float enemySpawnTime = 0;
private float enemySpawnInterval = 2;
private boolean doReset = false;
private Game() {
this(DIFFICULTIES.MEDIUM);
}
public void initializePlayer() {
// Not tested.
// player = openPlayerObject();
// if(player == null)
player = goFactory.createPlayer(new Vector2(0, 0), 0);
}
private Game(DIFFICULTIES d) {
setDifficulty(d);
world = new World(initGravity, true);
world.setContactListener(this);
gui = new GUI();
input = new Input(gui);
goFactory = new GameObjectFactory(d);
shop = new Shop();
menu = new Menu();
}
private static class GameHolder { // singleton holder
public static final Game INSTANCE = new Game();
}
public static Game getInstance() {
return GameHolder.INSTANCE;
}
@Override
public void start() {
Behavior.initFilters();
}
@Override
public void update() {
System.out.println("I update i game: " + Menu.isActive);
if (Shop.isActive || Menu.isActive) {
System.out.println("hest");
input.update();
return;
}
if (doReset) {
doReset = false;
doReset();
}
clearDestroyedBodiesList();
totalTime++;
if (Game.DEBUG)
System.out.println("Total game updates: " + totalTime);
time += Gdx.graphics.getDeltaTime();
if (time >= 0.01) {
input.update();
Body body = null;
GameObject go = null;
Iterator<Body> it = world.getBodies();
while (it.hasNext()) {
body = it.next();
if (body == null)
continue;
if (body.getType() == BodyType.StaticBody)
continue;
go = (GameObject) body.getUserData();
go.update();
}
time = 0;
}
// SPAWNING ENEMIES
if (!bossMode) {
if (player.getScore() >= bossInterval * bossCount) {
// System.out.println("Boss mode activated");
bossMode = true;
} else {
spawnEnemy();
}
} else {
spawnBoss();
}
}
private void spawnEnemy() {
if (!bossMode) {
enemySpawnTime += Gdx.graphics.getDeltaTime();
if (enemySpawnTime > enemySpawnInterval) {
// 2 = n-1. n=3, the number of enemies available in the switch
int random = randomNumber(0, 2);
switch (random) {
case 0:
spawnSmallLaserSquad();
break;
case 1:
spawnSmallKamikazeSquad();
break;
case 2:
spawnMediumKamikazeSquad();
break;
default:
break;
}
enemySpawnTime = 0;
}
}
}
private void spawnBoss() {
if (!bossAlive) {
bossTimer += Gdx.graphics.getDeltaTime();
// System.out.println("Trying to spawn boss{alive:" + bossAlive
// + "}, remaining time:" + bossTimer + "/5.0");
if (bossTimer >= 10.0) {
// System.out.println("Spawning boss!");
goFactory.createBoss(new Vector2(12, 0), (float) Math.PI);
bossAlive = true;
bossTimer = 0;
}
}
}
private void spawnSmallKamikazeSquad() {
int numberOfShips = (int) (Math.random() * 5 + 1);
while (numberOfShips-- > 0) {
goFactory.createSmallKamikazeShip(getNewEnemyPosition(), 0);
}
}
private void spawnMediumKamikazeSquad() {
int numberOfShips = (int) (Math.random() * 5 + 1);
while (numberOfShips-- > 0)
goFactory.createMediumKamikazeShip(getNewEnemyPosition(), 0);
}
private void spawnSmallLaserSquad() {
int numberOfShips = (int) (Math.random() * 5 + 1);
while (numberOfShips-- > 0) {
goFactory.createSmallLaserShip(getNewEnemyPosition(),
(float) Math.PI);
}
}
private Vector2 getNewEnemyPosition() {
float x_min, x_max, y_min, y_max, scale, widthClearnce, heightClearance, x, y;
scale = (float) Gdx.graphics.getHeight() / Gdx.graphics.getWidth();
x_min = Main.CAMERA_WIDTH;
x_max = Main.CAMERA_WIDTH * 2;
y_min = -Main.CAMERA_WIDTH * scale;
y_max = Main.CAMERA_WIDTH * scale;
widthClearnce = 3f;
heightClearance = 3f;
x = (float) ((x_min + widthClearnce / 2) + (x_max - x_min - widthClearnce)
* Math.random());
y = (float) ((y_min + heightClearance / 2) + (y_max - y_min - heightClearance)
* Math.random());
return new Vector2(x, y);
}
@Override
public void beginContact(Contact contact) {
Body A = contact.getFixtureA().getBody();
Body B = contact.getFixtureB().getBody();
GameObject goA = null;
GameObject goB = null;
if (A.getType() != BodyType.StaticBody)
goA = (GameObject) contact.getFixtureA().getBody().getUserData();
if (B.getType() != BodyType.StaticBody)
goB = (GameObject) contact.getFixtureB().getBody().getUserData();
// --- check if bodies are hitting the wall and act accordingly ---
if (goA == null && goB != null) {
goB.setScore(0); // player won't get any score for this
goB.contact(contact, Float.MAX_VALUE);
return;
} else if (goA != null && goB == null) {
goA.setScore(0); // player won't get any score for this
goA.contact(contact, Float.MAX_VALUE);
return;
}
// --- let's check if enemies are shooting at each other! ---
if (goB.isEnemy() && goA.isEnemy()) { // enemy objects hitting each
// other
if (goB.isProjectile()) {
goB.contact(contact, Float.MAX_VALUE);
}
if (goA.isProjectile()) {
goA.contact(contact, Float.MAX_VALUE);
}
return;
}
// okay, now we're talking! enemy or player damage!
goA.contact(contact, goB.getImpactDamage());
goB.contact(contact, goA.getImpactDamage());
}
@Override
public void endContact(Contact contact) {
}
private void clearDestroyedBodiesList() {
Body body = null;
for (int i = 0; i < destroyedBodiesList.size(); i++) {
body = destroyedBodiesList.get(i);
// System.out.println(body);
if (((GameObject) body.getUserData()).isExploding())
for (int j = 0; j < body.getFixtureList().size(); j++)
body.destroyFixture(body.getFixtureList().get(j));
else {
if ((bossMode && (GameObject) body.getUserData() instanceof Boss)) {
bossCount++;
bossMode = false;
bossAlive = false;
enemySpawnTime = 0;
enemySpawnInterval -= enemySpawnInterval * 0.1;
}
player.setScore(player.getScore()
+ ((GameObject) body.getUserData()).getScore());
world.destroyBody(body);
destroyedBodiesList.remove(i);
}
}
}
private Player openPlayerObject() {
Player player = null;
try {
InputStream is = PLAYER_FILE.read();
ObjectInputStream ois = new ObjectInputStream(is);
player = (Player) ois.readObject();
is.close();
ois.close();
} catch (Exception e) {
System.out.println(e.getMessage());
}
return player;
}
private void savePlayerObject(Player player) {
try {
OutputStream os = PLAYER_FILE.write(true);
ObjectOutputStream oos = new ObjectOutputStream(os);
oos.writeObject(player);
os.close();
oos.close();
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
// Getter's and setter's (No shit)
@Override
public void setGoFactory(GameObjectFactory goFactory) {
this.goFactory = goFactory;
}
@Override
public GameObjectFactory getGoFactory() {
return goFactory;
}
@Override
public void setPlayer(Player player) {
this.player = player;
}
@Override
public Player getPlayer() {
return player;
}
@Override
public void setShop(Shop shop) {
this.shop = shop;
}
@Override
public Shop getShop() {
return shop;
}
public Menu getMenu() {
return menu;
}
@Override
public void setInput(Input input) {
this.input = input;
}
@Override
public Input getInput() {
return input;
}
@Override
public void setGui(GUI gui) {
this.gui = gui;
}
@Override
public GUI getGui() {
return gui;
}
@Override
public void setDifficulty(DIFFICULTIES d) {
this.difficulty = d;
}
@Override
public DIFFICULTIES getDifficulty() {
return difficulty;
}
@Override
public void setUpdateRate(float updaterate) {
updateRate = updaterate;
}
@Override
public float getUpdateRate() {
return updateRate;
}
@Override
public void setMap(MapGenerator map) {
this.map = map;
}
@Override
public MapGenerator getMap() {
return map;
}
@Override
public void setWorld(World world) {
this.world = world;
}
@Override
public World getWorld() {
return world;
}
public ArrayList<Body> getDestroyedBodiesList() {
return destroyedBodiesList;
}
/**
* The boss interval decides at which score values bosses spawn. example:
* value set to 100 will spawn bosses when scores are above 100, 200, 300,
* etc.
*
* @param i
*/
public void setBossInterval(int i) {
this.bossInterval = i;
}
/**
* gets a random number between inclusive min and inclusive max
*
* @param min
* - the minimum value
* @param max
* - the maximum value
* @return
*/
public int randomNumber(int min, int max) {
return min + (int) Math.round((Math.random() * (max - min)));
}
public void reset() {
doReset = true;
}
private void doReset() {
destroyedBodiesList.clear();
Iterator<Body> it = world.getBodies();
Body body;
while (it.hasNext()) {
body = it.next();
if (body.getType() != BodyType.StaticBody)
destroyedBodiesList.add(body);
}
for (int i = 0; i < destroyedBodiesList.size(); i++) {
body = destroyedBodiesList.get(i);
world.destroyBody(body);
}
destroyedBodiesList.clear();
initializePlayer();
}
}