Implemented boss and tweaked spawning mechanism and scale factors

master
Jamie Munro 2 years ago
parent d96ce52696
commit c72f1df021
  1. 4
      Asteroid0.pde
  2. 6
      Asteroid1.pde
  3. 6
      Asteroid2.pde
  4. 216
      Boss.pde
  5. 12
      Configuration.pde
  6. 240
      Game.pde
  7. 11
      GunPlatform.pde
  8. 6
      Jellyfish.pde
  9. 2
      Player.pde
  10. 24
      Projectile.pde
  11. 6
      README.md
  12. 9
      Saucer.pde
  13. 28
      config.properties
  14. BIN
      res/sprites/boss0.png
  15. BIN
      res/sprites/boss1.png
  16. BIN
      res/sprites/bossProjectile.png
  17. BIN
      res/sprites/gunPlatformProjectile.png
  18. BIN
      res/sprites/saucerProjectile.png
  19. BIN
      res/tiles/10.png
  20. BIN
      res/tiles/11.png
  21. BIN
      res/tiles/12.png
  22. BIN
      res/tiles/13.png
  23. BIN
      res/tiles/14.png
  24. BIN
      res/tiles/15.png
  25. BIN
      res/tiles/16.png
  26. BIN
      res/tiles/17.png
  27. BIN
      res/tiles/18.png
  28. BIN
      res/tiles/19.png
  29. BIN
      res/tiles/20.png
  30. BIN
      res/tiles/21.png
  31. BIN
      res/tiles/22.png
  32. BIN
      res/tiles/23.png
  33. BIN
      res/tiles/24.png
  34. BIN
      res/tiles/3.png
  35. BIN
      res/tiles/4.png
  36. BIN
      res/tiles/5.png
  37. BIN
      res/tiles/6.png
  38. BIN
      res/tiles/7.png
  39. BIN
      res/tiles/8.png
  40. BIN
      res/tiles/9.png

@ -8,9 +8,9 @@ public class Asteroid0 implements Enemy {
public static final int MINIMUM_DIFFICULTY = 0;
public static final int SCORE = 50;
public static final int INITIAL_HIT_POINTS = 1;
public static final int SCALE_FACTOR = 10;
public static final int SCALE_FACTOR = 15;
public static final int CHANCE_OF_SPAWNING = 100;
public static final int MAX_SPEED = 5;
public static final int MAX_SPEED = 4;
private final PImage sprite;
private final int tintR;

@ -5,12 +5,12 @@
*/
public class Asteroid1 extends Asteroid0 {
public static final int SCALE_FACTOR = 20;
public static final int SCALE_FACTOR = 30;
public static final int ENEMIES_TO_SPAWN = 3;
public static final int MINIMUM_DIFFICULTY = 1;
public static final int SCORE = 100;
public static final int CHANCE_OF_SPAWNING = 25;
public static final int MAX_SPEED = 4;
public static final int CHANCE_OF_SPAWNING = 75;
public static final int MAX_SPEED = 3;
public Asteroid1(int x, int y, PImage sprite, Level level) {
super(x, y, sprite, level);

@ -5,12 +5,12 @@
*/
public class Asteroid2 extends Asteroid0 {
public static final int SCALE_FACTOR = 40;
public static final int SCALE_FACTOR = 100;
public static final int ENEMIES_TO_SPAWN = 3;
public static final int MINIMUM_DIFFICULTY = 2;
public static final int SCORE = 200;
public static final int CHANCE_OF_SPAWNING = 10;
public static final int MAX_SPEED = 3;
public static final int CHANCE_OF_SPAWNING = 70;
public static final int MAX_SPEED = 2;
public Asteroid2(int x, int y, PImage sprite, Level level) {
super(x, y, sprite, level);

@ -0,0 +1,216 @@
/**
* Copyright 2022 Jamie Munro, All rights reserved
* CS5041 P1
* Game 1
*/
public class Boss implements Enemy {
public static final int MINIMUM_DIFFICULTY = 6;
public static final int SCORE = 5000;
public static final int INITIAL_HIT_POINTS = 3;
public static final int SCALE_FACTOR = 50;
public static final int CHANCE_OF_SPAWNING = 2;
public static final int MAX_SPEED = 1;
public static final int ROTATION_SPEED = 3;
public static final int ANIMATION_INTERVAL = 1000;
private static final int MAX_SPRITE_INDEX = 1;
public static final int RELOAD_TIME = 3000;
public static final int PROJECTILE_SPEED = 3;
public static final int PROJECTILE_DAMAGE = 1;
public static final int PROJECTILE_RANGE = 200;
private final PImage[] sprites;
private int spriteIndex;
private final int tintR;
private final int tintG;
private final int tintB;
private final Level level;
private final Player player;
private int x;
private int y;
private int rotation;
private float speed;
private int hitPoints;
//animation variables
private long lastChange;
private boolean up;
//shot variables
private Projectile projectile;
private PImage projectileSprite;
private long lastShot;
public Boss(int x, int y, PImage[] sprites, PImage projectileSprite, Level level, Player player) {
this.x = x;
this.y = y;
this.rotation = int(random(0,360));
this.level = level;
this.player = player;
this.hitPoints = INITIAL_HIT_POINTS;
this.sprites = sprites;
this.tintR = int(random(0, 256));
this.tintG = int(random(0, 256));
this.tintB = int(random(0, 256));
this.speed = MAX_SPEED;
lastChange = millis();
up = true;
this.projectileSprite = projectileSprite;
lastShot = millis();
this.spriteIndex = 0;
}
@Override
public int getX() {
return this.x;
}
@Override
public int getY(){
return this.y;
}
@Override
public int getRotation(){
return this.rotation;
}
@Override
public PImage getSprite(){
return this.sprites[spriteIndex];
}
@Override
public int getScaleFactor() {
return SCALE_FACTOR;
}
@Override
public int getTintR() {
return this.tintR;
}
@Override
public int getTintG() {
return this.tintG;
}
@Override
public int getTintB() {
return this.tintB;
}
@Override
public int getMinimumDifficulty() {
return MINIMUM_DIFFICULTY;
}
@Override
public int getInitialHitPoints() {
return INITIAL_HIT_POINTS;
}
@Override
public int getHitPoints(){
return this.hitPoints;
}
@Override
public int getScore() {
return SCORE;
}
@Override
public int getChanceOfSpawning() {
return CHANCE_OF_SPAWNING;
}
@Override
public void update(){
//animate
long currentTime = millis();
if (currentTime - this.lastChange > ANIMATION_INTERVAL) {
this.lastChange = currentTime;
if (this.up) {
spriteIndex++;
if (spriteIndex == MAX_SPRITE_INDEX) up = false;
}
else {
spriteIndex--;
if (spriteIndex == 0) up = true;
}
}
//calculate bearing to player
double theta = Math.atan2(player.getX() - this.x, player.getY() - this.y);
if (theta < 0) theta += 2 * PI;
int degreesToPlayer = int(degrees((float) theta));
int desiredRotation = 180 - degreesToPlayer;
while (desiredRotation < 0) desiredRotation += 360;
if (Math.abs(this.rotation - desiredRotation) > ROTATION_SPEED) {
if (desiredRotation > this.rotation) this.rotation += ROTATION_SPEED;
else if (desiredRotation < this.rotation) this.rotation -= ROTATION_SPEED;
}
int newX = this.getX() + Math.round(this.speed * sin(radians(this.getRotation())));
int newY = this.getY() + Math.round(this.speed * -cos(radians(this.getRotation())));
//bounce off boundaries: https://forum.processing.org/two/discussion/10649/maths-calculate-reflection-angle.html
if ((newX <= 0) || (newX >= level.getCols()-1)) {
//verticle wall
this.rotation = 360 - rotation;
while (this.rotation < 0) this.rotation += 360;
}
else if ((newY <= 0) || (newY >= level.getRows()-1)){
//horizontal wall
this.rotation = 180 - rotation;
while (this.rotation < 0) this.rotation += 360;
}
else {
this.x = newX;
this.y = newY;
}
//shoot
if (currentTime - this.lastShot > RELOAD_TIME) {
lastShot = currentTime;
this.projectile = new Projectile(this.x, this.y, this.rotation, this.projectileSprite, PROJECTILE_SPEED, PROJECTILE_DAMAGE, PROJECTILE_RANGE);
}
else {
this.projectile = null;
}
}
@Override
public boolean hit() {
this.hitPoints--;
if (this.hitPoints <= 0) return true;
return false;
}
@Override
public List<Enemy> spawnlings() {
return null;
}
@Override
public Projectile projectile() {
return this.projectile;
}
}

@ -68,6 +68,7 @@ class Configuration {
public int headingThreshold;
public final int playerScaleFactor;
public final int playerProjectileScaleFactor;
public final float mainEngineForce;
public final float reverseEngineForce;
@ -86,11 +87,14 @@ class Configuration {
public final int maxPlayerProjectiles;
public final int reloadTime;
public final int sheildTime;
public final int shieldTime;
public final int extraLifeInterval;
public final int extraBombInterval;
public final int difficultyInterval;
public final int spawnInterval;
/**
* Private constructor
* Parses properties file and loads each parameter into relevent variable
@ -153,6 +157,7 @@ class Configuration {
this.headingThreshold = Integer.parseInt(prop.getProperty("headingThreshold"));
this.playerScaleFactor = Integer.parseInt(prop.getProperty("playerScaleFactor"));
this.playerProjectileScaleFactor = Integer.parseInt(prop.getProperty("playerProjectileScaleFactor"));
this.mainEngineForce = Float.parseFloat(prop.getProperty("mainEngineForce"));
this.reverseEngineForce = Float.parseFloat(prop.getProperty("reverseEngineForce"));
@ -171,11 +176,14 @@ class Configuration {
this.maxPlayerProjectiles = Integer.parseInt(prop.getProperty("maxPlayerProjectiles"));
this.reloadTime = Integer.parseInt(prop.getProperty("reloadTime"));
this.sheildTime = Integer.parseInt(prop.getProperty("sheildTime")); //<>// //<>// //<>//
this.shieldTime = Integer.parseInt(prop.getProperty("shieldTime"));
this.extraLifeInterval = Integer.parseInt(prop.getProperty("extraLifeInterval"));
this.extraBombInterval = Integer.parseInt(prop.getProperty("extraBombInterval"));
this.difficultyInterval = Integer.parseInt(prop.getProperty("difficultyInterval"));
this.spawnInterval = Integer.parseInt(prop.getProperty("spawnInterval"));
input.close();
}
}

@ -24,7 +24,6 @@ String activeSong;
Map<String, AudioPlayer> music;
Map<String, AudioPlayer> soundEffects;
Controller controller;
Serial port;
@ -32,6 +31,12 @@ Player player;
Level level;
TileProperties props;
//viewport variables
int startCol;
int endCol;
int startRow;
int endRow;
//game state
boolean loading;
boolean titleScreen;
@ -50,6 +55,7 @@ long startTime;
long pauseTime;
long lastShot;
long gameOverTime;
long spawnTime;
//story screen variables
int storyCounter;
@ -190,6 +196,8 @@ void serialEvent(Serial p) {
* Main game loop
*/
void game() {
updateViewportVariables();
//draw level background
renderLevel();
@ -230,28 +238,30 @@ void game() {
detectPlayerProjectileCollisions();
//spawn new enemies
spawnEnemy(true);
spawnEnemy(false);
//update difficulty
long currentTime = millis();
long secondsElapsed = (currentTime - startTime) / 1000;
difficulty = (int) secondsElapsed / 60;
difficulty = (int) secondsElapsed / conf.difficultyInterval;
checkForRewards();
}
void updateViewportVariables() {
//Calculate viewport bounds based on player position and viewport dimensions
startCol = player.getX() - (conf.viewportWidth / 2);
endCol = player.getX() + (conf.viewportWidth / 2);
startRow = player.getY() - (conf.viewportHeight / 2);
endRow = player.getY() + (conf.viewportHeight / 2);
}
/**
* Renders the level for the player's current viewport
* Based on example here: https://developer.mozilla.org/en-US/docs/Games/Techniques/Tilemaps/Square_tilemaps_implementation:_Scrolling_maps
*/
void renderLevel() {
//Calculate viewport bounds based on player position and viewport dimensions
int startCol = player.getX() - (conf.viewportWidth / 2);
int endCol = player.getX() + (conf.viewportWidth / 2);
int startRow = player.getY() - (conf.viewportHeight / 2);
int endRow = player.getY() + (conf.viewportHeight / 2);
//iterate through appropriate tiles
for (int col = startCol; col <= endCol; col++) {
for (int row = startRow; row <= endRow; row++) {
@ -421,7 +431,11 @@ void shoot() {
long currentTime = millis();
if (currentTime - lastShot >= conf.reloadTime) {
playSoundEffect("shoot");
playerProjectiles.add(new Projectile(player.getX(), player.getY(), player.getRotation(), spriteSet.get("player")[10], 10, 1, 260));
int x = player.getX();// - Math.round((player.getScaleFactor() / 2) * sin(radians(player.getRotation())));
int y = player.getY();// + Math.round((player.getScaleFactor() / 2) * -cos(radians(player.getRotation())));
playerProjectiles.add(new Projectile(x, y, player.getRotation(), spriteSet.get("player")[10], 10, 1, 260, 2));
lastShot = currentTime;
}
}
@ -442,101 +456,64 @@ void bomb() {
* Selects and spawns a random enemy based on difficulty level
*/
void spawnEnemy(boolean debug) {
int startCol = player.getX() - (conf.viewportWidth / 2);
int endCol = player.getX() + (conf.viewportWidth / 2);
int startRow = player.getY() - (conf.viewportHeight / 2);
int endRow = player.getY() + (conf.viewportHeight / 2);
//select random starting position outside of viewport
int col = int(random(0, level.getCols()));
int row = int(random(0, level.getRows()));
//ensure x is not inside viewport
while ((col >= startCol) && (col <= endCol)) {
col = int(random(0, level.getCols()));
}
//ensure y is not inside viewport
while ((row >= startRow) && (row <= endRow)) {
row = int(random(0, level.getRows()));
}
int r0 = int(random(0,conf.enemyTypes));
int r1 = int(random(1, 1001));
switch(r0) {
case 0: {
if ((r1 < Asteroid0.CHANCE_OF_SPAWNING) && (difficulty >= Asteroid0.MINIMUM_DIFFICULTY)) {
enemies.add(new Asteroid0(col, row, spriteSet.get("asteroid")[0], level));
if (debug) {
print("Asteroid0 spawned at: ");
print(col);
print(", ");
println(row);
}
}
long currentTime = millis();
if (currentTime - spawnTime > conf.spawnInterval) {
spawnTime = currentTime;
//select random starting position outside of viewport
int col = int(random(0, level.getCols()));
int row = int(random(0, level.getRows()));
//ensure x is not inside viewport
while ((col >= startCol) && (col <= endCol)) {
col = int(random(0, level.getCols()));
}
//ensure y is not inside viewport
while ((row >= startRow) && (row <= endRow)) {
row = int(random(0, level.getRows()));
}
int r = int(random(0, 101));
String name = "";
if ((r < Boss.CHANCE_OF_SPAWNING) && (difficulty >= Boss.MINIMUM_DIFFICULTY)) {
enemies.add(new Boss(col, row, spriteSet.get("boss"), spriteSet.get("boss")[2], level, player));
name = "Boss";
}
break;
case 1: {
if ((r1 < Asteroid1.CHANCE_OF_SPAWNING) && (difficulty >= Asteroid1.MINIMUM_DIFFICULTY)) {
enemies.add(new Asteroid1(col, row, spriteSet.get("asteroid")[1], level));
if (debug) {
print("Asteroid1 spawned at: ");
print(col);
print(", ");
println(row);
}
}
else if ((r < Saucer.CHANCE_OF_SPAWNING) && (difficulty >= Saucer.MINIMUM_DIFFICULTY)) {
enemies.add(new Saucer(col, row, spriteSet.get("saucer")[0], spriteSet.get("saucer")[1], level, player));
name = "Saucer";
}
break;
case 2: {
if ((r1 < Asteroid2.CHANCE_OF_SPAWNING) && (difficulty >= Asteroid2.MINIMUM_DIFFICULTY)) {
enemies.add(new Asteroid2(col, row, spriteSet.get("asteroid")[2], level));
if (debug) {
print("Asteroid2 spawned at: ");
print(col);
print(", ");
println(row);
}
}
else if ((r < GunPlatform.CHANCE_OF_SPAWNING) && (difficulty >= GunPlatform.MINIMUM_DIFFICULTY)) {
enemies.add(new GunPlatform(col, row, spriteSet.get("gunPlatform")[0], spriteSet.get("gunPlatform")[1], player));
name = "GunPlatform";
}
else if ((r < Jellyfish.CHANCE_OF_SPAWNING) && (difficulty >= Jellyfish.MINIMUM_DIFFICULTY)) {
enemies.add(new Jellyfish(col, row, spriteSet.get("jellyfish"), level, player));
name = "Jellyfish";
}
else if ((r < Asteroid2.CHANCE_OF_SPAWNING) && (difficulty >= Asteroid2.MINIMUM_DIFFICULTY)) {
enemies.add(new Asteroid2(col, row, spriteSet.get("asteroid")[2], level));
name = "Asteroid2";
}
else if ((r < Asteroid1.CHANCE_OF_SPAWNING) && (difficulty >= Asteroid1.MINIMUM_DIFFICULTY)) {
enemies.add(new Asteroid1(col, row, spriteSet.get("asteroid")[1], level));
name = "Asteroid1";
}
else if ((r < Asteroid0.CHANCE_OF_SPAWNING) && (difficulty >= Asteroid0.MINIMUM_DIFFICULTY)) {
enemies.add(new Asteroid0(col, row, spriteSet.get("asteroid")[0], level));
name = "Asteroid0";
}
if (debug) {
print(name);
print(" spawned at: ");
print(col);
print(", ");
println(row);
}
break;
case 3: {
if ((r1 < Jellyfish.CHANCE_OF_SPAWNING) && (difficulty >= Jellyfish.MINIMUM_DIFFICULTY)) {
enemies.add(new Jellyfish(col, row, spriteSet.get("jellyfish"), level, player));
if (debug) {
print("Jellyfish spawned at: ");
print(col);
print(", ");
println(row);
}
}
}
break;
case 4: {
if ((r1 < GunPlatform.CHANCE_OF_SPAWNING) && (difficulty >= GunPlatform.MINIMUM_DIFFICULTY)) {
enemies.add(new GunPlatform(col, row, spriteSet.get("gunPlatform")[0], spriteSet.get("gunPlatform")[1], player));
if (debug) {
print("GunPlatform spawned at: ");
print(col);
print(", ");
println(row);
}
}
}
break;
case 5: {
if ((r1 < Saucer.CHANCE_OF_SPAWNING) && (difficulty >= Saucer.MINIMUM_DIFFICULTY)) {
enemies.add(new Saucer(col, row, spriteSet.get("saucer")[0], spriteSet.get("saucer")[1], level, player));
if (debug) {
print("Saucer spawned at: ");
print(col);
print(", ");
println(row);
}
}
}
break;
}
}
@ -556,11 +533,6 @@ void updateEnemies() {
* render enemies within viewport
*/
void renderEnemies() {
int startCol = player.getX() - (conf.viewportWidth / 2);
int endCol = player.getX() + (conf.viewportWidth / 2);
int startRow = player.getY() - (conf.viewportHeight / 2);
int endRow = player.getY() + (conf.viewportHeight / 2);
for (Enemy enemy : enemies) {
int col = enemy.getX();
int row = enemy.getY();
@ -605,12 +577,7 @@ void updateProjectiles() {
/**
* render projectiles within viewport
*/
void renderProjectiles() {
int startCol = player.getX() - (conf.viewportWidth / 2);
int endCol = player.getX() + (conf.viewportWidth / 2);
int startRow = player.getY() - (conf.viewportHeight / 2);
int endRow = player.getY() + (conf.viewportHeight / 2);
void renderProjectiles() {
List<List<Projectile>> projectileLists = new ArrayList<List<Projectile>>();
projectileLists.add(playerProjectiles);
projectileLists.add(enemyProjectiles);
@ -631,7 +598,7 @@ void renderProjectiles() {
translate(x,y);
rotate(radians(projectile.getRotation()));
imageMode(CENTER);
image(projectile.getSprite(), 0, 0, dimensions.tileWidth, dimensions.tileHeight);
image(projectile.getSprite(), 0, 0, dimensions.tileWidth * projectile.getScaleFactor(), dimensions.tileHeight * projectile.getScaleFactor());
popMatrix();
}
}
@ -652,12 +619,18 @@ void detectPlayerProjectileCollisions() {
while(projectileIterator.hasNext()) {
Projectile projectile = projectileIterator.next();
int pX = projectile.getX();
int pY = projectile.getY();
int eX = enemy.getX();
int eY = enemy.getY();
//https://silentmatt.com/rectangle-intersection/
int eX1 = enemy.getX() - (enemy.getScaleFactor() / 2);
int eY1 = enemy.getY() - (enemy.getScaleFactor() / 2);
int eX2 = enemy.getX() + (enemy.getScaleFactor() / 2);
int eY2 = enemy.getY() + (enemy.getScaleFactor() / 2);
if ((pX > eX - (enemy.getScaleFactor() / 2)) && (pX < eX + (enemy.getScaleFactor() / 2)) && (pY > eY - (enemy.getScaleFactor() / 2)) && (pY < eY + (enemy.getScaleFactor() / 2))) {
int pX1 = projectile.getX() - (projectile.getScaleFactor() / 2);
int pY1 = projectile.getY() - (projectile.getScaleFactor() / 2);
int pX2 = projectile.getX() + (projectile.getScaleFactor() / 2);
int pY2 = projectile.getY() + (projectile.getScaleFactor() / 2);
if ((eX1 < pX2) && (eX2 > pX1) && (eY1 < pY2) && (eY2 > pY1)) {
for (int i = 0; i < projectile.getDamage(); i++) {
if(enemy.hit()) {
//DESTROYED!
@ -688,10 +661,18 @@ void detectEnemyProjectileCollision() {
while(projectileIterator.hasNext()) {
Projectile projectile = projectileIterator.next();
int eX = projectile.getX();
int eY = projectile.getY();
//https://silentmatt.com/rectangle-intersection/
int eX1 = projectile.getX() - (projectile.getScaleFactor() / 2);
int eY1 = projectile.getY() - (projectile.getScaleFactor() / 2);
int eX2 = projectile.getX() + (projectile.getScaleFactor() / 2);
int eY2 = projectile.getY() + (projectile.getScaleFactor() / 2);
int pX1 = player.getX() - (player.getScaleFactor() / 2);
int pY1 = player.getY() - (player.getScaleFactor() / 2);
int pX2 = player.getX() + (player.getScaleFactor() / 2);
int pY2 = player.getY() + (player.getScaleFactor() / 2);
if ((eX > player.getX() - (player.getScaleFactor() / 2)) && (eX < player.getX() + (player.getScaleFactor() / 2)) && (eY > player.getY() - (player.getScaleFactor() / 2)) && (eY < player.getY() + (player.getScaleFactor() / 2))) {
if ((eX1 < pX2) && (eX2 > pX1) && (eY1 < pY2) && (eY2 > pY1)) {
//if ((eX == player.getX()) && (eY == player.getY())) {
death();
projectileIterator.remove();
@ -744,9 +725,6 @@ void renderBomb() {
int col = bomb.x;
int row = bomb.y;
int startCol = player.getX() - (conf.viewportWidth / 2);
int startRow = player.getY() - (conf.viewportHeight / 2);
int x = dimensions.widthOffset + (col - startCol) * dimensions.tileWidth;
int y = dimensions.heightOffset + (row - startRow) * dimensions.tileHeight;
@ -950,6 +928,7 @@ void titleScreen() {
startTime = millis();
lastShot = millis();
spawnTime = millis();
}
}
@ -1080,6 +1059,7 @@ void loadResources() {
spriteSet.put("jellyfish", loadJellyfishSprites());
spriteSet.put("gunPlatform", loadGunPlatformSprites());
spriteSet.put("saucer", loadSaucerSprites());
spriteSet.put("boss", loadBossSprites());
soundEffects = loadSoundEffects();
music = loadMusic();
@ -1200,6 +1180,16 @@ PImage[] loadSaucerSprites() {
return sprites;
}
PImage[] loadBossSprites() {
PImage[] sprites = {
loadImage(sketchPath() + System.getProperty("file.separator") + conf.spritePath + System.getProperty("file.separator") + "boss0.png"),
loadImage(sketchPath() + System.getProperty("file.separator") + conf.spritePath + System.getProperty("file.separator") + "boss1.png"),
loadImage(sketchPath() + System.getProperty("file.separator") + conf.spritePath + System.getProperty("file.separator") + "bossProjectile.png")
};
return sprites;
}
Map<String, AudioPlayer> loadSoundEffects() {
Map<String, AudioPlayer> map = new HashMap<String, AudioPlayer>();

@ -8,12 +8,15 @@ public class GunPlatform implements Enemy {
public static final int MINIMUM_DIFFICULTY = 4;
public static final int SCORE = 800;
public static final int INITIAL_HIT_POINTS = 1;
public static final int SCALE_FACTOR = 15;
public static final int CHANCE_OF_SPAWNING = 5;
public static final int SCALE_FACTOR = 20;
public static final int CHANCE_OF_SPAWNING = 20;
public static final int MAX_SPEED = 0;
public static final int ROTATION_SPEED = 5;
public static final int RELOAD_TIME = 5000;
public static final int PROJECTILE_SPEED = 3;
public static final int PROJECTILE_DAMAGE = 1;
public static final int PROJECTILE_RANGE = 300;
private final PImage sprite;
@ -143,8 +146,8 @@ public class GunPlatform implements Enemy {
//shoot
long currentTime = millis();
if (currentTime - this.lastShot > RELOAD_TIME) {
lastShot = millis();
this.projectile = new Projectile(this.x, this.y, this.rotation, this.projectileSprite, 3, 1, 300);
lastShot = currentTime;
this.projectile = new Projectile(this.x, this.y, this.rotation, this.projectileSprite, PROJECTILE_SPEED, PROJECTILE_DAMAGE, PROJECTILE_RANGE);
}
else {
this.projectile = null;

@ -8,9 +8,9 @@ public class Jellyfish implements Enemy {
public static final int MINIMUM_DIFFICULTY = 3;
public static final int SCORE = 400;
public static final int INITIAL_HIT_POINTS = 1;
public static final int SCALE_FACTOR = 15;
public static final int CHANCE_OF_SPAWNING = 10;
public static final int MAX_SPEED = 3;
public static final int SCALE_FACTOR = 20;
public static final int CHANCE_OF_SPAWNING = 35;
public static final int MAX_SPEED = 2;
public static final int ROTATION_SPEED = 5;
public static final int ANIMATION_INTERVAL = 100;

@ -63,7 +63,7 @@ class Player extends Camera {
public boolean getSheild() {
if (GOD_MODE) return true;
long currentTime = millis();
return (currentTime - hitTime <= conf.sheildTime);
return (currentTime - hitTime <= conf.shieldTime);
}
/**

@ -10,13 +10,29 @@ public class Projectile {
private final int range;
private final int rotation;
private PImage sprite;
private final PImage sprite;
private final int scaleFactor;
private int x;
private int y;
private int distanceTravelled;
public Projectile(int initialX, int initialY, int initialRotation, PImage sprite, int speed, int damage, int range, int scaleFactor) {
this.x = initialX;
this.y = initialY;
this.rotation = initialRotation;
this.sprite = sprite;
this.speed = speed;
this.damage = damage;
this.range = range;
this.distanceTravelled = 0;
this.scaleFactor = scaleFactor;
}
public Projectile(int initialX, int initialY, int initialRotation, PImage sprite, int speed, int damage, int range) {
this.x = initialX;
this.y = initialY;
@ -28,6 +44,8 @@ public class Projectile {
this.range = range;
this.distanceTravelled = 0;
this.scaleFactor = 1;
}
public int getX() {
@ -58,6 +76,10 @@ public class Projectile {
return this.range;
}
public int getScaleFactor() {
return this.scaleFactor;
}
/*
* Update projectile position
* @return true if projectile should be destroyed

@ -16,7 +16,7 @@ Micro:bit controller code [here](https://git.jbm.fyi/jbm/CS5041_P1_Microbit)
## Gameplay instructions
### Story
Equipt with the latest starfighter, you have returned to Earth to find nothing but an asteroid field. The planet has been destroyed. You don't have much fuel left and have no choice but to spend the final hours of your life fighting the aliens that destroyed your homeworld and avenging your people. Initially the aliens don't pay you much attention and you will encounter nothing but asteroids (Earth fragments) for the first 3 minutes. However, after 3 minutes, the aliens begin to take notice and will continue to send stronger forces every minute. Try to earn as many points as possible and give Earth the funeral it deserves. Into the breach....
Equipt with the latest starfighter, you have returned to Earth to find nothing but an asteroid field. The planet has been destroyed. You don't have much fuel left and have no choice but to spend the final hours of your life fighting the aliens that destroyed your homeworld and avenging your people. Initially the aliens don't pay you much attention and you will encounter nothing but asteroids (Earth fragments) for the first 1.5 minutes. However, after 1.5 minutes, the aliens begin to take notice and will continue to send stronger forces every 30 seconds. Try to earn as many points as possible and give Earth the funeral it deserves. Into the breach....
### Controls
- Tip forwards: Accelerate
@ -33,6 +33,7 @@ Equipt with the latest starfighter, you have returned to Earth to find nothing b
Fly around the map avoiding enemies and racking up points. Gain points by destroying enemies using your laser, or by dropping bombs. You only have a limited number of bombs, shown by the icons in the bottom right corner of the screen. Your score is shown in the top right corner. You have 3 lives, shown in the top left corner of the screen. You will take damage if you hit an enemy or an enemy projectile. If you take damage, but still have lives remaining, your sheild will be activated for 5 seconds, during which time you are invulnerable, but you can't use bombs. Your sheild will also be activated for the first 5 seconds of the game. Once you run out of lives, it's game over. You will earn an additional bomb every 25,000 points (but you can have no more then 5) and an extra life every 50,000 points (you can have more then 3). Try to survive as long as you can!
## Troubleshooting
- Game settings have been optimised for 1080p monitor, you should select and alternative viewport dimensions according to the method decribed in config.properties for different monitor sizes (or set resolution to 1080p).
- If the controller and reciever are communicating, the yellow LED next to the USB port on the receiver will flash when the game is open. If it is not flashing this indicates a connection issue.
- Connection issues can usually be resolved by resetting (using the reset button) first the controller and failing this the receiver as well.
- If this still does not resolve the issue, try disconnecting and reconnecting the battery pack on the controller (this seems to be required alot in windows for some reason).
@ -49,7 +50,8 @@ Fly around the map avoiding enemies and racking up points. Gain points by destro
- "Bomb" sprite adapted from andreasisnes's [Elitekollektivet.Minesweeper.Sprites](https://github.com/andreasisnes/Elitekollektivet.Minesweeper.Sprites) repo and originally by TCRF's Minesweeper (winmine31) on Windows NTF4/2000. Spritesheet [here](https://github.com/andreasisnes/Elitekollektivet.Minesweeper.Sprites/blob/master/minesweeper/images/tiles/2000.png)
- Player death, asteroid explosion, forward/reverse/rotation engine, sheild and shoot sounds effects from [kenney's](https://kenney.nl) [Sci-fi sounds pack](https://kenney.nl/assets/sci-fi-sounds)
- Pause and Resume sounds from [kenney's](https://kenney.nl) [Interface sounds pack](https://kenney.nl/assets/interface-sounds)
- Music tracks - Cold Moon, Cyber REM, Dystopic Factory, Escape from the Insane Machines, Light Years, Retro Sci-fi Planet, Sector Off Limits, Terraforming Begins and Trouble on Mercury and bomb sound effect by [Eric Matyas](https://soundimage.org/)
- Music tracks - Cold Moon, Cyber REM, Dystopic Factory, Escape from the Insane Machines, Light Years, Retro Sci-fi Planet, Sector Off Limits, Terraforming Begins and Trouble on Mercury and bomb sound effect by [Eric Matyas](https://soundimage.org/)
- "Boss" sprite inspired by Taito/Midway/Tomohiro Nishikado's Space Invaders crab (1978)
## Licence
Copyright 2022 Jamie Munro, All Rights Reserved.

@ -9,11 +9,14 @@ public class Saucer implements Enemy {
public static final int SCORE = 1600;
public static final int INITIAL_HIT_POINTS = 1;
public static final int SCALE_FACTOR = 15;
public static final int CHANCE_OF_SPAWNING = 3;
public static final int CHANCE_OF_SPAWNING = 10;
public static final int MAX_SPEED = 1;
public static final int ROTATION_SPEED = 5;
public static final int RELOAD_TIME = 3000;
public static final int PROJECTILE_SPEED = 3;
public static final int PROJECTILE_DAMAGE = 1;
public static final int PROJECTILE_RANGE = 200;
private final PImage sprite;
@ -47,7 +50,6 @@ public class Saucer implements Enemy {
this.hitPoints = INITIAL_HIT_POINTS;
this.sprite = sprite;
this.projectileSprite = projectileSprite;
this.tintR = 255;
this.tintG = 255;
@ -55,6 +57,7 @@ public class Saucer implements Enemy {
this.speed = MAX_SPEED;
this.projectileSprite = projectileSprite;
lastShot = millis();
}
@ -162,7 +165,7 @@ public class Saucer implements Enemy {
long currentTime = millis();
if (currentTime - this.lastShot > RELOAD_TIME) {
lastShot = millis();
this.projectile = new Projectile(this.x, this.y, this.rotation, this.projectileSprite, 3, 1, 200);
this.projectile = new Projectile(this.x, this.y, this.rotation, this.projectileSprite, PROJECTILE_SPEED, PROJECTILE_DAMAGE, PROJECTILE_RANGE);
}
else {
this.projectile = null;

@ -20,18 +20,21 @@ aspectY=3
# PERFORMANCE PARAMETERS #
###################################################################################################
#frames per second (lower is performance is struggling)
#frames per second
framerate=30
###################################################################################################
# VIEWPORT PARAMETERS #
###################################################################################################
#This cause stretching if not set according to aspect ratio, and slightly off center if even
#This causes stretching/misplaced sprites if not set correctly
#METHOD: select a common factor of your adjusted width and height
#set viewport width to adjusted width / common factor
#set viewport height to adjusted height / common factor
#adjustedWidth = windowHeight * (aspectX/aspectY)
#adjustedHeight = windowWidth / (aspectX/aspectY)
#viewport width in tiles
viewportWidth=360
@ -42,10 +45,10 @@ viewportHeight=270
# LEVEL PARAMETERS #
###################################################################################################
#Level width in tiles
levelWidth=5000
levelWidth=3000
#Level Height in tiles
levelHeight=5000
levelHeight=3000
###################################################################################################
# RESOURCE FILEPATHS #
@ -119,7 +122,7 @@ storyCrawl=INTO THE BREACH\n\nHow did it come to this?\n\nFirst there were the w
gameOverMsg=GAME OVER
#Credits
credits=Credits:\n2022 Jamie Munro, All rights reserved\nGame Design, Progamming and Graphics by Jamie Munro\nMusic by Eric Matyas\nSound effects by Kenny.nl\nBomb icon inspired by TCRF's Minesweeper
credits=Credits:\n2022 Jamie Munro, All rights reserved\nGame Design, Progamming and Graphics by Jamie Munro\nMusic by Eric Matyas\nSound effects by Kenny.nl\nBomb icon inspired by TCRF's Minesweeper\n"Boss" sprite inspired by Taito/Midway/Tomohiro Nishikado's Space Invaders crab
###################################################################################################
# CONTROLLER PARAMETERS #
@ -161,7 +164,7 @@ mainEngineForce=0.25
reverseEngineForce=0.175
#number of degrees rotated per unit time side engine is firing
rotationSpeed=5
rotationSpeed=4
#Maximum forwards momentum
maxForwardsMomentum=6
@ -184,6 +187,9 @@ scrollSpeed = 2
#Player scale factor in relation to tile size
playerScaleFactor=12
#Player projectile scale factor in relation to tile size
playerProjectileScaleFactor=2
#starting lives
initialLives=3
@ -191,7 +197,7 @@ initialLives=3
initialBombs=5
#number of different types of enemy
enemyTypes=6
enemyTypes=7
#maximum number of player projectiles in flight
maxPlayerProjectiles=100
@ -200,11 +206,17 @@ maxPlayerProjectiles=100
reloadTime=250
#time shielded for after a hit
sheildTime=5000
shieldTime=5000
#speed of bomb expansion
bombSpeed=2
#amount of time per difficulty increase (seconds)
difficultyInterval=30
#amount of time per spawn (ms)
spawnInterval=1000
###################################################################################################
# REWARD PARAMETERS #
###################################################################################################

Binary file not shown.

Before

Width:  |  Height:  |  Size: 207 B

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 219 B

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 125 B

After

Width:  |  Height:  |  Size: 120 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 129 B

After

Width:  |  Height:  |  Size: 120 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 197 B

After

Width:  |  Height:  |  Size: 192 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 195 B

After

Width:  |  Height:  |  Size: 164 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 203 B

After

Width:  |  Height:  |  Size: 165 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 210 B

After

Width:  |  Height:  |  Size: 166 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 198 B

After

Width:  |  Height:  |  Size: 157 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 188 B

After

Width:  |  Height:  |  Size: 165 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 192 B

After

Width:  |  Height:  |  Size: 167 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 204 B

After

Width:  |  Height:  |  Size: 161 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 206 B

After

Width:  |  Height:  |  Size: 167 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 212 B

After

Width:  |  Height:  |  Size: 163 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 182 B

After

Width:  |  Height:  |  Size: 166 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 213 B

After

Width:  |  Height:  |  Size: 167 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 192 B

After

Width:  |  Height:  |  Size: 161 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 201 B

After

Width:  |  Height:  |  Size: 167 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 192 B

After

Width:  |  Height:  |  Size: 164 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 189 B

After

Width:  |  Height:  |  Size: 156 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 194 B

After

Width:  |  Height:  |  Size: 158 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 196 B

After

Width:  |  Height:  |  Size: 170 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 197 B

After

Width:  |  Height:  |  Size: 158 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 178 B

After

Width:  |  Height:  |  Size: 169 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 172 B

After

Width:  |  Height:  |  Size: 162 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 184 B

After

Width:  |  Height:  |  Size: 159 B

Loading…
Cancel
Save