package fr.umlv.escapeir.level;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Random;
import org.jbox2d.common.Vec2;
import fr.umlv.escapeir.EscapeIR;
import fr.umlv.escapeir.EscapeIR.StateID;
import fr.umlv.escapeir.menu.Menu;
import fr.umlv.escapeir.model.element.AbstractElement;
import fr.umlv.escapeir.model.element.BossShip;
import fr.umlv.escapeir.model.element.Bullet;
import fr.umlv.escapeir.model.element.EnnemyShip;
import fr.umlv.escapeir.model.element.EnnemyShipFactory;
import fr.umlv.escapeir.model.element.PlayerShip;
import fr.umlv.escapeir.model.element.EnnemyShipFactory.Difficulty;
import fr.umlv.escapeir.physic.World;
import fr.umlv.escapeir.utils.ImageStore;
import fr.umlv.escapeir.utils.Renderable;
import fr.umlv.escapeir.utils.Updatable;
/**
*
* @author Joachim ARCHAMBAULT, Alexandre ANDRE
* This class represents a level
* It contains everything you need to create a new level
* The boss's properties are defined in the level class
*/
public abstract class AbstractLevel implements Updatable, Renderable {
/**
*
* @author Joachim ARCHAMBAULT, Alexandre ANDRE
* This class represents the background of the game
*/
private class Background implements Updatable, Renderable {
private static final int SCROLL_SPEED = 2;
private static final int ROTATE_SPEED = 1;
private BufferedImage backgroundImage;
private BufferedImage planetImage;
private int yScroll = 0;
private int rotate = 0;
/**
* @param bgFilename
* @param planetFilename
*/
public Background(String bgFilename, String planetFilename) {
try {
this.backgroundImage = ImageStore.getImage(bgFilename);
this.planetImage = ImageStore.getImage(planetFilename);
} catch (IOException exception) {
System.err.println("Unfindable image " + exception.getMessage());
return;
}
}
public void update(double delta) {
this.yScroll += Background.SCROLL_SPEED * delta;
if (this.yScroll > this.backgroundImage.getHeight())
this.yScroll = 0;
this.rotate += Background.ROTATE_SPEED * delta;
}
@Override
public void render(Graphics2D graphics) {
for (int x = 0 ; x < EscapeIR.WIDTH ; x += this.backgroundImage.getWidth()) {
for (int y = -this.backgroundImage.getHeight() ; y < EscapeIR.HEIGHT ; y += this.backgroundImage.getHeight()) {
graphics.drawImage(this.backgroundImage, null, x, y + this.yScroll);
}
}
final double angle = Math.toRadians(this.rotate);
final AffineTransform transform = AffineTransform.getRotateInstance(angle, this.planetImage.getWidth() / 2, this.planetImage.getHeight() / 2);
final AffineTransformOp operation = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR);
graphics.drawImage(operation.filter(this.planetImage, null), EscapeIR.WIDTH - (this.planetImage.getWidth() / 2), 0, null);
}
}
private final Menu menu;
private final Background background;
@SuppressWarnings("unused")
private World world;
private int ships;
private ArrayList<EnnemyShip> currentShips;
private BossShip boss;
private final PlayerShip player;
private static final ArrayList<Bullet> bullets = new ArrayList<>();
private static Point currentPosition = new Point();
private final Difficulty difficulty;
public static ArrayList<Bullet> getBullets(){
return bullets;
}
/**
*
* @return the current position of the player
*/
public static Point getPosition(){
return currentPosition;
}
/**
*
* @param planet
* @param difficulty
* Creates a level depending on a difficulty and a planet
* The difficulty will determine the number of life the enemies have and the planet will determine the background.
*
*/
public AbstractLevel(String planet, Difficulty difficulty) {
int playerLife = 150;
switch (difficulty) {
case HARD:
playerLife -= 50;
case MEDIUM:
playerLife -= 50;
break;
case EASY:
default:
break;
}
this.difficulty = difficulty;
this.background = new Background("stars.png", planet + ".png");
this.world = new World(new Vec2(0, 0));
this.player = new PlayerShip(playerLife);
this.ships = 10;
this.currentShips = new ArrayList<>();
this.menu = new Menu();
}
public boolean isOver(){
if(!boss.isAlive())
return true;
return false;
}
/**
* This method create a new army of ship the hero has to kill.
*/
public void fillCurrentShip(int ships){
currentShips = EnnemyShipFactory.buildShipArmy(this.difficulty, ships);
}
@Override
public void update(double delta) {
ArrayList<AbstractElement> toDelete = new ArrayList<>();
World.WORLD.step(EscapeIR.FPS, 8, 6);
World.WORLD.clearForces();
this.background.update(delta);
this.player.update(delta);
if (this.player.getLife() < 0)
EscapeIR.stateSwitcher(StateID.QUIT);
if(currentShips.isEmpty() && this.ships != 0){
this.fillCurrentShip(this.ships);
}else{
for (EnnemyShip ship : currentShips) {
if(!ship.isAlive()) {
this.player.getWeapons().get(ship.getSelectedWeapon().getId()).addAmmo(new Random().nextInt(ship.getInitialLife() + 1));
World.WORLD.destroyBody(ship.getBody());
toDelete.add(ship);
this.ships--;
}
ship.update(delta);
}
currentShips.removeAll(toDelete);
}
for (Bullet bullet : bullets) {
if(bullet.getHit()){
World.WORLD.destroyBody(bullet.getBody());
toDelete.add(bullet);
}
bullet.update(delta);
}
bullets.removeAll(toDelete);
currentPosition = World.toPixel(this.player.getBody().getPosition());
if (this.boss != null) {
this.boss.update(delta);
if (!this.boss.isAlive()) {
World.WORLD.destroyBody(this.boss.getBody());
}
}
if (!this.player.isAlive())
EscapeIR.stateSwitcher(StateID.LOOSE);
}
@Override
public void render(Graphics2D graphics) {
this.background.render(graphics);
this.player.render(graphics);
this.menu.render(graphics);
for (Bullet bullet : bullets) {
bullet.render(graphics);
}
for ( EnnemyShip ship : currentShips) {
if(!ship.isAlive()){
graphics.setColor(Color.WHITE);
}
ship.render(graphics);
}
if (this.boss != null && this.boss.isAlive())
this.boss.render(graphics);
}
public int getShips() {
return this.ships;
}
public void setBoss(BossShip boss) {
if (this.boss != null)
return;
this.boss = boss;
}
public BossShip getBoss() {
return this.boss;
}
}