From bdc40dfd7ef8da4965f6cb11202d056867b64beb Mon Sep 17 00:00:00 2001 From: David Lin <dllin@student.unimelb.edu.au> Date: Sat, 13 Jun 2020 15:37:48 +1000 Subject: [PATCH] levels implemented --- src/{lists => }/Airplane.java | 22 +- src/{lists => }/ApexSlicer.java | 10 +- src/{lists => }/Explosive.java | 14 +- src/{lists => }/MegaSlicer.java | 10 +- src/{lists => }/Projectile.java | 10 +- src/{lists => }/RegularSlicer.java | 9 +- src/ShadowDefend.java | 750 +++++++++++++++++++++++++++++ src/{lists => }/Slicer.java | 35 +- src/{lists => }/Sprite.java | 2 - src/{lists => }/SuperSlicer.java | 9 +- src/{lists => }/SuperTank.java | 4 +- src/{lists => }/Tank.java | 30 +- src/lists/ShadowDefend.java | 557 --------------------- 13 files changed, 845 insertions(+), 617 deletions(-) rename src/{lists => }/Airplane.java (88%) rename src/{lists => }/ApexSlicer.java (77%) rename src/{lists => }/Explosive.java (82%) rename src/{lists => }/MegaSlicer.java (77%) rename src/{lists => }/Projectile.java (93%) rename src/{lists => }/RegularSlicer.java (77%) create mode 100644 src/ShadowDefend.java rename src/{lists => }/Slicer.java (79%) rename src/{lists => }/Sprite.java (98%) rename src/{lists => }/SuperSlicer.java (77%) rename src/{lists => }/SuperTank.java (88%) rename src/{lists => }/Tank.java (67%) delete mode 100644 src/lists/ShadowDefend.java diff --git a/src/lists/Airplane.java b/src/Airplane.java similarity index 88% rename from src/lists/Airplane.java rename to src/Airplane.java index 3bee4ac..f1c6785 100644 --- a/src/lists/Airplane.java +++ b/src/Airplane.java @@ -1,5 +1,3 @@ -package lists; - import bagel.Input; import bagel.util.Point; import bagel.util.Vector2; @@ -18,10 +16,12 @@ public class Airplane extends Sprite{ private double speed; + private int damage; private boolean finished, isVertical; private double frameCount; private Random r = new Random(); private double nothingTime; + private Point explode; @@ -30,16 +30,25 @@ public class Airplane extends Sprite{ public Airplane(Point point, boolean isVertical, String imageSrc){ super(point,imageSrc); this.speed = 1.5; + this.damage = 500; this.finished = false; this.isVertical = isVertical; this.frameCount = Integer.MAX_VALUE; this.nothingTime = Math.round((TIME_MIN + (TIME_MAX - TIME_MIN) * r.nextDouble())*1000); this.explosives = new ArrayList<>(); + this.explode = null; } + public Point getExplode(){ + return this.explode; + } + public int getDamage(){ + return this.damage; + } @Override public void update(Input input) { + explode = null; frameCount += ShadowDefend.getTimescale(); if (finished) { return; @@ -68,21 +77,26 @@ public class Airplane extends Sprite{ // Check if we have reached the end if ((currentPoint.x >= WIDTH || currentPoint.y >= HEIGHT) && explosives.isEmpty()) { - System.out.println("out"); + //System.out.println("out"); finished = true; return; } for (int i = explosives.size() - 1; i >= 0; i--) { if(!explosives.isEmpty()){ - System.out.println(explosives); + //System.out.println(explosives); Explosive v = explosives.get(i); v.update(input); + if (v.isFinished()) { + + explode = v.getPoint(); + explosives.remove(i); } } } + // Move towards the target point // We do this by getting a unit vector in the direction of our target, and multiplying it // by the speed of the slicer (accounting for the timescale) diff --git a/src/lists/ApexSlicer.java b/src/ApexSlicer.java similarity index 77% rename from src/lists/ApexSlicer.java rename to src/ApexSlicer.java index 3d29462..6172da7 100644 --- a/src/lists/ApexSlicer.java +++ b/src/ApexSlicer.java @@ -1,8 +1,6 @@ -package lists; - import bagel.Input; import bagel.util.Point; -import bagel.util.Vector2; + import java.util.List; /** @@ -17,14 +15,14 @@ public class ApexSlicer extends Slicer { * * @param polyline The polyline that the slicer must traverse (must have at least 1 point) */ - public ApexSlicer(List<Point> polyline,String imageSrc) { - super(polyline, imageSrc); + public ApexSlicer(List<Point> polyline,int targetPointIndex, Point point,String imageSrc) { + super(polyline, targetPointIndex, point, imageSrc); this.speed = 0.375; this.health = 25; this.reward = 150; this.penalty = 16; - + this.spawnOnDeath = 4; } /** diff --git a/src/lists/Explosive.java b/src/Explosive.java similarity index 82% rename from src/lists/Explosive.java rename to src/Explosive.java index 837b173..b70e162 100644 --- a/src/lists/Explosive.java +++ b/src/Explosive.java @@ -1,15 +1,12 @@ -package lists; - import bagel.Input; import bagel.util.Point; -import java.util.Random; - public class Explosive extends Sprite{ private static final double COOLDOWN = 2000; - private double radius,damage,frameCount; + private double radius,frameCount; private boolean finished; + private Point point; @@ -18,13 +15,16 @@ public class Explosive extends Sprite{ public Explosive(Point point, String imageSrc){ super(point,imageSrc); this.radius = 200; - this.damage = 500; + + this.point = point; this.finished = false; this.frameCount = 0; } - + public Point getPoint(){ + return this.point; + } @Override public void update(Input input) { frameCount += ShadowDefend.getTimescale(); diff --git a/src/lists/MegaSlicer.java b/src/MegaSlicer.java similarity index 77% rename from src/lists/MegaSlicer.java rename to src/MegaSlicer.java index d356f07..f992cdc 100644 --- a/src/lists/MegaSlicer.java +++ b/src/MegaSlicer.java @@ -1,8 +1,6 @@ -package lists; - import bagel.Input; import bagel.util.Point; -import bagel.util.Vector2; + import java.util.List; /** @@ -17,14 +15,14 @@ public class MegaSlicer extends Slicer { * * @param polyline The polyline that the slicer must traverse (must have at least 1 point) */ - public MegaSlicer(List<Point> polyline,String imageSrc) { - super(polyline, imageSrc); + public MegaSlicer(List<Point> polyline, int targetPointIndex, Point point,String imageSrc) { + super(polyline, targetPointIndex, point,imageSrc); this.speed = 0.75; this.health = 2; this.reward = 10; this.penalty = 4; - + this.spawnOnDeath = 2; } /** diff --git a/src/lists/Projectile.java b/src/Projectile.java similarity index 93% rename from src/lists/Projectile.java rename to src/Projectile.java index 408e650..4a38e94 100644 --- a/src/lists/Projectile.java +++ b/src/Projectile.java @@ -1,5 +1,3 @@ -package lists; - import bagel.Input; import bagel.util.Point; import bagel.util.Vector2; @@ -18,9 +16,15 @@ public class Projectile extends Sprite { this.speed = 5; this.damage = damage; this.slicerIndex = slicerIndex; + } + public int getSlicerIndex(){ + return this.slicerIndex; + } - + public int getDamage() { + return this.damage; } + @Override public void update(Input input) { if (finished) { diff --git a/src/lists/RegularSlicer.java b/src/RegularSlicer.java similarity index 77% rename from src/lists/RegularSlicer.java rename to src/RegularSlicer.java index 11a1e09..ca63d6b 100644 --- a/src/lists/RegularSlicer.java +++ b/src/RegularSlicer.java @@ -1,8 +1,6 @@ -package lists; - import bagel.Input; import bagel.util.Point; -import bagel.util.Vector2; + import java.util.List; /** @@ -15,13 +13,14 @@ public class RegularSlicer extends Slicer { * * @param polyline The polyline that the slicer must traverse (must have at least 1 point) */ - public RegularSlicer(List<Point> polyline,String imageSrc) { - super(polyline, imageSrc); + public RegularSlicer(List<Point> polyline, int targetPointIndex, Point point, String imageSrc) { + super(polyline, targetPointIndex, point, imageSrc); this.speed = 1; this.health = 1; this.reward = 2; this.penalty = 1; + this.spawnOnDeath = 0; } diff --git a/src/ShadowDefend.java b/src/ShadowDefend.java new file mode 100644 index 0000000..7f9742f --- /dev/null +++ b/src/ShadowDefend.java @@ -0,0 +1,750 @@ +import bagel.*; +import bagel.Font; +import bagel.Image; + +import bagel.map.TiledMap; +import bagel.util.Colour; +import bagel.util.Point; +import bagel.util.Rectangle; + +import java.io.File; +import java.io.FileNotFoundException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Scanner; + + +/** + * ShadowDefend, a tower defence game. + * Used Rohyl's template from Project 1 + */ +public class ShadowDefend extends AbstractGame { + private static final String RSLICER = "res/images/slicer.png"; + private static final String SSLICER = "res/images/superslicer.png"; + private static final String MSLICER = "res/images/megaslicer.png"; + private static final String ASLICER = "res/images/apexslicer.png"; + private static final int HEIGHT = 768; + private static final int WIDTH = 1024; + private static final int HALF_WIDTH = WIDTH/2; + private static final int QUAR_WIDTH = WIDTH/4; + private static final int EXP_RADIUS = 200; + + private static final String SHOP_FILE = "res/images/buypanel.png"; + private static final String STATUS_FILE = "res/images/statuspanel.png"; + private static final String TANK_FILE = "res/images/tank.png"; + private static final String TANK_PROJ_FILE = "res/images/tank_projectile.png"; + private static final String STANK_PROJ_FILE = "res/images/supertank_projectile.png"; + private static final String STANK_FILE = "res/images/supertank.png"; + private static final String PLANE_FILE = "res/images/airsupport.png"; + private static final String FONT_FILE = "res/fonts/DejaVuSans-Bold.ttf"; + private static final String INFO = "Key binds:\n\nS - Start Wave\nL - Increase Timescale\nK - Decrease Timescale"; + private static final String WAVES_FILE = "res/levels/waves.txt"; + private DrawOptions colour = new DrawOptions(); + // Change to suit system specifications. This could be + // dynamically determined but that is out of scope. + public static final double FPS = 60; + // The spawn delay (in seconds) to spawn slicers + + private static final int INTIAL_TIMESCALE = 1; + + // Timescale is made static because it is a universal property of the game and the specification + // says everything in the game is affected by this + private static int timescale = INTIAL_TIMESCALE; + + private final Image shop, statusPanel, tankIcon, stankIcon, planeIcon; + + private final List<Slicer> slicers; + private final List<Projectile> projectiles; + + + private final List<Tank> tanks; + + private final List<Airplane> planes; + + private final Rectangle window; + private String map_file = "res/levels/1.tmx"; + private TiledMap map; + private List<String> event; + private List<Point> polyline; + + private List<List<String>> events; + private Font goldDisplay, keyInstruction, costText, statusText; + private Image placingIcon; + private double frameCount; + private double projCount; + private int spawnedSlicers; + private int nothingTime; + private int spawnDelay; + private int spawnCount; + private int eventType; + private int level; + private int waveCounter; + private int eventCounter; + private int prevWaveState; + private int slicerIndex; + private boolean eventWait; + private String enemyType; + private String placedImage; + private boolean tankBlocked; + private boolean mapSet; + private boolean waveStarted; + private boolean eventStarted = true; + private boolean isVertical = false; + private boolean hasTarget = false; + private static int gold, lives, waveNumber, waveState; + + + /** + * Creates a new instance of the ShadowDefend game + */ + public ShadowDefend() { + + super(WIDTH, HEIGHT, "ShadowDefend"); + + gold = 50000; + lives = 25; + waveNumber = 1; + waveState = 0; + this.window = new Rectangle(0,0,WIDTH,HEIGHT); + this.map = new TiledMap(map_file); + this.shop = new Image(SHOP_FILE); + this.statusPanel = new Image(STATUS_FILE); + this.tankIcon = new Image(TANK_FILE); + this.stankIcon = new Image(STANK_FILE); + this.planeIcon = new Image(PLANE_FILE); + this.goldDisplay = new Font(FONT_FILE,50); + this.keyInstruction = new Font(FONT_FILE,16); + this.costText = new Font(FONT_FILE,20); + this.statusText = new Font(FONT_FILE,16); + this.polyline = map.getAllPolylines().get(0); + this.slicers = new ArrayList<>(); + this.projectiles = new ArrayList<>(); + + this.tanks = new ArrayList<>(); + + this.planes = new ArrayList<>(); + + this.events = new ArrayList<>(); + this.event = new ArrayList<>(); + this.level = 1; + this.spawnedSlicers = 0; + this.waveStarted = false; + this.frameCount = Integer.MAX_VALUE; + this.projCount = Integer.MAX_VALUE; + this.waveCounter = 1; + this.eventCounter = 0; + this.eventWait = false; + this.mapSet = false; + this.tankBlocked = false; + + try { + File wavesText = new File(WAVES_FILE); + Scanner fr = new Scanner(wavesText); + while (fr.hasNextLine()) { + events.add(Arrays.asList(fr.nextLine().split(","))); + } + fr.close(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + + + + // Temporary fix for the weird slicer map glitch (might have to do with caching textures) + // This fix is entirely optional + //new Slicer(polyline); + } + + /** + * The entry-point for the game + * + * @param args Optional command-line arguments + */ + public static void main(String[] args) { + new ShadowDefend().run(); + } + + public static int getTimescale() { + return timescale; + } + + /** + * Increases the timescale + */ + private void increaseTimescale() { + if(timescale!=5){ + timescale++; + } + + } + + /** + * Decreases the timescale but doesn't go below the base timescale + */ + private void decreaseTimescale() { + if (timescale > INTIAL_TIMESCALE) { + timescale--; + } + } + /** + * Resets the game for new level but maintaining gold + */ + private void resetLevel(){ + map = new TiledMap(map_file); + mapSet = false; + level += 1; + slicers.clear(); + tanks.clear(); + planes.clear(); + projectiles.clear(); + polyline = map.getAllPolylines().get(0); + eventCounter = 0; + waveCounter = 1; + waveState = 0; + waveStarted = false; + } + + /** + * Draws the shop panel + */ + private void drawShopPanel(){ + //Draw shop panel at top left + shop.drawFromTopLeft(0,0); + + // Draw icons + tankIcon.draw(64,(shop.getHeight()/2)-10); + stankIcon.draw(184,(shop.getHeight()/2)-10); + planeIcon.draw(304,(shop.getHeight()/2)-10); + + // Draw information + keyInstruction.drawString(INFO,(shop.getWidth()/2)-keyInstruction.getWidth(INFO)/2,20); + + // Draw gold amount + if(gold >= 1000){ + // Add comma if gold count over 4 digits, can use for loop for more than 7 digits + // not realistic to have over a million gold in this game + String extra = Integer.toString(gold).substring(Integer.toString(gold).length() -3); + String thousandth = Integer.toString(gold).substring(0,Integer.toString(gold).length() -3); + goldDisplay.drawString("$"+ thousandth + "," + extra,shop.getWidth()-200,65); + + } else { + goldDisplay.drawString("$"+ gold,shop.getWidth()-200,65); + } + + // Draw the cost text for Tank with colouring + // RED: gold not enough + if(gold < 250){ + costText.drawString("$"+250,64-(tankIcon.getWidth()/2), + (tankIcon.getHeight()/2)+(shop.getHeight()/2+5), + colour.setBlendColour(Colour.RED)); + + } else { + costText.drawString("$"+250,64-(tankIcon.getWidth()/2), + (tankIcon.getHeight()/2)+(shop.getHeight()/2+5), + colour.setBlendColour(Colour.GREEN)); + } + + // Draw the cost text for SuperTank with colouring + // RED: gold not enough + if(gold < 600){ + costText.drawString("$"+600,184-(stankIcon.getWidth()/2), + (stankIcon.getHeight()/2)+(shop.getHeight()/2+5), + colour.setBlendColour(Colour.RED)); + + } else { + costText.drawString("$"+600,184-(stankIcon.getWidth()/2), + (stankIcon.getHeight()/2)+(shop.getHeight()/2+5), + colour.setBlendColour(Colour.GREEN)); + + } + + // Draw the cost text for Plane with colouring + // RED: gold not enough + if(gold < 500){ + costText.drawString("$"+500,304-(planeIcon.getWidth()/2), + (planeIcon.getHeight()/2)+(shop.getHeight()/2+5), + colour.setBlendColour(Colour.RED)); + + } else { + costText.drawString("$"+500,304-(planeIcon.getWidth()/2), + (planeIcon.getHeight()/2)+(shop.getHeight()/2+5), + colour.setBlendColour(Colour.GREEN)); + + } + } + + /** + * Draws the status panel + */ + private void drawStatusPanel(){ + //Draw status panel at bottom + statusPanel.drawFromTopLeft(0,HEIGHT - statusPanel.getHeight()); + + // Draw wave number on left side + statusText.drawString("Wave: " + waveNumber,5,HEIGHT-6); + + // Draw timescale with colouring + // GREEN: over 1x timescale + if(timescale>1){ + statusText.drawString("Timescale: " + timescale + ".0", + QUAR_WIDTH, + HEIGHT-6, + colour.setBlendColour(Colour.GREEN)); + + } else { + statusText.drawString("Timescale: " + timescale + ".0",QUAR_WIDTH,HEIGHT-6); + } + + // Draw wave state in middle of panel + switch(waveState) { + case 0: + statusText.drawString("Status: Awaiting Start", + HALF_WIDTH, + HEIGHT-6); + break; + case 1: + statusText.drawString("Status: Wave In Progress", + HALF_WIDTH, + HEIGHT-6); + break; + case 2: + statusText.drawString("Status: Placing", + HALF_WIDTH, + HEIGHT-6); + break; + case 3: + statusText.drawString("Status: Winner!", + HALF_WIDTH, + HEIGHT-6); + break; + } + + // Draw number of remaining lives on right side + statusText.drawString("Lives: " + lives, + WIDTH-statusText.getWidth("Lives: " + lives)-5, + HEIGHT-6); + + } + /** + * Get whether mouse pointer is hovering over an already placed tank + * + * @param input The current mouse/keyboard state + */ + private void getTankBlocked(Input input){ + tankBlocked = false; + // Loop through tanks + for (int j = tanks.size() - 1; j >= 0; j--) { + if (!tanks.isEmpty()) { + Tank v = tanks.get(j); + // Checks the mouse pointer does not intersect with a tank + if(v.getRect().intersects(input.getMousePosition())){ + tankBlocked = true; + } + } + } + } + /** + * Breakdown an event into usable data + */ + private void getEventData(){ + if(event.size() == 3){ + // Delay event + eventType = 0; + waveNumber = Integer.parseInt(event.get(0)); + nothingTime = Integer.parseInt(event.get(2)); + } else { + // Spawn event + eventType = 1; + waveNumber = Integer.parseInt(event.get(0)); + spawnCount = Integer.parseInt(event.get(2)); + enemyType = event.get(3); + spawnDelay = Integer.parseInt(event.get(4)); + } + + } + + + + + /** + * Update the state of the game, potentially reading from input + * + * @param input The current mouse/keyboard state + */ + @Override + protected void update(Input input) { + // Increase the frame counter by the current timescale + frameCount += getTimescale(); + projCount += getTimescale(); + + // Draw map from the top left of the window + map.draw(0, 0, 0, 0, WIDTH, HEIGHT); + + + //----------------------- Handle key presses ------------------------------------------------------------ + // MOUSE KEY PRESSES + //_______________________________________________________________________________________________________ + // User has left clicked + if(input.wasPressed(MouseButtons.LEFT)){ + // Checks if mouse above the tank icon when left clicked and if enough gold + if(tankIcon.getBoundingBoxAt(new Point(64,(shop.getHeight()/2)-10)).intersects(input.getMousePosition()) + && gold >= 250){ + // Create image of tank and set wave state to Placing + placingIcon = new Image(TANK_FILE); + placedImage = "tank"; + prevWaveState = waveState; + waveState = 2; + } + + // Checks if mouse above the super tank icon when left clicked and if enough gold + if(stankIcon.getBoundingBoxAt(new Point(184,(shop.getHeight()/2)-10)).intersects(input.getMousePosition()) + && gold >= 600){ + // Create image of super tank and set wave state to Placing + placingIcon = new Image(STANK_FILE); + placedImage = "stank"; + prevWaveState = waveState; + waveState = 2; + } + + // Checks if mouse above the plane icon when left clicked and if enough gold + if(planeIcon.getBoundingBoxAt(new Point(304,(shop.getHeight()/2)-10)).intersects(input.getMousePosition()) + && gold >= 500){ + // Create image of plane and set wave state to Placing + placingIcon = new Image(PLANE_FILE); + placedImage = "plane"; + prevWaveState = waveState; + waveState = 2; + } + } + + // User has selected an icon + if(input.isUp(MouseButtons.LEFT) && placingIcon != null){ + // Check pointer still within window + if(window.intersects(input.getMousePosition())){ + // Get whether pointer hovering over already placed tanks + getTankBlocked(input); + // Filter blocked areas + if(!map.hasProperty((int)Math.round(input.getMouseX()),(int)Math.round(input.getMouseY()),"blocked") + && !shop.getBoundingBox().intersects(input.getMousePosition()) + && !statusPanel.getBoundingBoxAt(new Point(HALF_WIDTH,HEIGHT - statusPanel.getHeight()/2)).intersects(input.getMousePosition()) + && !tankBlocked){ + // Draw icon + placingIcon.draw(input.getMouseX(),input.getMouseY()); + } + } + + } + + // User has placed tower by left clicking again, filter blocked areas + if(input.wasPressed(MouseButtons.LEFT) && placingIcon != null + && !map.hasProperty((int)Math.round(input.getMouseX()),(int)Math.round(input.getMouseY()),"blocked") + && !shop.getBoundingBox().intersects(input.getMousePosition()) + && !statusPanel.getBoundingBoxAt(new Point(HALF_WIDTH,HEIGHT - statusPanel.getHeight()/2)).intersects(input.getMousePosition()) + && !tankBlocked){ + // Add tank tower if tank and update gold + if(placedImage.equals("tank")){ + tanks.add(new Tank(input.getMousePosition(),TANK_FILE)); + gold-=250; + } + // Add super tank tower if super tank and update gold + if(placedImage.equals("stank")) { + tanks.add(new SuperTank(input.getMousePosition(), STANK_FILE)); + gold-=600; + } + // Add plane if plane and update gold + if(placedImage.equals("plane")) { + // Create new plane object with direction given + if (isVertical) { + planes.add(new Airplane(new Point(input.getMouseX(), 0), isVertical, PLANE_FILE)); + isVertical = false; + } else { + planes.add(new Airplane(new Point(0, input.getMouseY()), isVertical, PLANE_FILE)); + isVertical = true; + } + + gold -= 500; + + } + // Reset wave state and placing image to previous wave state and null after placing is complete + waveState = prevWaveState; + placingIcon = null; + } + // KEYBOARD KEY PRESSES + //_______________________________________________________________________________________________________ + // User has pressed S + if (input.wasPressed(Keys.S)) { + // Start a wave if wave state is not Wave in progress + if(waveState != 1){ + waveStarted = true; + // Set wave state to Wave in progress + if(waveState<=1){ + waveState = 1; + } + + } + + } + + // User has pressed L + if (input.wasPressed(Keys.L)) { + increaseTimescale(); + } + + // User has pressed K + if (input.wasPressed(Keys.K)) { + decreaseTimescale(); + } + + // MAIN UPDATE ---------------------------------------------------------------------- + // Checks if user has lives and not beaten the levels yet + if(waveState!=3 && lives>0){ + // Checks if a wave has started and is in progress + if(waveStarted){ + // Run through each event + if(eventCounter<events.size()){ + event = events.get(eventCounter); + // Checks if event is part of a new wave and if event has completed + if(waveCounter == Integer.parseInt(event.get(0)) && !eventWait){ + getEventData(); + eventStarted = true; + eventCounter++; + // Since it is a new wave, increment wave counter and wait for user to begin next wave + } else if(waveCounter != Integer.parseInt(event.get(0)) && !eventWait){ + waveCounter++; + waveStarted = false; + } + // Events have reached the last event + } else { + // Checks no slicers on map + if(slicers.isEmpty()){ + // Set incremented level as new map, if not already set + if(!mapSet){ + mapSet = true; + map_file = map_file.split(String.valueOf(level))[0]+(level+1) + +map_file.split(String.valueOf(level))[1]; + } + // If level does not exist, user has beaten all available levels + if(!(new File(map_file).exists())){ + // Wave state set to Winner! + waveState = 3; + // Set up new level and reset + } else { + resetLevel(); + } + + } + + + + } + // Wave has just finished so set to Awaiting and update gold + } else { + if(waveState == 1 && slicers.isEmpty()){ + gold += waveNumber*100+150; + waveState = 0; + } + } + + // Run an event + if(eventStarted){ + // Event is a spawn event + if (eventType == 1) { + // Event not yet complete + eventWait = true; + + // Spawn slicers with specified spawn count and delay + if (frameCount*1000 / FPS >= spawnDelay && spawnedSlicers != spawnCount) { + switch(enemyType) { + case "slicer": + slicers.add(new RegularSlicer(polyline,1,polyline.get(0),RSLICER)); + break; + case "superslicer": + slicers.add(new SuperSlicer(polyline,1,polyline.get(0),SSLICER)); + break; + case "megaslicer": + slicers.add(new MegaSlicer(polyline,1,polyline.get(0),MSLICER)); + break; + case "apexslicer": + slicers.add(new ApexSlicer(polyline,1,polyline.get(0),ASLICER)); + break; + } + // Increment spawned slicer count + spawnedSlicers += 1; + // Reset frame counter + frameCount = 0; + + // Event has spawned specified amount + } else if (spawnedSlicers == spawnCount) { + // Reset wait, started and spawned slicer count for next event + eventWait = false; + eventStarted = false; + spawnedSlicers = 0; + + } + // Event is a delay event + } else if (eventType == 0) { + eventWait = true; + // Wait out specified delay + if (frameCount*1000 / FPS >= nothingTime) { + // Reset wait, started and frame count for next event + eventWait = false; + eventStarted = false; + // Reset frame counter + frameCount = 0; + } + } + + } + } + + + + + + + // Update all sprites, and remove them if they've finished + + // Update all tanks + for (int j = tanks.size() - 1; j >= 0; j--) { + if (!tanks.isEmpty()) { + // Select a tank object + Tank v = tanks.get(j); + // Set tank target to null + v.setTarget(null); + // Find closest slicer + for (int i = 0; i <= slicers.size() - 1; i++) { + if(!slicers.isEmpty()){ + Slicer s = slicers.get(i); + // Checks if slicer within range and has health + if (v.getCenter().distanceTo(s.getCenter()) < v.getRadius() && s.getHealth() > 0 && !hasTarget) { + // Successfully found closest slicer and within tank range + v.setTarget(s); + slicerIndex = i; + hasTarget = true; + } + } + } + // Checks if tank has target + if(hasTarget){ + // Shoot projectile at target once in every cooldown period + if (projCount*1000 / FPS >= v.getCooldown()) { + if(v.getDamage() == 1){ + // Tank projectile + projectiles.add(new Projectile(v.getTankPoint(),v.getTarget(),v.getDamage(),slicerIndex,TANK_PROJ_FILE)); + } else { + // Super Tank projectile + projectiles.add(new Projectile(v.getTankPoint(),v.getTarget(),v.getDamage(),slicerIndex,STANK_PROJ_FILE)); + } + // Reset projectile frame count + projCount = 0; + } + + } + + v.update(input); + hasTarget = false; + + + } + } + // Update all projectiles + for (int i = projectiles.size() - 1; i >= 0; i--) { + if(!projectiles.isEmpty()){ + Projectile t = projectiles.get(i); + + t.update(input); + // Projectile has hit a slicer + if (t.isFinished()) { + if(t.getSlicerIndex()<slicers.size()){ + // Remove appropriate health from slicer + slicers.get(t.getSlicerIndex()).setHealth(slicers.get(t.getSlicerIndex()).getHealth()-t.getDamage()); + } + + // Remove projectile + projectiles.remove(i); + } + + } + + } + // Update all planes + for (int i = planes.size() - 1; i >= 0; i--) { + if(!planes.isEmpty()){ + Airplane v = planes.get(i); + v.update(input); + // Check if any of the plane's explosives are going to explode + if(v.getExplode()!=null){ + // One of the planes explosives is ready to explode + // Create a range for explosion to occur + Rectangle r = new Rectangle(v.getExplode().x-EXP_RADIUS, + v.getExplode().y-EXP_RADIUS, + EXP_RADIUS*2, + EXP_RADIUS*2); + // Remove appropriate health from all slicers in range + for (int j = slicers.size() - 1; j >= 0; j--) { + if(slicers.get(j).getRect().intersects(r)){ + slicers.get(j).setHealth(slicers.get(j).getHealth()-v.getDamage()); + } + } + } + // Remove plane + if (v.isFinished()) { + planes.remove(i); + } + } + + } + // Update all slicers + for (int i = slicers.size() - 1; i >= 0; i--) { + if(!slicers.isEmpty()){ + Slicer s = slicers.get(i); + + s.update(input); + // Checks if specified slicer is finished + if (s.isFinished()) { + // Checks if slicer was finished by depleting health + if(s.getHealth()<=0){ + // Spawn slicers on death if so + if(s.getPenalty() == 2){ + for (int j = 0; j < s.getSpawnOnDeath(); j++) { + slicers.add(new RegularSlicer(polyline, s.getTargetPointIndex(), s.getCurrentPoint(), RSLICER)); + } + + } else if(s.getPenalty() == 4){ + for (int j = 0; j < s.getSpawnOnDeath(); j++) { + slicers.add(new SuperSlicer(polyline,s.getTargetPointIndex(),s.getCurrentPoint(),SSLICER)); + } + + } else if(s.getPenalty() == 16){ + for (int j = 0; j < s.getSpawnOnDeath(); j++) { + slicers.add(new MegaSlicer(polyline,s.getTargetPointIndex(),s.getCurrentPoint(),MSLICER)); + } + + } + // Update gold for slicer kill + gold += s.getReward(); + } else { + // Update lives if slicer completed the run + lives -= s.getPenalty(); + } + // Remove slicer + slicers.remove(i); + } + + } + + } + //Draw shop panel + drawShopPanel(); + + // Draw status panel + drawStatusPanel(); + + + + + + + } +} diff --git a/src/lists/Slicer.java b/src/Slicer.java similarity index 79% rename from src/lists/Slicer.java rename to src/Slicer.java index 1e3f6c8..29a9f45 100644 --- a/src/lists/Slicer.java +++ b/src/Slicer.java @@ -1,5 +1,3 @@ -package lists; - import bagel.Input; import bagel.util.Point; import bagel.util.Vector2; @@ -12,7 +10,7 @@ public class Slicer extends Sprite { protected double speed,reward,penalty; - protected int health; + protected int health, spawnOnDeath; protected final List<Point> polyline; protected int targetPointIndex; protected boolean finished; @@ -22,17 +20,41 @@ public class Slicer extends Sprite { * * @param polyline The polyline that the slicer must traverse (must have at least 1 point) */ - public Slicer(List<Point> polyline,String imageSrc) { - super(polyline.get(0), imageSrc); + public Slicer(List<Point> polyline,int targetPointIndex, Point point,String imageSrc) { + super(point, imageSrc); this.polyline = polyline; - this.targetPointIndex = 1; + this.targetPointIndex = targetPointIndex; this.finished = false; } + + public int getTargetPointIndex() { + return this.targetPointIndex; + } + + public double getReward() { + return this.reward; + } + + public int getSpawnOnDeath() { + return this.spawnOnDeath; + } + + public int getHealth(){ + return this.health; + } + + public double getPenalty() { + return this.penalty; + } + public void setHealth(int health){ this.health = health; } + public Point getCurrentPoint(){ + return getCenter(); + } /** * Updates the current state of the slicer. The slicer moves towards its next target point in * the polyline at its specified movement rate. @@ -64,6 +86,7 @@ public class Slicer extends Sprite { } if(health<=0){ + finished = true; return; } diff --git a/src/lists/Sprite.java b/src/Sprite.java similarity index 98% rename from src/lists/Sprite.java rename to src/Sprite.java index 4e36d74..4ca3eee 100644 --- a/src/lists/Sprite.java +++ b/src/Sprite.java @@ -1,5 +1,3 @@ -package lists; - import bagel.DrawOptions; import bagel.Image; import bagel.Input; diff --git a/src/lists/SuperSlicer.java b/src/SuperSlicer.java similarity index 77% rename from src/lists/SuperSlicer.java rename to src/SuperSlicer.java index 7fe3b58..03f7aec 100644 --- a/src/lists/SuperSlicer.java +++ b/src/SuperSlicer.java @@ -1,8 +1,6 @@ -package lists; - import bagel.Input; import bagel.util.Point; -import bagel.util.Vector2; + import java.util.List; /** @@ -17,13 +15,14 @@ public class SuperSlicer extends Slicer { * * @param polyline The polyline that the slicer must traverse (must have at least 1 point) */ - public SuperSlicer(List<Point> polyline,String imageSrc) { - super(polyline, imageSrc); + public SuperSlicer(List<Point> polyline, int targetPointIndex, Point point,String imageSrc) { + super(polyline,targetPointIndex,point, imageSrc); this.speed = 0.75; this.health = 1; this.reward = 15; this.penalty = 2; + this.spawnOnDeath = 2; } diff --git a/src/lists/SuperTank.java b/src/SuperTank.java similarity index 88% rename from src/lists/SuperTank.java rename to src/SuperTank.java index 2c3e7ae..4202cba 100644 --- a/src/lists/SuperTank.java +++ b/src/SuperTank.java @@ -1,5 +1,3 @@ -package lists; - import bagel.Input; import bagel.util.Point; @@ -10,7 +8,7 @@ public class SuperTank extends Tank{ public SuperTank(Point point, String imageSrc){ super(point,imageSrc); this.radius = 150; - this.damage = 1; + this.damage = 3; this.cooldown = 500; } diff --git a/src/lists/Tank.java b/src/Tank.java similarity index 67% rename from src/lists/Tank.java rename to src/Tank.java index 262c007..9a0e755 100644 --- a/src/lists/Tank.java +++ b/src/Tank.java @@ -1,12 +1,6 @@ -package lists; - import bagel.Input; import bagel.util.Point; -import java.util.ArrayList; - -import java.util.List; - public class Tank extends Sprite{ protected double radius,cooldown; protected int damage; @@ -22,13 +16,23 @@ public class Tank extends Sprite{ this.target = null; } - - public void attack(Slicer slicer){ - if (slicer.health > 0){ - slicer.health-=damage; - - - } + public void setTarget(Slicer givenTarget){ + this.target = givenTarget; + } + public Point getTankPoint(){ + return this.tankPoint; + } + public Slicer getTarget(){ + return this.target; + } + public int getDamage(){ + return this.damage; + } + public double getRadius(){ + return this.radius; + } + public double getCooldown(){ + return this.cooldown; } @Override public void update(Input input) { diff --git a/src/lists/ShadowDefend.java b/src/lists/ShadowDefend.java deleted file mode 100644 index 91bf947..0000000 --- a/src/lists/ShadowDefend.java +++ /dev/null @@ -1,557 +0,0 @@ -package lists; - -import bagel.*; -import bagel.Font; -import bagel.Image; - -import bagel.map.TiledMap; -import bagel.util.Colour; -import bagel.util.Point; -import bagel.util.Rectangle; - -import java.io.File; -import java.io.FileNotFoundException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Scanner; - - -/** - * ShadowDefend, a tower defence game. - * Used Rohyl's template from Project 1 - */ -public class ShadowDefend extends AbstractGame { - private static final String RSLICER = "res/images/slicer.png"; - private static final String SSLICER = "res/images/superslicer.png"; - private static final String MSLICER = "res/images/megaslicer.png"; - private static final String ASLICER = "res/images/apexslicer.png"; - private static final int HEIGHT = 768; - private static final int WIDTH = 1024; - private static final String MAP_FILE = "res/levels/1.tmx"; - private static final String SHOP_FILE = "res/images/buypanel.png"; - private static final String STATUS_FILE = "res/images/statuspanel.png"; - private static final String TANK_FILE = "res/images/tank.png"; - private static final String TANK_PROJ_FILE = "res/images/tank_projectile.png"; - private static final String STANK_FILE = "res/images/supertank.png"; - private static final String PLANE_FILE = "res/images/airsupport.png"; - private static final String FONT_FILE = "res/fonts/DejaVuSans-Bold.ttf"; - private static final String INFO = "Key binds:\n\nS - Start Wave\nL - Increase Timescale\nK - Decrease Timescale"; - private static final String WAVES_FILE = "res/levels/waves.txt"; - private DrawOptions colour = new DrawOptions(); - private File wavesText = new File(WAVES_FILE); - private Scanner fr; - // Change to suit system specifications. This could be - // dynamically determined but that is out of scope. - public static final double FPS = 60; - // The spawn delay (in seconds) to spawn slicers - private static final int SPAWN_DELAY = 5; - private static final int INTIAL_TIMESCALE = 1; - private static final int MAX_SLICERS = 5; - // Timescale is made static because it is a universal property of the game and the specification - // says everything in the game is affected by this - private static int timescale = INTIAL_TIMESCALE; - private final TiledMap map; - private final Image shop, statusPanel, tankIcon, stankIcon, planeIcon; - private final List<Point> polyline; - private final List<Slicer> slicers; - private final List<Projectile> projectiles; - - private final List<Tank> tanks; - - private final List<Airplane> planes; - - private final Rectangle window; - private Point p; - private List<String> event; - private String prev_event; - private List<List<String>> events; - private Font goldDisplay, keyInstruction, costText, statusText; - private Image placingIcon; - private double frameCount; - private double projCount; - private int spawnedSlicers; - private int nothingTime; - private int spawnDelay; - private int spawnCount; - private int eventType; - private int waveCounter; - private int eventCounter; - private int prevWaveState; - private int slicerIndex; - private boolean eventWait; - private String enemyType; - private String placedImage; - private boolean waveStarted; - private boolean eventStarted = true; - private boolean isVertical = false; - private boolean hasTarget = false; - private static int gold, lives, waveNumber, waveState; - - - /** - * Creates a new instance of the ShadowDefend game - */ - public ShadowDefend() { - - super(WIDTH, HEIGHT, "ShadowDefend"); - - gold = 50000; - lives = 25; - waveNumber = 1; - waveState = 0; - this.window = new Rectangle(0,0,WIDTH,HEIGHT); - this.map = new TiledMap(MAP_FILE); - this.shop = new Image(SHOP_FILE); - this.statusPanel = new Image(STATUS_FILE); - this.tankIcon = new Image(TANK_FILE); - this.stankIcon = new Image(STANK_FILE); - this.planeIcon = new Image(PLANE_FILE); - this.goldDisplay = new Font(FONT_FILE,50); - this.keyInstruction = new Font(FONT_FILE,16); - this.costText = new Font(FONT_FILE,20); - this.statusText = new Font(FONT_FILE,16); - this.polyline = map.getAllPolylines().get(0); - this.slicers = new ArrayList<>(); - this.projectiles = new ArrayList<>(); - - this.tanks = new ArrayList<>(); - - this.planes = new ArrayList<>(); - - this.events = new ArrayList<>(); - this.event = new ArrayList<>(); - - this.spawnedSlicers = 0; - this.waveStarted = false; - this.frameCount = Integer.MAX_VALUE; - this.projCount = Integer.MAX_VALUE; - this.waveCounter = 1; - this.eventCounter = 0; - this.eventWait = false; - try { - this.fr = new Scanner(wavesText); - while (fr.hasNextLine()) { - events.add(Arrays.asList(fr.nextLine().split(","))); - } - fr.close(); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } - - - - // Temporary fix for the weird slicer map glitch (might have to do with caching textures) - // This fix is entirely optional - //new Slicer(polyline); - } - - /** - * The entry-point for the game - * - * @param args Optional command-line arguments - */ - public static void main(String[] args) { - new ShadowDefend().run(); - } - - public static int getTimescale() { - return timescale; - } - - /** - * Increases the timescale - */ - private void increaseTimescale() { - timescale++; - } - - /** - * Decreases the timescale but doesn't go below the base timescale - */ - private void decreaseTimescale() { - if (timescale > INTIAL_TIMESCALE) { - timescale--; - } - } - private void getEventData(){ - if(event.size() == 3){ - // Delay event - eventType = 0; - waveNumber = Integer.parseInt(event.get(0)); - nothingTime = Integer.parseInt(event.get(2)); - - - } else { - // Spawn event - eventType = 1; - waveNumber = Integer.parseInt(event.get(0)); - spawnCount = Integer.parseInt(event.get(2)); - enemyType = event.get(3); - spawnDelay = Integer.parseInt(event.get(4)); - System.out.println(waveNumber); - System.out.println(spawnCount); - System.out.println(enemyType); - System.out.println(spawnDelay); - } - - } - /** - * Update the state of the game, potentially reading from input - * - * @param input The current mouse/keyboard state - */ - @Override - protected void update(Input input) { - // Increase the frame counter by the current timescale - frameCount += getTimescale(); - projCount += getTimescale(); - - - // Draw map from the top left of the window - map.draw(0, 0, 0, 0, WIDTH, HEIGHT); - - //Draw shop panel - shop.drawFromTopLeft(0,0); - - tankIcon.draw(64,(shop.getHeight()/2)-10); - stankIcon.draw(184,(shop.getHeight()/2)-10); - planeIcon.draw(304,(shop.getHeight()/2)-10); - keyInstruction.drawString(INFO,(shop.getWidth()/2)-keyInstruction.getWidth(INFO)/2,20); - if(gold > 999){ - String extra = Integer.toString(gold).substring(Integer.toString(gold).length() -3); - String thousandth = Integer.toString(gold).substring(0,Integer.toString(gold).length() -3); - goldDisplay.drawString("$"+ thousandth + "," + extra,shop.getWidth()-200,65); - - } else { - goldDisplay.drawString("$"+ gold,shop.getWidth()-200,65); - } - if(gold < 250){ - costText.drawString("$"+250,64-(tankIcon.getWidth()/2), - (tankIcon.getHeight()/2)+(shop.getHeight()/2+5), - colour.setBlendColour(Colour.RED)); - - } else { - costText.drawString("$"+250,64-(tankIcon.getWidth()/2), - (tankIcon.getHeight()/2)+(shop.getHeight()/2+5), - colour.setBlendColour(Colour.GREEN)); - } - - if(gold < 600){ - costText.drawString("$"+600,184-(stankIcon.getWidth()/2), - (stankIcon.getHeight()/2)+(shop.getHeight()/2+5), - colour.setBlendColour(Colour.RED)); - - } else { - costText.drawString("$"+600,184-(stankIcon.getWidth()/2), - (stankIcon.getHeight()/2)+(shop.getHeight()/2+5), - colour.setBlendColour(Colour.GREEN)); - - } - if(gold < 500){ - costText.drawString("$"+500,304-(planeIcon.getWidth()/2), - (planeIcon.getHeight()/2)+(shop.getHeight()/2+5), - colour.setBlendColour(Colour.RED)); - - } else { - costText.drawString("$"+500,304-(planeIcon.getWidth()/2), - (planeIcon.getHeight()/2)+(shop.getHeight()/2+5), - colour.setBlendColour(Colour.GREEN)); - - } - - //Draw status panel - statusPanel.drawFromTopLeft(0,HEIGHT - statusPanel.getHeight()); - statusText.drawString("Wave: " + waveNumber,5,HEIGHT-6); - if(timescale>1){ - statusText.drawString("Timescale: " + timescale + ".0", - WIDTH/4, - HEIGHT-6, - colour.setBlendColour(Colour.GREEN)); - - } else { - statusText.drawString("Timescale: " + timescale + ".0",WIDTH/4,HEIGHT-6); - } - switch(waveState) { - case 0: - statusText.drawString("Status: Awaiting Start", - WIDTH/2, - HEIGHT-6); - break; - case 1: - statusText.drawString("Status: Wave In Progress", - WIDTH/2, - HEIGHT-6); - break; - case 2: - statusText.drawString("Status: Placing", - WIDTH/2, - HEIGHT-6); - break; - case 3: - statusText.drawString("Status: Winner!", - WIDTH/2, - HEIGHT-6); - break; - } - statusText.drawString("Lives: " + lives, - WIDTH-statusText.getWidth("Lives: " + lives)-5, - HEIGHT-6); - - // Handle key presses - if(input.wasPressed(MouseButtons.LEFT)){ - System.out.println(input.getMousePosition()); - if(tankIcon.getBoundingBoxAt(p = new Point(64,(shop.getHeight()/2)-10)).intersects(input.getMousePosition()) - && gold >= 250){ - placingIcon = new Image(TANK_FILE); - placedImage = "tank"; - prevWaveState = waveState; - waveState = 2; - } - if(stankIcon.getBoundingBoxAt(p = new Point(184,(shop.getHeight()/2)-10)).intersects(input.getMousePosition()) - && gold >= 600){ - placingIcon = new Image(STANK_FILE); - placedImage = "stank"; - prevWaveState = waveState; - waveState = 2; - } - if(planeIcon.getBoundingBoxAt(p = new Point(304,(shop.getHeight()/2)-10)).intersects(input.getMousePosition()) - && gold >= 500){ - placingIcon = new Image(PLANE_FILE); - placedImage = "plane"; - prevWaveState = waveState; - waveState = 2; - } - } - if(input.isUp(MouseButtons.LEFT)){ - if(window.intersects(input.getMousePosition())){ - if(placingIcon != null - && !map.hasProperty((int)Math.round(input.getMouseX()),(int)Math.round(input.getMouseY()),"blocked") - && !shop.getBoundingBox().intersects(input.getMousePosition()) - && !statusPanel.getBoundingBoxAt(p = new Point(WIDTH/2,HEIGHT - statusPanel.getHeight()/2)).intersects(input.getMousePosition())){ - - placingIcon.draw(input.getMouseX(),input.getMouseY()); - } - } - - } - if(input.wasPressed(MouseButtons.LEFT) && placingIcon != null - && !map.hasProperty((int)Math.round(input.getMouseX()),(int)Math.round(input.getMouseY()),"blocked") - && !shop.getBoundingBox().intersects(input.getMousePosition()) - && !statusPanel.getBoundingBoxAt(p = new Point(WIDTH/2,HEIGHT - statusPanel.getHeight()/2)).intersects(input.getMousePosition())){ - - if(placedImage.equals("tank")){ - tanks.add(new Tank(input.getMousePosition(),TANK_FILE)); - gold-=250; - System.out.println(tanks); - } - if(placedImage.equals("stank")) { - tanks.add(new SuperTank(input.getMousePosition(), STANK_FILE)); - gold-=600; - System.out.println(tanks); - } - if(placedImage.equals("plane")) { - if(isVertical){ - planes.add(new Airplane(new Point(input.getMouseX(),0),isVertical, PLANE_FILE)); - isVertical = false; - } else { - planes.add(new Airplane(new Point(0,input.getMouseY()),isVertical, PLANE_FILE)); - isVertical = true; - } - - gold-=500; - System.out.println(planes); - } - waveState = prevWaveState; - placingIcon = null; - - - - } - if (input.wasPressed(Keys.S)) { - if(waveState != 1){ - waveStarted = true; - waveState = 1; - } - - } - - if (input.wasPressed(Keys.L)) { - increaseTimescale(); - } - - if (input.wasPressed(Keys.K)) { - decreaseTimescale(); - } - - - if(waveStarted){ - if(eventCounter<events.size()){ - event = events.get(eventCounter); - if(waveCounter == Integer.parseInt(event.get(0)) && !eventWait){ - getEventData(); - eventStarted = true; - eventCounter++; - } else if(waveCounter != Integer.parseInt(event.get(0))){ - waveCounter++; - waveStarted = false; - - - - } - - } else { - if(lives>0 && slicers.isEmpty()){ - if(waveState != 3){ - gold += waveNumber*100+150; - } - waveState = 3; - - - - } - - - } - - } - if(waveState == 1 && !waveStarted && slicers.isEmpty()){ - if(waveState != 0){ - gold += waveNumber*100+150; - } - - waveState = 0; - - } - if(eventStarted){ - if (eventType == 1) { - eventWait = true; - if (frameCount*1000 / FPS >= spawnDelay && spawnedSlicers != spawnCount) { - switch(enemyType) { - case "slicer": - slicers.add(new RegularSlicer(polyline,RSLICER)); - break; - case "superslicer": - //System.out.println("in"); - slicers.add(new SuperSlicer(polyline,SSLICER)); - break; - case "megaslicer": - slicers.add(new MegaSlicer(polyline,MSLICER)); - break; - case "apexslicer": - slicers.add(new ApexSlicer(polyline,ASLICER)); - break; - } - - spawnedSlicers += 1; - // Reset frame counter - frameCount = 0; - } else if (spawnedSlicers == spawnCount) { - System.out.println("done"); - eventWait = false; - eventStarted = false; - spawnedSlicers = 0; - - } - } else if (eventType == 0) { - eventWait = true; - if (frameCount*1000 / FPS >= nothingTime) { - eventWait = false; - eventStarted = false; - // Reset frame counter - frameCount = 0; - } - } - - } - - // Wave begin - - - - - // Close game if all slicers have finished traversing the polyline - /*if (spawnedSlicers == MAX_SLICERS && slicers.isEmpty()) { - Window.close(); - }*/ - - // Update all sprites, and remove them if they've finished - for (int j = tanks.size() - 1; j >= 0; j--) { - if (!tanks.isEmpty()) { - Tank v = tanks.get(j); - v.target = null; - - for (int i = 0; i <= slicers.size() - 1; i++) { - if(!slicers.isEmpty()){ - Slicer s = slicers.get(i); - if (v.getCenter().distanceTo(s.getCenter()) < v.radius && s.health > 0 && !hasTarget) { - v.target = s; - slicerIndex = i; - hasTarget = true; - } - } - } - if(hasTarget){ - if (projCount*1000 / FPS >= v.cooldown) { - - projectiles.add(new Projectile(v.tankPoint,v.target,v.damage,slicerIndex,TANK_PROJ_FILE)); - projCount = 0; - } - - } - - v.update(input); - hasTarget = false; - - - } - } - for (int i = projectiles.size() - 1; i >= 0; i--) { - if(!projectiles.isEmpty()){ - Projectile t = projectiles.get(i); - - t.update(input); - if (t.isFinished()) { - - slicers.get(t.slicerIndex).setHealth(slicers.get(t.slicerIndex).health-t.damage); - System.out.println(slicers.get(t.slicerIndex).health); - projectiles.remove(i); - } - - } - - } - for (int i = slicers.size() - 1; i >= 0; i--) { - if(!slicers.isEmpty()){ - Slicer s = slicers.get(i); - - s.update(input); - if (s.isFinished()) { - if(s.health<=0){ - gold += s.reward; - } else { - lives -= s.penalty; - } - slicers.remove(i); - } - - } - - } - - - - - - for (int i = planes.size() - 1; i >= 0; i--) { - if(!planes.isEmpty()){ - Airplane v = planes.get(i); - v.update(input); - if (v.isFinished()) { - planes.remove(i); - } - } - - } - } -} -- GitLab