/* SWEN20003 Object Oriented Software Development
* Space Game Engine (Sample Project)
* Author: Matt Giuca <mgiuca>
* Modified: Matthew Rossi <mrossi>, October 2013
*/
import org.newdawn.slick.Graphics;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.tiled.TiledMap;
import java.util.ArrayList;
import java.util.Iterator;
//import java.util.List;
import org.newdawn.slick.Color;
/** Represents the entire game world.
* (Designed to be instantiated just once for the whole game).
*/
public class World
{
/** Map, containing terrain tiles. */
private TiledMap map;
/** The player's ship. */
private Player player;
/** The camera. */
private Camera camera;
/** The panel */
private Panel panel;
/** The boss */
private Boss boss;
// ArrayLists containing all GameObjects
private ArrayList<Item> items;
private ArrayList<GameObject> enemies;
private ArrayList<Missile> redMissile;
private ArrayList<Missile> blueMissile;
/** Linear model of player movement post-death of boss */
private LinearModel line;
// Array of y-coordinate checkpoints for teleportation post-player death
private int[] checkpoints = {13716, 9756, 7812, 5796, 2844};
/** Get the width of the game world in pixels. */
public int getWidth()
{
return map.getWidth() * map.getTileWidth();
}
/** Get the height of the game world in pixels. */
public int getHeight()
{
return map.getHeight() * map.getTileHeight();
}
/** Get reference to camera object */
protected Camera getCameraRef() {
return camera;
}
/** Get reference to player object */
protected Player getPlayerRef() {
return player;
}
/** Create a new World object. */
public World()
throws SlickException
{
map = new TiledMap(Game.ASSETS_PATH + "/map.tmx", Game.ASSETS_PATH);
player = new Player(1296, 13616-Panel.PANEL_HEIGHT);
panel = new Panel();
// Instantiate lists
items = new ArrayList<Item>();
enemies = new ArrayList<GameObject>();
redMissile = new ArrayList<Missile>();
blueMissile = new ArrayList<Missile>();
// Instantiate other game objects and insert into lists
insertFighters();
insertDrones();
insertAsteroids();
insertBosses();
insertRepair();
insertShield();
insertFirepower();
// Create a camera, centred and with the player at the bottom
camera = new Camera(this, player);
}
/* Instantiate fighter units */
private void insertFighters() throws SlickException {
enemies.add(new Fighter(1166, 12869));
enemies.add(new Fighter(1119, 12394));
enemies.add(new Fighter(1246, 12303));
enemies.add(new Fighter(1809, 10923));
enemies.add(new Fighter(1662, 10847));
enemies.add(new Fighter(1161, 10857));
enemies.add(new Fighter(934, 10810));
enemies.add(new Fighter(787, 10782));
enemies.add(new Fighter(1971, 5494));
enemies.add(new Fighter(2012, 5452));
enemies.add(new Fighter(2078, 5394));
enemies.add(new Fighter(1125, 4930));
enemies.add(new Fighter(1633, 3280));
enemies.add(new Fighter(1487, 3230));
enemies.add(new Fighter(1407, 3173));
enemies.add(new Fighter(1335, 3117));
enemies.add(new Fighter(1248, 12696));
enemies.add(new Fighter(1530, 9141));
enemies.add(new Fighter(1450, 9093));
enemies.add(new Fighter(1365, 9062));
enemies.add(new Fighter(1351, 9031));
enemies.add(new Fighter(1285, 8985));
enemies.add(new Fighter(1222, 8924));
enemies.add(new Fighter(1155, 8867));
enemies.add(new Fighter(1072, 8812));
enemies.add(new Fighter(1273, 8375));
enemies.add(new Fighter(1408, 8292));
enemies.add(new Fighter(1519, 8205));
enemies.add(new Fighter(1612, 8086));
enemies.add(new Fighter(685, 5581));
enemies.add(new Fighter(628, 3904));
enemies.add(new Fighter(569, 3396));
enemies.add(new Fighter(484, 3317));
enemies.add(new Fighter(753, 1883));
enemies.add(new Fighter(1410, 6835));
enemies.add(new Fighter(1251, 6697));
enemies.add(new Fighter(1405, 6482));
enemies.add(new Fighter(1406, 5614));
enemies.add(new Fighter(1939, 3040));
enemies.add(new Fighter(540, 3708));
enemies.add(new Fighter(612, 3564));
enemies.add(new Fighter(684, 3420));
enemies.add(new Fighter(612, 3204));
enemies.add(new Fighter(540, 3060));
enemies.add(new Fighter(324, 2052));
enemies.add(new Fighter(612, 1980));
}
/* Instantiate drone units */
private void insertDrones() throws SlickException {
enemies.add(new Drone(1139, 11772));
enemies.add(new Drone(1499, 11659));
enemies.add(new Drone(1271, 11370));
enemies.add(new Drone(1542, 9877));
enemies.add(new Drone(1877, 9704));
enemies.add(new Drone(1848, 7649));
enemies.add(new Drone(1961, 7477));
enemies.add(new Drone(1431, 7555));
enemies.add(new Drone(970, 7331));
enemies.add(new Drone(1437, 7100));
enemies.add(new Drone(1582, 6796));
enemies.add(new Drone(1024, 6907));
enemies.add(new Drone(717, 6419));
enemies.add(new Drone(1677, 3880));
enemies.add(new Drone(1370, 3780));
enemies.add(new Drone(1679, 3670));
enemies.add(new Drone(1353, 3560));
enemies.add(new Drone(2053, 2155));
enemies.add(new Drone(1582, 1831));
enemies.add(new Drone(1249, 1960));
enemies.add(new Drone(1221, 1346));
enemies.add(new Drone(1340, 1214));
enemies.add(new Drone(1297, 9517));
enemies.add(new Drone(1143, 9310));
enemies.add(new Drone(1379, 7762));
enemies.add(new Drone(750, 7469));
enemies.add(new Drone(543, 4479));
enemies.add(new Drone(893, 2367));
enemies.add(new Drone(1194, 2272));
enemies.add(new Drone(1905, 922));
enemies.add(new Drone(1990, 701));
enemies.add(new Drone(1935, 10541));
enemies.add(new Drone(1595, 10209));
enemies.add(new Drone(1808, 10057));
enemies.add(new Drone(1708, 9964));
enemies.add(new Drone(2056, 8122));
enemies.add(new Drone(1803, 8098));
enemies.add(new Drone(975, 7076));
enemies.add(new Drone(1967, 4770));
enemies.add(new Drone(1961, 3243));
enemies.add(new Drone(1835, 3180));
enemies.add(new Drone(1904, 2539));
enemies.add(new Drone(108, 7050));
enemies.add(new Drone(756, 7050));
enemies.add(new Drone(108, 6590));
enemies.add(new Drone(756, 6590));
enemies.add(new Drone(252, 5292));
enemies.add(new Drone(828, 3780));
enemies.add(new Drone(828, 3420));
enemies.add(new Drone(828, 3060));
enemies.add(new Drone(108, 1260));
enemies.add(new Drone(756, 1260));
}
/* Instantiate asteroid units */
private void insertAsteroids() throws SlickException {
enemies.add(new Asteroid(585, 10440));
enemies.add(new Asteroid(717, 10369));
enemies.add(new Asteroid(640, 10223));
enemies.add(new Asteroid(1116, 10088));
enemies.add(new Asteroid(2127, 9349));
enemies.add(new Asteroid(2050, 9164));
enemies.add(new Asteroid(2127, 8972));
enemies.add(new Asteroid(1980, 8849));
enemies.add(new Asteroid(1853, 8692));
enemies.add(new Asteroid(2025, 8617));
enemies.add(new Asteroid(1892, 8488));
enemies.add(new Asteroid(1766, 8420));
enemies.add(new Asteroid(1952, 8299));
enemies.add(new Asteroid(1812, 8255));
enemies.add(new Asteroid(1305, 6123));
enemies.add(new Asteroid(1564, 6101));
enemies.add(new Asteroid(1325, 4382));
enemies.add(new Asteroid(1437, 4317));
enemies.add(new Asteroid(1514, 2783));
enemies.add(new Asteroid(1347, 2602));
enemies.add(new Asteroid(1428, 2326));
enemies.add(new Asteroid(1756, 2290));
enemies.add(new Asteroid(1516, 11086));
enemies.add(new Asteroid(834, 10463));
enemies.add(new Asteroid(735, 9994));
enemies.add(new Asteroid(608, 9919));
enemies.add(new Asteroid(801, 9717));
enemies.add(new Asteroid(1193, 7965));
enemies.add(new Asteroid(840, 7742));
enemies.add(new Asteroid(644, 7629));
enemies.add(new Asteroid(1218, 7200));
enemies.add(new Asteroid(1455, 7256));
enemies.add(new Asteroid(1709, 7068));
enemies.add(new Asteroid(1798, 6894));
enemies.add(new Asteroid(1544, 6881));
enemies.add(new Asteroid(1271, 6868));
enemies.add(new Asteroid(1082, 6685));
enemies.add(new Asteroid(857, 6694));
enemies.add(new Asteroid(1148, 6510));
enemies.add(new Asteroid(1409, 6641));
enemies.add(new Asteroid(1809, 6421));
enemies.add(new Asteroid(1908, 6203));
enemies.add(new Asteroid(1603, 6259));
enemies.add(new Asteroid(1403, 6138));
enemies.add(new Asteroid(1075, 6094));
enemies.add(new Asteroid(836, 5974));
enemies.add(new Asteroid(732, 5098));
enemies.add(new Asteroid(550, 4723));
enemies.add(new Asteroid(616, 4611));
enemies.add(new Asteroid(500, 2704));
enemies.add(new Asteroid(607, 2650));
enemies.add(new Asteroid(563, 2559));
enemies.add(new Asteroid(832, 2187));
enemies.add(new Asteroid(903, 1692));
enemies.add(new Asteroid(677, 1529));
enemies.add(new Asteroid(493, 1453));
enemies.add(new Asteroid(643, 1344));
enemies.add(new Asteroid(1018, 1400));
enemies.add(new Asteroid(2127, 1973));
enemies.add(new Asteroid(1961, 1820));
enemies.add(new Asteroid(1507, 1887));
enemies.add(new Asteroid(1753, 1532));
enemies.add(new Asteroid(1471, 1378));
enemies.add(new Asteroid(2021, 10605));
enemies.add(new Asteroid(1738, 10420));
enemies.add(new Asteroid(1547, 10447));
enemies.add(new Asteroid(1375, 10278));
enemies.add(new Asteroid(1708, 9852));
enemies.add(new Asteroid(1567, 9768));
enemies.add(new Asteroid(1281, 9768));
enemies.add(new Asteroid(1157, 9588));
enemies.add(new Asteroid(1477, 9330));
enemies.add(new Asteroid(1197, 9167));
enemies.add(new Asteroid(1129, 9081));
enemies.add(new Asteroid(1462, 8904));
enemies.add(new Asteroid(1415, 7971));
enemies.add(new Asteroid(1790, 7881));
enemies.add(new Asteroid(1240, 7443));
enemies.add(new Asteroid(1651, 6628));
enemies.add(new Asteroid(1880, 6537));
enemies.add(new Asteroid(1885, 6312));
enemies.add(new Asteroid(1739, 6126));
enemies.add(new Asteroid(1395, 5995));
enemies.add(new Asteroid(1135, 5954));
enemies.add(new Asteroid(1909, 5271));
enemies.add(new Asteroid(2034, 4906));
enemies.add(new Asteroid(2054, 4843));
enemies.add(new Asteroid(1852, 2894));
enemies.add(new Asteroid(2019, 2703));
enemies.add(new Asteroid(2099, 2612));
enemies.add(new Asteroid(1764, 2061));
enemies.add(new Asteroid(1929, 1255));
enemies.add(new Asteroid(252, 7308));
enemies.add(new Asteroid(684, 7236));
enemies.add(new Asteroid(396, 7164));
enemies.add(new Asteroid(180, 7084));
enemies.add(new Asteroid(327, 6940));
enemies.add(new Asteroid(72, 6875));
enemies.add(new Asteroid(428, 6842));
enemies.add(new Asteroid(380, 6720));
enemies.add(new Asteroid(612, 6684));
enemies.add(new Asteroid(538, 6620));
enemies.add(new Asteroid(810, 6592));
enemies.add(new Asteroid(480, 6520));
enemies.add(new Asteroid(270, 6382));
enemies.add(new Asteroid(520, 6201));
enemies.add(new Asteroid(370, 6031));
enemies.add(new Asteroid(430, 5928));
enemies.add(new Asteroid(612, 5868));
enemies.add(new Asteroid(36, 1764));
enemies.add(new Asteroid(792, 1548));
}
/* Instantiate boss units */
private void insertBosses() throws SlickException {
boss = new Boss(1301, 144);
enemies.add(boss);
}
/* Instantiate repair units */
private void insertRepair() throws SlickException {
items.add(new Repair(974, 10404));
items.add(new Repair(826, 9474));
items.add(new Repair(693, 6704));
items.add(new Repair(613, 5432));
items.add(new Repair(536, 3626));
items.add(new Repair(464, 3423));
items.add(new Repair(612, 1921));
items.add(new Repair(1263, 1551));
items.add(new Repair(1678, 11552));
items.add(new Repair(1622, 9449));
items.add(new Repair(968, 8663));
items.add(new Repair(1028, 7527));
items.add(new Repair(1060, 6515));
items.add(new Repair(1673, 6131));
items.add(new Repair(968, 5144));
items.add(new Repair(1187, 3041));
items.add(new Repair(1334, 2127));
items.add(new Repair(1909, 1976));
items.add(new Repair(1546, 1547));
items.add(new Repair(1407, 1112));
}
/* Instantiate shield items */
private void insertShield() throws SlickException {
items.add(new Shield(824, 11052));
items.add(new Shield(824, 11052));
items.add(new Shield(1253, 7065));
items.add(new Shield(759, 4646));
items.add(new Shield(1623, 12633));
items.add(new Shield(1983, 10982));
items.add(new Shield(1187, 10616));
items.add(new Shield(1237, 9821));
items.add(new Shield(903, 8024));
items.add(new Shield(2046, 7163));
items.add(new Shield(1033, 6868));
items.add(new Shield(1540, 6636));
items.add(new Shield(1191, 2630));
items.add(new Shield(1112, 1184));
}
/* Instantiate firepower items */
private void insertFirepower() throws SlickException {
items.add(new Firepower(758, 8266));
items.add(new Firepower(1393, 6082));
items.add(new Firepower(831, 4137));
items.add(new Firepower(968, 11342));
items.add(new Firepower(1695, 8230));
items.add(new Firepower(900, 5812));
items.add(new Firepower(1455, 5216));
items.add(new Firepower(1330, 4784));
items.add(new Firepower(1766, 3777));
}
/** True if the camera has reached the top of the map. */
public boolean reachedTop()
{
return camera.getTop() <= 0;
}
/** Update the game state for a frame.
* @param dir_x The player's movement in the x axis (-1, 0 or 1).
* @param dir_y The player's movement in the y axis (-1, 0 or 1).
* @param delta Time passed since last frame (milliseconds).
*/
public void update(double dir_x, double dir_y, int delta)
throws SlickException
{
// Move the camera automatically
camera.update(delta);
// Move the player automatically, and manually (by dir_x, dir_y)
if (boss.isDead() && line != null)
player.update(line, delta);
else
player.update(this, camera, dir_x, dir_y, delta);
// Determine whether the player is dead
if (player.getShield() <= 0 || player.getY() >= camera.getBottom()-Panel.PANEL_HEIGHT) {
// Teleport the player to the last-traversed checkpoint
playerDeath();
}
// Update enemy units
for (GameObject obj: enemies) {
Enemy e = (Enemy)obj;
if (e.isDead() || !inScreen(e))
continue;
e.update(this, delta);
}
// Check collision between player and units
enemies.add(player);
detectCollision(enemies);
enemies.remove(player);
if (boss.isDead() && line==null)
line = new LinearModel(player.getX(), player.getY());
// Update missile objects
updateMissiles(redMissile, delta);
updateMissiles(blueMissile, delta);
// Check collision between units and missiles
detectCollision(enemies, redMissile);
detectCollision(redMissile, player);
detectCollision(enemies, blueMissile);
// Check collision between player and items
detectCollision(player, items);
// Centre the camera (in x-axis) over the player and bound to map
camera.follow (player);
}
/* Undertake player post-death housekeeping before respawning */
private void playerDeath() {
// Reset player to a predefined checkpoint based on its coordinates
player.unkill(checkpoints);
// Adjust camera to new player coordinates
camera.centerOnPlayer(this, player);
// Delete all missiles
deleteMissiles(redMissile);
deleteMissiles(blueMissile);
// Respawn enemies
respawn(enemies);
}
/* Detect collision between all units */
private void detectCollision(ArrayList<GameObject> list) {
int size = list.size();
Unit hold, next;
for (int i=0; i < size; i++) {
hold = (Unit)list.get(i);
if (list.get(i).isDead() || !inScreen(list.get(i)))
continue;
for (int j=i+1; j < size; j++) {
next = (Unit)list.get(j);
if (hold.isColliding(next) && !checkIfDead(next, hold)) {
hold.adjustShield(next);
next.adjustShield(hold);
}
}
}
}
/* Detect collision between units and missiles */
private void detectCollision(ArrayList<GameObject> list1, ArrayList<Missile> list2) {
int size1 = list1.size();
int size2 = list2.size();
Missile hold;
Unit next;
for (int i=0; i < size2; i++) {
hold = (Missile)list2.get(i);
// Skip iteration if missile is marked dead or is not on the screen
if (list2.get(i).isDead() || !inScreen(list2.get(i)))
continue;
for (int j=0; j < size1; j++) {
next = (Unit)list1.get(j);
// Check for collision and both units not being dead
if (hold.isColliding(next) && !checkIfDead(next, hold)) {
next.adjustShield(hold);
hold.setDead(true);
}
}
}
}
/* Detect collision between the player and missiles */
private void detectCollision(ArrayList<Missile> list, Player player) {
for (Missile m: list) {
if (player.isColliding(m) && !checkIfDead(player, m) && !m.equals(player)) {
player.adjustShield(m);
m.setDead(true);
}
}
}
/* Detect collision between the player and items */
private void detectCollision(Player player, ArrayList<Item> items) {
Iterator<Item> iterItem = items.iterator();
Item i;
while (iterItem.hasNext()) {
i = iterItem.next();
if (player.isColliding(i) && !checkIfDead(player, i)) {
i.update(player);
iterItem.remove();
}
}
}
/* Check if one or both of two GameObjects are dead */
private boolean checkIfDead(GameObject obj1, GameObject obj2) {
if (obj1.isDead()) return true;
if (obj2.isDead()) return true;
return false;
}
/* Check if a GameObject is within the camera boundaries */
private boolean inScreen(GameObject unit) {
if (unit.getX() < camera.getLeft())
return false;
if (unit.getX() > camera.getRight())
return false;
if (unit.getY() < camera.getTop())
return false;
if (unit.getY() > camera.getBottom() - Panel.PANEL_HEIGHT - 1)
return false;
return true;
}
/** Render the entire screen, so it reflects the current game state.
* @param g The Slick graphics object, used for drawing.
* @param textrenderer A TextRenderer object.
*/
public void render(Graphics g)
throws SlickException
{
// Calculate the camera location (in tiles) and offset (in pixels)
int cam_tile_x = (int) camera.getLeft() / map.getTileWidth();
int cam_offset_x = (int) camera.getLeft() % map.getTileWidth();
int cam_tile_y = (int) camera.getTop() / map.getTileHeight();
int cam_offset_y = (int) camera.getTop() % map.getTileHeight();
// Render w+1 x h+1 tiles (where w and h are 12x9; add one tile extra
// to account for the negative offset).
map.render(-cam_offset_x, -cam_offset_y, cam_tile_x, cam_tile_y,
getScreenTileWidth()+1, getScreenTileHeight()+1);
// Render the player
player.render(g, camera);
Color VALUE = new Color(1.0f, 1.0f, 1.0f); // White
g.setColor(VALUE);
panel.render(g, player.getShield(), player.getFullShield(), player.getFirepower());
// Render enemies
for (GameObject unit: enemies) {
if (!unit.isDead() && inScreen(unit))
unit.render(g, camera);
}
// Render items
for (Item item: items) {
if (inScreen(item))
item.render(g, camera);
}
// Render red missiles
for (Missile missile: redMissile) {
if (!missile.isDead() && inScreen(missile))
missile.render(g, camera);
}
// Render blue missiles
for (Missile missile: blueMissile) {
if (!missile.isDead() && inScreen(missile))
missile.render(g, camera);
}
}
/**
* Add a blue missile to the world.
*
* @param missile A blue missile.
*/
public void addMissile(MissileBlue missile) {
blueMissile.add(missile);
}
/**
* Add a red missile to the world.
*
* @param missile A red missile.
*/
public void addMissile(MissileRed missile) {
redMissile.add(missile);
}
/**
* Fire missile from player as a result of keyboard command.
*
* @param delta Time passed since last frame (milliseconds).
* @throws SlickException Handles exceptions arising from Slick2D library.
*/
public void addMissile(int delta)
throws SlickException {
player.createMissile(this, delta);
}
/**
* Set missile status as dead.
*
* @param missile A missile object.
*/
public void removeMissile(Missile missile) {
missile.setDead(true);
}
/* Update position of missile objects */
private void updateMissiles(ArrayList<Missile> list, int delta) {
for (Missile m: list) {
if (m.isDead() || !inScreen(m))
continue;
m.autoMove(this, delta);
}
}
/* Delete all missiles in a missile list*/
private void deleteMissiles(ArrayList<Missile> list) {
Iterator<Missile> iterMissile = list.iterator();
@SuppressWarnings("unused")
Missile m;
while (iterMissile.hasNext()) {
m = iterMissile.next();
iterMissile.remove();
}
}
/**
* Respawn a list of GameObjects upon the death and teleportation of the player
*
* @param list A list of GameObjects
*/
private void respawn(ArrayList<GameObject> list) {
for (GameObject e: list) {
if (e.isDead()) {
e.setDead(false);
e.setCord(e.originalX, e.originalY);
}
}
}
/** Determines whether a particular map location blocks movement due to
* terrain.
* @param x Map x coordinate (in pixels).
* @param y Map y coordinate (in pixels).
* @return true if the location blocks movement due to terrain.
*/
public boolean terrainBlocks(double x, double y)
{
int tile_x = (int) x / map.getTileWidth();
int tile_y = (int) y / map.getTileHeight();
// Check if the location is off the map. If so, assume it doesn't
// block (potentially allowing ships to fly off the map).
if (tile_x < 0 || tile_x >= map.getWidth()
|| tile_y < 0 || tile_y >= map.getHeight())
return false;
// Get the tile ID and check whether it blocks movement.
int tileid = map.getTileId(tile_x, tile_y, 0);
String block = map.getTileProperty(tileid, "block", "0");
return Integer.parseInt(block) != 0;
}
/** Get the width of the screen in tiles, rounding up.
* For a width of 800 pixels and a tilewidth of 72, this is 12.
*/
private int getScreenTileWidth()
{
return (Game.screenwidth / map.getTileWidth()) + 1;
}
/** Get the height of the screen in tiles, rounding up.
* For a height of 600 pixels and a tileheight of 72, this is 9.
*/
private int getScreenTileHeight()
{
return (Game.screenheight / map.getTileHeight()) + 1;
}
}