For the Week 3 assignment, I decided to make a game, and in order to make it a little more fun, I decided to make it NYUAD-themed (at least a little). However, this turned out a little harder than I expected it to be. I had the idea of a fun but very simple game, but the implementation was not-so-simple.
My game is based on a very basic concept. The player plays the game as Faiza the Falcon, and uses arrow keys to help Faiza dodge all distractions on the way and to eventually reach the 4.0 GPA. I was so excited when I started making the game that I created the sprite for Faiza myself using https://www.piskelapp.com/. Attached below is a screenshot of the game. A screen recording is also attached at the end (I’m sorry for the lag, my laptop does not cooperate when I start screen recording).
Implementation
Even when I started creating the game, it was clear that I had to create it using four classes; the Faiza class, the GPA class, the Distractions class and the main Game class.
Within the Faiza class, I had to work on controlling Faiza through the arrow keys, checking edges to ensure that Faiza didn’t go beyond the screen, displaying Faiza, and checking Faiza’s collisions with the distractions and with the GPA (collision with the GPA marked the end of the game). I made a separate distance() method within the Faiza class for collision detection. This method would return the distance between Faiza and the other object, and if this distance was less than the sum of their radii, then a collision was detected. Figuring this out was one of the more difficult parts of making the game.
The GPA class was straightforward and was nothing more than displaying the GPA.
The distractions class involved some additional elements. I instantiated each distraction at specific coordinates (because if it was random then there could be a scenario where it would be almost impossible to win the game). I assigned random x and y velocities (but within a certain range) to each distraction which would mean that the structure of the game was different every time. It was also important to ensure that the distractions would rebound whenever any of them hit any of the walls.
Lastly, the game class was mainly about displaying text and calling display methods of other objects.
Challenges
Firstly, I had a hard time working with methods of classes. The update and display methods of each class left me confused. I knew I had to use these two methods but couldn’t figure out how to exactly work with them. I ended up calling my update() method inside the display() method, and now I understand how it did the job for me.
Working with image objects was confusing for some reason. I never intended to use so many different images but then the game would look boring. I had to do a lot of research to get comfortable with using images.
Attached below are the video and the code.
import java.lang.Math; import processing.sound.*; SoundFile file; String audioName = "intro.mp3"; String path; PImage[] images; Game game; // creating an array for distractions which are used later Distractions[] distractions; class Faiza{ float posX, posY; float radius; float velocityX; float velocityY; float imgwidth, imgheight; String directionX; String keyY, keyX; boolean alive; int counter, frame; Faiza(float x, float y, float r, float img_w, float img_h){ posX = x; posY = y; radius = r; velocityX = 0; velocityY = 0; imgwidth = img_w; imgheight = img_h; directionX = "right"; keyY = "none"; keyX = "none"; alive = true; counter = 0; frame = 0; } void display(){ update(); if (directionX == "right"){ image(images[0], float(int(posX - imgwidth/2)), float(int(posY - imgheight/2)), imgwidth, imgheight, int(frame * imgwidth), 0, int((frame + 1) * imgwidth), int(imgheight)); } else if (directionX == "left"){ image(images[0], float(int(posX - imgwidth/2)), float(int(posY - imgheight/2)), imgwidth, imgheight, int((frame + 1) * imgwidth), 0, int(frame * imgwidth), int(imgheight)); } } void update(){ //The condition below is for when Faiza moves left if (keyX == "left"){ velocityX = -2; if (posX - radius + velocityX < 6){ velocityX = 0; } posX += velocityX; } //The condition below is for when Faiza moves right else if (keyX == "right"){ velocityX = 2; if (posX + radius + velocityX > 1018){ velocityX = 0; } posX += velocityX; } //If none of the left and right keys are being pressed, Faiza stops moving horizontally else{ velocityX = 0; } if (keyY == "up"){ velocityY = -2; if (posY - radius + velocityY <= 5){ velocityY = 0; } posY += velocityY; } //The condition below is for when Faiza moves downwards else if (keyY == "down"){ velocityY = 2; if (posY + radius + velocityY >= 762){ velocityY = 0; } posY += velocityY; } //If none of the up and down keys are being pressed, Faiza stops moving vertically else{ velocityY = 0; } if (distance(game.gpa) <= (radius + game.gpa.radius)){ game.level += 1; } if (!(posX >= 0 && posX <= 100 && posY >= 530 && posY <= 640)){ for (int i = 0; i < 6; i++){ if (distance(distractions[i]) <= radius + distractions[i].radius){ counter += 1; println(counter); alive = false; } } } } // this distance method will be used to check for collisions with distractions double distance(Distractions target){ float a = (posX - target.posX); float b = (posY - target.posY); double c = Math.pow(a, 2); double d = Math.pow(b, 2); return Math.pow(c + d, 0.5); } // this distance method will be used to check for collisions with the gpa (marking the end of the game) double distance(GPA target){ float a = (posX - target.posX); float b = (posY - target.posY); double c = Math.pow(a, 2); double d = Math.pow(b, 2); return Math.pow(c + d, 0.5); } } class Distractions{ float posX, posY; float radius; float imgwidth, imgheight; int frame; PImage img; float velocityX, velocityY; Distractions(float x, float y, float r, String _img, float img_w, float img_h){ posX = x; posY = y; radius = r; img = loadImage(_img); imgwidth = img_w; imgheight = img_h; frame = 0; velocityX = random(2,5); velocityY = -1 * random(2,5); } void update(){ if (posX + radius >= 1024){ velocityX *= -1; } if (posX - radius <= 0){ velocityX *= - 1; } if (posY - radius <= 10){ velocityY *= -1; } if (posY + radius >= 780){ velocityY *= -1; } posX += velocityX; posY += velocityY; } void display(){ update(); image(img, float(int(posX - imgwidth/2)), float(int(posY - imgheight/2)), imgwidth, imgheight, int(frame * imgwidth), 0, int((frame + 1) * imgwidth), int(imgheight)); } } class GPA{ float posX, posY; float radius; float imgwidth, imgheight; int frame; GPA(float x, float y, float r, float img_w, float img_h){ posX = x; posY = y; radius = r; imgwidth = img_w; imgheight = img_h; frame = 0; } void display(){ image(images[1], float(int(posX - imgwidth/2)), float(int(posY - imgheight/2)), imgwidth, imgheight, int(frame * imgwidth), 0, int((frame + 1) * imgwidth), int(imgheight)); } } class Game{ float game_width, game_height; Faiza faiza; GPA gpa; int level; Game(float game_wth, float game_hght){ level = 1; game_width = game_wth; game_height = game_hght; faiza = new Faiza(34, 585, 27, 66, 66); gpa = new GPA(990, 35, 25, 70, 56); } void update(){ if (faiza.alive == false){ faiza.posX = 34; faiza.posY = 585; faiza.alive = true; } } void display(){ update(); image(images[2], 0, 0); if (level == 1){ textMode(CENTER); textSize(40); fill(255, 213, 43); text("GET THAT 4.0!", 310, 65); } if (level != 1){ textSize(150); fill(255, 213, 43); text("GAME", 270, 220); text("OVER", 290,350); textSize(50); text(faiza.counter + " distractions later,", 240, 550); text("you achieved that 4.0 GPA!", 200, 600); } if (level == 1){ faiza.display(); gpa.display(); } for (int i = 0; i < 6; i++){ distractions[i].display(); } } } void setup(){ size(1024,768); game = new Game(1024, 768); path = sketchPath(audioName); file = new SoundFile(this, path); file.loop(); images = new PImage[3]; images[0] = loadImage("faiza.png"); images[1] = loadImage("gpa.png"); images[2] = loadImage("background.png"); distractions = new Distractions[6]; distractions[0] = new Distractions(100, 300, 58, "jake.png", 120, 120); distractions[1] = new Distractions(444, 333, 48, "insta.png", 100, 100); distractions[2] = new Distractions(900, 120, 48, "facebook.png", 100, 100); distractions[3] = new Distractions(887, 635, 48, "netflix.png", 100, 100); distractions[4] = new Distractions(134, 587, 48, "youtube.png", 100, 100); distractions[5] = new Distractions(55, 100, 48, "ps.png", 120, 120); } void draw(){ background(255, 255, 255); game.display(); } // allowing key presses to dictate Faiza's movement void keyPressed(){ if (key == CODED){ if (keyCode == RIGHT){ game.faiza.keyX = "right"; } if (keyCode == LEFT){ game.faiza.keyX = "left"; } if (keyCode == UP){ game.faiza.keyY = "up"; } if (keyCode == DOWN){ game.faiza.keyY = "down"; } } } void keyReleased(){ if (key == CODED){ if (keyCode == RIGHT){ game.faiza.keyX = "none"; } if (keyCode == LEFT){ game.faiza.keyX = "none"; } if (keyCode == UP){ game.faiza.keyY = "none"; } if (keyCode == DOWN){ game.faiza.keyY = "none"; } } }