Mid Term Project

BUBBLE POPPER – AN EDUCATIONAL APPROACH TO BUBBLE POPPING:)

  • Concept

The project is an educational game for children learning how to spell. The letters fall down from the top and the user (child in this case) can select the letters to make up the word that shows up on the screen.

The game was inspired by this small toy that my father bought for me when I was 5 years old. It had a small screen and the letters would drop down slowly.

The game is also just meant to be satisfying. During midterm season, I would just sit in the library and just pop the bubbles in the game just to relieve stress.

  • Description

The game works by creating circles with a letter associated with the circle. The circle is derived as a object of the droppedShape class. The objects populate an array that deletes them after the shapes or circles exit the screen. This was done as to not use up too much memory. The object also has access to the letter it hold. This letter is therefore, when clicked, on added to a new string that checks in every iteration if the target word had been made up.

The surrounding functions help display text and display the level/score. These variables are all globally stored. Which is conventionally a bad practice but help access the variable and manipulate in many different functions uniquely.

I’m particularly happy about the droppedShape class as it has been a running template for me to learn OOP. Outside of the project, I’ve tried to implement different things to this class and its nice to see it working well in the project.

//declare global variables 
let s;
let bubbleArr = [];
let numShapes = 10;
let howmanycircles = 10;
let deletedcircles = 0;
let rr = 0;
let bb = 0;
let gg = 0;
let img;
let timer = 5;
let newLetter;
var word;
var newword="";
let flag=true;
var new_wordSound;
var bpopped_sound;
let level=1;
let menu =0;
let gOverimage;
let bpop;

//alphabet array
const texts1 = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" ];

//letter concentration
let texts = ["A", "B", "C", "D", "E", "F", "G", "T", "T","U","H","R"];

//word bank

const words= ["CAT", "BAT", "HAT", "RAT", "MAT", "CAN", "JAM", "RAN"];

function preload(){
  img=loadImage("cat.webp");
  //loadSound('assets/new word sound.mp3');
  gOverimage=loadImage("game_over.gif");
  bpop = loadSound('sfx-pop.mp3');
}

//function for detecting the mouse press
function mousePressed(){
  for(let i = 0; i < bubbleArr.length; i++){
    bubbleArr[i].clicked(mouseX,mouseY,i);
    
  }
}

//text on top
class topText{
  constructor(){
    this.word=random(words);
    
  }
  disp(){
    if (flag==false){
      fill("red");
      for(let i=0;i<3;i++){
         while (newLetter==this.word[i]){
         textAlign(CENTER);
         text(this.word[i],50,200);
      }
     
    }
    }
    fill("white");
    //stroke("black");
    //strokeWeight(2);
    
    for(let i=0;i<3;i++){
      textSize(100);
      textAlign(CENTER);
      text(this.word[i],50,200);
    }
    
    
  }
  success(){
              if(newLetter==this.word[1]&&newLetter==this.word[2]&&newLetter==this.word[3]){
      flag=false;
      disp();
    
    }
    if(newLetter==this.word[1]||newLetter==this.word[2]||newLetter==this.word[3]){
      
    }
  }
  
}

//Shape being dropped 
class droppedCircle{
  constructor() {
    this.x = random(width);
    this.y = 0;
    this.width = random(38, 45);
    this.speed = random(0.5,3);
    this.r = random(250);
    this.g = random(250);
    this.b = random(250);
    this.text= texts[Math.floor(Math.random() * texts.length)]
  }
   move() {
    this.y += this.speed;
  }

  display() {
    fill(this.r,this.g,this.b);
    stroke(255);
    strokeWeight(2);
    ellipse(this.x, this.y, this.width, this.width);
    for (let i = 0; i < bubbleArr.length; i++){
          strokeWeight(1);
          fill("#000000");
          textAlign(CENTER);
          textSize((bubbleArr[i].width)/2);
          text(bubbleArr[i].text, bubbleArr[i].x, bubbleArr[i].y);
        
      
    }

    this.move();
  }

  clicked(px,py,index){
    let d = dist(px,py,this.x,this.y);
    if(d < this.width){
      rr = this.r;
      bb = this.b;
      gg = this.g;
      //insert sound
      bpop.play();
      
      bubbleArr.splice(index,1);
      numShapes--;
      newLetter=this.text;
      //console.log(newLetter);
      newword+=newLetter;
        
      
      //console.log(newword);
      if (match(newword, word)==word){
        //console.log("Success");
        word=random(words);
        level++;
        //new_wordSound.play();
        //if (new_wordSound.isPlaying()){
        //  new_wordSound.stop();
        //}
      }
    }
    
  }
  
}

function setup() {
  createCanvas(400, 400);
  s = new droppedCircle();
  
  for(let i = 0; i < numShapes; i++){
    bubbleArr[i] = new droppedCircle();
  }
  //m= new topText();
  //topText.disp();
  word=random(words);
}

//prints word to screen
function drawWord(Aword){
  let success = 0;
  while (success!=1){
    textSize(100);
    textAlign(CENTER);
    text(Aword,200,100);
    
    success=1;
  }
}

function printScore(L){
    textSize(10);
    textAlign(CENTER);
    text("LEVEL: ", 20,10);
    text(L,50,10);
}

function makeArr(arrWord){
  for (let i=0; i<length.arrWord; i++){
    
    append(texts,arrWord[i]);
    
    
  }
  for (let i=0;i<level;i++){
    append(texts, random(texts1));
  }
}

//HOME SCREEN
function homeScreen(){
  background(img);
  textSize(30);
  textAlign(CENTER);
  text("PWEESE PWES ENTER",200,50);
}


//GAME
function playGame(){
  
  background(rr,gg,bb);
  //image(img,0,0);
  smooth();
  fill("white");
  stroke(20);
  textSize(50);
  text(timer, 350, 50);
  if (frameCount % 60 == 0 && timer > 0) { 
    timer --;
  }
  if (timer == 0) {
    text("GAME OVER", width/2, height*0.7);
    //noLoop();
  }
   
  printScore(level);
  //console.log(word);
  drawWord(word);
  makeArr(word);
  
  //s.display();
  
  for(let i = 0; i < numShapes; i++){
    bubbleArr[i].display();
    if(bubbleArr[i].y > height){
      bubbleArr.splice(i,1);
      numShapes--;
      deletedcircles++;
    }
   for(let i = 0; i < words.size; i++){
     //while ()
    
       
    }
  }
  
  
  // print("numshapes:",numShapes,howmanycircles,deletedcircles);
  
  
  let rand = int(random(0, 100));
  let rand2 = int(random(0, 100));
  if(rand % 7 == 0){
    if(rand2 % 3 == 0){
    bubbleArr[numShapes] = new droppedCircle();
    numShapes++;
      howmanycircles++;
     }
  }
  // print(numShapes,rand);
}

//EXIT SCREEN
function exitScreen(){
    background("black");
    image(gOverimage, 0, 0);
    textAlign(LEFT);
    fill("red");
    text("Press ESC", 250,300);
}

//togoling between game modes
function keyPressed(){
  if (keyCode === ENTER) {
    menu=1;
  } 
  if (keyCode===' '){
    menu=1;
  }
  if (keyCode===ESCAPE){
    menu=0;
  }
}

//main function
function draw() {
  if (timer==1){
    exitScreen();
    
    
    if (menu==0){
      homeScreen();
      timer=30;
    }
  }
  else if (menu==0){
    homeScreen();
    if (keyPressed==1) { menu=1;}
  }
  else if(menu ==1){
    playGame();
  }
  
  //playGame();
  //console.log(timer)
  
  
  
  

}

And the following is the sketch:

  • Problems

A large I could not overcome was the proper implementation of the diplayedWord class, this was intended to highlight every letter of the target word in a different color when the bubble containing the letter is clicked. However, I believe my implementation of the call had a incorrect constructor not allowing the object to be properly created.

The second problem was the program slowing down significantly after the first iteration. This is probably because of the program does not reset the game mode when replaying.

The third problem was the randomization. It proves to be the fatal flaw in the program keeping in mind the purpose and the intended audience. The letters that fall are much too randomized and must have been more concentrated to have provided a better gaming/ learning experience.

 

Leave a Reply