Your browser does not support the canvas tag.

previous        Show / Hide Source        Download        next
/*
 Spooky Scary Skeleton Boss
 By Sebastian Scaini
 
 How to play:
 Move with the mouse and dodge the spooky scary skeleton's bullets.
 Click to shoot your bullets at him. You have to hit his head or he won't take damage!
 But be careful, if his bullets hit you you'll take damage.
 May the best player/skeleton win!
*/

// Make various variables to create player, skeleton, hyperdrive and control the flow of the game.
int numberOfEffects = 400;
int timeCheck;
ship playerShip;
hyperdriveEffect[] hyperdrive;
boss skeleton;
healthBar bossHealth;
healthBar playerHealth;
String status;

void setup() {

  ellipseMode(RADIUS);

  size(400, 600);
  
  //create all the in-game elements.
  playerShip = new ship();
  hyperdrive = new hyperdriveEffect[numberOfEffects];
  skeleton = new boss(160, 0, 600);
  bossHealth = new healthBar(0, 0, skeleton.health, 10, #FF0000);
  playerHealth = new healthBar(0, 590, 10, playerShip.health, #08E813);

  //start the timeCheck
  timeCheck = millis();

  //create the hyperdrive effect
  for (int i = 0; i < hyperdrive.length; i++) {
    hyperdrive[i] = new hyperdriveEffect(random(0, 400), -10, 0, random(5, 20));
  }
}

void draw() {
  background(#0E1538);

  //control and display the hyperdrive effect
  for (int i = 0; i < hyperdrive.length; i++) {
    hyperdrive[i].make();
    hyperdrive[i].move();
  }
  //control and display the player's bullets
  playerShip.moveBullets();
  


  //control and display the player's ship
  playerShip.move();
  //update player's health bar
  playerHealth.barWidth = playerShip.health;
  //update skeleton's health bar
  bossHealth.barHeight = skeleton.health;
  
  playerShip.display();

  //display the skeleton's health bar

  bossHealth.display();

  //display the player's health bar

  playerHealth.display();
  //display the skeleton boss
  skeleton.display();

  // shoot when the mouse is pressed and delay it to shoot every few milliseconds.
  if (mousePressed) {
    if (millis() >= timeCheck + 100) {
      playerShip.shoot();

      timeCheck = millis();
    }
  }
  
  //check the status of the game (win/lose)
  checkGameStatus();
}

//inspired by the circle_overlap adventures in code excersize and http://www.openprocessing.org/sketch/8005
//Check collisions of the player's bullets with the skeleton's head
boolean checkPBCollision() {
  if (dist(playerShip.bullet.position.x, playerShip.bullet.position.y, skeleton.bossCollision.position.x, skeleton.bossCollision.position.y) < playerShip.bullet.bulletRadius + skeleton.bossCollision.collisionWidth) {
    playerShip.bullet.moved = true;
    return true;
  } else {
    return false;
  }
}

// check the collisions of the skeleton's left hand's bullets and the player's ship
String checkLeftEBCollision() {
  if (dist(skeleton.leftHand.bullet1.position.x, skeleton.leftHand.bullet1.position.y, playerShip.shipCollision.position.x, playerShip.shipCollision.position.y) < skeleton.leftHand.bullet1.bulletRadius + playerShip.shipCollision.collisionWidth) {
    skeleton.leftHand.bullet1.removeBullet = true;
    return "L1";
  }
  if (dist(skeleton.leftHand.bullet2.position.x, skeleton.leftHand.bullet2.position.y, playerShip.shipCollision.position.x, playerShip.shipCollision.position.y) < skeleton.leftHand.bullet2.bulletRadius + playerShip.shipCollision.collisionWidth) {
    skeleton.leftHand.bullet2.removeBullet = true;
    return "L2";
  }
  if (dist(skeleton.leftHand.bullet3.position.x, skeleton.leftHand.bullet3.position.y, playerShip.shipCollision.position.x, playerShip.shipCollision.position.y) < skeleton.leftHand.bullet3.bulletRadius + playerShip.shipCollision.collisionWidth) {
    skeleton.leftHand.bullet3.removeBullet = true;
    return "L3";
  }
  if (dist(skeleton.leftHand.bullet4.position.x, skeleton.leftHand.bullet4.position.y, playerShip.shipCollision.position.x, playerShip.shipCollision.position.y) < skeleton.leftHand.bullet4.bulletRadius + playerShip.shipCollision.collisionWidth) {
    skeleton.leftHand.bullet4.removeBullet = true;
    return "L4";
  } else {
    return null;
  }
}

// check the collisions of the skeleton's right hand's bullets and the player's ship
String checkRightEBCollision() {
  if (dist(skeleton.rightHand.bullet1.position.x, skeleton.rightHand.bullet1.position.y, playerShip.shipCollision.position.x, playerShip.shipCollision.position.y) < skeleton.rightHand.bullet1.bulletRadius + playerShip.shipCollision.collisionWidth) {
    skeleton.rightHand.bullet1.removeBullet = true;
    return "R1";
  }
  if (dist(skeleton.rightHand.bullet2.position.x, skeleton.rightHand.bullet2.position.y, playerShip.shipCollision.position.x, playerShip.shipCollision.position.y) < skeleton.rightHand.bullet2.bulletRadius + playerShip.shipCollision.collisionWidth) {
    skeleton.rightHand.bullet2.removeBullet = true;
    return "R2";
  }
  if (dist(skeleton.rightHand.bullet3.position.x, skeleton.rightHand.bullet3.position.y, playerShip.shipCollision.position.x, playerShip.shipCollision.position.y) < skeleton.rightHand.bullet3.bulletRadius + playerShip.shipCollision.collisionWidth) {
    skeleton.rightHand.bullet3.removeBullet = true;
    return "R3";
  }
  if (dist(skeleton.rightHand.bullet4.position.x, skeleton.rightHand.bullet4.position.y, playerShip.shipCollision.position.x, playerShip.shipCollision.position.y) < skeleton.rightHand.bullet4.bulletRadius + playerShip.shipCollision.collisionWidth) {
    skeleton.rightHand.bullet4.removeBullet = true;
    return "R4";
  } else {
    return null;
  }
}

//check the game's status. Trigger game over if win/lose conditions are met.
void checkGameStatus() {
  if (skeleton.health <= 0) {
    status = "win";
    gameOver();
  }
  if (playerShip.health <= 0) {
    status = "lose";
    gameOver();
  }
}

//end the game by filling the screen with black and showing win/lose text.
void gameOver() {
  fill(0);
  rect(0, 0, 400, 600);
  fill(255);
  if (status == "win") {
    textSize(50);
    text("You win!", 100, 300);
  } else if (status == "lose") {
    textSize(50);
    text("You lose!", 100, 300);
  }
}
class boss {

  // variables
  PVector position = new PVector(), velocity = new PVector();
  float health;
  bossHand leftHand = new bossHand(100, 70, 1, 0, 40, 140, "left"), rightHand = new bossHand(300, 70, 1, 0, 260, 360, "right");
  collision bossCollision;

  //set variables for this object
  boss(float tempPosX, float tempPosY, float tempHealth) {
    this.position.x = tempPosX;
    this.position.y = tempPosY;
    this.health = tempHealth;
    bossCollision = new collision(position.x + 40, position.y + 30, 40, 40);
  }

  void display() {
    //draw the head
    drawHead();

    //draw and update the left arm and hand
    leftHand.move();
    leftHand.display();
    drawLeftArm();

    //draw and update the right arm and hand
    rightHand.move();
    rightHand.display();
    drawRightArm();

    //update collision ellipse on the boss head.
    bossCollision.update();
  }

  //draw the head
  void drawHead() {
    stroke(0);
    fill(255);
    rect(position.x, position.y, 80, 60);
    rect(position.x + 20, position.y + 60, 40, 20);

    strokeWeight(3);
    line(position.x + 30, position.y + 15, position.x + 30, position.y + 35);
    line(position.x + 50, position.y + 15, position.x + 50, position.y + 35);

    line(position.x + 30, position.y + 65, position.x + 30, position.y + 75);
    line(position.x + 40, position.y + 65, position.x + 40, position.y + 75);
    line(position.x + 50, position.y + 65, position.x + 50, position.y + 75);
    strokeWeight(1);
  }
  
  //draw the left arm
  void drawLeftArm() {
    stroke(0);
    fill(255);
    quad(160, 0, 160, 20, leftHand.position.x + 20, leftHand.position.y + 15, leftHand.position.x, leftHand.position.y);
  }

  //draw the right arm  
  void drawRightArm() {
    stroke(0);
    fill(255);
    quad(240, 0, 240, 20, rightHand.position.x - 20, rightHand.position.y + 15, rightHand.position.x, rightHand.position.y);
  }
  
  //take damage
  void takeDamage() {
    health -= 0.3;
  }
}
class bossHand {
  
  // make variables
  PVector position = new PVector(), velocity = new PVector();
  float leftBounds, rightBounds;
  int timeCheck = millis();
  boolean swap = true;
  String type;
  ArrayList<enemyBullet> bossBullets;
  enemyBullet bullet1, bullet2, bullet3, bullet4;
  
  //set variables for this object
  bossHand(float tempPosX, float tempPosY, float tempVelX, float tempVelY, float tempBoundL, float tempBoundR, String tempType){
    this.position.x = tempPosX;
    this.position.y = tempPosY;
    this.velocity.x = tempVelX;
    this.velocity.y = tempVelY;
    this.type = tempType;
    this.leftBounds = tempBoundL;
    this.rightBounds = tempBoundR;
    
    bossBullets = new ArrayList();
  }
  
  void display(){
    //draw hand
    stroke(0);
    fill(255);
    triangle(position.x, position.y, position.x + 20, position.y + 15, position.x - 20, position.y + 15);
    rect(position.x - 20, position.y + 15, 5, 10);
    rect(position.x - 7.5, position.y + 15, 5, 10);
    rect(position.x + 5, position.y + 15, 5, 10);
    rect(position.x + 15, position.y + 15, 5, 10);
    
    //shoot with a random time interval
    if (millis() >= timeCheck + random(50, 100)){
      shoot();
      
      timeCheck = millis();
    }
    //move bullets
    moveBullets();
  }
  
  //move hands
  void move(){
    //swap swaps directions based off true or false
    if (swap){
      position.add(velocity);
      
      if (position.x == rightBounds){
        swap = false;
      } 
    }
    else if (!swap){
      position.sub(velocity);

      if (position.x == leftBounds){
        swap = true;
      }
    }
  }
  
  //shoot bullets
  void shoot(){
    bullet1 = new enemyBullet(position.x - 20, position.y + 15, random(-10, 10), random(2, 8), 5, #E82C0C);
    bullet2 = new enemyBullet(position.x - 7.5, position.y + 15, random(-10, 10), random(2, 8), 5, #E82C0C);
    bullet3 = new enemyBullet(position.x + 5, position.y + 15, random(-10, 10), random(2, 8), 5, #E82C0C);
    bullet4 = new enemyBullet(position.x + 15, position.y + 15, random(-10, 10), random(2, 8), 5, #E82C0C);
    
    bossBullets.add(bullet1);
    bossBullets.add(bullet2);
    bossBullets.add(bullet3);
    bossBullets.add(bullet4);
  }
  
  //move bullets
  void moveBullets(){
    for (enemyBullet bullet1 : bossBullets){
      bullet1.update();
      bullet1.display();
        
        //check collisions for bullets from left hand with the player's ship, remove if collided
        if (type == "left"){
          if (checkLeftEBCollision() == "L1" && !bullet1.hit){
            bullet1.removeBullet = true;
            bullet1.hit = true;
            playerShip.health -= 0.5;
          }
          else if (checkLeftEBCollision() == "L2" && !bullet2.hit){
            bullet2.removeBullet = true;
            bullet2.hit = true;
            playerShip.health -= 0.5;
          }
          else if (checkLeftEBCollision() == "L3" && !bullet3.hit){
            bullet3.removeBullet = true;
            bullet3.hit = true;
            playerShip.health -= 0.5;
          }
          else if (checkLeftEBCollision() == "L4" && !bullet4.hit){
            bullet4.removeBullet = true;
            bullet4.hit = true;
            playerShip.health -= 0.5;
          }
        }
        //check collisions for bullets from right hand, remove if collided
        else if (type == "right"){
          if (checkRightEBCollision() == "R1" & !bullet1.hit){
            bullet1.removeBullet = true;
            bullet1.hit = true;
            playerShip.health -= 0.5;
          }
          else if (checkRightEBCollision() == "R2" & !bullet2.hit){
            bullet2.removeBullet = true;
            bullet2.hit = true;
            playerShip.health -= 0.5;
          }
          else if (checkRightEBCollision() == "R3" & !bullet3.hit){
            bullet3.removeBullet = true;
            bullet3.hit = true;
            playerShip.health -= 0.5;
          }
          else if (checkRightEBCollision() == "R4" & !bullet4.hit){
            bullet4.removeBullet = true;
            bullet4.hit = true;
            playerShip.health -= 0.5;
          }
        }
    }
  }
}
class collision{
  
  //make variables
  PVector position = new PVector();
  float collisionWidth, collisionHeight;
  
  //set variables
  collision(float tempX, float tempY, float tempWidth, float tempHeight){
    this.position.x = tempX;
    this.position.y = tempY;
    this.collisionWidth = tempWidth;
    this.collisionHeight = tempHeight;
  }
  
  void update(){
    //draw invisible collision ellipse
    noStroke();
    fill(0, 0, 0, 0);
    ellipse(position.x, position.y, collisionWidth, collisionHeight);
  }
}
class enemyBullet{
  
  // make variables
  PVector position = new PVector(), velocity = new PVector();
  color bulletColour;
  boolean removeBullet = false, hit = false;
  float bulletRadius;
  
  //set variables
  enemyBullet(float tempPX, float tempPY, float tempVX, float tempVY, float tempRadius, color tempColour){
    this.position.x = tempPX;
    this.position.y = tempPY;
    this.velocity.x = tempVX;
    this.velocity.y = tempVY;
    this.bulletRadius = tempRadius;
    this.bulletColour = tempColour;
  }
  
  void display(){
    //if the bullet is not removed, draw bullet
    if(!removeBullet){
      stroke(0);
      fill(bulletColour);
      ellipse(position.x, position.y, bulletRadius, bulletRadius);
    }
    // if the bullet goes out of bounds, remove it
    if(position.y > 620 || position.x < 0 || position.x > 400){
      removeBullet = true;
    }
  }
  
  void update(){
    //if the bullet is not removed, move it
    if(!removeBullet){
      position.add(velocity);
    }
  }
}
class healthBar {
  
  float x, y, barHeight, barWidth;
  color barColor;
  
  healthBar(float tempX, float tempY, float tempHeight, float tempWidth, color tempColor){
    this.x = tempX;
    this.y = tempY;
    this.barHeight = tempHeight;
    this.barWidth  = tempWidth;
    this.barColor = tempColor;
  }
  
  void display(){
    //draw the health bar
    stroke(0);
    fill(barColor);
    rect(x, y, barWidth, barHeight);
  }
}
class hyperdriveEffect {
  
  PVector position = new PVector(), velocity = new PVector();
  
  hyperdriveEffect(float tempPosX, float tempPosY, float tempVelX, float tempVelY){
    
    this.position.x = tempPosX;
    this.position.y = tempPosY;
    this.velocity.x = tempVelX;
    this.velocity.y = tempVelY;
  }
  
  void make(){
    //draw the effect
    noStroke();
    fill(255, 255, 255, 150);
    rect(position.x, position.y, random(1, 2), 10);
  }
  
  void move(){
    //move it
    position.add(velocity);
    
    //if the y position is offscreen, reset the y position at a new x position and a new random velocity
    if(position.y > 610){
      position.y = -10;
      position.x = random(0, 400);
      velocity.y = random(5, 20);
    }
  }
}
class playerBullet {

  PVector position = new PVector(), velocity = new PVector();
  float bulletRadius;
  color bulletColour;
  boolean moved = false, hit = false;
  
  playerBullet(float tempPositionX, float tempPositionY, float tempRadius, float tempVelocityX, float tempVelocityY, color tempColour) {
    this.position.x = tempPositionX;
    this.position.y = tempPositionY;
    this.bulletRadius = tempRadius;
    this.velocity.x = tempVelocityX;
    this.velocity.y = tempVelocityY;
    this.bulletColour = tempColour;
  }

  void display() {
    //draw bullet
    if (!moved){
      fill(bulletColour);
      ellipse(position.x, position.y, bulletRadius, bulletRadius);
    }
  }

  void move() {
  //move bullet. remove if it goes offscreen
    if(!moved){
      position.sub(velocity);
  
      if (position.y < -20) { 
          moved = true;
      }
    }
  }
}
class ship {

  ArrayList <playerBullet> bulletArrayList;
  PVector position = new PVector();
  float health = 400;
  playerBullet bullet, bullet2;
  collision shipCollision;

  ship() {
    bulletArrayList = new ArrayList();
    shipCollision = new collision(position.x, position.y, 20, 20);
  }

  void display() {
  //draw ship
    stroke(0);
    fill(#FF6300);
    rect(position.x - 5, position.y, 10, 20);

    fill(255);
    triangle(position.x - 7.5, position.y, position.x, position.y - 10, position.x + 7.5, position.y);

    rect(position.x - 12.5, position.y + 12, 3, -10);
    rect(position.x + 10, position.y + 12, 3, -10);

    fill(#FFEA02);
    triangle(position.x - 5, position.y + 5, position.x - 20, position.y + 20, position.x - 5, position.y + 20);
    triangle(position.x + 5, position.y + 5, position.x + 20, position.y + 20, position.x + 5, position.y + 20);
    
    //update collisions to follow ship
    shipCollision.update();
  }

  void move() {
    //move ship relative to mouse location
    if (mouseY > 100) {
      position.x = mouseX;
      position.y = mouseY;
      shipCollision.position.x = mouseX + 1;
      shipCollision.position.y = mouseY + 10;
    }
    // prevent the ship from going higher than 100
    else {
      position.x = mouseX;
      shipCollision.position.x = mouseX + 1;
    }
  }

  void shoot() {
    
    //make and shoot bullets
    bullet = new playerBullet(position.x - 12.5, position.y, 3, 0, 10, #FFEA02);
    bullet2 = new playerBullet(position.x + 12.5, position.y, 3, 0, 10, #FFEA02);

    bulletArrayList.add(bullet);
    bulletArrayList.add(bullet2);
  }

  void moveBullets() {
    //move and display bullets
    for (playerBullet bullet : bulletArrayList) {
      bullet.move();
      bullet.display();
      // check bullet collisions if they have collided with the skeleton
      if (checkPBCollision() && !bullet.hit) {
        skeleton.takeDamage();
        bullet.hit = true;
      }
    }
  }
}