package model_pkg;
import java.util.*;
import model_pkg.gameobject_pkg.*;
import model_pkg.CloudInitializer.CloudSpec;
import def_classes.*;
import display_pkg.*;
/**
* The world. Only one of these should be created.
* @author Alving J., Johansson M., Kullman K.
*
*/
public class World implements Model {
private static World me;
private Dimensions worldSize = new Dimensions(1280, 1600);
private boolean showBoundingBoxes; // for debugging purposes
private int cookieCounter;
private int currentLevel;
private ArrayList<Background> backgrounds;
private ArrayList<GameObject> instances;
private ArrayList<GameObject> instancesToAdd;
private ArrayList<Integer> instancesToRemove;
private View vwFullGame;
private int viewWidth = 800;
private int viewHeight = 600;
private Background bgBlue;
private Player objPlayer;
//private Towelie objTowelie;
/**
*
*/
private World() {
currentLevel = 0;
showBoundingBoxes = false;
GameObject.setMyWorld(this);
instances = new ArrayList<GameObject>();
instancesToAdd = new ArrayList<GameObject>();
instancesToRemove = new ArrayList<Integer>();
backgrounds = new ArrayList<Background>();
vwFullGame = new View(new Box(0, 0, viewWidth, viewHeight), worldSize);
loadResources();
loadNewLevel();
}
/**
* Loads the resources required to run the game
*/
private void loadResources() {
bgBlue = new Background("/sprites/environment/background.png");
bgBlue.setDimensions(new Dimensions(640, 480));
backgrounds.add(bgBlue);
PlayerFactory.setTemplateSpriteSheet(new SpriteSheet("player.txt"));
GroundFactory.setTemplateSpriteSheet(new SpriteSheet("ground.txt"));
CloudFactory.setTemplateSpriteSheet(new SpriteSheet("clouds.txt"));
TowelieFactory.setTemplateSpriteSheet(new SpriteSheet("towelie.txt"));
BalloonFactory.setTemplateSpriteSheet(new SpriteSheet("balloon.txt"));
CookieFactory.setTemplateSpriteSheet(new SpriteSheet("cookie.txt"));
BulletFactory.setTemplateSpriteSheet(new SpriteSheet("bullet.txt"));
TowelieSmokeFactory.setTemplateSpriteSheet(new SpriteSheet("smoke.txt"));
}
private boolean loadNewLevel() {
currentLevel++;
backgrounds.clear();
instances.clear();
instancesToAdd.clear();
objPlayer = null;
if (currentLevel > 2) {
return false;
}
switch (currentLevel) {
case 1:
loadLevel1();
break;
case 2:
loadLevel2();
break;
}
return true;
}
/**
* Loads level 1
*/
private void loadLevel1() {
backgrounds.add(bgBlue);
createGround(1600);
createClouds("clouds_init.txt");
createBalloons("balloons_init.txt");
createPlayer(new Point(10,1577));
vwFullGame.setPosition(0, 1577);
createTowelie(new Point(50,1577));
}
/**
* Loads level 2
*/
public void loadLevel2() {
backgrounds.add(bgBlue);
createGround(1600);
createPlayer(new Point(10,1577));
cookieCounter = 1;
vwFullGame.setPosition(0, 1577);
}
/**
* Returns this world
* @return This world
*/
public static World getWorld() {
if (me == null) {
me = new World();
}
return me;
}
/**
* Gets the current view of the game world
*/
public View getView() {
return vwFullGame;
}
/**
* Sets the players horisontal movement
*/
public void setPlayerHorisontalMotion(int horisontal) {
objPlayer.setHorisontalMovement(horisontal);
}
/**
* Sets the players jumping state
*/
public void setPlayerJumping(boolean pJumping) {
objPlayer.setJumping(pJumping);
}
/**
* Sets the players crouching state
*/
public void setPlayerCrouching(boolean pCrouching) {
objPlayer.setCrouching(pCrouching);
}
/**
* Sets the players shooting state
*/
public void setPlayerShooting(boolean pShooting) {
objPlayer.setShooting(pShooting);
}
/**
* Draws the world by first drawing the backgrounds, and then the game objects
* in the order they have been added.
*/
public void drawWorld(Display destination) {
for (Iterator<Background> it = backgrounds.iterator(); it.hasNext();) {
Background currBg = it.next();
currBg.drawBackground(destination);
}
for (Iterator<GameObject> it = instances.iterator(); it.hasNext();) {
GameObject currObj = it.next();
if (showBoundingBoxes) {
currObj.drawBoundingBox(destination);
} else {
currObj.drawObject(destination);
}
}
}
/**
* Sets if whether to draw bounding boxes or sprites
*/
public void showBoundingBoxes(boolean p) {
showBoundingBoxes = p;
}
/**
* General update function for the game world.
* This is called by the controller every frame
*/
public boolean updateGameWorld() {
for (Iterator<GameObject> it = instances.iterator(); it.hasNext();) {
it.next().updateObject();
}
addInstances();
removeInstances();
vwFullGame.updateVelocity(objPlayer.getWorldPosition());
vwFullGame.updatePosition();
if (cookieCounter > 4) {
if (!loadNewLevel()) {
return false;
}
}
return true;
}
/**
* Adds instances that has been added this frame
*/
private void addInstances() {
for (Iterator<GameObject> it = instancesToAdd.iterator(); it.hasNext();) {
GameObject go = it.next();
instances.add(go);
}
instancesToAdd.clear();
}
/**
* Removes instances that are waiting for removal
*/
private void removeInstances() {
for ( Iterator<GameObject> it = instances.iterator();
it.hasNext() && !instancesToRemove.isEmpty();) {
GameObject currObj = it.next();
Iterator<Integer> it2 = instancesToRemove.iterator();
for (; it2.hasNext();) {
Integer i = it2.next();
if (currObj.getObjectID() == i.intValue()) {
it.remove();
it2.remove();
break;
}
}
}
}
/**
* If a bounding box is outside the world this function returns the new
* world position for that bounding box which will move the bounding box
* into the world.
* @param bbox The bounding box of the game object
* @return Returns the new world-position that's within the world
*/
public Vector2D clipMovement(Box bbox, Point position, Vector2D movement) {
double dx, dy; // the relative position between pos and the new point
Vector2D newPosition = new Vector2D(position);
newPosition.addRel(movement);
if (newPosition.getX()< 0) {
dx = -newPosition.getX();
} else if ((newPosition.getX() + bbox.getWidth()) > worldSize.getWidth()) {
dx = worldSize.getWidth() - (newPosition.getX() + bbox.getWidth());
} else {
dx = 0;
}
if (newPosition.getY() < 0) {
dy = -newPosition.getY();
} else if ((newPosition.getY() + bbox.getHeight()) > worldSize.getHeight()) {
dy = worldSize.getHeight() - (newPosition.getY() + bbox.getHeight());
} else {
dy = 0;
}
return new Vector2D(dx + movement.getX(),dy + movement.getY());
}
/** * Checks if an object is on the way to move outside the world and
* * bounces it's movement if it does.
* * @param bbox
* * @param position
* * @param movement
* * @return New position
* */
public Vector2D reboundMovement(Box bbox, Point position, Vector2D movement) {
double dx, dy; // the relative position between pos and the new point
Vector2D newPosition = new Vector2D(position);
newPosition.addRel(movement);
if (newPosition.getX()< 0) {
dx = -movement.getX();
} else if (newPosition.getX() + bbox.getWidth() > worldSize.getWidth()) {
dx = -movement.getX();
} else {
dx = movement.getX();
}
if (newPosition.getY() < 0) {
dy = -movement.getY();
} else if (newPosition.getY() + bbox.getHeight() > worldSize.getHeight()) {
dy = -movement.getY();
} else {
dy = movement.getY();
}
return new Vector2D(dx,dy);
}
/**
* Gets the world dimensions
*/
public Dimensions getWorldDimensions() {
return worldSize;
}
/**
* Gets the players world coordinates
*/
public Point getPlayerCoordinate() {
return new Point();
}
/**
* Main collision detection method, takes an object, checks if it collides
* with anything and sends a message to it if it does.
* @param go
*/
public void checkForCollisions(GameObject go) {
double velocityX = go.getVelocity().getX();
double velocityY = go.getVelocity().getY();
Vector2D offsetDisplacement;
if (!(velocityX == 0 && velocityY == 0)) {
for (Iterator<GameObject> it = instances.iterator(); it.hasNext();) {
GameObject current = it.next();
if (current.getObjectID() != go.getObjectID()) {
offsetDisplacement = go.checkCollision(current);
if (!offsetDisplacement.zeroVector()) {
go.collisionOccured(current, offsetDisplacement );
}
}
}
}
}
/**
* Can the object be at the position without colliding with something?
* @param go the object in question.
* @return true or false...
*/
public boolean checkValidPosition(GameObject go) {
double velocityX = go.getVelocity().getX();
double velocityY = go.getVelocity().getY();
Vector2D offsetDisplacement;
Vector2D newPosition = new Vector2D(go.getWorldPosition());
newPosition.add(go.getMovement());
if (!(velocityX == 0 && velocityY == 0)) {
for (Iterator<GameObject> it = instances.iterator(); it.hasNext();) {
GameObject current = it.next();
if (current.getObjectID() != go.getObjectID()) {
offsetDisplacement = go.checkCollision(current);
if (!offsetDisplacement.zeroVector() && current.isSolidSurfaceP()) {
return false;
}
}
}
}
if ((newPosition.getX()< 0) | (newPosition.getX() + go.getBoundingBox().getWidth() > worldSize.getWidth())) {
return false;
}
if ((newPosition.getY() < 0) | (newPosition.getY() + go.getBoundingBox().getHeight() > worldSize.getHeight())) {
return false;
}
return true;
}
/**
* Uses a factory to create and add an instance to the world
* @param factory a factory
* @return the game object created
*/
public GameObject createInstance(GameObjectFactory factory) {
GameObject go = factory.instantiate();
instancesToAdd.add(go);
return go;
}
/**
* Removes a game object with a specific object id.
* @param objID the id of the object to be removed
*/
public void removeInstance(int objID) {
instancesToRemove.add(objID);
}
private void createPlayer(Point pos) {
PlayerFactory.setTemplatePosition(pos);
objPlayer = (Player)createInstance(PlayerFactory.getFactory());
}
private void createTowelie(Point pos) {
TowelieFactory.setTemplatePosition(pos);
//objTowelie = (Towelie)createInstance(TowelieFactory.getFactory());
createInstance(TowelieFactory.getFactory());
}
private void createGround(int levelHeight) {
GroundFactory.setLevelHeight(levelHeight);
GroundFactory.setGroundXPosition(0);
createInstance(GroundFactory.getFactory());
GroundFactory.setGroundXPosition(1280/2);
createInstance(GroundFactory.getFactory());
}
private void createClouds(String file) {
CloudInitializer initClouds = new CloudInitializer(file);
int cloudAmount;
CloudSpec cloudSpecification;
cloudAmount = initClouds.getCloudAmount();
for (int i = 0; i < cloudAmount; i++) {
cloudSpecification = initClouds.getCloudSpec(i);
CloudFactory.setCloudSize(cloudSpecification.getCloudSize());
CloudFactory.setMotionType(cloudSpecification.getMotionType());
CloudFactory.setStartPosition(cloudSpecification.getStartPosition());
CloudFactory.setEndPosition(cloudSpecification.getEndPosition());
CloudFactory.setBoundingBox(cloudSpecification.getBBox());
CloudFactory.setVelocity(cloudSpecification.getVelocity());
createInstance(CloudFactory.getFactory());
}
}
private void createBalloons(String initFile) {
BalloonInitializer initBalloons = new BalloonInitializer(initFile);
int balloonAmount = initBalloons.getBalloonAmount();
for (int i = 0; i < balloonAmount; i++) {
BalloonFactory.setTemplatePosition(initBalloons.getPosition(i));
createInstance(BalloonFactory.getFactory());
}
}
/**
* Increases the cookie counter
*/
public void pickUpCookie() {
cookieCounter++;
}
/**
* Reloads the current level
*/
@Override
public void reloadWorld() {
loadNewLevel();
}
/**
* Sets the current level.<br />
* <i>Note: </i>The level is not loaded until reloadLevel is called.
*/
@Override
public void setCurrentLevel(int lvl) {
currentLevel = lvl-1;
}
}