Midterm Project: Catching Fallen Stars (Taiwanese Version)

Catching fallen stars(Taiwanese Version)

INSPIRATION:

There is a Taiwanese myth about catching fallen stars to make a wish come true. I intend to create a game that consists of a traditional Taiwanese bamboo woven basket and white stars falling from the night sky.

RULES:

The way to win is to collect 66 stars (white). The players would lose one life if hit by fallen satellite remains (red). They have three lives in total and loses the game when all three lives are wasted. However, players can catch Taiwanese street food (green) to restore lost lives.

OBJECTS:
  • Background: import an image of the Taiwanese famous night sky of lanterns
  • Sound: Background music – summer night time in Taiwanese mountains
  • Object behavior:
    1. Stars: falling with medium speed
    2. Satellite: falling with extremely fast speed
    3. Food: falling with extremely low speed
STORYBOARD:
  1. MENU (START)
  2. STORY
  3. RULES
  4. GAME
  5. Restart
    1. win
    2. lose
CHALLENGES: 
    1. The hardest part was the collision detection. It was hard to wrap my head around the logic. For the satellite remains, player lives should have decrement one when one satellite hits, but for some reason, perhaps the boundary setting or the collision content, player lives decrease ridiculously fast. However, sometimes it works perfectly. I am still in the process of figuring it out.
    2. Slight mistake: not clarifying how to play the game (what key to press)
CODES:
1. Main Function
PImage sky;
PImage stinkyTofu;
PImage sausage;
PImage oysterOmlette; 

//another variable name to create another object
Fall [] fallStars;
Fall [] fallGood;
Fall [] fallBad;

import processing.sound.*;
SoundFile bgMusic;
//SoundFile winMusic;
//SoundFile loseMusic;

//setup the basket
int stage;
float basketWidth = 100;
float basketHeight = 50;
float X = 384;
float Y = 723;
color basketColor = color(188, 123, 25);
int lives = 3;
int stars = 0;
boolean goLeft = false;
boolean goRight = false;


void setup() {
  size (1024, 768);
  
  bgMusic = new SoundFile (this, "/Users/chi-tingtsai/Downloads/summer night.mp3");
  bgMusic.loop();
  //winMusic = new SoundFile (this, "/Users/chi-tingtsai/Documents/Processing/Intro_to_IM_Midterm_ver2/data/win.mp3");
  //loseMusic = new SoundFile (this, "/Users/chi-tingtsai/Documents/Processing/Intro_to_IM_Midterm_ver2/data/lose.mp3");
  stage = 0;
  
  //setup the falling objects
  fallStars = new Fall[10];
  for (int k=0; k<fallStars.length; k++) {
    fallStars[k] = new Fall(random(width), 0, random(2, 7), color(255));
  }
  fallGood = new Fall[5];
  for (int i=0; i<fallGood.length; i++) {
    fallGood[i] = new Fall(random(width), 0, random(1, 5), color(94, 240, 134));
  }
  fallBad = new Fall[15];
  for (int l=0; l<fallBad.length; l++) {
    fallBad[l] = new Fall(random(width), 0, random(6, 10), color(234, 83, 131));
  }
}

//EXECUTION
void draw () {
  if (stage == 0) {
    menu();
  }
  if (stage == 3) {
    playGame();
  }
}

void keyReleased() {
  goLeft = false;
  goRight = false;
  if (key == ' ' && stage == 0) {
    stage = 1;
    story();
  } else if (key == ' ' && stage == 1) {
    stage = 2;
    rules();
  } else if (key == ' ' && stage == 2) {
    stage = 3;
  } else if (key == ' ' && stage == 3) {
    for (int k=0; k<fallStars.length; k++) {
      fallStars[k].restart();
    }

    for (int i=0; i<fallGood.length; i++) {
      fallGood[i].restart();
    }

    for (int l=0; l<fallBad.length; l++) {
      fallBad[l].restart();
    }
  }
}
2. MENU FUNCTION:
color frame = color(237, 168, 17);

void menu() {
  background(color(99, 144, 130));
  fill(255);
  textAlign(CENTER);
  PFont F = createFont("PatuaOne-Regular", 1);

  //explain how to start
  textFont(F, 30);
  text("Press Space Bar to Begin Game", width/2, height*3/4);
  //explain this game
  textFont(F, 50);
  text("CATCHING FALLEN STARS\n(TAIWANESE VERSION)", width/2, height/2-50);

  //frame
  noStroke();
  rectMode(CENTER);
  fill(frame);
  rect(width/2, 10, width, 20);
  rect(width/2, height-10, width, 20);
  rect(10, height/2, 20, height);
  rect(width-10, height/2, 20, height);
}
3. STORY:
int rectWidth = width/10;
int rectHeight = height/10;
float bg, up, mid, down;

void story() {
  background(color(99, 144, 130));
  fill(255);
  textAlign(CENTER);
  PFont F = createFont("PatuaOne-Regular", 1);

  //explain how to start
  textFont(F, 50);
  text("STORY", width/2, height/4);
  textFont(F, 30);
  text("A long time ago,\nDeep in the mountains of Yu and Ali,\nThere was a lake called Sun Moon Lake.\nRumor has it that if you collected enough fallen stars\nDuring Mid Autumn Festival,\nYour fears will disipate,\nInsecurities will calm,\nAnd peace will shine on you.", width/2, height/2-120);

  //frame
  noStroke();
  rectMode(CENTER);
  fill(frame);
  rect(width/2, 10, width, 20);
  rect(width/2, height-10, width, 20);
  rect(10, height/2, 20, height);
  rect(width-10, height/2, 20, height);

  //Next to Rules
  textFont(F, 40);
  text("Press Space Bar to Continue", width/2, height*3/4+75);
}
4. RULES:
int size = 200;
void rules() {
  stinkyTofu = loadImage("stinkytofu.jpeg");
  stinkyTofu.resize(size, size);
  sausage = loadImage("sausage.jpeg");
  sausage.resize(size, size);
  oysterOmlette = loadImage("oysteromlette.jpeg");
  oysterOmlette.resize(size-30, size-30);

  background(color(99, 144, 130));
  fill(255);
  textAlign(CENTER);
  PFont F = createFont("PatuaOne-Regular", 1);

  //display images of food
  image(stinkyTofu, 30, 30);
  image(sausage, 784, 30);
  image(oysterOmlette, width-200, height - 200);

  //explain how to play
  textFont(F, 50);
  text("RULES", width/2, height/4);
  textFont(F, 30);
  text("The way to win is to catch 66 stars(white)\nwith you bamboo woven basket\nYou have three lives in total.\nYou lose one life if hit by a satellite (red).\nYou lost the game when all lives are wasted.\nHowever, you can catch Taiwanese street food(green)\nto restore lost lives.", width/2, height/2-60);

  //frame
  noStroke();
  rectMode(CENTER);
  fill(frame);
  rect(width/2, 10, width, 20);
  rect(width/2, height-10, width, 20);
  rect(10, height/2, 20, height);
  rect(width-10, height/2, 20, height);
}
5. PLAY GAME:
void playGame() {
  sky = loadImage("pinxi sky lantern.jpeg");
  sky.resize(width, height);
  PFont F = createFont("PatuaOne-Regular", 1);
  noStroke();

  //background
  background (255);
  image (sky, 0, 0);

  //objects start falling
  for (int k=0; k<fallStars.length; k++) {
    fallStars[k].runFall();
  }

  for (int i=0; i<fallGood.length; i++) {
    fallGood[i].runFall();
  }

  for (int l=0; l<fallBad.length; l++) {
    fallBad[l].runFall();
  }

  //different kinds of collision
  for (int i=0; i<fallStars.length; i++) {
    fallStars[i].starcollision();
  }

  for (int k=0; k<fallGood.length; k++) {
    fallGood[k].goodcollision();
  }

  for (int l=0; l<fallBad.length; l++) {
    fallBad[l].badcollision();
  }

  //player basket
  rectMode(CENTER);
  fill(basketColor);
  rect(X, Y, basketWidth, basketHeight);
  if (goLeft == true) {
    X -= 15;
  }
  if (goRight == true) {
    X += 15;
  }

  if (stars == 66 && stage == 3) {
    background(color(99, 144, 130));
    textFont(F, 80);
    fill(255);
    text("Congratulations! You have done it!", width/2, height/2);
    textFont(F, 50);
    text("Have you found your peace?\nOr even more chaotic?\nhehe)", width/2, height/2-50);
    textFont(F, 30);
    text("Press Space Bar to Restart", width/2, height/2+50);
  }

  if (lives == 0 && stage == 3) {
    background(color(99, 144, 130));
    textFont(F, 80);
    fill(255);
    text("Game Over...", width/2, height/2);
    textFont(F, 50);
    text("Awwww... Press Space Bar to Restart?", width/2, height/2+50);
  }

  //show lives to player
  textSize(24);
  fill(color(90, 167, 247));
  text("LIVES:", width -120, height - 50);
  text(lives, width - 60, height - 50);

  //show lives to player
  fill(color(255));
  text("STARS:", 90, 60);
  text(stars, 160, 60);

  //frame
  noStroke();
  rectMode(CENTER);
  fill(frame);
  rect(width/2, 10, width, 20);
  rect(width/2, height-10, width, 20);
  rect(10, height/2, 20, height);
  rect(width-10, height/2, 20, height);
}

void keyPressed() {
  if (keyCode == LEFT) {
    goLeft = true;
  } 
  else if (keyCode == RIGHT) {
    goRight = true;
  }
  if (X <= basketWidth/2 + 10) {
    goLeft = false;
    X = basketWidth/2;
  }
  if (X >= width - basketWidth/2 - 10) {
    goRight = false;
    X = width - basketWidth/2;
  }
}
6. CLASS for Fallen Objects:
//VARIABLE
boolean goodtouch = false;
boolean badtouch = false;
boolean startouch = false;

class Fall {
  float posX, posY;
  float objectWidth;
  float objectHeight;
  color fallColor;
  float speed;

  //CONSTRUCTER
  Fall(float _posX, float _posY, float _speed, color _colorFall) {
    posX = _posX;
    posY = _posY;
    objectWidth = objectHeight = 20;
    fallColor = _colorFall;
    speed = _speed;
  }

  //FUNCTIONALITY
  void runFall() {
    colorFall();
    beginFall();
  }

  void colorFall() {
    fill(fallColor);
    noStroke();
    rect(posX, posY, objectWidth, objectHeight);
  }

  void beginFall() {
    posY += speed;
    if (posY > height+objectHeight/2) {
      posY = -objectHeight/2;
      reset();
    }
  }

  void reset() {
    posX = random(0, width);
  }

  void goodcollision() {
    if (posY + (objectHeight+basketHeight)/2 > Y && posY - (objectHeight+basketHeight)/2 < Y &&
      posX - (objectHeight+basketHeight)/2 < X && posX + (objectHeight+basketHeight)/2 > X && !goodtouch) {
      goodtouch = true;
      lives ++;
    }
    if (posY > height && goodtouch ==true) {
      goodtouch = false;
    }
    if (lives > 3) {
      lives = 3;
    }
  }

  void badcollision() {
    if (posY + (objectHeight+basketHeight)/2 > Y && posY - (objectHeight+basketHeight)/2 < Y
      && posX - (objectHeight+basketHeight)/2 < X && posX + (objectHeight+basketHeight)/2 > X && !badtouch) {
      badtouch =true;
      lives --;
    }
    if (posY > height && badtouch ==true) {
      badtouch = false;
    }
    if (lives < 0) {
      lives = 0;
    }
  }

  void starcollision() {
    if (posY + (objectHeight+basketHeight)/2 > Y && posY - (objectHeight+basketHeight)/2 < Y
      && posX - (objectHeight+basketHeight)/2 < X && posX + (objectHeight+basketHeight)/2 > X && !startouch) {
      startouch = true;
      stars ++;
    }
    if (posY > height && startouch ==true) {
      startouch = false;
    }
  }
  
  void restart() {
    stage = 3;
    lives = 3;
    stars = 0;
    posY = 0;
  }
}

 

Leave a Reply