diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml
new file mode 100644
index 000000000..27221ab51
--- /dev/null
+++ b/.github/workflows/maven.yml
@@ -0,0 +1,26 @@
+# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time
+# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
+
+name: Java CI with Maven
+
+on:
+ push:
+ branches: [ main ]
+ pull_request:
+ branches: [ main ]
+
+jobs:
+ build:
+
+ runs-on: windows-latest
+
+ steps:
+ - uses: actions/checkout@v2
+ - name: Set up JDK 11
+ uses: actions/setup-java@v2
+ with:
+ java-version: '11'
+ distribution: 'adopt'
+ cache: maven
+ - name: Build with Maven
+ run: mvn -B package --file pom.xml
diff --git a/.gitignore b/.gitignore
index aeed73a98..7f72f0bf9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -167,5 +167,7 @@ pip-log.txt
#############
log*
-*.ttf
-.checkstyle
\ No newline at end of file
+.checkstyle
+*.class
+.idea/
+out/
\ No newline at end of file
diff --git a/README.md b/README.md
index 48d20a1b2..46ad64bc8 100644
--- a/README.md
+++ b/README.md
@@ -1,26 +1,33 @@
Invaders
=
-[Space Invaders](http://en.wikipedia.org/wiki/Space_Invaders) clone, written in Java.
-###Screenshots
-![](http://i.minus.com/ijt8HhaA8laZq.png)
+Welcome to our Space Invaders java project developed as part of our Software Development Practices class at Hanyang University. We were tasked with adding features onto a previously developed space invaders game.
-###Download
-[Dropbox](https://dl.dropboxusercontent.com/u/23829102/invaders.zip)
+### Team
-Mirror: [Mediafire](http://www.mediafire.com/download/kwv9s90j9i1o4kc/invaders.zip)
+Our team is called Team Aliens, it comprises of 5 members.
-###Installation
-After downloading the file above, unpack it and save it to an appropiate location.
+ * Elias - https://github.com/eliasb1
+ * Luca - https://github.com/56luca
+ * Janae - https://github.com/jfarinas96
+ * Sophie - https://github.com/sibylle221
+ * Josh - https://github.com/Josholeary
-Open the directory and double-click invaders.jar. In some systems (i.e. Ubuntu) you may need to select 'Open with OpenJDK 7 Runtime' or similar from the context menu.
+### Features
-If the Java path is not set correctly, you can also navigate to the directory from the command line and execute
+The following is a list of the features we added.
->java -jar invaders.jar
+ - Add dying effect (screen shake)
+ - Add SFX & BGM (background music and sound effects)
+ - Add various monsters (making higher hp monsters and different monster formations)
+ - Display HP Color (coordinating colours to reflect monster hp)
+ - Add Setting function (screen resizing, game speed selecting etc)
+ - Add game summary (controls/manual)
+ - Add pause function
-###System Requirements
-Requires Java 7 or better.
+ ### CI/CD
+We used Github Actions for CI/CD, these are the specific tools we are using for this project:
+
+ - Maven to build the project
+ - CodeFactor for code checking
-###Resources
-[Space Invaders Regular (font)](http://www.fonts2u.com/space-invaders-regular.font) - © kylemaoin 2010
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 000000000..59dd58c35
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,33 @@
+
+
+ 4.0.0
+
+ com.setb
+ Invaders
+ 1.0-SNAPSHOT
+
+
+
+
+ src/main/resources
+
+
+
+
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ 5.8.2
+ test
+
+
+
+
+ 11
+ 11
+
+
+
\ No newline at end of file
diff --git a/src/engine/Cooldown.java b/src/main/java/engine/Cooldown.java
similarity index 100%
rename from src/engine/Cooldown.java
rename to src/main/java/engine/Cooldown.java
diff --git a/src/engine/Core.java b/src/main/java/engine/Core.java
similarity index 86%
rename from src/engine/Core.java
rename to src/main/java/engine/Core.java
index 35cc8274c..f63b50b5e 100644
--- a/src/engine/Core.java
+++ b/src/main/java/engine/Core.java
@@ -8,11 +8,7 @@
import java.util.logging.Level;
import java.util.logging.Logger;
-import screen.GameScreen;
-import screen.HighScoreScreen;
-import screen.ScoreScreen;
-import screen.Screen;
-import screen.TitleScreen;
+import screen.*;
/**
* Implements core game logic.
@@ -23,9 +19,9 @@
public final class Core {
/** Width of current screen. */
- private static final int WIDTH = 448;
+ private static int WIDTH = 448;
/** Height of current screen. */
- private static final int HEIGHT = 520;
+ private static int HEIGHT = 520;
/** Max fps of current screen. */
private static final int FPS = 60;
@@ -59,7 +55,7 @@ public final class Core {
new GameSettings(8, 7, 2, 500);
/** Frame to draw the screen on. */
- private static Frame frame;
+ public static Frame frame;
/** Screen currently shown. */
private static Screen currentScreen;
/** Difficulty settings list. */
@@ -114,6 +110,8 @@ public static void main(final String[] args) {
GameState gameState;
+ Sound.playMusic();
+
int returnCode = 1;
do {
gameState = new GameState(1, 0, MAX_LIVES, 0, 0);
@@ -121,6 +119,12 @@ public static void main(final String[] args) {
switch (returnCode) {
case 1:
// Main menu.
+ frame.setVisible(false); // This makes the old window disappear
+ frame = new Frame(WIDTH, HEIGHT); // This creates a new window with new width & height values
+ DrawManager.getInstance().setFrame(frame);
+ width = frame.getWidth();
+ height = frame.getHeight();
+
currentScreen = new TitleScreen(width, height, FPS);
LOGGER.info("Starting " + WIDTH + "x" + HEIGHT
+ " title screen at " + FPS + " fps.");
@@ -172,6 +176,22 @@ public static void main(final String[] args) {
returnCode = frame.setScreen(currentScreen);
LOGGER.info("Closing high score screen.");
break;
+ case 4:
+ // Help.
+ currentScreen = new HelpScreen(width, height, FPS);
+ LOGGER.info("Starting " + WIDTH + "x" + HEIGHT
+ + " help screen at " + FPS + " fps.");
+ returnCode = frame.setScreen(currentScreen);
+ LOGGER.info("Closing help screen.");
+ break;
+ case 5:
+ // Settings.
+ currentScreen = new SettingsScreen(width, height, FPS);
+ LOGGER.info("Starting " + WIDTH + "x" + HEIGHT
+ + " settings screen at " + FPS + " fps.");
+ returnCode = frame.setScreen(currentScreen);
+ LOGGER.info("Closing settings screen.");
+ break;
default:
break;
}
@@ -250,4 +270,9 @@ public static Cooldown getVariableCooldown(final int milliseconds,
final int variance) {
return new Cooldown(milliseconds, variance);
}
+
+ public static void setSize(int width, int height) {
+ WIDTH = width;
+ HEIGHT = height;
+ }
}
\ No newline at end of file
diff --git a/src/engine/DrawManager.java b/src/main/java/engine/DrawManager.java
similarity index 71%
rename from src/engine/DrawManager.java
rename to src/main/java/engine/DrawManager.java
index 3d61ca503..eabd865cf 100644
--- a/src/engine/DrawManager.java
+++ b/src/main/java/engine/DrawManager.java
@@ -283,15 +283,18 @@ public void drawHorizontalLine(final Screen screen, final int positionY) {
*/
public void drawTitle(final Screen screen) {
String titleString = "Invaders";
- String instructionsString =
- "select with w+s / arrows, confirm with space";
+ String[] instructionsStrings = {"Select with w+s / arrows", "Confirm with space"};
+ int i = 0;
backBufferGraphics.setColor(Color.GRAY);
- drawCenteredRegularString(screen, instructionsString,
- screen.getHeight() / 2);
+ for (String instructionString : instructionsStrings) {
+ drawCenteredRegularString(screen, instructionString,
+ screen.getHeight() * 4 / 15 + fontRegularMetrics.getHeight() * 2 * i);
+ i++;
+ }
backBufferGraphics.setColor(Color.GREEN);
- drawCenteredBigString(screen, titleString, screen.getHeight() / 3);
+ drawCenteredBigString(screen, titleString, screen.getHeight() / 6);
}
/**
@@ -305,26 +308,40 @@ public void drawTitle(final Screen screen) {
public void drawMenu(final Screen screen, final int option) {
String playString = "Play";
String highScoresString = "High scores";
- String exitString = "exit";
+ String helpString = "Help";
+ String settingsString = "Settings";
+ String exitString = "Exit";
if (option == 2)
backBufferGraphics.setColor(Color.GREEN);
else
backBufferGraphics.setColor(Color.WHITE);
drawCenteredRegularString(screen, playString,
- screen.getHeight() / 3 * 2);
+ screen.getHeight() * 11 / 20);
if (option == 3)
backBufferGraphics.setColor(Color.GREEN);
else
backBufferGraphics.setColor(Color.WHITE);
- drawCenteredRegularString(screen, highScoresString, screen.getHeight()
- / 3 * 2 + fontRegularMetrics.getHeight() * 2);
+ drawCenteredRegularString(screen, highScoresString,
+ screen.getHeight() * 11 / 20 + fontRegularMetrics.getHeight() * 2);
+ if (option == 4)
+ backBufferGraphics.setColor(Color.GREEN);
+ else
+ backBufferGraphics.setColor(Color.WHITE);
+ drawCenteredRegularString(screen, helpString,
+ screen.getHeight() * 11 / 20 + fontRegularMetrics.getHeight() * 4);
+ if (option == 5)
+ backBufferGraphics.setColor(Color.GREEN);
+ else
+ backBufferGraphics.setColor(Color.WHITE);
+ drawCenteredRegularString(screen, settingsString,
+ screen.getHeight() * 11 / 20 + fontRegularMetrics.getHeight() * 6);
if (option == 0)
backBufferGraphics.setColor(Color.GREEN);
else
backBufferGraphics.setColor(Color.WHITE);
- drawCenteredRegularString(screen, exitString, screen.getHeight() / 3
- * 2 + fontRegularMetrics.getHeight() * 4);
+ drawCenteredRegularString(screen, exitString,
+ screen.getHeight() * 11 / 20 + fontRegularMetrics.getHeight() * 8);
}
/**
@@ -488,15 +505,169 @@ public void drawHighScores(final Screen screen,
}
/**
- * Draws a centered string on regular font.
- *
+ * Draws help screen
+ *
+ * @param screen
+ * Screen to draw on.
+ */
+ public void drawHelp(final Screen screen) {
+ String helpString = "Help";
+ String instructionsString = "Press Space to return";
+ String[] rule1 = {"Press the arrow keys", "(or the A or D keys)", "to move your ship"};
+ String[] rule2 = {"Press space to shoot", "missiles at the enemy ships"};
+ String[] rule3 = {"Avoid the missiles shot", "by the enemy ships"};
+ String[] rule4 = {"The color of an enemy ship", "depends on their remaining", "health points"};
+ String[][] rules = {rule1, rule2, rule3, rule4};
+ int i = 0;
+ int j = 0;
+
+ backBufferGraphics.setColor(Color.GREEN);
+ drawCenteredBigString(screen, helpString, screen.getHeight() / 8);
+
+ backBufferGraphics.setColor(Color.GRAY);
+ drawCenteredRegularString(screen, instructionsString,
+ screen.getHeight() / 5);
+
+ backBufferGraphics.setColor(Color.WHITE);
+ for (String[] rule : rules) {
+ for (String ruleString : rule) {
+ drawCenteredRegularString(screen, ruleString,
+ screen.getHeight() * 3 / 10
+ + fontRegularMetrics.getHeight() * i
+ + fontRegularMetrics.getHeight() * 2 * j);
+ i++;
+ }
+ j++;
+ }
+ }
+
+ /**
+ * Draws settings screen
+ *
+ * @param screen
+ * Screen to draw on.
+ */
+ public void drawSettings(final Screen screen) {
+ String settingsString = "Settings";
+ String[] instructionsString1 = {"Use A+D / Arrows", "to change settings", "", "Press space to return",
+ "and apply changes"};
+ int i = 0;
+
+ backBufferGraphics.setColor(Color.GREEN);
+ drawCenteredBigString(screen, settingsString, screen.getHeight() / 8);
+
+ backBufferGraphics.setColor(Color.GRAY);
+ for (String instructionsString : instructionsString1) {
+ drawCenteredRegularString(screen, instructionsString,
+ (int) (screen.getHeight() / 5 + Math.round(fontRegularMetrics.getHeight() * 1.5 * i)));
+ i++;
+ }
+
+ backBufferGraphics.setColor(Color.WHITE);
+ }
+
+ /**
+ * Draws settings options
+ *
* @param screen
* Screen to draw on.
- * @param string
- * String to draw.
- * @param height
- * Height of the drawing.
*/
+ public void drawSettingsOptions(final Screen screen, final int option) {
+ String screenSizeString = "Screen size";
+ String difficultyString = "Difficulty";
+ String volumeString = "Volume";
+
+ if (option == 1)
+ backBufferGraphics.setColor(Color.GREEN);
+ else
+ backBufferGraphics.setColor(Color.WHITE);
+ drawCenteredRegularString(screen, screenSizeString,
+ screen.getHeight() * 11 / 20 + fontRegularMetrics.getHeight() * 4);
+ if (option == 2)
+ backBufferGraphics.setColor(Color.GREEN);
+ else
+ backBufferGraphics.setColor(Color.WHITE);
+ drawCenteredRegularString(screen, difficultyString,
+ screen.getHeight() * 11 / 20 + fontRegularMetrics.getHeight() * 6);
+ if (option == 3)
+ backBufferGraphics.setColor(Color.GREEN);
+ else
+ backBufferGraphics.setColor(Color.WHITE);
+ drawCenteredRegularString(screen, volumeString,
+ screen.getHeight() * 11 / 20 + fontRegularMetrics.getHeight() * 8);
+ }
+
+ /**
+ * Draws settings options to change
+ *
+ * @param screen
+ * Screen to draw on.
+ */
+ public void drawSettingsChange(final Screen screen, final int option, final int change) {
+ String screenSizeOption1 = "Standard";
+ String screenSizeOption2 = "Extended";
+ String screenSizeOption3 = "Full screen";
+ String difficultyOption1 = "Easy";
+ String difficultyOption2 = "Medium";
+ String difficultyOption3 = "Hard";
+ String volumeOption1 = "25%";
+ String volumeOption2 = "50%";
+ String volumeOption3 = "75%";
+ String volumeOption4 = "100%";
+ String volumeOption5 = "Mute";
+ String displayOption = "Nothing to display";
+
+
+ // Screen size
+ if (option == 1) {
+ if (change == 1)
+ displayOption = screenSizeOption1;
+ if (change == 2)
+ displayOption = screenSizeOption2;
+ if (change == 3)
+ displayOption = screenSizeOption3;
+ }
+ // Difficulty
+ else if (option == 2) {
+ if (change == 1)
+ displayOption = difficultyOption1;
+ if (change == 2)
+ displayOption = difficultyOption2;
+ if (change == 3)
+ displayOption = difficultyOption3;
+ }
+ // Volume
+ else if (option == 3) {
+ if (change == 1)
+ displayOption = volumeOption1;
+ if (change == 2)
+ displayOption = volumeOption2;
+ if (change == 3)
+ displayOption = volumeOption3;
+ if (change == 4)
+ displayOption = volumeOption4;
+ if (change == 5)
+ displayOption = volumeOption5;
+ }
+ // Default
+ else {
+ displayOption = "Nothing to display";
+ }
+
+ backBufferGraphics.setColor(Color.darkGray);
+ drawCenteredBigString(screen, displayOption, screen.getHeight() / 2 + fontRegularMetrics.getHeight() * 2);
+ }
+
+ /**
+ * Draws a centered string on regular font.
+ *
+ * @param screen
+ * Screen to draw on.
+ * @param string
+ * String to draw.
+ * @param height
+ * Height of the drawing.
+ */
public void drawCenteredRegularString(final Screen screen,
final String string, final int height) {
backBufferGraphics.setFont(fontRegular);
@@ -559,4 +730,21 @@ else if (number != 0)
drawCenteredBigString(screen, "GO!", screen.getHeight() / 2
+ fontBigMetrics.getHeight() / 3);
}
+
+ /**
+ * Shows a pause screen when the game is paused
+ *
+ * @param screen
+ * Screen to draw on.
+ */
+ public void drawPaused(final Screen screen) {
+ int rectWidth = screen.getWidth();
+ int rectHeight = screen.getHeight() / 6;
+ backBufferGraphics.setColor(Color.BLACK);
+ backBufferGraphics.fillRect(0, screen.getHeight() / 2 - rectHeight / 2,
+ rectWidth, rectHeight);
+ backBufferGraphics.setColor(Color.GREEN);
+
+ drawCenteredBigString(screen, "Paused",screen.getHeight() / 2 + fontBigMetrics.getHeight() / 3);
+ }
}
diff --git a/src/engine/FileManager.java b/src/main/java/engine/FileManager.java
similarity index 100%
rename from src/engine/FileManager.java
rename to src/main/java/engine/FileManager.java
diff --git a/src/engine/Frame.java b/src/main/java/engine/Frame.java
similarity index 84%
rename from src/engine/Frame.java
rename to src/main/java/engine/Frame.java
index b52997a8c..c4183348b 100644
--- a/src/engine/Frame.java
+++ b/src/main/java/engine/Frame.java
@@ -6,6 +6,8 @@
import screen.Screen;
+
+
/**
* Implements a frame to show screens on.
*
@@ -15,20 +17,24 @@
@SuppressWarnings("serial")
public class Frame extends JFrame {
- /** Frame width. */
+ /**
+ * Frame width.
+ */
private int width;
- /** Frame height. */
+ /**
+ * Frame height.
+ */
private int height;
- /** Screen currently shown. */
+ /**
+ * Screen currently shown.
+ */
private Screen currentScreen;
/**
* Initializes the new frame.
- *
- * @param width
- * Frame width.
- * @param height
- * Frame height.
+ *
+ * @param width Frame width.
+ * @param height Frame height.
*/
public Frame(final int width, final int height) {
setSize(width, height);
@@ -48,9 +54,8 @@ public Frame(final int width, final int height) {
/**
* Sets current screen.
- *
- * @param screen
- * Screen to show.
+ *
+ * @param screen Screen to show.
* @return Return code of the finished screen.
*/
public final int setScreen(final Screen screen) {
@@ -61,7 +66,7 @@ public final int setScreen(final Screen screen) {
/**
* Getter for frame width.
- *
+ *
* @return Frame width.
*/
public final int getWidth() {
@@ -70,11 +75,13 @@ public final int getWidth() {
/**
* Getter for frame height.
- *
+ *
* @return Frame height.
*/
public final int getHeight() {
return this.height;
}
+
+
}
diff --git a/src/engine/GameSettings.java b/src/main/java/engine/GameSettings.java
similarity index 100%
rename from src/engine/GameSettings.java
rename to src/main/java/engine/GameSettings.java
diff --git a/src/engine/GameState.java b/src/main/java/engine/GameState.java
similarity index 100%
rename from src/engine/GameState.java
rename to src/main/java/engine/GameState.java
diff --git a/src/engine/InputManager.java b/src/main/java/engine/InputManager.java
similarity index 100%
rename from src/engine/InputManager.java
rename to src/main/java/engine/InputManager.java
diff --git a/src/engine/MinimalFormatter.java b/src/main/java/engine/MinimalFormatter.java
similarity index 100%
rename from src/engine/MinimalFormatter.java
rename to src/main/java/engine/MinimalFormatter.java
diff --git a/src/engine/Score.java b/src/main/java/engine/Score.java
similarity index 100%
rename from src/engine/Score.java
rename to src/main/java/engine/Score.java
diff --git a/src/main/java/engine/Sound.java b/src/main/java/engine/Sound.java
new file mode 100644
index 000000000..480bc352f
--- /dev/null
+++ b/src/main/java/engine/Sound.java
@@ -0,0 +1,135 @@
+package engine;
+
+//Responsible for the sounds of the game
+
+import javax.sound.sampled.*;
+import java.io.File;
+
+public class Sound
+{
+
+ private static float decibels = 0;
+
+ private static Clip musicClip;
+
+ public static void playMusic() //background music class
+ {
+ File musicfile = new File("src/main/resources/sounds/music.wav");
+ try
+ {
+ AudioInputStream Audio = AudioSystem.getAudioInputStream(musicfile);
+ Clip clip = AudioSystem.getClip();
+ clip.open(Audio);
+ setGain(clip);
+ clip.start();
+ clip.loop(Clip.LOOP_CONTINUOUSLY);
+
+ musicClip = clip;
+ }
+ catch(Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ public static void shoot() //shooting sound effect
+ {
+ File shot = new File("src/main/resources/sounds/shot.wav");
+ try
+ {
+ AudioInputStream Audio = AudioSystem.getAudioInputStream(shot);
+ Clip clip = AudioSystem.getClip();
+ clip.open(Audio);
+ setGain(clip);
+ clip.start();
+ }
+ catch(Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ public static void death() //shooting sound effect
+ {
+ File dead = new File("src/main/resources/sounds/death.wav");
+ try
+ {
+ AudioInputStream Audio = AudioSystem.getAudioInputStream(dead);
+ Clip clip = AudioSystem.getClip();
+ clip.open(Audio);
+ setGain(clip);
+ clip.start();
+ }
+ catch(Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+
+
+ public static void enemydeath() //shooting sound effect
+ {
+ File bang = new File("src/main/resources/sounds/boom.wav");
+ try
+ {
+ AudioInputStream Audio = AudioSystem.getAudioInputStream(bang);
+ Clip clip = AudioSystem.getClip();
+ clip.open(Audio);
+ setGain(clip);
+ clip.start();
+ }
+ catch(Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ public static void enemyshot() //shooting sound effect
+ {
+ File zap = new File("src/main/resources/sounds/zap.wav");
+ try
+ {
+ AudioInputStream Audio = AudioSystem.getAudioInputStream(zap);
+ Clip clip = AudioSystem.getClip();
+ clip.open(Audio);
+ setGain(clip);
+ clip.start();
+ }
+ catch(Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ public static void gameover() //shooting sound effect
+ {
+ File over = new File("src/main/resources/sounds/go.wav");
+ try
+ {
+ AudioInputStream Audio = AudioSystem.getAudioInputStream(over);
+ Clip clip = AudioSystem.getClip();
+ clip.open(Audio);
+ setGain(clip);
+ clip.start();
+ }
+ catch(Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ public static void stop() {
+ musicClip.stop();
+ }
+
+ public static void setGain(Clip clip) {
+ FloatControl gainControl = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN);
+ gainControl.setValue(-decibels); // Reduce volume by decibels
+ }
+
+ public static void setDecibels(float newDecibels) {
+ decibels = newDecibels;
+ }
+
+}
diff --git a/src/entity/Bullet.java b/src/main/java/entity/Bullet.java
similarity index 100%
rename from src/entity/Bullet.java
rename to src/main/java/entity/Bullet.java
diff --git a/src/entity/BulletPool.java b/src/main/java/entity/BulletPool.java
similarity index 98%
rename from src/entity/BulletPool.java
rename to src/main/java/entity/BulletPool.java
index ae74e5606..04abdcfbe 100644
--- a/src/entity/BulletPool.java
+++ b/src/main/java/entity/BulletPool.java
@@ -1,5 +1,7 @@
package entity;
+import engine.Sound;
+
import java.util.HashSet;
import java.util.Set;
diff --git a/src/entity/EnemyShip.java b/src/main/java/entity/EnemyShip.java
similarity index 77%
rename from src/entity/EnemyShip.java
rename to src/main/java/entity/EnemyShip.java
index 19d9958ad..862d37338 100644
--- a/src/entity/EnemyShip.java
+++ b/src/main/java/entity/EnemyShip.java
@@ -1,10 +1,12 @@
package entity;
import java.awt.Color;
+import java.util.HashMap;
import engine.Cooldown;
import engine.Core;
import engine.DrawManager.SpriteType;
+import engine.Sound;
/**
* Implements a enemy ship, to be destroyed by the player.
@@ -22,6 +24,13 @@ public class EnemyShip extends Entity {
private static final int C_TYPE_POINTS = 30;
/** Point value of a bonus enemy. */
private static final int BONUS_TYPE_POINTS = 100;
+ /** Different health values with their corresponding colors. */
+ private static final HashMap HEALTH_COLOR_CODES =
+ new HashMap(){{
+ put(1, Color.WHITE);
+ put(3, Color.YELLOW);
+ put(5, Color.BLUE);
+ }};
/** Cooldown between sprite changes. */
private Cooldown animationCooldown;
@@ -29,6 +38,8 @@ public class EnemyShip extends Entity {
private boolean isDestroyed;
/** Values of the ship, in points, when destroyed. */
private int pointValue;
+ /** Health value of the ship, when spawned */
+ private int health;
/**
* Constructor, establishes the ship's properties.
@@ -39,14 +50,17 @@ public class EnemyShip extends Entity {
* Initial position of the ship in the Y axis.
* @param spriteType
* Sprite type, image corresponding to the ship.
+ * @param health
+ * Initial health of the ship.
*/
public EnemyShip(final int positionX, final int positionY,
- final SpriteType spriteType) {
- super(positionX, positionY, 12 * 2, 8 * 2, Color.WHITE);
+ final SpriteType spriteType, final int health) {
+ super(positionX, positionY, 12 * 2, 8 * 2, HEALTH_COLOR_CODES.get(health));
this.spriteType = spriteType;
this.animationCooldown = Core.getCooldown(500);
this.isDestroyed = false;
+ this.health = health;
switch (this.spriteType) {
case EnemyShipA1:
@@ -137,10 +151,21 @@ public final void update() {
* Destroys the ship, causing an explosion.
*/
public final void destroy() {
+ Sound.enemydeath();
this.isDestroyed = true;
this.spriteType = SpriteType.Explosion;
}
+ /**
+ * Reduces the health of the ship by 1 and changes the
+ * color of the ship when a specific health was reached.
+ */
+ public final void reduceHealth() {
+ this.health--;
+ if (HEALTH_COLOR_CODES.containsKey(this.health))
+ this.setColor(HEALTH_COLOR_CODES.get(this.health));
+ }
+
/**
* Checks if the ship has been destroyed.
*
@@ -149,4 +174,13 @@ public final void destroy() {
public final boolean isDestroyed() {
return this.isDestroyed;
}
-}
+
+ /**
+ * Returns the current remaining health.
+ *
+ * @return Integer value of the health field.
+ */
+ public final int getHealth() {
+ return this.health;
+ }
+}
\ No newline at end of file
diff --git a/src/entity/EnemyShipFormation.java b/src/main/java/entity/EnemyShipFormation.java
similarity index 93%
rename from src/entity/EnemyShipFormation.java
rename to src/main/java/entity/EnemyShipFormation.java
index 04bf96326..a8954e386 100644
--- a/src/entity/EnemyShipFormation.java
+++ b/src/main/java/entity/EnemyShipFormation.java
@@ -7,12 +7,9 @@
import java.util.Set;
import java.util.logging.Logger;
+import engine.*;
import screen.Screen;
-import engine.Cooldown;
-import engine.Core;
-import engine.DrawManager;
import engine.DrawManager.SpriteType;
-import engine.GameSettings;
/**
* Groups enemy ships into a formation that moves together.
@@ -94,6 +91,14 @@ public class EnemyShipFormation implements Iterable {
private List shooters;
/** Number of not destroyed ships. */
private int shipCount;
+ /** Set health of enemy ships. */
+ private static int health;
+ /** Health of enemy ships type A. */
+ private static int A_health = 1;
+ /** Health of enemy ships type B. */
+ private static int B_health = 3;
+ /** Health of enemy ships type C. */
+ private static int C_health = 5;
/** Directions the formation can move. */
private enum Direction {
@@ -103,7 +108,7 @@ private enum Direction {
LEFT,
/** Movement to the bottom of the screen. */
DOWN
- };
+ }
/**
* Constructor, sets the initial conditions.
@@ -138,18 +143,24 @@ public EnemyShipFormation(final GameSettings gameSettings) {
for (List column : this.enemyShips) {
for (int i = 0; i < this.nShipsHigh; i++) {
- if (i / (float) this.nShipsHigh < PROPORTION_C)
+ if (i / (float) this.nShipsHigh < PROPORTION_C) {
spriteType = SpriteType.EnemyShipC1;
+ health = C_health;
+ }
else if (i / (float) this.nShipsHigh < PROPORTION_B
- + PROPORTION_C)
+ + PROPORTION_C) {
spriteType = SpriteType.EnemyShipB1;
- else
+ health = B_health;
+ }
+ else {
spriteType = SpriteType.EnemyShipA1;
+ health = A_health;
+ }
column.add(new EnemyShip((SEPARATION_DISTANCE
* this.enemyShips.indexOf(column))
+ positionX, (SEPARATION_DISTANCE * i)
- + positionY, spriteType));
+ + positionY, spriteType, health));
this.shipCount++;
}
}
@@ -336,6 +347,7 @@ public final void shoot(final Set bullets) {
EnemyShip shooter = this.shooters.get(index);
if (this.shootingCooldown.checkFinished()) {
+ Sound.enemyshot();
this.shootingCooldown.reset();
bullets.add(BulletPool.getBullet(shooter.getPositionX()
+ shooter.width / 2, shooter.getPositionY(), BULLET_SPEED));
@@ -426,4 +438,25 @@ public final Iterator iterator() {
public final boolean isEmpty() {
return this.shipCount <= 0;
}
+
+ /**
+ * Set health for enemy ships type A.
+ */
+ public static void setA_Health(int newHealth) {
+ A_health = newHealth;
+ }
+
+ /**
+ * Set health for enemy ships type A.
+ */
+ public static void setB_Health(int newHealth) {
+ B_health = newHealth;
+ }
+
+ /**
+ * Set health for enemy ships type A.
+ */
+ public static void setC_Health(int newHealth) {
+ C_health = newHealth;
+ }
}
diff --git a/src/entity/Entity.java b/src/main/java/entity/Entity.java
similarity index 94%
rename from src/entity/Entity.java
rename to src/main/java/entity/Entity.java
index 9fe604fdf..7183cd1ba 100644
--- a/src/entity/Entity.java
+++ b/src/main/java/entity/Entity.java
@@ -57,6 +57,14 @@ public final Color getColor() {
return color;
}
+ /**
+ * Setter for the color of the entity.
+ *
+ * @param color
+ * New color of the entity.
+ */
+ public final void setColor(Color color) { this.color = color; }
+
/**
* Getter for the X axis position of the entity.
*
diff --git a/src/entity/Ship.java b/src/main/java/entity/Ship.java
similarity index 96%
rename from src/entity/Ship.java
rename to src/main/java/entity/Ship.java
index fd007fde1..0f62b2ec6 100644
--- a/src/entity/Ship.java
+++ b/src/main/java/entity/Ship.java
@@ -6,6 +6,8 @@
import engine.Cooldown;
import engine.Core;
import engine.DrawManager.SpriteType;
+import engine.Sound;
+import screen.Shakeframe;
/**
* Implements a ship, to be controlled by the player.
@@ -68,6 +70,7 @@ public final void moveLeft() {
*/
public final boolean shoot(final Set bullets) {
if (this.shootingCooldown.checkFinished()) {
+ Sound.shoot();
this.shootingCooldown.reset();
bullets.add(BulletPool.getBullet(positionX + this.width / 2,
positionY, BULLET_SPEED));
@@ -91,6 +94,9 @@ public final void update() {
*/
public final void destroy() {
this.destructionCooldown.reset();
+
+ Sound.death();
+ Shakeframe.vibrate();
}
/**
diff --git a/src/screen/GameScreen.java b/src/main/java/screen/GameScreen.java
similarity index 72%
rename from src/screen/GameScreen.java
rename to src/main/java/screen/GameScreen.java
index 4e76259d0..9b0589863 100644
--- a/src/screen/GameScreen.java
+++ b/src/main/java/screen/GameScreen.java
@@ -71,6 +71,10 @@ public class GameScreen extends Screen {
/** Checks if a bonus life is received. */
private boolean bonusLife;
+ boolean paused = false;
+ private static final int SELECTION_TIME = 200;
+ private Cooldown selectionCooldown;
+
/**
* Constructor, establishes the properties of the screen.
*
@@ -78,7 +82,7 @@ public class GameScreen extends Screen {
* Current game state.
* @param gameSettings
* Current game settings.
- * @param bonnusLife
+ * @param bonusLife
* Checks if a bonus life is awarded this level.
* @param width
* Screen width.
@@ -101,6 +105,9 @@ public GameScreen(final GameState gameState,
this.lives++;
this.bulletsShot = gameState.getBulletsShot();
this.shipsDestroyed = gameState.getShipsDestroyed();
+
+ this.selectionCooldown = Core.getCooldown(SELECTION_TIME);
+ this.selectionCooldown.reset();
}
/**
@@ -125,6 +132,10 @@ public final void initialize() {
this.gameStartTime = System.currentTimeMillis();
this.inputDelay = Core.getCooldown(INPUT_DELAY);
this.inputDelay.reset();
+
+ this.gameStartTime = System.currentTimeMillis();
+ this.inputDelay = Core.getCooldown(INPUT_DELAY);
+ this.inputDelay.reset();
}
/**
@@ -141,73 +152,100 @@ public final int run() {
return this.returnCode;
}
+ public final boolean isPaused() {
+ return this.paused;
+ }
+
+ public final void pause() {
+ this.paused = !paused;
+ }
/**
* Updates the elements on screen and checks for events.
*/
protected final void update() {
super.update();
- if (this.inputDelay.checkFinished() && !this.levelFinished) {
+ if (this.selectionCooldown.checkFinished() && this.inputDelay.checkFinished()) {
+ if (inputManager.isKeyDown(KeyEvent.VK_P) && this.isPaused()) {
+ pause();
+ this.logger.info("Game unpaused");
+ this.selectionCooldown.reset();
+ } else if (inputManager.isKeyDown(KeyEvent.VK_P)) {
+ pause();
+ this.logger.info("Game paused");
+ this.selectionCooldown.reset();
+
+ drawManager.drawPaused(this);
+ drawManager.drawHorizontalLine(this, this.height / 2 - this.height / 12);
+ drawManager.drawHorizontalLine(this, this.height / 2 + this.height / 12);
+ drawManager.completeDrawing(this);
+ }
+ }
- if (!this.ship.isDestroyed()) {
- boolean moveRight = inputManager.isKeyDown(KeyEvent.VK_RIGHT)
- || inputManager.isKeyDown(KeyEvent.VK_D);
- boolean moveLeft = inputManager.isKeyDown(KeyEvent.VK_LEFT)
- || inputManager.isKeyDown(KeyEvent.VK_A);
+ if(!this.isPaused())
+ {
+ if (this.inputDelay.checkFinished() && !this.levelFinished) {
- boolean isRightBorder = this.ship.getPositionX()
- + this.ship.getWidth() + this.ship.getSpeed() > this.width - 1;
- boolean isLeftBorder = this.ship.getPositionX()
- - this.ship.getSpeed() < 1;
+ if (!this.ship.isDestroyed()) {
+ boolean moveRight = inputManager.isKeyDown(KeyEvent.VK_RIGHT)
+ || inputManager.isKeyDown(KeyEvent.VK_D);
+ boolean moveLeft = inputManager.isKeyDown(KeyEvent.VK_LEFT)
+ || inputManager.isKeyDown(KeyEvent.VK_A);
- if (moveRight && !isRightBorder) {
- this.ship.moveRight();
- }
- if (moveLeft && !isLeftBorder) {
- this.ship.moveLeft();
+ boolean isRightBorder = this.ship.getPositionX()
+ + this.ship.getWidth() + this.ship.getSpeed() > this.width - 1;
+ boolean isLeftBorder = this.ship.getPositionX()
+ - this.ship.getSpeed() < 1;
+
+ if (moveRight && !isRightBorder) {
+ this.ship.moveRight();
+ }
+ if (moveLeft && !isLeftBorder) {
+ this.ship.moveLeft();
+ }
+ if (inputManager.isKeyDown(KeyEvent.VK_SPACE))
+ if (this.ship.shoot(this.bullets))
+ this.bulletsShot++;
}
- if (inputManager.isKeyDown(KeyEvent.VK_SPACE))
- if (this.ship.shoot(this.bullets))
- this.bulletsShot++;
- }
- if (this.enemyShipSpecial != null) {
- if (!this.enemyShipSpecial.isDestroyed())
- this.enemyShipSpecial.move(2, 0);
- else if (this.enemyShipSpecialExplosionCooldown.checkFinished())
- this.enemyShipSpecial = null;
+ if (this.enemyShipSpecial != null) {
+ if (!this.enemyShipSpecial.isDestroyed())
+ this.enemyShipSpecial.move(2, 0);
- }
- if (this.enemyShipSpecial == null
- && this.enemyShipSpecialCooldown.checkFinished()) {
- this.enemyShipSpecial = new EnemyShip();
- this.enemyShipSpecialCooldown.reset();
- this.logger.info("A special ship appears");
- }
- if (this.enemyShipSpecial != null
- && this.enemyShipSpecial.getPositionX() > this.width) {
- this.enemyShipSpecial = null;
- this.logger.info("The special ship has escaped");
- }
+ else if (this.enemyShipSpecialExplosionCooldown.checkFinished())
+ this.enemyShipSpecial = null;
- this.ship.update();
- this.enemyShipFormation.update();
- this.enemyShipFormation.shoot(this.bullets);
- }
+ }
+ if (this.enemyShipSpecial == null
+ && this.enemyShipSpecialCooldown.checkFinished()) {
+ this.enemyShipSpecial = new EnemyShip();
+ this.enemyShipSpecialCooldown.reset();
+ this.logger.info("A special ship appears");
+ }
+ if (this.enemyShipSpecial != null
+ && this.enemyShipSpecial.getPositionX() > this.width) {
+ this.enemyShipSpecial = null;
+ this.logger.info("The special ship has escaped");
+ }
- manageCollisions();
- cleanBullets();
- draw();
+ this.ship.update();
+ this.enemyShipFormation.update();
+ this.enemyShipFormation.shoot(this.bullets);
+ }
- if ((this.enemyShipFormation.isEmpty() || this.lives == 0)
- && !this.levelFinished) {
- this.levelFinished = true;
- this.screenFinishedCooldown.reset();
- }
+ manageCollisions();
+ cleanBullets();
+ draw();
- if (this.levelFinished && this.screenFinishedCooldown.checkFinished())
- this.isRunning = false;
+ if ((this.enemyShipFormation.isEmpty() || this.lives == 0)
+ && !this.levelFinished) {
+ this.levelFinished = true;
+ this.screenFinishedCooldown.reset();
+ }
+ if (this.levelFinished && this.screenFinishedCooldown.checkFinished())
+ this.isRunning = false;
+ }//pause
}
/**
@@ -285,9 +323,12 @@ private void manageCollisions() {
for (EnemyShip enemyShip : this.enemyShipFormation)
if (!enemyShip.isDestroyed()
&& checkCollision(bullet, enemyShip)) {
- this.score += enemyShip.getPointValue();
- this.shipsDestroyed++;
- this.enemyShipFormation.destroy(enemyShip);
+ enemyShip.reduceHealth();
+ if (enemyShip.getHealth() == 0) {
+ this.score += enemyShip.getPointValue();
+ this.shipsDestroyed++;
+ this.enemyShipFormation.destroy(enemyShip);
+ }
recyclable.add(bullet);
}
if (this.enemyShipSpecial != null
diff --git a/src/main/java/screen/HelpScreen.java b/src/main/java/screen/HelpScreen.java
new file mode 100644
index 000000000..e78c66bac
--- /dev/null
+++ b/src/main/java/screen/HelpScreen.java
@@ -0,0 +1,64 @@
+package screen;
+
+import java.awt.event.KeyEvent;
+import java.io.IOException;
+import java.util.List;
+
+import engine.Core;
+import engine.Score;
+
+/**
+ * Implements the help screen, it shows the player instructions on how to play the game.
+ */
+
+public class HelpScreen extends Screen {
+ /**
+ * Constructor, establishes the properties of the screen.
+ *
+ * @param width
+ * Screen width.
+ * @param height
+ * Screen height.
+ * @param fps
+ * Frames per second, frame rate at which the game is run.
+ */
+ public HelpScreen(final int width, final int height, final int fps) {
+ super(width, height, fps);
+
+ this.returnCode = 1;
+ }
+
+ /**
+ * Starts the action.
+ *
+ * @return Next screen code.
+ */
+ public final int run() {
+ super.run();
+
+ return this.returnCode;
+ }
+
+ /**
+ * Updates the elements on screen and checks for events.
+ */
+ protected final void update() {
+ super.update();
+
+ draw();
+ if (inputManager.isKeyDown(KeyEvent.VK_SPACE)
+ && this.inputDelay.checkFinished())
+ this.isRunning = false;
+ }
+
+ /**
+ * Draws the elements associated with the screen.
+ */
+ private void draw() {
+ drawManager.initDrawing(this);
+
+ drawManager.drawHelp(this);
+
+ drawManager.completeDrawing(this);
+ }
+}
\ No newline at end of file
diff --git a/src/screen/HighScoreScreen.java b/src/main/java/screen/HighScoreScreen.java
similarity index 100%
rename from src/screen/HighScoreScreen.java
rename to src/main/java/screen/HighScoreScreen.java
diff --git a/src/screen/ScoreScreen.java b/src/main/java/screen/ScoreScreen.java
similarity index 98%
rename from src/screen/ScoreScreen.java
rename to src/main/java/screen/ScoreScreen.java
index ff215715d..6ec2ee833 100644
--- a/src/screen/ScoreScreen.java
+++ b/src/main/java/screen/ScoreScreen.java
@@ -5,10 +5,7 @@
import java.util.Collections;
import java.util.List;
-import engine.Cooldown;
-import engine.Core;
-import engine.GameState;
-import engine.Score;
+import engine.*;
/**
* Implements the score screen.
@@ -61,7 +58,7 @@ public class ScoreScreen extends Screen {
public ScoreScreen(final int width, final int height, final int fps,
final GameState gameState) {
super(width, height, fps);
-
+ Sound.gameover();
this.score = gameState.getScore();
this.livesRemaining = gameState.getLivesRemaining();
this.bulletsShot = gameState.getBulletsShot();
diff --git a/src/screen/Screen.java b/src/main/java/screen/Screen.java
similarity index 100%
rename from src/screen/Screen.java
rename to src/main/java/screen/Screen.java
diff --git a/src/main/java/screen/SettingsScreen.java b/src/main/java/screen/SettingsScreen.java
new file mode 100644
index 000000000..1d3015499
--- /dev/null
+++ b/src/main/java/screen/SettingsScreen.java
@@ -0,0 +1,243 @@
+package screen;
+
+import java.awt.*;
+import java.awt.event.KeyEvent;
+import engine.Cooldown;
+import engine.Core;
+import engine.Sound;
+import entity.EnemyShipFormation;
+
+import javax.sound.sampled.Clip;
+
+/**
+ * Implements the Settings screen, it shows the options to change the settings of the game.
+ */
+
+public class SettingsScreen extends Screen {
+ /** Number of options in the settings menu. */
+ private static final int NO_OF_OPTIONS = 3;
+ /** Current settings option. */
+ private static int settingsOption;
+ /** Change settings. */
+ private static int change;
+ /** Milliseconds between changes in user selection. */
+ private static final int SELECTION_TIME = 200;
+ /** Time between changes in user selection. */
+ private Cooldown selectionCooldown;
+ /** Get screen size using the Toolkit class */
+ Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
+
+ /**
+ * Constructor, establishes the properties of the screen.
+ *
+ * @param width
+ * Screen width.
+ * @param height
+ * Screen height.
+ * @param fps
+ * Frames per second, frame rate at which the game is run.
+ */
+ public SettingsScreen(final int width, final int height, final int fps) {
+ super(width, height, fps);
+
+ this.returnCode = 1;
+ this.settingsOption = 1;
+ this.change = 1;
+
+ this.selectionCooldown = Core.getCooldown(SELECTION_TIME);
+ this.selectionCooldown.reset();
+ }
+
+ /**
+ * Starts the action.
+ *
+ * @return Next screen code.
+ */
+ public final int run() {
+ super.run();
+
+ return this.returnCode;
+ }
+
+ /**
+ * Updates the elements on screen and checks for events.
+ */
+ protected final void update() {
+ super.update();
+
+ draw();
+
+ if (this.selectionCooldown.checkFinished()
+ && this.inputDelay.checkFinished()) {
+ if (inputManager.isKeyDown(KeyEvent.VK_UP)
+ || inputManager.isKeyDown(KeyEvent.VK_W)) {
+ previousMenuItem();
+ this.change = 1;
+ this.selectionCooldown.reset();
+ }
+ if (inputManager.isKeyDown(KeyEvent.VK_DOWN)
+ || inputManager.isKeyDown(KeyEvent.VK_S)) {
+ nextMenuItem();
+ this.change = 1;
+ this.selectionCooldown.reset();
+ }
+ if (inputManager.isKeyDown(KeyEvent.VK_LEFT)
+ || inputManager.isKeyDown(KeyEvent.VK_A)) {
+ previousMenuChange();
+ this.selectionCooldown.reset();
+ }
+ if (inputManager.isKeyDown(KeyEvent.VK_RIGHT)
+ || inputManager.isKeyDown(KeyEvent.VK_D)) {
+ nextMenuChange();
+ this.selectionCooldown.reset();
+ }
+ if (inputManager.isKeyDown(KeyEvent.VK_SPACE)) {
+ Sound.stop();
+ Sound.playMusic();
+ this.isRunning = false;
+ }
+
+ // Change screen size
+ if (this.settingsOption == 1) {
+ changeScreenSize();
+ }
+
+ // Change difficulty
+ if (this.settingsOption == 2) {
+ changeDifficulty();
+ }
+
+ // Adjust volume
+ if (this.settingsOption == 3) {
+ adjustVolume();
+ }
+ }
+ }
+
+ /**
+ * Change difficulty level
+ */
+ private void changeDifficulty() {
+ if (this.change == 1) { // Easy
+ EnemyShipFormation.setA_Health(1);
+ EnemyShipFormation.setB_Health(1);
+ EnemyShipFormation.setC_Health(1);
+ }
+
+ if (this.change == 2) { // Medium
+ EnemyShipFormation.setA_Health(1);
+ EnemyShipFormation.setB_Health(3);
+ EnemyShipFormation.setC_Health(5);
+ }
+
+ if (this.change == 3) { // Hard
+ EnemyShipFormation.setA_Health(5);
+ EnemyShipFormation.setB_Health(5);
+ EnemyShipFormation.setC_Health(5);
+ }
+
+ }
+
+ /**
+ * Adjust volume
+ */
+ private void adjustVolume() {
+ if (this.change == 1) // 25% volume
+ Sound.setDecibels(40);
+ if (this.change == 2) // 50% volume
+ Sound.setDecibels(35);
+ if (this.change == 3) // 75% volume
+ Sound.setDecibels(30);
+ if (this.change == 4) // 100% volume
+ Sound.setDecibels(0);
+ if (this.change == 5) // Mute
+ Sound.setDecibels(100);
+ }
+
+ /**
+ * Changes the screen size
+ */
+ private void changeScreenSize() {
+ if (this.change == 1) // Standard
+ Core.setSize(448, 520);
+ else if (this.change == 2) // Extended
+ Core.setSize(1020,520);
+ else if (this.change == 3) // Full Screen
+ Core.setSize(screenSize.width, screenSize.height);
+ }
+
+ /**
+ * Shifts the focus to the next menu item.
+ */
+ private void nextMenuItem() {
+ if (this.settingsOption == NO_OF_OPTIONS)
+ this.settingsOption = 1;
+ else if (this.settingsOption == 1)
+ this.settingsOption = 2;
+ else
+ this.settingsOption++;
+ }
+
+ /**
+ * Shifts the focus to the previous menu item.
+ */
+ private void previousMenuItem() {
+ if (this.settingsOption == 1)
+ this.settingsOption = NO_OF_OPTIONS;
+ else if (this.settingsOption == 2)
+ this.settingsOption = 1;
+ else
+ this.settingsOption--;
+ }
+
+ /**
+ * Shifts the focus to the next change in the settings option.
+ */
+ private void nextMenuChange() {
+ int no_of_changes = 3;
+
+ if(this.settingsOption == 3)
+ no_of_changes = 5;
+
+ if (this.change == no_of_changes)
+ this.change = 1;
+ else if (this.change == 1)
+ this.change = 2;
+ else
+ this.change++;
+ }
+
+ /**
+ * Shifts the focus to the previous change in the settings option.
+ */
+ private void previousMenuChange() {
+ int no_of_changes;
+
+ if(this.settingsOption == 3)
+ no_of_changes = 5;
+ else
+ no_of_changes = 3;
+
+ if (this.change == 1)
+ this.change = no_of_changes;
+ else if (this.change == 2)
+ this.change = 1;
+ else
+ this.change--;
+ }
+
+ /**
+ * Draws the elements associated with the screen.
+ */
+ private void draw() {
+ drawManager.initDrawing(this);
+ drawManager.drawSettings(this);
+ drawManager.drawSettingsChange(this, settingsOption, change);
+ drawManager.drawSettingsOptions(this, settingsOption);
+ drawManager.completeDrawing(this);
+ }
+
+ public static int getChange() {
+ return change;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/screen/Shakeframe.java b/src/main/java/screen/Shakeframe.java
new file mode 100644
index 000000000..7c994e007
--- /dev/null
+++ b/src/main/java/screen/Shakeframe.java
@@ -0,0 +1,41 @@
+package screen;
+
+import static engine.Core.frame;
+
+public class Shakeframe extends Screen {
+
+ private final static int VIB_LENGTH = 20;
+ private final static int VIB_VEL = 5;
+
+ /**
+ * Constructor, establishes the properties of the screen.
+ *
+ * @param width Screen width.
+ * @param height Screen height.
+ * @param fps
+ */
+ public Shakeframe(int width, int height, int fps) {
+ super(width, height, fps);
+ }
+
+
+ public static void vibrate() {
+ try {
+ final int originalX = frame.getLocationOnScreen().x;
+ final int originalY = frame.getLocationOnScreen().y;
+ for(int i = 0; i < VIB_LENGTH; i++) {
+ Thread.sleep(10);
+ frame.setLocation(originalX, originalY + VIB_VEL);
+ Thread.sleep(10);
+ frame.setLocation(originalX, originalY - VIB_VEL);
+ Thread.sleep(10);
+ frame.setLocation(originalX + VIB_VEL, originalY);
+ Thread.sleep(10);
+ frame.setLocation(originalX, originalY);
+ }
+ }
+ catch (Exception err) {
+ err.printStackTrace();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/screen/TitleScreen.java b/src/main/java/screen/TitleScreen.java
similarity index 96%
rename from src/screen/TitleScreen.java
rename to src/main/java/screen/TitleScreen.java
index a8229b463..43e0c7aef 100644
--- a/src/screen/TitleScreen.java
+++ b/src/main/java/screen/TitleScreen.java
@@ -1,6 +1,7 @@
package screen;
import java.awt.event.KeyEvent;
+import engine.Sound;
import engine.Cooldown;
import engine.Core;
@@ -77,7 +78,7 @@ protected final void update() {
* Shifts the focus to the next menu item.
*/
private void nextMenuItem() {
- if (this.returnCode == 3)
+ if (this.returnCode == 5)
this.returnCode = 0;
else if (this.returnCode == 0)
this.returnCode = 2;
@@ -90,7 +91,7 @@ else if (this.returnCode == 0)
*/
private void previousMenuItem() {
if (this.returnCode == 0)
- this.returnCode = 3;
+ this.returnCode = 5;
else if (this.returnCode == 2)
this.returnCode = 0;
else
@@ -108,4 +109,5 @@ private void draw() {
drawManager.completeDrawing(this);
}
+
}
diff --git a/src/main/resources/font.ttf b/src/main/resources/font.ttf
new file mode 100644
index 000000000..4730e4458
Binary files /dev/null and b/src/main/resources/font.ttf differ
diff --git a/res/graphics b/src/main/resources/graphics
similarity index 100%
rename from res/graphics
rename to src/main/resources/graphics
diff --git a/res/scores b/src/main/resources/scores
similarity index 100%
rename from res/scores
rename to src/main/resources/scores
diff --git a/src/main/resources/sounds/boom.wav b/src/main/resources/sounds/boom.wav
new file mode 100644
index 000000000..a7ebe875f
Binary files /dev/null and b/src/main/resources/sounds/boom.wav differ
diff --git a/src/main/resources/sounds/death.wav b/src/main/resources/sounds/death.wav
new file mode 100644
index 000000000..a9959c595
Binary files /dev/null and b/src/main/resources/sounds/death.wav differ
diff --git a/src/main/resources/sounds/go.wav b/src/main/resources/sounds/go.wav
new file mode 100644
index 000000000..3ed6a9d48
Binary files /dev/null and b/src/main/resources/sounds/go.wav differ
diff --git a/src/main/resources/sounds/music.wav b/src/main/resources/sounds/music.wav
new file mode 100644
index 000000000..54f1819b9
Binary files /dev/null and b/src/main/resources/sounds/music.wav differ
diff --git a/src/main/resources/sounds/shot.wav b/src/main/resources/sounds/shot.wav
new file mode 100644
index 000000000..1d9d9c3de
Binary files /dev/null and b/src/main/resources/sounds/shot.wav differ
diff --git a/src/main/resources/sounds/zap.wav b/src/main/resources/sounds/zap.wav
new file mode 100644
index 000000000..64db3f0d0
Binary files /dev/null and b/src/main/resources/sounds/zap.wav differ
diff --git a/src/test/java/entity/EnemyShipTest.java b/src/test/java/entity/EnemyShipTest.java
new file mode 100644
index 000000000..6ef8cf05c
--- /dev/null
+++ b/src/test/java/entity/EnemyShipTest.java
@@ -0,0 +1,40 @@
+package entity;
+
+import engine.DrawManager.SpriteType;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.awt.*;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class EnemyShipTest {
+
+ EnemyShip testShip;
+
+ @BeforeEach
+ void setUp() {
+ // positionX, positionY and spriteType are just placeholders
+ // they are not necessary for our tests
+ testShip = new EnemyShip(0, 0, SpriteType.EnemyShipA1, 5);
+ }
+
+ @Test
+ void getHealth() {
+ assertEquals(5, testShip.getHealth());
+ }
+
+ @Test
+ void reduceHealthWithoutColorChange() {
+ testShip.reduceHealth();
+ assertEquals(4, testShip.getHealth());
+ }
+
+ @Test
+ void reduceHealthWithColorChange() {
+ testShip.reduceHealth();
+ testShip.reduceHealth();
+ assertEquals(3, testShip.getHealth());
+ assertEquals(Color.YELLOW, testShip.getColor());
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/entity/EntityTest.java b/src/test/java/entity/EntityTest.java
new file mode 100644
index 000000000..614cf5556
--- /dev/null
+++ b/src/test/java/entity/EntityTest.java
@@ -0,0 +1,31 @@
+package entity;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.awt.*;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class EntityTest {
+
+ Entity testEntity;
+
+ @BeforeEach
+ void setUp() {
+ // positionX, positionY, width and height are just placeholders
+ // they are not necessary for our tests
+ testEntity = new Entity(0,0,0,0, Color.WHITE);
+ }
+
+ @Test
+ void getColor() {
+ assertEquals(Color.WHITE, testEntity.getColor());
+ }
+
+ @Test
+ void setColor() {
+ testEntity.setColor(Color.GREEN);
+ assertEquals(Color.GREEN, testEntity.getColor());
+ }
+}
\ No newline at end of file
diff --git a/target/classes/graphics b/target/classes/graphics
new file mode 100644
index 000000000..ea318b6a5
--- /dev/null
+++ b/target/classes/graphics
@@ -0,0 +1,12 @@
+00001111000111110001111100011111000111110111111111111111011111110001111100011111000111110001111100001111
+00000100000000010001001100000011000001111011001100001111001011110000001100101111010010010000010000000011
+100001111110000
+000011111100001
+001110010111100101111010011011101110110011111010111110101110110001101110011110100111100100111001
+001110000111101001111111011011011110110011111010111110101110110001101101011111110111101000111000
+000000000000111000011000101111100110110100111101001111000011110101101101101111100001100000001110
+000000000111100000011101101111100110110000111100001111000011110001101100101111100001110101111000
+000000000000000000011010001111010110100011111100111111000110100000111101000110100000000000000000
+000000000000000000011001001110100110110111111010111110100110110100111010000110010000000000000000
+0000100000110000111100110111011111011111001110100111111011111101110100111110001111100110111001111000011000000100
+0001000100100101000100010100100000101000100000000010001010000010010100010001010010010001000
\ No newline at end of file
diff --git a/target/classes/scores b/target/classes/scores
new file mode 100644
index 000000000..a4cc05c7a
--- /dev/null
+++ b/target/classes/scores
@@ -0,0 +1,8 @@
+ROB
+6500
+PAT
+6000
+KOF
+5500
+BYR
+5000
\ No newline at end of file
diff --git a/target/classes/sounds/boom.wav b/target/classes/sounds/boom.wav
new file mode 100644
index 000000000..a7ebe875f
Binary files /dev/null and b/target/classes/sounds/boom.wav differ
diff --git a/target/classes/sounds/death.wav b/target/classes/sounds/death.wav
new file mode 100644
index 000000000..a9959c595
Binary files /dev/null and b/target/classes/sounds/death.wav differ
diff --git a/target/classes/sounds/go.wav b/target/classes/sounds/go.wav
new file mode 100644
index 000000000..3ed6a9d48
Binary files /dev/null and b/target/classes/sounds/go.wav differ
diff --git a/target/classes/sounds/music.wav b/target/classes/sounds/music.wav
new file mode 100644
index 000000000..54f1819b9
Binary files /dev/null and b/target/classes/sounds/music.wav differ
diff --git a/target/classes/sounds/shot.wav b/target/classes/sounds/shot.wav
new file mode 100644
index 000000000..1d9d9c3de
Binary files /dev/null and b/target/classes/sounds/shot.wav differ
diff --git a/target/classes/sounds/zap.wav b/target/classes/sounds/zap.wav
new file mode 100644
index 000000000..64db3f0d0
Binary files /dev/null and b/target/classes/sounds/zap.wav differ