Your browser does not support the canvas tag.

previous        Show / Hide Source        Download        next
/**
 ** BUST THOSE GHOSTS!
 ** By: Jensen Verlaan
 ** 
 ** It's almost Halloween and the ghosts of the graveyard are running rampant again!
 ** While some are friendly and well behaved, others are acting out and causing mischief around town!
 ** As the local witch doctor, it's up to you to calm these restless spirits!
 ** Shoot the bad spirits with your one-of-a-kind "Witch Doctor Zapper Gun" to return them to a peaceful slumber!
 ** The upper middle score will keep count of how many naughty spirits you send back to their graves!
 ** But watch out!!! Shooting peaceful spirits will lower your score.
 ** Happy hunting and Happy Halloween!!!
 **
 ** This work was inspired by "gone_fishing_oo" by Nicolas Hesler and "Balloon Pop" by Ali O'Conner.
 **/

//Declare objects as global variables
int numberOfGhosts = 10;
int score = 0;

FriendlyGhosts[] friendlyGhosts = new FriendlyGhosts[numberOfGhosts];
EvilGhosts[] evilGhosts = new EvilGhosts[numberOfGhosts];

Tombstone[] grave1 = new Tombstone[3];
Tombstone[] grave2 = new Tombstone[4];
Tombstone[] grave3 = new Tombstone[5];

void setup() {
  //Set canvas size to 400 x 400 pixels
  size(400, 400);
  //set frame rate to 60
  frameRate(60);
  noStroke();
  noCursor();

  //Initialize objects in setup() by calling constructor
  createFriendlyGhosts();
  createEvilGhosts();

  //hardcode locations values into each tombstone
  grave1[0] = new Tombstone(20, 220, 40, 70);
  grave1[1] = new Tombstone(160, 220, 40, 70);
  grave1[2] = new Tombstone(320, 220, 40, 70);

  grave2[0] = new Tombstone(-30, 150, 30, 40);
  grave2[1] = new Tombstone(100, 150, 30, 40);
  grave2[2] = new Tombstone(240, 150, 30, 40);
  grave2[3] = new Tombstone(380, 150, 30, 40);

  grave3[0] = new Tombstone(-20, 100, 20, 30);
  grave3[1] = new Tombstone(80, 100, 20, 30);
  grave3[2] = new Tombstone(180, 100, 20, 30);
  grave3[3] = new Tombstone(280, 100, 20, 30);
  grave3[4] = new Tombstone(380, 100, 20, 30);
}

//Add a number value to each Evil Ghost in the array from 0 - 19
void createEvilGhosts() {
  for (int i = 0; i < evilGhosts.length; i++) {
    evilGhosts[i] = new EvilGhosts();
  }
}

//Add a number value to each Friendly Ghost in the array from 0 - 19
void createFriendlyGhosts() {
  for (int i = 0; i < friendlyGhosts.length; i++) {
    friendlyGhosts[i] = new FriendlyGhosts();
  }
}

void draw() {

  ////////////////
  /////UPDATE/////
  ////////////////

  //update FriendlyGhosts
  for (int i = 0; i < friendlyGhosts.length; i++) {
    friendlyGhosts[i].update();
  }
  //updateEvilGhosts
  for (int i = 0; i < evilGhosts.length; i++) {
    evilGhosts[i].update();
  }

  /////////////////
  /////DISPLAY/////
  /////////////////

  background(0);
  //Draw the background
  setting();
  //Draw the tombstones
  for (int i = 0; i < grave1.length; i++) {
    grave1[i].display();
  }
  for (int i = 0; i < grave2.length; i++) {
    grave2[i].display();
  }
  for (int i = 0; i < grave3.length; i++) {
    grave3[i].display();
  }
  //Draw single cross grave
  singleCrossGrave();

  //display Friendly Ghosts
  for (int i = 0; i < friendlyGhosts.length; i++) {
    friendlyGhosts[i].display();
  }
  //display evil ghosts
  for (int i = 0; i < evilGhosts.length; i++) {
    evilGhosts[i].display();
  }
  aimingReticle();

  //display the score
  updateScore();
}

////////////////////////////
/////SINGLE CROSS GRAVE/////
////////////////////////////

//for the aesthetic
void singleCrossGrave() {
  fill(75);
  rect(180, 70, 30, 60, 7);
  rect(170, 80, 50, 20, 7);
  fill(125);
  rect(180, 70, 20, 60, 7);
  rect(170, 80, 40, 20, 7);
}

////////////////////
/////BACKGROUND/////
////////////////////

//Draw the background
void setting() {
  noStroke();
  fill(48, 53, 30);
  rect(0, 125, width, height);
  fill(84, 92, 61);
  rect(0, 185, width, height);
  fill(87, 103, 72);
  rect(0, 280, width, height);
}

//////////////////////
///AIMING RETICLE/////
//////////////////////

//Create Crosshairs that follow the cursor's location
void aimingReticle() {
  noFill();
  stroke(100, 200, 100);
  strokeWeight(3);
  ellipse(mouseX, mouseY, 30, 30);
  line(mouseX -  20, mouseY, mouseX -10, mouseY);
  line(mouseX + 20, mouseY, mouseX + 10, mouseY);
  line(mouseX, mouseY + 20, mouseX, mouseY +10);
  line(mouseX, mouseY - 20, mouseX, mouseY - 10);
  fill(255, 100, 100);
  stroke(100, 200, 100);
  strokeWeight(5);
  point(mouseX, mouseY);
}

///////////////
/////SCORE/////
///////////////

//Create a score that will display in the upper middle of the canvas
void updateScore() {
  fill(255);
  textSize(32);
  text(score, width/2, height/10);
}
class EvilGhosts {

  //Declare EvilGhost variables
  PVector position = new PVector();
  PVector velocity = new PVector();
  float wide = 50;
  float tall = 70;

  boolean startWidth = true;
  boolean startHeight = true;

  EvilGhosts() {
    initialize();
  }

  void initialize() {
    //declare starting ghost values
    //booleans allows ghosts to spawn in all corners
    if (startWidth == true && startHeight == true) {
      position.x=width;
      position.y=height;
      startWidth = false;
    } else if (startWidth == false && startHeight == true) {
      position.x=0;
      position.y=height;
      startHeight = false;
    } else if (startWidth == false && startHeight == false) {
      position.x=0;
      position.y=0;
      startWidth = true;
    } else {
      position.x=width;
      position.y=0;
      startHeight=true;
    }
    velocity.x = random(-5, 10);
    velocity.y = random(-5, 10);
  }

  void display() {
    rectMode(CORNER);
    ellipseMode(CENTER);
    //body
    fill(255, 125);
    rect(position.x, position.y, wide, tall, 10);
    //tail that wiggles
    triangle(position.x + 5, position.y + tall, position.x + wide, position.y + tall, position.x + wide + random(10, 20), position.y + tall + random(10, 20));
    //skull
    fill(255);
    ellipse(position.x + wide/2, position.y + 10, wide-15, wide-15);
    //teeth
    ellipse(position.x + wide/3, position.y +25, wide-40, wide-35);
    ellipse(position.x + wide/2, position.y + 25, wide - 40, wide - 30);
    ellipse(position.x + wide/3*2, position.y + 25, wide - 40, wide - 35);
    //eyes
    fill(0);
    ellipse(position.x + wide/3, position.y + 10, wide-40, wide-30);
    ellipse(position.x + wide/3*2, position.y + 10, wide-40, wide-30);
    //angry eyebrows
    fill(255);
    quad(position.x + 10, position.y, position.x + 25, position.y + 10, position.x + 25, position.y, position.x + 10, position.y);
    quad(position.x + 40, position.y, position.x + 25, position.y + 10, position.x + 25, position.y, position.x + 40, position.y);
  }

  void update() {
    position.add(velocity);

    //if ghost had moved off screen, re-initialise ghost
    if (position.x < -50 || position.y < -50 || position.x > 450 || position.y > 450) {
      initialize();
    }

    //if ghost is shot, increase score
    if (dist(mouseX, mouseY, position.x, position.y) < 30 && mousePressed) {
      initialize();
      score = score+1;
    }
  }
}
class FriendlyGhosts {

  //Declare FriendlyGhost variables
  PVector position = new PVector();
  PVector velocity = new PVector();
  float wide = 50;
  float tall = 70;

  boolean startWidth = true;
  boolean startHeight = true;

  FriendlyGhosts() {
    initialize();
  }

  void initialize() {
    //declare starting ghost values
    //booleans allows ghosts to spawn in all corners
    if (startWidth == true && startHeight == true) {
      position.x=width;
      position.y=height;
      startWidth = false;
    } else if (startWidth == false && startHeight == true) {
      position.x=0;
      position.y=height;
      startHeight = false;
    } else if (startWidth == false && startHeight == false) {
      position.x=0;
      position.y=0;
      startWidth = true;
    } else {
      position.x=width;
      position.y=0;
      startHeight=true;
    }
    velocity.x = random(-5, 10);
    velocity.y = random(-5, 10);
  }

  void display() {
    rectMode(CORNER);
    ellipseMode(CENTER);
    //body
    fill(255, 125);
    rect(position.x, position.y, wide, tall, 10);
    //tail that wiggles
    triangle(position.x + 5, position.y + tall, position.x + wide, position.y + tall, position.x + wide + random(10, 20), position.y + tall + random(10, 20));
    //skull
    fill(255);
    ellipse(position.x + wide/2, position.y + 10, wide-15, wide-15);
    //eyes
    fill(0);
    ellipse(position.x + wide/3, position.y + 10, wide-40, wide-30);
    ellipse(position.x + wide/3*2, position.y + 10, wide-40, wide-30);
    //eye smile
    fill(255);
    rect(position.x+ 10, position.y +15, 30, 5);
    //smile
    fill(0);
    triangle(position.x + wide/2 - 5, position.y +20, position.x + wide/2 + 5, position.y + 20, position.x + wide/2, position.y +25);
  }

  void update() {
    position.add(velocity);

    //if ghost had moved off screen, re-initialise ghost
    if (position.x < -50 || position.y < -50 || position.x > 450 || position.y > 450) {
      initialize();
    }

    //if ghost is shot, decrease score
    if (dist(mouseX, mouseY, position.x, position.y) < 30 && mousePressed) {
      initialize();
      score = score-1;
    }
  }
}
//Create a class that draws a tombstone
class Tombstone {

  //Declare Tombstone variables
  float positionX;
  float positionY;
  float wide;
  float tall;

  //Define Tombstone constructor
  Tombstone(float tempPositionX, float tempPositionY, float tempWide, float tempTall) {
    positionX = tempPositionX;
    positionY = tempPositionY;
    wide = tempWide;
    tall = tempTall;
  }

  //Create a display function for the tombstones
  void display() {
    noStroke();
    rectMode(CORNER);
    ellipseMode(CENTER);
    fill(63, 65, 64);
    rect(positionX + 10, positionY, wide, tall, 7);
    fill(99, 102, 100);
    rect(positionX, positionY, wide, tall, 7);
    fill(0);
    textSize(wide/3);
    text("R.I.P.", positionX + wide/8, positionY + tall/2);
    fill(38, 21, 10);
    ellipse(positionX + wide/2 - 5, positionY + tall+5, wide + 40, tall - 20);
  }
}