MIDTERM: PONG STREAK

Concept:

My idea for my midterm project has changed more times than I count. What was first supposed to be a snowball fight became a volleyball game, then a tennis rally, and then finally settled into a ping pong streak game. Because I kept facing challenges and had to make adjustments to my plans and codes, this project took SUCH a long time even though the end result seems to be (a little bit too) simple. I decided to make the game in such a way so that the way to win is to get 5 points under the time constraint of 20 seconds.

Process/Coding:

Because my pong streak game was inspired by/is an alteration of the pong game, I decided to play the actual online pong game in order to get a grasp of what kind of elements I should add in my coding. Then, I searched up simulations/coding process of the pong game that others have posted, and I found this video to be extremely helpful in terms of what kind of objects that I will need to include in my tennis game as well as what point of the game I can start from, such as “paddles” and the pong ball.

One technique that came in handy was the “function preload()” skill, which I used to upload an image, audio file, and a font style! Here’s the code that I used with this function:

function preload() {
  font = loadFont("JetBrainsMono-ExtraBold.ttf");
  song = loadSound("media_doorbell.mp3");
  photo = loadImage("cat.webp");
}

Then, I used the mouseX function for the pong bar/paddle so that it will freely move by the player’s intentions.

Once I was done with the paddle, I moved onto creating the title of the game, as well as the tennis ball itself. As for inserting the title “PONG STREAK,” I used the skills that I’ve learned from last time with our text assignment; I downloaded my desired text file from this website and inserted it into p5.js, and was able to use the “loadFont” function to load the text into the canvas, which produced the following title font:

Now that I had the basics such as the title, background, canvas, etc. done, it was time to code the details – the first and the biggest part of my code for this project was called “class pongBall.” Because I had to add many details for the ball in order to make it move, I decided that creating a class might be easier, which made it easier for me to include everything such as “move,” “draw,” and “barCollisions” under a single class. Here’s the code that I used for my pong ball:

class pongBall {
  constructor() {
    this.xPos = xBall;
    this.yPos = 50;
    this.xSpeed = (5, 9);
    this.ySpeed = (-9, -5);
  }

  move() {
    xBall += xSpeed;
    yBall += ySpeed;
  }

  checkForCollisions() {
    if (xBall < 10 || xBall > 500 - 10) {
      xSpeed *= -1;
    }
    if (yBall < 10 || yBall > 445 - 10) {
      ySpeed *= -1;
    }
  }

  draw() {
    fill(218, 255, 115);
    ellipse(xBall, yBall, 20, 20);
  }

  // Bounce off the bar
  barCollisions() {
    if (xBall > mouseX && xBall < mouseX + 90 && yBall + 10 >= 440) {
      xSpeed *= -1;
      ySpeed *= -1;
      score++;
      song.play();
    }
  }
}

It was after this part of my progress when things started to get really confusing. Having to use completely new functions such as “gameState” with different sub-actions such as “start” and “play” or creating new functions such as “startScreen” and “playScreen” and having my game run through these different stages smoothly took a long, LONG time.

And because I wanted to make my game include time constraint as well as an outcome (win/lose), having to figure these out was a tricky process. Thankfully, I was able to use this p5.js resource to guide me through the timer/countdown code process, which was a lot more simple compared to other methods that I found online. Here’s the code highlight for the countdown function:

//countdown
 textAlign(CENTER, CENTER);
 fill("white");
 textSize(50);
 text(timer, width / 2, height / 2);
 if (frameCount % 60 == 0 && timer > 0) {
   // if the frameCount is divisible by 60, then a second has passed. it will stop at 0
   timer--;
 }

As for the win/lose outcome, I ended up just combining it with the countdown function instead of separating it, so that it just continued without a break.

if (timer == 0) {
   gameState = "end";
   image(photo, 200, 200, 250, 250);
   fill(255);
   textSize(25);
   text("GAME OVER", width / 2, height * 0.7);
   {
     if (score >= 5) {
       text("YOU WIN", width / 2, height / 3);
     } else {
       text("YOU LOSE", width / 2, height / 3);
     }
   }

I was pretty happy with myself by this point, where my project looked something like this when you reached the end of the game – I especially liked the little kitten’s grin, which was an image I got from this site:

At this point, I felt like I was on the verge of going absolute bonkers because I have been spending 3 days on this project; and while I really tried to make my game reset/restart without closing the program, I never succeeded in making it work in the end. Here’s the code that I used, and I hope I’ll be able to identify the problem later on when I have more time in my hands to do so.

function draw() {
  if (gameState == "start") {
    startScreen();
  }
  if (gameState == "play") {
    playScreen();
  }
  if (gameState == "end") {
    restartScreen();
  }
}

function restartScreen() {
  if (keyCode == ENTER) {
    gameState = "start";
  }
}

Final Product:

Despite the ups-and-downs that I’ve had with this project, I’m pretty proud of my super-simple, very quick game:

Reflection:

This was undoubtedly the most challenging yet the most eye-opening/fulfilling project that I’ve had so far in this course! While it consisted of multiple mental breakdowns and panic attacks, it also really pushed me to understand all the skills I’ve learned throughout this semester because it really tested my knowledge that I’ve gained till now. It was both satisfying yet disappointing to see my skills so plainly through this project because while I did make progress in coding from my initial “absolutely no knowledge in coding whatsoever” stage, I also realized just how much there is to learn still. It was disheartening to see that none of my creative ideas and anticipations for exploring couldn’t come alive because of my limitations in coding. Something that I definitely enjoyed was installing sound effects as well as learning how to add points each time the ping pong ball hit the paddle/bar, because it was really satisfying to see how the points accumulated! It was cool to see how I was actually trying out all the back-end details that went behind the video games that I so casually played without giving thought about what kind of coding was necessary for those games to work. Next time I’ll definitely figure out how to make the game reset without having to refresh the page again, because that was a limitation that I couldn’t overcome for this project; I’d also love to create something with more color, photos, and a story rather than just creating a basic game like this one!

Midterm – Goomba Spotting

Concept

While playing Mario Party earlier this month, I was struck with the idea to recreate one of the game’s many minigames. After some thought, I settled on one named Goomba Spotting, in which players attempt to accurately tally the number of Goombas—a species of mushroom-like beings from the Mario series—that run across the screen. This is what it looks like:

Players try to count the Goombas that pass by on screen.

While it would certainly be a massive challenge unlike anything I had done before, it was one I felt I could tackle at my current level. After mentally dissecting the game into a number of key components, I set out to work.


Challenges and Highlights

I first prepared the images that would be used in the game: one for the background and one for the Goombas. One decision I had made from the start was to have NYUAD be the setting for the game: the premise would be that a Goomba invasion had happened in our beloved institute, and that the two players were “Goomba Spotters” tasked with tallying the Goombas. I edited an image of NYUAD as seen from its entrance into two separate images, a foreground and a background—the Goombas would pass in between. For the Goomba itself, I selected a sprite online and edited the background away.

With the stage now in place, I decided to immediately take on the biggest challenge of coding the Goombas. How would they move? How many should there be? With questions brewing in my head, I created a class specifically for the Goombas and their movement. By adding new functions and adjusting values as needed, I was able to settle on a comprehensive block of code that worked.

One particular highlight from this process was figuring out a way to “stall” the Goombas so that they would come out one by one, instead of all at once. This is the function used to achieve this:

//Create Class for Goombas
class Goomba {
  constructor(){
    this.xPos = 0;
    this.yPos = 492;
    this.xSpeed = random(5, 10);
    this.ySpeed = 0;
    this.check = false;
  }
  //Used to "Stall" Each Goomba to Make Them Come Out in Order
  stall(order){
    if((frameCount - frameCheck) / (25 * (order)) == 1){
      this.check = true;
    }
  }
  //Changes Goomba's Position Based on Speed
  move(){
    if(this.check == true){
      this.xPos += this.xSpeed;
      this.yPos += this.ySpeed;
    }
  }
  //Draws Goomba
  draw(){
    image(photo, this.xPos, this.yPos, 60, 70);
  }
  //There is more code in the class, but it is truncated here to keep things short.
}

This function effectively staggers the Goombas’ initial movement speeds by 25 frames each; in other words, the next Goomba in line will start moving 25 frames after the one before it has started moving. 

(frameCount – frameCheck) is used to calculate the number of frames that have passed since the actual game has started (frameCheck is a variable that I made—it is defined as the frameCount at the time the gameState is set to ‘playing‘); said number is then divided by (25 * order),  in which order is a parameter that corresponds to the “order” of the Goomba (calculated as i + 1).

The result of this division is then checked if it is equal to 1—and if so, this.check is set to true. As seen in the move() function, this.check has to be true in order for the Goomba to be able to move. A small self-congratulatory round of applause was in order.

Another major part of the code is a separate class I created for calculating tallies and results. Each click of a player’s assigned key (A for Player 1 and L for Player 2) is one tally, and this is kept track through this block of code:

//Create a Class for Tally
class Tally {
  constructor(){
    this.p1Number = 0;
    this.p2Number = 0;
  }
  //Keeps Track of Each Press; One Press = One Tally
  checkP1Click(){
    this.p1Number ++;
  }
  checkP2Click(){
    this.p2Number ++;
  }
  //There is more code in the class, but it is truncated here to keep things short.
}

//Function for Checking Key Presses
function keyPressed() {
  //Player 1: A Key
  if (keyCode === 65) {
    tally.checkP1Click();
  }
  //Player 2: L Key
  if (keyCode === 76) {
    tally.checkP2Click();
  }
}

65 and 76 are respective key codes for the A and L keys—so when pressed, the functions checkP1Click() and checkP2Click() are activated. This respectively adds 1 to this.p1Number and this.p2Number, which are the variables used to track the players’ tallies. These tallies are then compared to the actual number of Goombas at the end of the game to calculate the results (these are done through functions that are part of the truncated code mentioned above).

These two classes of Goomba() and Tally() are central to the game, which is in itself brought forth using a function named gameScreen(), which is called when gameState == ‘playing.’ On that note, it must be mentioned that the variable gameState is pivotal to this project, as it is used to transition between the start screen, game screen, and end screen. These three scenes are represented by three separate functions: startScreen(), gameScreen(), and endScreen(), which contain the code needed to bring each screen to life. These functions work in tandem with gameState, which has three values it alternates between: ‘start,’ ‘playing,’ and ‘end.’ The value of gameState is continually checked in the draw() function, and either startScreen(), gameScreen(), or endScreen() is called depending on the respective value. The code for this looks like:

//Draw Function: Displays Different Screen Based on gameState
function draw() {
  //For Start
  if (gameState == 'start') {
    startScreen();
  } //For Playing
  else if (gameState == 'playing') {
    gameScreen();
  } //For End
  else if (gameState == 'end') {
    endScreen();
  }
}
//Code has been abridged for convenience.

The start screen and end screen share an identical template (the same background and gray box is used) with different text. Another coding highlight is present within the background, a gradient made with an interesting function called lerpColor() that I learned anew for this specific task. lerpColor() blends two colors and finds a third color between the two, and the coder can also control how close the interpolated color is to either of the two colors. Using lerpColor() within a for() loop, I painted in thin rectangles that start near the first color (orange) and grow closer to the second color (light blue) with each iteration of the loop, giving off the impression of a gradient:

//Make Gradient Background
  let from = color(255, 135, 0);
  let to = color(0, 240, 255);
  noStroke();
  for (let i = 0; i < 664; i = i + 6.64){
    fill(lerpColor(from, to, 0 + i * 0.0015))
    rect(0, i, 820, 7);
  }

Other highlights include figuring out ways to 1) vary the dialogue in the end screen based on the results (by using variables that functions in Tally() can alter to contain different text depending on the results), 2) change the number of Goombas in each game (by using a variable named randI, the value of which is reset every time the game is played), 3) make the Finish button appear after the game has actually ended (by tying the button to a variable named gameEnd that relies on the position of the last Goomba), and more.

Finally, here is the completed game:


Reflections

Whoa, what a project. Undoubtedly the biggest and toughest one yet—but I made it through! I feel pride in how I was able to achieve what I set out to do without making any major compromises. I admittedly felt incredibly stuck and confused at many points, unable to pull off certain effects I was aiming to implement (successfully stalling the movement of Goombas was especially challenging). Despite said difficulties, I was ultimately able to find a solution through each and every one of the major challenges I set out to tackle.

It’s been quite the journey! I started the class with a nearly blank slate, having only minimal coding experience (none with Javascript). Looking back, I’ve come quite far; it was a magical experience to be able to make something of my own that I personally envisioned and designed. And this will certainly not be the last.

Midterm – Garden Walk

Garden Walk
Here is the link: link

For my Midterm project I was inspired by the idea of catching games. In fact, this time I thought long enough about the idea of my project, because there were so many options. Once I chose a game that I want to create, I began to describe the concept and in the process of research found other interesting games that captivated me more. One of the interesting sites I found https://codeguppy.com/, there I came across many impressive concepts, moreover, on this site I looked tutorials to create the game (collision, score counter, etc.).
The point of the game is that the player needs to collect 11 flowers to make your bouquet. The complexity of the game is that each time the speed of falling flower increases, and at the end of the player must be careful to quickly collect the falling flowers. If one flower falls and the player does not have time to catch it, the game is lost.
To build the Garden Walk game, I was inspired by the cartoon “Sofia the First”, a cute cartoon about a girl who unexpectedly becomes a princess, and characteristic of every princess, she lives in harmony with the flora and fauna around her. As for the painting in the background of the main game I chose (I have no idea why) a painting by Claude Monet. I chose as my theme and in the process just picked out pictures that I liked. For the audio I chose a quiet music for background sound and short sounds to announce the winning/losing.
Basically I liked the way the totally random images looked together and the way everything looked in the game. I’m also particularly proud of the work done on the game screen functions, where I was initially confused.
In the process, I ran into all kinds of problems that would eventually affect the outcome of the work. It took me a long time to figure out the variables and the gameplay steps, which led me to get confused with my own data. However, thanks to some useful tutorials on the internet, I was able to solve these problems as well. Furthermore, in the process, I wanted to change the player’s movement. I spent some time exploring different options, and achieved small results with the use of OOP. In this link you can see another outcome of my attempts.
here

Also, here are some useful links that helped me get ahead in my work:

link1

link2

link3

In general, I am happy with the result of my work. I believe I still have a lot to work on, yet it was a good start. In the future, I would like to eliminate past mistakes and add to my game:
* Many types of flowers so that there is variety.
* Change Sofia’s movement so that she moves all over the canvas and can catch flowers at any point.
* Make the game more difficult with the addition of “trash” So if the player caught trash, his game will be lost.
* Create a unified design for the entire game

Midterm Project: Minion Puzzle

a snapshot from the puzzle

Inspiration:

My inspiration for this game was my puzzle assignments from Intro to CS that involved matrices calculations and boards (tik tac to, connect 4, etc.) and also this artwork in the Arts Center hallway:

The idea of the game is very simple. Just like the frame above, there is only one empty tile (randomly placed as a result of shuffling). Click on any empty tile’s adjacent cell to swap the two. Continue till all the pieces are in place!

Implementation:

Two (huge) classes Puzzle and Tile, seven methods, eight functions, 292 lines, and lots of debugging prints in between. 

The basic idea is how you think about any puzzle; we need to create a board, divide it into cells (that can be replaced or swapped), assign each tile a pattern in such a way that the whole board represents a complete photo, then shuffle the cells and try to solve the puzzle. Each puzzle has a different set of rules; in this puzzle, you have one empty cell and are allowed to swap it with an adjacent cell.

The tiles:

It starts with a single tile. The tile class creates an object Tile with the appropriate properties. Each tile object has a specific position on the board tile[row][column]:

// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
class Tile {
  
  constructor (r, c, img_index, numRows, numCols) {   
    this.r = r;
    this.c = c;
    this.numRows = numRows;
    this.numCols = numCols;
    this.img_index = img_index;
    this.img = loadImage ('resources/' + this.img_index+ '.png');
    // print("image index is: ", this.img_index);
  }
}
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Each tile object is also assigned an image index ranging from 0-15, and the way we are displaying it is by multiplying the tile’s row and column number by its size (defined at the beginning of the program):

// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
display_tile () { 
  if (this.img_index != (this.numRows*this.numCols) - 1) {
  // print("image index is: ", this.img_index)
  image(this.img, this.c*my_width, this.r*my_height, my_width, my_height);
  }
}
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

The board (matrix):

We are now ready to populate an array of arrays with our tile objects. The Puzzle class has a createBoard() method that loops through the range of numRows and numCols (passed as arguments in the Puzzle object constructor). A temporary array is created for each row in numRows, and then numCols arrays (numbers of columns) are pushed into the temp array. Then a new Tile object is created for each cell. Then we push this temporary list to the board (every tile is in the correct place at this point). Now before you exit the function, you shuffle all the tiles.

// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    createBoard () {
      this.board = [];
      
      for (var r=0; r<this.numRows; r++) {
        // for each row create a temp list
        var tempList = [];
        
        // add numCols tiles to the list
        for (var c=0; c<this.numCols; c++) {
          // r*c is the image index
          var new_tile = new Tile(r, c, r*this.numCols+c, this.numRows, this.numCols);
          tempList.push(new_tile);
        }
        
        // push the list to the board
        this.board.push(tempList);
      }
      this.shuffle_tiles();
    }
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Shuffling tiles:

Picking random values for any tile’s [r] and [c] values (ranging from 0 to 4). Identify its neighbors -> [[0,-1], [1,0], [0,1], [-1,0]]. Swap the tile with a neighbor from this list (also random). 

// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    shuffle_tiles () {
      
      // var current_r = this.numRows-1;
      // var current_c = this.numCols-1;
      var current_r = int(random(0,4));  // initially 0-3, left most cells or right most? 
      var current_c = int(random(0,4));      

      var neighbors = [[0,-1], [1,0], [0,1], [-1,0]];
      
      // increase s to have a more standard shuffle - was 20 initially
      for (var s=0; s<10; s++) {
        var empty_tile = this.board[current_r][current_c];
        var shuffling = random(neighbors);

        var destination_r = current_r + shuffling [0];
        var destination_c = current_c + shuffling [1];

        while (destination_r < 0 || destination_c < 0 || destination_r > this.numRows-1 || destination_c > this.numCols-1) {
          shuffling = random(neighbors);
          destination_r = current_r + shuffling [0];
          destination_c = current_c + shuffling [1];
        }

        var new_tile = this.board[destination_r][destination_c];
        
        // print("Before swap: " + str(this.board [current_r][current_c].img_index) + ", " + str(this.board [destination_r][destination_c].img_index));
        
        var temp = empty_tile.img_index;
        empty_tile.img_index = new_tile.img_index;
        new_tile.img_index = temp;

        // print("After swap: " + str(this.board [current_r][current_c].img_index) + ", " + str(this.board [destination_r][destination_c].img_index));

        current_r = destination_r;
        current_c = destination_c;

        for (var r=0; r<this.numRows; r++) {
          for (var c=0; c<this.numCols; c++) {
              var the_tile = this.board[r][c];
              the_tile.img = loadImage ('resources/'+str(the_tile.img_index)+'.png');
          }
        }
      }
    }
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Swapping tiles:

Method tile_empty_adj() returns two important values: the current empty tile (empty tile has a fixed index of [3][3], but it moves around as a result of shuffle), and also a list of empty tile’s neighbors.

We record mouse[x][y] when a click happens on the empty cell’s neighbors and swap their img_index so at the next iteration of draw() when the display() method is called, the tiles would be switched and now you have a new empty cell. Repeat process.

// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    swap(nonempty, empty) {
      // takes coordinates of two tiles, swap their index
      var empty_tile = this.board[empty[0]][empty[1]];
      // print("this is empty tile & img index: ", empty_tile, empty_tile.img_index);
      var new_tile = this.board [nonempty[0]][nonempty[1]];
      // print("this is new tile & img index: ", new_tile, new_tile.img_index);

      var temp = empty_tile.img_index;
      empty_tile.img_index = new_tile.img_index;
      new_tile.img_index = temp;


      var tmp=new_tile.img;
      new_tile.img = empty_tile.img;
      // loadImage ('resources/'+str(new_tile.img_index)+'.png');
      empty_tile.img = tmp;
      // loadImage ('resources/'+str(empty_tile.img_index)+'.png');
      
      // print("after swap: ", empty_tile, empty_tile.img_index);
      // print("after swap: ", new_tile, new_tile.img_index);

      for (var r=0; r<this.numRows; r++) {            
        for (var c=0; c<this.numCols; c++) {
          // print(r,c, this.board[r][c].img_index);
          if (this.board[r][c].img_index != r*4 + c) {
              return false;
          }
        }
      }

      this.win = true;
      print ("won game!");
      this.win_sound.play();
    }
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function mouseClicked () {
  
  var empty, adj, empty_adj; 
  empty_adj = my_puzzle.tile_empty_adj();

  empty = empty_adj[0];
  adj = empty_adj[1];
  // print("adjacent cells: ", adj);

  mouse = [int(mouseY/my_height), int(mouseX/my_width)];

  // print(mouse);
  for(var i=0; i<adj.length;i++) {
    if(mouse[0] == adj[i][0] && mouse[1] == adj[i][1]) {
      // print("we are here in the swap call\n");
      // switch the empty and non-empty slots
      my_puzzle.swap(mouse, empty);
      // my_puzzle.display();
    }
  }
}
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Win conditions:

You win if ALL the tiles in the board have the img_index initially assigned to them e.g. tile[0][0] -> img_index 0, tile[2][3] -> img_index 12 and so on. The empty cell belongs to the last tile (tile[4][4]) and that’s where it should end up for the win condition to be true.

// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      for (var r=0; r<this.numRows; r++) {            
        for (var c=0; c<this.numCols; c++) {
          // print(r,c, this.board[r][c].img_index);
          if (this.board[r][c].img_index != r*4 + c) {
              return false;
          }
        }
      }

      this.win = true;
      print ("won game!");
      this.win_sound.play();
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Gameplay:

I tried to keep the instructions very minimal:

1) User is presented with an instructions screen that they can go back to at any point in the game by pressing i (i = instructions)

2) User can start the game by pressing p (p = puzzle)

3) User has the choice to play the minions’ music or mute it while they solve the puzzle (it has a low amplitude anyway). (m = mute, u = unmute)

4) In some rounds the shuffling is very complicated (due to randomness) and the user might not want to spend a lot of time on solving it (e.g. for playtesting purposes). The user has the option to reshuffle the board by pressing s (s = shuffle).

Embedded sketch:

Improvements:

Currently, I’m working on writing a function that slices any image into X equal parts (very useful for puzzle purposes). This can extend the current program from a minion puzzle to any puzzle of the user’s choosing. While this function is easy to implement, the next step that involves saving each slice (of image) back to the assets folder is a bit tricky and needs some research. But overall I think the createBoard()/swap()/shuffle()/display() methods are very extendible and are basic foundations for many board games.

[the end]

Midterm project – Final version

The game:

link: here

inspiration:

There used to be this game called Purble Place by Oberon Games. This game was available on windows operating systems by was removed from the newer ones. The game has a collection of smaller games and the one I was most inspired by was called comfy cakes.

The goal of the game is to try and mimic the cake displayed in the top left corner while the conveyer belt moves the plate(papers in this case). The game has buttons to move the conveyer belt however the cake orders would keep coming so you would need to work fast.

what my version has:
I looked at the game version and picked the aspects I want to recreate and the ones I wanted to change. I watched a few videos of the game, and looked at pictures since I couldn’t play the game because it’s no longer available. I decided to simplify the graphics so I can focus on the code aspect. (Picture of notes on the side, not sure why it’s blurry)

I also had to decide on a game logic of how the players win and lose and so on. This would also help me decide on what classes would control which part. This is the logic I decided on:

      • the player would first be presented with the main page the move to the instructions page after-which the player can start the game
      • the game it self would consist of a conveyer belt that moves the plates. once the cake is under one the dispensers the player must click the dispenser to add the cake part.
      • The player’s goal is to add as many cake parts correctly before running out of orders.
      • The player wins if the player gets at scores 80%.

things implemented successfully:

      • a new cakes are being automatically recreated once the current one leaves the window
      • two classes are created (
          • cake creator class
            • keeps track of the total score
            • number of cakes
            • creates new cakes
            • draws the cakes
        • single cake class
          • creates only one cake
          • adds parts to said cake
          • keeps track of only it’s score
          • check if said cake is under (within a certain range of) the dispenser
      • the cake parts are added once the user clicks on the dispensers

Features I didn’t plan to implement but would be cool:

      • a score board (learned how to send and req data from APIs in connections lab, so I can use a google sheets API to store the user’s data and display them)
      • Different difficulty levels
      • add more cake features to make it more challenging

 

Design aspects

    • I also wanted to work on the design aspect and make sure that the design of each page is intuitive and also has a consistent theme.
      • The main page looks like this. I looked for free graphics online and cropped the ones I liked. the cake slices are rotated and “float”(move) a round a bit to make the page less static. The background has sprinkles which are randomly drawn lines.
      • there is a button that says start. if the user hovers over it it darkens to make it clearer that it is a button. the cursor also changes to a pointer.
      • the instruction page has the same sprinkles but has a translucent rectangle in front of it to make sure that the text is readable. this page also has a button
      • This is the game page. it shows the score and the number of orders left. It also shows what the cake should look like. It has an audio that indicates that a new cakes is created and another that plays when the dispensers are used.
      • One thing I would change is the way the dispensers look. I wanted to get better graphics for them and include the text better did not have time to do that.
      • This is the end game page. It offers the user the option to go to the home page or to restart the game. It also displays if the user won or lost and their score (the score here is there was only one cake order, I was only testing here)
      • The page also has the same translucent layer as the instructions page  but here I added some more graphics.

aspects that I am proud of:

I think that the code was neater than I expected it would turn out. I anticipating that this project would be a long one and that things might not be as intuitive looking back a few days later I tried to neaten the code as I went, keep the variable names descriptive, and create functions for things that I expect to use multiple times (like the buttons). But I usually say I’d do that and end up being lazy and picking unintuitive names for variables, but I stuck to it this time which I am proud of. I think that the code could still benefit from being spread on multiple js files (if that is possible).

challenges:

one of the challenges was handling all the different components of the game. The code got really long (like I assumed it would), I tried to prepare for that by making sure that my code is modular and by using many drafts with clearly stating the functions each draft achieves. Those two things made it easier for me to go back to previous versions, and also ensured that  if a feature did break, the code would be minimally affected and recovering would be easier. I changed the cursor when hovering over the navigation buttons, added an instructions page, and tried to keep the design simple. However, I believe that there are still some things that I didn’t anticipate the user would need. I’ll fix this gap by letting someone interact with the game and noting down where they struggled and what they didn’t understand on their own. I think that this would give me more insight into the user’s experience however I did not have the time to do this for this project.

some things that were helpful in p5js:

          • you can use textWidth(“Text”) to get the width of the text. this helps when centering text
          • you can do random(list_name) to get a variable from the list instead of doing random( list_name[random(range)) and using a function to get random integers to get an index.

Aisha – Floor Is Lava Midterm

Concept:

For my Midterm Project, I decided I wanted to create a sidescroller game similar to Super Mario and Geometry Dash. After contemplating the idea of the game, I chose to create a floor lava game.  The user starts on the left side of the map with the aim of getting to the finish line (right side of the map). The user must jump on platforms to avoid falling into the ‘lava pit’ and dying. There is a title screen displaying the name, levels (Easy, Medium, and Hard),  and instructions. The user can pick any level to start off with.  If the user falls into the ‘lava’ a screen will be displayed informing them that they lost and they can go back to the menu. If they successfully reach the other side, a screen will be displayed informing them that they have won and that they can go back to the menu. There is a continuous lava sound playing in the background of the game.  Link to game: https://editor.p5js.org/aishaalketbi_/sketches/LH21rAmDW

How the Game Works:

With the help of Chris Courses on Youtube (Mario Game Tutorial with JavaScript and HTML Canvas), I managed to get things working. I first created a Class of the Player and Ground to test whether scrolling, collision, and movement would work. I gave my Player a constant velocity. For collision, I created a for loop that detected If the player was on top of the ground it would not fall through. For scrolling the ground, I coded that once the player reaches 450 on the X axis, the ground X axis would be decreased to the left to create the illusion of scrolling. Once I managed to get that working I added the platform as well. Here is the code for scrolling:

if (player.x < 450) {
      player.x += player.xg;
      player.xg += player.v;

      ground.forEach((ground) => {
        //moves the ground to the left to create the illusion of scrolling
        ground.x -= 10;
        scrollOffset += 5;
      });
      platforms.forEach((platforms) => {
        //moves the ground to the left to create the illusion of scrolling
        platforms.x -= 10;
      });
    }

Furthermore, with the help of Mangs code, I allowed the background to scroll continuously.

The function keypressed is essential to my code as it not only allows the user to jump with the use of gravity but also allows the user to navigate between different levels and to the menu. Here is a photo of the title screen:

Good Game Design:

Originally I was only going to put platforms (the shorter platform) for the user to jump on however, I decided to add both longer (the ground) and shorter platforms to make the game more difficult for the user. The key pressed-up function also is a good game design as the user doesn’t have to worry about moving the ball itself, all they have to do is jump.

 

Challenges:

There were a few challenges I came across. Firstly, I wasn’t sure how to use a for loop for the platforms and the grounds. It didn’t seem to work when it came to changing the position. So to tackle this, I used Chris Courses code which made it much easier and simpler for me. This is the code and it is the one I’m most proud of:

// collision (ball stops above platorm)
    ground.forEach((ground) => {
      if (
        player.y + player.d <= ground.y &&
        player.y + player.d + player.yg >= ground.y &&
        player.x + player.d >= ground.x &&
        player.x <= ground.x + ground.width
      ) {
        player.yg = 0;
      }
    });

    platforms.forEach((platforms) => {
      if (
        player.y + player.d <= platforms.y &&
        player.y + player.d + player.yg >= platforms.y &&
        player.x + player.d >= platforms.x &&
        player.x <= platforms.x + platforms.width
      ) {
        player.yg = 0;
      }
    });

Furthermore, adding a sound took longer than usual as for some reason it would say “Loading…” when I clicked play for so long.

Here is the game:

 

 

 

 

Midterm

Concept

A balloon inflation game that assesses risk-taking abilities through a series of 8 rounds. The one-player game starts with a small balloon to be pumped as many times as they wish. The more you inflate, the more money you earn. At each point, you may bank the sum earned and move to the next balloon. However, if the balloon is pumped too much and the balloon pops, all that round’s money is lost. This is inspired by the famous Pymetrics balloon game. A player who manages to collect all the balloons but earns very low sums is classified as cautious, whereas a player who tends to pop a lot of balloons but gain higher sums is considered a risk-taker and adventurous.

Implementation

https://editor.p5js.org/hessaala/sketches/wcdYbG-aD

The game starts with an instructions page, explaining the different buttons and game idea to the player. As soon as the player is ready to proceed, a click on the screen takes them to the main game page. The game page has an inflatable balloon and 2 buttons, “inflate” which increases the balloon size, and “collect” which banks the money at any stage. It also presents information on the number of pumps and current earned in every round, and updates the total earned. After 8 rounds, the game ends and the score is displayed.

Challenges

It was a bit confusing working with different pages for the game. For regular shapes and text, it was relatively simple to figure out. The thing I struggled with the most is working with buttons in the separate pages. I figured that they don’t work like the shapes, rather they’re a separate element that are not actually on a ‘canvas’. The solution was to use the show() and hide() features.

Design Choices

Since it’s a balloon game, I immediately thought of making it a kid’s game. So, the theme I went for is light and plain but also child friendly. I used object-oriented programming for the main game page (moving clouds), and a garden image in the end page.

Future Direction

I would love to make the balloons pop at different planned rates and not random based on their colors. This game could be used for investment banking tests to analyze candidates risk-taking and learning abilities.

Midterm Project- Circle Eater

Concept of project

I decided for the midterm project to design a game that is very similar to the maze action video game, Pacman. Therefore, the main concept of my game is that there is a main character that looks like a green arc who tries to avoid the ghost enemies and eat circles, the more circles the character eats the more points he gets. The player will win the game if he or she can eat fifteen circles before bumping into one of the ghosts. On the other hand, if one of these ghosts catches the player before reaching a score of 15 circles eaten, then the player will lose the game.

I decided to create a game with this concept because I enjoyed playing Pacman as a kid and wanted to explore if I might be able to make a game that is very similar to my favorite childhood game. To make this project even more interesting, I decided to change some of the instructions of the normal Pacman game. If the main player eats a circle, the circle should change colors from yellow to red. Moreover, the main player can eat a circle more than one time. These new rules are what made this game even more exciting to play.

Project Implementation

To implement this project, I created four different scenes. I also used game state variables to transfer between scenes. These scenes are mainly the main menu scene represented by the start state, the game scene represented by the playing state, the winning scene, and the closing scene which are represented by the winning and losing states respectively. You can find an image of the instruction page and game scenes attached below. To play the full game and see the code press here: https://editor.p5js.org/AhmadFraij/sketches/7QkOMfogm

Instruction Page of the Game

Game Design & Technical Decisions

In the main menu scene, I loaded an image of Pacman and three ghosts and made it the background of my main menu screen. On top of this background, I added the title of the game along with the instructions using the text function in p5.js and preloaded a special font type into the game. The game should receive input from the user which is pressing the enter button to move to the game scene.

Game Scene

To create the game scene, I designed a maze using different sizes of rectangles. Then, I used object-oriented programming to come up with the main player. Therefore, I created the main player class and defined a constructor with all the necessary variables, and added other functions inside the class that controls the motion of the main player and check if the player hits any of the rectangles inside the maze.

Most importantly, I created some circles around the maze and added a function that determines whether the main player is eating a circle. If this condition is met, then I increment the score until I reach the value needed to win the game. Furthermore, I created a class for the enemy ghosts, and whenever one of these ghosts’ positions equals the position of the main player then the user loses the game.

I was proud of how I linked the different scenes in the game by using a game state method that I understood from Professor Mang’s code. Furthermore, I am proud of how I was able to apply the score counter. To make the score counter work, I kept track of the previous counter and only incremented the previous counter after the current counter is incremented, in this way I made sure that the score only increments by 1 because when I first did the scoring algorithm I used to have the issue of having the counter increasing more than one unit.

 

While developing this game I also faced so many issues. It was so difficult for me to determine when a moving ghost hit a moving main player. However, after trying different ways I realized with the help of the professor that the best way to do this is by creating a class for the ghosts and a class for the main player and having a function in the ghosts class that takes the x and y positions of the main player and compares them with current x and y positions of every ghost.

Furthermore, figuring out how to check whether the main player eats one of the circles took so much time and I implemented it using so many if statements. Therefore some future improvements to this game would be to create a separate class for the yellow circles and have a function inside these classes that determines whether the main player hits a circle or not. Finally, I added some sound effects to the game to make it more interesting

Midterm Project: Asteroids Game

Concept:

Asteroids is a classic video game that has captivated players for decades. As a child, I was drawn to the game’s simple yet challenging gameplay and the excitement of blasting asteroids into tiny pieces. When I heard that I had the option to choose my own midterm project, I immediately knew that I wanted to create my own version of the Asteroids game. One of the reasons I chose to create an Asteroids game is because it is a fun and engaging project. The game’s simple premise and mechanics make it easy to understand and play, but it also offers a challenge for players to master. I enjoy games that are easy to pick up but difficult to master, and Asteroids fits that description perfectly. Another reason I chose to create an Asteroids game is because it reminds me of my childhood. I have fond memories of playing Asteroids at the arcade with my friends, and I wanted to recreate that experience for myself and others. By creating my own version of the game, I can relive those memories and share them with others.

Reflections and improvements:

Creating an Asteroids game in p5.js was a challenging and rewarding experience. This required a lot of experimentation and trial and error, but I found the process to be enjoyable and educational. Challenge I faced was making the game visually appealing. In the original Asteroids game, the graphics were simple but effective, with clean lines and geometric shapes. I wanted to recreate this aesthetic in my game, so I spent a lot of time experimenting with different design choices to find the right look. I also had to figure out how to make the game run smoothly, so that the movement and shooting would feel responsive and satisfying to the player. In the end, I was able to create a functional and visually appealing version of the Asteroids game in p5.js. I was proud of the work I had done, and I received positive feedback from my peers and instructors. Overall, the experience of creating an Asteroids game in p5.js was challenging but rewarding, and I learned a lot about game development and programming in the process.

Midterm Project: Tanks

In-game display

This game is inspired by Tanks, a game which user(s) can control tanks to destroy enemy tanks. To play this game, each player needs to apply basic geometry and trigonometry to target and hit enemy tanks.

My version of Tanks has similar mechanics with some differences. The game will rotate turns between players, limiting each turns to take no more than 20 seconds. During their turns, players can adjust launch angle, launch power, position, and launch shells to attack opponent(s) using a keyboard. Launched shells will follow a simple physics law and eventually land on either the landscape or an opponent tank, permanently changing the landscape or damaging the opponent tank. While the game is running, there will be a dashboard which indicate which player is playing, how much HP (life) is remaining, what angle the tank is aiming, how strong the launching power will be, and how much time left before the turn ends. The match/game ends when there is one or zero (there can be a tie!) players on the map with some health.


On browser that blocks canvas-based fingerprinting, the game may not work as intended.
 

When I started working on this project, I tried to implement a lot of features. And later, I realized that I again underestimated the work I need to do to write this game. The below is the list of canceled/partially implemented features of this game due to limitations of reality.

    1. Adjustable number of players
    2. Customizable tank colors
    3. Map generator (users can draw their own map)
    4. More sound effects

However, there are also many features that are implemented successfully.

    1. Interactable instructions page
    2. In-game menu for pause, restart, and exit the game.
    3. Multiplayer (hardcoded 2)
    4. Image-based maps (drawn on mspaint.exe)
    5. Interactable modifications on the map
    6. Tanks and their controllable features
    7. Turns, player indicator (the yellow arrow) and time limits
    8. Functioning dashboard
    9. Physics of launched shells
    10. Some sound effects
    11. Etc.

Among those, I am especially proud of 4 and 5. Below, I will spend some time explaining how they are done.

function preload() {
  for (let i=1;i<=5;i++) {
    append(gameMaps, loadImage("maps/map_"+i+".png"));
  }
  ...
}

First, images of maps needs to be loaded before the game starts. To be used as maps, they need to at least satisfy two things. First, the pixel color for air must be similar to [190, 251, 254, 255]. Second, there must be enough non-air pixels for tanks to land on when the game starts. If these two are satisfied, pretty much any image can be used as a playable map. Once the maps are loaded, Tank objects and Shell objects can interact with air and non-air pixels.

function compareColors(a, b) {
  // used to compare colors
  if (!a || !b) {
    return false;
  } // if one of them is null, false
  if (a.length != b.length) {
    return false;
  } // if length differs, false
  for (let i = 0; i < a.length; i++) {
    if (abs(a[i] - b[i]) > 7) {
      return false;
    } // difference may be negligible
  }
  return true;
}

// Partial code from class Shell
...
if (this.y>0&&!compareColors(get(this.x, this.y), c.ac)) {
  this.explode();
}
if (this.y > height) {
  this.explode();
}
...

The above code uses a get() function to check whether a launched shell is in the air or overlapped with non-air pixels (ground, map boundaries, and tanks) and decide if it will explode or not. If it chooses to explode, it will trigger the below code.

append(c.explosions, [this.x, this.y, this.explosionRadius]);

It records where the explosion happened and the size of the explosion. The recorded explosions are later used in the below code so the pixels affected by the explosions are “erased” or filled with air color.

modifyMap() {
  push();
  noStroke();
  fill(this.ac);
  for (let i = 0; i < this.explosions.length; i++) {
    let tmp = this.explosions[i];
    circle(tmp[0], tmp[1], tmp[2]);
  }
  pop();
}

Of course, there were(and still are) a lot of difficulties when writing this game, and below are the major ones.

    • Object overlapping
      • Because the map is modifiable, positions of all objects are relative to their surroundings, and in some cases, tanks can overlap each other and show unintended behavior. There seems no easy fix for this.
    • Continuous sound effect
      • When tried to use sound effects for continuous events (such as tanks moving, aim adjusting, etc.), it results in undesirable sound. This may be solvable by finding a good sound file that has matching start and end tone, but I could not find those. So I removed those sound effects.
    • Uphill/Downhill movement
      • Similar to object overlapping, tanks moving uphill and downhill causes them to stutter.
    • Interaction failure with air and non-air pixels
      • In the early stage of coding this game, tanks could stop in the air or indefinitely fall down into the ground. This is mainly due to pixels being meshed together when pixel density is not 1, but it is fixed by having threshold on color differences.
    • Simultaneous keyboard control
      • There were times when multiple keys were pressed, only one (the latest) one will be recognized, and this key will remain recognized unless all keys are released or a new key is pressed. Fixed this issue by using keyIsDown() in draw() instead of keyPressed().
    • There may be other major issues that I have encountered, but I cannot remember them at this point.

From this project, I learned that even a simple-looking feature can be long and complex to implement. For the later projects,  I will try not to focus on implementing multiple features; I will instead focus on making small features more reliable and smooth.