Your browser does not support the canvas tag.

previous        Show / Hide Source        Download        next
/*
Shield Defense Base: By Michael Downey

A small little game where you control a slippery moving tank that
generates a shield above it, and try to defend the base beneath
you against a meteor shower. As the game goes on, the sky gets
darker, the meteors speed up, and the impact deals more damage.
However, faster meteors give a higher score. When the base is
destroyed, your final score is displayed.
*/


//declare all objects

int numberOfRocks = 5;
int numberOfStars = 20;
Rock[] meteorShower= new Rock[numberOfRocks];
Base base;
//Collision[] explosions= new Collision[numberOfRocks];
Star[] stars= new Star[numberOfStars];
Tank tank;
Timer timer;

//declare all global variables

float difficultyTimer;
float score = 0;
int scoreDisplay = 0;
int finalScore = 0;

//declare all values related to the base globally to ensure that other classes can use them

float baseLeft = 0;
float baseTop = 500; 
float baseRight = 800;
float baseBottom = 600;
float baseHealth = 500; //health of the military base

//declare shield collision values globally to ensure that other classes

float shieldLeft;
float shieldTop; 
float shieldRight;
float shieldBottom;

//declare booleans for movement and game over

boolean leftPressed = false;
boolean rightPressed = false;
boolean gameOver = false;

void setup() {
  //set up the window size, the frame rate, and the main background color
  size(800, 600);
  frameRate(60);
  rectMode(CORNERS);
  noStroke();

  //Activates the game objects
  createMeteorShower();
  //createExplosions();
  createStars();
  base=new Base();
  tank=new Tank();
  timer=new Timer();
}

void createMeteorShower() {
  for (int i=0; i<meteorShower.length; i++) {
    meteorShower[i]=new Rock();
  }
}

//explosions were going to be a seperate class, but creating them in the same class as the meteors proved mroe efficient

/*void createExplosions() {
 for (int i=0; i<explosions.length; i++) {
 explosions[i]=new Collision();
 }
 }*/

void createStars() {
  for (int i=0; i<stars.length; i++) {
    stars[i]=new Star();
  }
}

void draw() {

  //updates all of the major game objects
  timer.update();
  for (int i=0; i<stars.length; i++) {
    stars[i].update();
  }
  for (int i=0; i<meteorShower.length; i++) {
    meteorShower[i].update();
  }
  tank.update();

  //prevents the base health from going below zero
  if (baseHealth < 0) {
    baseHealth = 0;
  }

  //draw the background
  background(0, 0, 30);
  for (int i=0; i<stars.length; i++) {
    stars[i].display();
  }
  fill(0, 200, 255, 250 - difficultyTimer / 100); //The brightness of the background is an indicator of the meteor shower's average speed
  noStroke();
  rectMode(CORNERS);
  rect(0, 0, 800, 600);

  //display major game objects
  base.display();
  tank.display();
  for (int i=0; i<meteorShower.length; i++) {
    meteorShower[i].display();
  }

  //display the score
  fill(0 + difficultyTimer / 100);
  textSize(32);
  scoreDisplay = int(score);
  text("Score:" + scoreDisplay, 0, 32);

  //Activates game over and reveals final score
  if (baseHealth <= 0) {
    fill(0);
    gameOver = true;
    rectMode(CORNERS);
    rect(0, 0, 800, 600);
    fill(255);
    textSize(64);
    finalScore = int(score);
    text("GAME OVER! Score:" + finalScore, 25, 300);
  }
}

void keyPressed() {
  //detect if the player has pressed left or right
  switch(key) {
  case 'a':
    leftPressed = true;
    break;
  case 'd':
    rightPressed = true;
    break;
  }
}

void keyReleased() {
  //detect if the player has pressed left or right
  switch(key) {
  case 'a':
    leftPressed = false;
    break;
  case 'd':
    rightPressed = false;
    break;
  }
}
class Base {
  
  int colorVariation = 0; //variable for animating base lights
  int variationIncrement = 2; //controls the incrementation of the color shift
  
  Base() {
    init();
  }
  
  void init() {
  }
  
  void update() {
  }
  
  void display() {
    
    //draw the base itself
    
    noStroke();
    rectMode(CORNERS);
    fill(150,150,150,255);
    rect(baseLeft, baseTop, baseRight, baseBottom);
    
    //draw the base's lights
    
    ellipseMode(RADIUS);
    fill(128 + colorVariation,0,0);
    ellipse(80,550,5,5);
    ellipse(160,550,5,5);
    ellipse(240,550,5,5);
    ellipse(320,550,5,5);
    ellipse(400,550,5,5);
    ellipse(480,550,5,5);
    ellipse(560,550,5,5);
    ellipse(640,550,5,5);
    ellipse(720,550,5,5);
    
    //control the light "animation"
    
    colorVariation = colorVariation + variationIncrement;
    if (colorVariation > 50) {
      variationIncrement = -2;
    }
    if (colorVariation < -50) {
      variationIncrement = 2;
    }
    
    //draw the base's health bar
    
    fill(255,0,0);
    rect(275,565,525,585);
    fill(0,255,0);
    rect(275,565,275 + baseHealth / 2,585);
  }
}
/*class Bullet {
  
  Bullet() {
    init();
  }
  
  void init() {
  }
  
  void update() {
  }
  
  void display() {
  }
}*/

//There were plans to use a superweapon, but gameplay tests without it seemed simple and fun enough to determine it wasn't needed, leaving this bullet a remnant.
/*class Collision {
  
  Collision() {
    init();
  }
  
  void init() {
  }
  
  void update() {
  }
  
  void display() {
  }
}*/

//Initial plans were to code the base explosions into this collision class, however, it was decided that coding the explosions into the rocks worked just as well
class Rock {

  //declare necessary PVectors
  
  PVector position = new PVector();
  PVector oldPosition = new PVector();
  PVector velocity = new PVector();

  //declare necessary variables
  
  float rockLeft, rockRight, rockTop, rockBottom;
  float rockDamage;
  int explosionCounter;
  boolean rockBoomBase = false;
  boolean rockBoomShield = false;

  Rock() {
    init();
  }

  void init() {
    //set initial rock values.
    position.x = random(0, 800);
    position.y = 0 - random(200);
    velocity.y = random(.5, 2) + difficultyTimer / 600;
  }

  void update() {
    //checks for game over
    if (gameOver == false) {
      //move the rock downwards
      position.add(velocity);

      //reconfirms the rock's position for collisions
      rockLeft = position.x;
      rockTop = position.y;
      rockRight = position.x + 50;
      rockBottom = position.y + 50;

      //checks to see if the rock has impacted the base
      if (rockBottom > baseTop) {
        rockBoomBase = true;
        rockBoomShield = false;
        explosionCounter = 0;
        rockDamage = 2 + velocity.y;
        oldPosition.x = position.x + 25;
        oldPosition.y = position.y + 50;
        init();
        baseHealth = baseHealth - rockDamage;
      }

      //checks to see if the rock has impacted the shield
      if (rockRight > shieldLeft && rockLeft < shieldRight && rockBottom > shieldTop && rockTop < shieldBottom) {
        rockBoomShield = true;
        rockBoomBase = false;
        score = score + 5 * velocity.y;
        explosionCounter = 0;
        oldPosition.x = position.x + 25;
        oldPosition.y = position.y + 50;
        init();
      }
    }
  }

  void display() {
    
    //draws the rock
    
    noStroke();
    ellipseMode(CORNERS);
    fill(147, 83, 0, 255);
    ellipse(position.x, position.y, position.x + 50, position.y + 50);
    triangle(position.x, position.y - 10, position.x + 35, position.y + 10, position.x, position.y + 20);
    triangle(position.x + 10, position.y + 15, position.x + 35, position.y, position.x + 60, position.y + 15);
    triangle(position.x + 9, position.y + 15, position.x + 34, position.y + 30, position.x + 59, position.y + 15);
    triangle(position.x, position.y + 25, position.x + 20, position.y + 55, position.x + 50, position.y + 25);
    triangle(position.x, position.y + 25, position.x - 5, position.y + 55, position.x + 30, position.y + 50);
    
    //checks for base explosion and draws it
    
    if (rockBoomBase == true) {
      fill(255, 150, 0, 255 - explosionCounter * 5);
      ellipseMode(CENTER);
      ellipse(oldPosition.x, oldPosition.y, 15 + explosionCounter * 2, 15 + explosionCounter * 2);
      explosionCounter++;
    }
    
    //checks for shield break and draws it
    
    if (rockBoomShield == true) {
      fill(147, 83, 0, 255 - explosionCounter * 5);
      ellipseMode(CENTER);
      ellipse(oldPosition.x, oldPosition.y, 5 + explosionCounter * 2, 5 + explosionCounter * 2);
      explosionCounter++;
    }
  }
}
/*class Shield {
  
  Shield() {
    init();
  }
  
  void init() {
  }
  
  void update() {
  }
  
  void display() {
  }
}*/

//Originally, the shield and the tank would be seperate classes, but making them into the same class was more efficient
class Star {
  //declares variables
  PVector position = new PVector();
  float transparency;
  int lengthIncrease;
  
  Star() {
    init();
  }
  
  void init() {
    //sets the position and transparency of the star
    position.x = random(800);
    position.y = random(600);
    transparency = random(200,255);
    lengthIncrease = 1;
  }
  
  void update() {
    //controls animation parameters
    lengthIncrease = lengthIncrease + 1;
    transparency = transparency - 10;
    if (transparency < -50) {
      init();
    }
  }
  
  void display() {
    //draws the star
    stroke(255,255,255,transparency);
    strokeWeight(random(2,6));
    line(position.x,position.y,position.x + 1 * lengthIncrease,position.y);
    line(position.x,position.y,position.x - 1 * lengthIncrease,position.y);
    line(position.x,position.y,position.x,position.y + 1 * lengthIncrease);
    line(position.x,position.y,position.x,position.y - 1 * lengthIncrease);
  }
}
class Tank {

  //declares necessary pVectors
  PVector position = new PVector();
  PVector velocity = new PVector();

  //declares animation variables
  int glowVariation = 200;
  int variationIncrement = 5;

  //declare shield position

  float shieldPositionLeft;
  float shieldPositionRight;
  float shieldPositionTop;
  float shieldPositionBottom;

  Tank() {
    init();
  }

  void init() {
    //sets tank starting point
    position.x = 400;
    position.y = 500;
    velocity.x = 0;
  }

  void update() {

    //checks for game over

    if (gameOver == false) {

      //update the shield position

      shieldPositionLeft = position.x - 50;
      shieldPositionRight = position.x + 50;
      shieldPositionTop = position.y - 70;
      shieldPositionBottom = position.y - 60;

      //updates the shield collision
      shieldLeft = shieldPositionLeft;
      shieldRight = shieldPositionRight;
      shieldTop = shieldPositionTop;
      shieldBottom = shieldPositionBottom;

      //alter the tank's velocity, increasing and decreasing speed with button presses, as opposed to basic left button moves left and right button moves right
      if (leftPressed == true) {
        velocity.x--;
      }
      if (rightPressed == true) {
        velocity.x++;
      }

      if (velocity.x > 10) {
        velocity.x = 10;
      }
      if (velocity.x < -10) {
        velocity.x = -10;
      }

      position.add(velocity);
      if (position.x > 800) {
        position.x = 800;
      }
      if (position.x < 0) {
        position.x = 0;
      }
    }
  }

  void display() {

    //change the glow on the glowing parts

    glowVariation = glowVariation + variationIncrement;
    if (glowVariation > 200) {
      variationIncrement = -5;
    }
    if (glowVariation < 50) {
      variationIncrement = 5;
    }

    //display the tank

    ellipseMode(CENTER);
    fill(0, 255, 255);
    ellipse(position.x, position.y - 36, 32, 32);
    fill(255, 255, 255, 0 + glowVariation);
    ellipse(position.x, position.y - 36, 36, 36);
    rectMode(CENTER);
    fill(105, 160, 15, 255);
    rect(position.x, position.y - 25, 36, 36);
    ellipseMode(CENTER);
    fill(110, 40, 35, 255);
    ellipse(position.x - 18, position.y - 7, 20, 20);
    ellipse(position.x + 18, position.y - 7, 20, 20);

    //display the shield near the tank itself
    rectMode(CORNERS);
    fill(0, 255, 255);
    rect(shieldPositionLeft, shieldPositionTop, shieldPositionRight, shieldPositionBottom);
    fill(255, 255, 255, 0 + glowVariation);
    rect(shieldPositionLeft - 2, shieldPositionTop - 2, shieldPositionRight + 2, shieldPositionBottom + 2);
  }
}
class Timer {
  
  Timer() {
    init();
  }
  
  void init() {
  }
  
  void update() {
    difficultyTimer++; //increments the timer
  }
  
  void display() {
  }
}