This week’s assignment was to create a game using Object-Oriented Programming. My idea for the game was inspired by one of my favorite childhood computer games in which we had to collect apples to gain points and beware of the bombs which reduced points. For this project, I wanted to recreate this game.
Object-Oriented Programming was ideal to create this game because I could create the falling objects and the basket as separate classes and then manipulate each one of those in a much easier manner by just varying a few parameters than having to deal with each object individually.
I started with first creating a falling object class in which I had apples and my first goal was to make them move as required – changing their x position each time they came again onto the screen for the next round and even increasing their speed the longer the game progresses to increase difficulty (see below). Then came the basket class and making it move according to user input.
With the basket:
Once I managed to move the apple and the basket as I desired, the next step was to check whether the user actually caught the fruit in the basket or not. Checking for this and increasing the score for it was relatively easy, however, creating a sense that the fruit was actually being captured in the basket was quite difficult. See my first attempt to check for collision:
Clearly, the score is increasing, but no user would know they caught the fruit unless they look at it. This is not user-friendly at all because you cannot concentrate not the game if you have to look at the score again and again. so, it was important that the fruits disappeared once they collided with the basket. However, the problem with this was that I was displaying the fruit image in the run() method of the class but I was checking for collision outside the class. So, if I used tint() to make the opacity of the object zero, everything on the canvas would go transparent. If I put this in the class function, the image in the run() would still draw the fruit, and the purpose of making it invisible failed.
I managed to solve this problem by first rearranging a few lines in the code so that the layering would be appropriate for what I was going to do next. I then created another class member (variable) which kept track if the object collided or not. I would only display the image in the run() method of the class if visible was true (see code below).
DETAILING
Once I got the semantics of the game in place, it was time for some diversity! I first added a scenic background to make it interface pleasing and then I decided to have different fruits; each amounting to different points. I also decided to have a stone (equivalent to the bomb in my childhood game) to make it more interesting. The game would finish when the score would go less than zero.
USER EXPERIENCE
What is a game if you do not know what to do or see how your game went? So, along with creating an illusion of fruits falling in the basket by making my fruits disappear after collision, I decided to have an initial instructions menu and a “Game Over” comment in the end with the display of the user’s highest score achieved during the game for enhanced user experience. I learned how to display text on the screen for this project!
See a video of my final game in progress:
The speed of the falling fruits increases the longer the game progresses to increase the difficulty:
CODE
My class Obj for the falling objects (the different fruits and stones):
class Obj { float posX, posY; float objWidth, objHeight; float speed; PImage objImg; int points; int imgCode; boolean scored; //to not keep adding score for basket height boolean visible; //to make it dissapear when fals in the basket //constructor Obj(int _imgCode, PImage _img) { objWidth = random(30, 60); objHeight = objWidth*780/801; //original pic ratio = 801x780 posX = random(width-objWidth)+objWidth/2; posY = 0-objHeight/2; speed = random(1, 3); imgCode= _imgCode; objImg = _img; //points = 10; scored = false; visible = true; assign(); println(speed); } void fallObj() { posY += speed; if (frameCount%300==0 && speed<25) //cap on speed so that it doesnt get too fast { speed*=1.2; //speed of game keeps increasing to increase difficulty //println(frameCount); //println(speed); } } void checkEdge() { if (posY > height+objHeight/2) { posX = random(width-objWidth)+objWidth/2; posY = 0-objHeight/2; scored = false; visible = true; } } void run() { fallObj(); if (visible == true) image(objImg, posX, posY, objWidth, objHeight); checkEdge(); } void assign() { if (imgCode == 0) { points = -50; speed++; //icrease the speed of rocks a bit } else if (imgCode == 1) points = 5; else if (imgCode == 2) points = 15; else if (imgCode == 3) points = 20; } }
My class Basket:
class Basket { float posX, posY; float bWidth, bHeight; float speed; PImage bImg; //int points; //constructor Basket(PImage _img) { bWidth = 180; bHeight = bWidth/2; //original pic ratio = posX = width/2; posY = height-bHeight/2; speed=15; bImg = _img; } void run() { image(bImg, posX, posY, bWidth, bHeight); if (frameCount%300==0 && speed<40) //cap on speed so that it doesnt get too fast { speed*=1.5; //to increase speed of basket as game gets faster } } void shiftR() { //if (posX<width-bWidth/2) if (posX<width-bWidth/2-speed) posX+=speed; else posX=width-bWidth/2; image(bImg, posX, posY, bWidth, bHeight); } void shiftL() { if (posX>0+bWidth/2+speed) posX-=speed; else posX=bWidth/2; image(bImg, posX, posY, bWidth, bHeight); } }
The main draw() function:
Obj[] objects; Basket basket; PImage[] objImgs; PImage basketImg; PImage bg; //background image for game int score = 0; int maxScore = 0; //to display in the end boolean started = false; //to keep track of start screen color beige = color(225, 198, 153); //================================================================================================== void setup() { size(1000, 650); //fullScreen(); //loading the background bg = loadImage("bg7.jpeg"); //loading the various object images - fruits, basket and stone objImgs = new PImage[4]; objImgs[1] = loadImage("apple1.png"); //code 1 = apple = 5 points objImgs[2] = loadImage("mango1.png"); //code 2 = mango = 15 ponits objImgs[3] = loadImage("pear1.png"); //code 3 = pear = 20 ponts objImgs[0] = loadImage("rock.png"); //code 0 = enemy = -50 points basketImg = loadImage("basket4.png"); rectMode(CENTER); imageMode(CENTER); //creating my objects for the game basket = new Basket(basketImg); //falling objects objects = new Obj[9]; for (int i=0; i<objects.length; i++) { int imgCode = i%objImgs.length; objects[i] = new Obj(imgCode, objImgs[i%objImgs.length]); } } //================================================================================================== void draw() { if (started == false) startScreen(); else { //background(bg); image(bg, width/2, height/2, width, height); basket.run(); for (int i = 0; i<objects.length; i++) { objects[i].run(); } scoring(); } } //================================================================================================== void keyPressed() { if (started) { if (key == 'd' || (key == CODED && keyCode == RIGHT)) basket.shiftR(); if (key == 'a' || (key == CODED && keyCode == LEFT)) basket.shiftL(); } if (key == ENTER) started = true; if (key == BACKSPACE) endScreen(); } //================================================================================================== void scoring() { fill(255); textSize(30); textAlign(LEFT); text("SCORE: " + score, 20, 40); //check if any fruit caught in basket for (int i=0; i<objects.length; i++) { if (objects[i].posX+objects[i].objWidth/2>=basket.posX-basket.bWidth/2 && objects[i].posX-objects[i].objWidth/2<=basket.posX+basket.bWidth/2 && objects[i].posY>=basket.posY-basket.bHeight/3 && objects[i].scored == false) { score+=objects[i].points; objects[i].scored = true; objects[i].visible = false; } } if (maxScore<score) maxScore=score; if (score<0) endScreen(); } //================================================================================================== void startScreen() { background(beige); fill(255); textAlign(CENTER); textSize(40); text("SHREYA'S FARMLAND", width/2, height/4); textSize(20); text("Collect the fruits in the basket,", width/2, height/3); text("BEWARE of the stones!", width/2, height/3+25); textSize(15); text("Points gained are as follows:", width/2, height/3+80); //textAlign(LEFT,CENTER); text("Apple : +05", width/2, height/3+100); text("Mango: +15", width/2, height/3+120); text("Pear : +20", width/2, height/3+140); text("Stone : -50", width/2, height/3+160); textSize(15); text("Press ENTER to start the game, press BACKSPACE to quit", width/2, height*3/4); //text("Press BACKSPACE to quit", width/2, height*3/4); } //================================================================================================== void endScreen() { noLoop(); //tint(255,50); background(beige); //noTint(); fill(255); textAlign(CENTER); textSize(40); text("GAME OVER!", width/2, height/2-40); textSize(20); text("Your Highest Score: " + maxScore, width/2, height/2+20); }