Midterm Project: final update

THE FINAL PRODUCT  

The link the code on the web editor can be found here here. I have also embedded the sketch below, although the game must be viewed in full screen on Chrome, with the Bookmarks tab hidden. I made this choice to have the canvas size this large so that the user could be fully immersed in the game. Since this isn’t one of those games that’s meant to be played to pass the time, I didn’t want a small canvas size and other tabs to distract from the experience. Of course, headphones with decent sound quality also enhance the experience.

 

CHANGES & SIMILARITIES FROM THE STORYBOARD 

Overall, the final product is very similar to the storyboard created in last weeks post, although some of the games have been modified. A theme that I wanted to establish from the start was an 80’s arcade aesthetic. The aesthetic is very nostalgic of the gameboy and nintendo games I used to play as a child, and because the game is sort of reflective of my life as an adoptee up until now, I think it is fitting. I wanted there to be lots of pixelated images, saturated colors, and sounds that are reminiscent of old computers. In terms of the story I was telling, I wanted the text to be informative and genuine so as to represent my experiences as authentically as possible, but still very personal  and quirky. I think I accomplished this  quite well.

In terms of the actual games, I did make some changes in the final product. For the first chapter, I felt that the “lost treasure” analogy (explained on the mind map) was difficult to capture and more complex than I anticipated. Instead I decided to make a maze. In the second chapter, I still wanted to express the idea of mixing culture, but due to time constraints, I simplified the game that was intended to be a chasing game, where the blue monster is controlled by the user and the red controlled by the computer. Unfortunately, I was unable to make the red monster move on its own, so for now, it remains stationary while the user is able to move the blue monster freely. Finally, for the third chapter, I felt that the original game was too similar to the previous chapter. I began to think about the most important thing to represent, which was the idea of presenting differently to please others. Hence, I decided to make a dress up game where the user can dress up a chameleon with different accessories. The last chapter remained the same.

Although I had to simplify my original storyboard to fit with the time constraints of the project, I’m glad that I had to. It made me think about the power of simple but effective analogy, and challenged me to think of new ways I could show an aspect of my experience, rather than tell the user directly. I think with game design, it’s sometimes easy to forget that the user indeed can put pieces together themselves without the game having to explicitly show every part of the plot and meaning.

Finally, when it came to writing the text, I decided to divide the game by “chapters” rather than levels. Though subtle, I think this choice of diction makes a significant difference. Similarly, I avoid using language such as “you lost” or “you won,” as I think it breaks up the story and doesn’t allow for a smooth transition between one chapter and the next.

ESSENTIAL CODE 

Although the game has far too many lines to go into detail in this post, I will share some pieces of the code that I found essential to this entire process. For one, two classes that were reused many times were the Button and Sign class. The Button class allowed me to create buttons that played the next slide of text, switched to the next chapter (changing the game state in the process), replaying games, and more. The Sign class is what I used to place all of my text on screen. Because there were a lot of specifics involving margins, font color, and positioning, having a class to hold this information was helpful. The code for the two classes is shown below:

class Button{ 
  constructor(x, y, font_color,font_size, string, btn_w, btn_h){ 
    this.x = x; 
    this.y = y; 
    this.string = string;
    this.age = frameCount; 
    this.opacity = 255; 
    this.hover = false; 
    this.width = btn_w; 
    this.height = btn_h;
    this.font_color = font_color; 
    this.font_size = font_size; 
  }
  
  display() { 
    if (mouseX < this.x+this.width/2 &&
        mouseX > this.x - this.width/2 &&
        mouseY > this.y-this.height/2 && 
        mouseY < this.y+this.height/2){ 
      this.hover = true; 
    }
    else { 
      this.hover = false;
    }
    if (this.hover) {
      this.opacity = 100; 
    }
    else { 
      this.opacity = 255; 
    }
    
  //FILL OF BUTTON 
  //next buttons with gray center 
  if (game_state!=0 && game_state != 5 && game_state!=6 && game_state!=16 && game_state!=11 && game_state !=1 && game_state!=20){
    fill(180);
  }
  else { 
    noFill();
  }

  //STROKE OF BUTTON 
  if (game_state == 1 || game_state == 5 ||game_state == 0 || game_state == 20) { 
    this.font_color = color(255, 255, 255); 
  }
  else { 
    this.font_color = color(0,0,0); 
  }
  push(); 
  strokeWeight(2); 
  stroke(red(this.font_color),green(this.font_color), blue(this.font_color), this.opacity); 
  rect(this.x, this.y, this.width, this.height); 
  pop(); 
    
  //TEXT OF BUTTON 
  noStroke(); 
  if (game_state == 1|| game_state == 5 || game_state == 0 || game_state == 20){ 
    this.font_color = color(255, 255, 255); 
    fill(255, 255, 255, this.opacity); 
  }
  else { 
    this.font_color = color(0,0,0); 
  }
  textAlign(CENTER); 
  textSize(this.font_size); 
  fill(red(this.font_color),green(this.font_color), blue(this.font_color), this.opacity); 
  text(this.string, this.x, this.y, this.width, this.height); 
}

  
  mouse_over() {  
    if ((mouseX >=(this.x - this.width/2) && mouseX <=this.x+this.width/2) &&   (mouseY >= (this.y-this.height/2) && mouseY<=(this.y+this.height/2))) {
    return true; 
    }
  }

}

In the Button class, it has a variable named this.font_color, which changes depending on the current game state, so that it draws in black or white depending on the background. It also has a method called mouse_over(), which returns true if the mouse is inside the button. If true, a variable called this.opacity_changes, allowing the button to fade on hover.

class Sign{ 
  constructor(x, y, font_color, font_size, string, sign_w, sign_h) { 
    this.x = x; 
    this.y = y; 
    this.string = string;
    this.age = frameCount; 
    this.speed = 20; 
    this.font_size = 0; 
    this.width = sign_w; 
    this.height = sign_h;
    this.font_color = font_color;
    this.font_size = font_size; 
  }

  display(){ 
    push(); 
    rectMode(CENTER); 
    textFont('VT323');
    textAlign(CENTER);
    textSize(this.font_size); 
    noStroke(); 
    fill(this.font_color); 
    text(this.string, this.x, this.y, this.width, this.height);
    pop(); 
  } 
}

The Sign class is very similar to the Button class, containing all the same attributes, although the way the text animates is defined outside the class in the type() function.

The type() function was the most reused function of the entire program, and it really brought the entire game to life. Given that most of it is text based, adding a typewriting effect made it more visually interesting and immersive, forcing the user to slow down their reading speed to match the speed at which the text was appearing on screen.  The code is shown below:

function type(current, string) {
  if (current==0) { 
    start_typing(); 
  }
  if (current_char>= string.length-1){
    stop_typing(); 
  }
  let current_str = string.substring(0, current); 
  textSize(30);
  text(current_str, windowWidth/2, windowHeight/2, windowHeight-200-margin, windowHeight/3-margin);
  current_char +=random(0.1, 0.6);

Essentially, the function takes a string as its input and prints a substring of the string that increases with each successive frame, giving the illusion of typing. The substring starts with length 0 and ends at length string.length, incremented by the current_char variable. The curent_char variable is incremented in random values to give the appearance of natural typing.

CHALLENGES 

The most challenging part for me was understanding the concept of game states as a way to organize my code. In the beginning, I was writing the code for each game in separate files, and thought that keeping separate functions would be enough to organize the code. However, I experienced a lot of difficulty trying combine multiple sketches. After creating the global variable game_state, which was a numerical value that kept track of the current game_state, it was much easier to organize the code and have the program transition from one scene to another. For example, the draw() function simply consists of several if statements that say “when the game state is __ number, go to __ function”, where each function corresponded to a certain “scene” in the game, such as the winning screen to chapter 1, or the instruction screen for chapter 3. Also, the game_state could be changed almost only with the mouseClicked() function. Inside the mouseClicked() function, it deals with every button that is used in the program, and depending on what type of button is clicked, it increments or decrements the game state.

 

BORROWED CODE 

The only outside sources that were used in making this game was the algorithm used to make the maze, and the typing function. Of course, I adapted each of them slightly to fit my game. For example, the maze was built using a depth first recursive program made by The Coding Train, though it only generated the pattern and did not allow the user to actually move through the maze. The code that was used to allow the user to actually play the maze was completed on my own. Secondly, the original typing function that I found only worked with single strings, and I adapted this to fit with a list of strings, as well as display a new message with the click of a button.

The link to the maze algorithm can be found below:  https://editor.p5js.org/codingtrain/sketches/EBkm4txSA

The link to the typing effect can be found below:

https://editor.p5js.org/cfoss/sketches/SJggPXhcQ

IMPROVEMENTS  FOR THE FUTURE 

Of course, I would love to finish the second chapter so that the game is complete. I would also like to refine the code more. I recognize that as the process went on, I became lazy and hardcoded much of it. Editing it by adding some intermediary variables, making variable names more clear, and even reducing the amount of Button and Sign instances would make the code not only shorter, but more organized. Additionally, as brought up by my professor, using Javascript objects would be incredibly useful for this project. For example, I use two arrays: invader_keys and alien_keys, which are both arrays of 4 elements that store boolean values, each corresponding to an arrow key. Each arrow key is represented by the indexes of 0, 1, 2 and 3, which is very unclear and confusing to someone who doesn’t know the code.

 

Midterm Documentation – Final Part

Save the Zombie!

Overall Concept

For my midterm, I decided to recreate the google dinosaur game that pops up whenever you try to go on a google web browser without a connection to the internet. In the dinosaur game, there is a dinosaur, cacti, and a simple background containing moving clouds. The game prompts the player to use their keyboard keys to make the dinosaur jump over the cacti as the cacti randomly enter the canvas. If the player does not press the key or presses it at the wrong time, the dinosaur will collide with the cacti and the game ends. To goal of the game is to avoid as many cacti as you can. To keep the player intrigued with the game, the game displays the player’s score and their high score.

I find that it is a very simple but engaging game. The purpose of it is very user-oriented since it allows the player to do something while they wait for their internet to connect again.  I also decided to go with this concept because it looked simple and achievable for me. In the beginning I was exploring other games that I used to play when I was a kid, but I thought dress-up and restaurant games would be too complicated. To make it my own, I decided to go with a Halloween theme since we are in October, I love Halloween, and I am going to miss the Halloween decoration from home. I did change a few things as I was creating the game in terms of the narrative and how the player would win. Instead of having a high score, I made it so that the player has to reach a certain number of jumps in order to save the zombie from a pumpkin attack.

Technical Decisions & Game Design

It is important to note that I took inspiration from Dan from The Coding Train on YouTube. He made a video replicating the dinosaur game with his own twist that included different images and controlling the character using the player’s voice. I decided to omit the voice control portion, but used his code as my base code. I knew I still needed to add other parts to meet the midterm requirements such as on-screen text, sound, the start screen, and a way to restart the game without restarting the program.

The start screen with instructions

My Zombie game includes the start screen, the game scene, and two different end screens depending on whether the player saves the Zombie from a pumpkin attack or lets him die (again). Using Dan’s code as my base code, I also had to change a few things. For example, his game used noLoop() to stop his sketch completely. He also continuously drew the pumpkins because he had no need to restart the game. I used the class sample code by Professor Mang that showed how to restart the game and implemented it into my code. I found out that because I did this, I also had to change how the pumpkins would show up in the game. To do this I created a pumpkin array and an if statement that said if the gameState == “playing” is true and the chance of adding a new pumpkin is random is also true, then a new pumpkin is created. I was proud that I was able to integrate the code into a base code that I changed, it really forced me to go through the code and understand every single part in order to figure out what parts go together. It was almost as if I was solving a puzzle.

I also wanted to end the game in a certain way instead of having the player make the Zombie jump as many times as they can. To do this I decided to create a storyline. In this game, the player is trying to save the Zombie from getting attacked and killed (again) by the pumpkins. In order to do this, the Zombie needs to avoid (jump over) the randomly generated pumpkins 10 times. I chose this number randomly.

Walking zombie with a cheat circle
Problems I Ran Into & Improvements

Even though I used a base code, I ran into so many tedious issues. I appreciate what coding does and admire everyone who is able to think like a coder, however I think I find it almost as scary as some aspects of Halloween. I mentioned in my second part of my documentation that I had trouble with just loading an image, I think that issue was probably the issue I took the longest on. It was not the correct path and I simply replaced the Zombie image with one that was not in a sprite sheet. I also struggled in integrating new code in an already existing code, mainly because I obviously did not make it and I had to take time to really familiarize myself with it in order to put the puzzle pieces together. Once I did familiarize myself with it though, I was able to figure out where everything else is supposed to go.

Another issue I had was that at first I did not include circles on top of the character images. However, that made the user experience difficult because even though the Zombie itself would not touch the pumpkin, I am guessing the background of the image did. This would cause the game to end even though the player didn’t know that the images touched since you visually couldn’t see that. To solve this I decided to add circles over the images to clearly define the borders and help the player better calculate when to press the space bar. I call it the cheat circle since it makes it really useful to jump at the right time and save the Zombie. Overall, I am glad I was able to combine what we have learned so far into a simple version of the dinosaur game that represents one of my favorite holidays.

Midterm Game

Concept:

I thought the snake game will be fun to implement – it is simple, fun, and can be done easily using OOP. It turned out to be a little more difficult than I expected it to be. Nevertheless, it was satisfying to implement a game I grew up playing 🙂

Challenges:

One of the most difficult parts was figuring out the algorithm for the movement of snake. It took me a lot of time. The way the algorithm works is that it the snake head (which is a class of itself) moves independently. It changes the direction based on the input key. The rest of the body of the snake is stored in an array. I run a for loop starting from the last index of the array and assign the last element’s x and y coordinate to the second last element. I do so until the second element’s x and y coordinate is equal to the first element’s values. Then I update the the first element’s values basis the position of the head for which I have 4 if conditions.

Another smaller issue I ran into was not being able to make a class which inherits from Arrays. I am not sure if that is possible in JS.

This is the bit on which I spent most of my time.

if(this.direction=="RIGHT"){
    for(let i=(g.arr.length)-1; i>1; i--){  //g is the snake head
        print("LOK");
        g.arr[i].row = g.arr[i-1].row;
        g.arr[i].col = g.arr[i-1].col; 
        g.arr[i].display();
    }
    g.arr[1].row = this.row+0.5;
    g.arr[1].col = this.col+0.5;
    g.arr[1].display();
    this.headimage;
}

else if(this.direction=="LEFT"){
    for(let i=(g.arr.length)-1; i>1; i--){
        print("LOK");
        g.arr[i].row = g.arr[i-1].row;
        g.arr[i].col = g.arr[i-1].col; 
        g.arr[i].display();
    }
    g.arr[1].row = this.row+0.5;
    g.arr[1].col = this.col+0.5;
    g.arr[1].display();
    this.headimage;
}
else if(this.direction=="UP"){
    for(let i=(g.arr.length)-1; i>1; i--){
        print("LOK");
        g.arr[i].row = g.arr[i-1].row;
        g.arr[i].col = g.arr[i-1].col; 
        g.arr[i].display();
    }
    g.arr[1].row = this.row+0.5;
    g.arr[1].col = this.col+0.5;
    g.arr[1].display();
    this.headimage;
}
else if(this.direction=="DOWN"){
    for(let i=(g.arr.length)-1; i>1; i--){
        g.arr[i].row = g.arr[i-1].row;
        g.arr[i].col = g.arr[i-1].col; 
        g.arr[i].display();
    }
    g.arr[1].row = this.row+0.5;
    g.arr[1].col = this.col+0.5;
    g.arr[1].display();
    this.headimage;
}
this.headimage;
this.row += this.vr; 
this.col += this.vc;

Other than that, the code is pretty much straightforward. There are 4 classes: SnakeHead, SnakeElements, Snake (initialises the game), and Food. I use function which calls the necessary class objects in a fucntion called restart which is called every time you click the canvas after losing. The game uses 3 pictures, 2 sounds, OOP, multiple shapes, on screen texts, and has a restart option.

Game: 

Reflections: 

It was a lot of fun to make, but I am unhappy with the aesthetics of the entire game. I also want to make it look a lot more smoother, but I’m not sure if my current algorithm will allow that. Another issue is that there is a possibility that the food can spawn at a location which is currently occupied by the snake – which can get slightly annoying. However, I learnt a lot and gained useful knowledge 🙂

 

Midterm Project- Tarek Nabih

Inspiration:

I came up with the game while thinking about my childhood games. Before starting to work on the project I kept brainstorming possible ideas that I can work on. One thing in particular that crossed my mind was to make the snake game as it was the main game that we all played on our Nokia devices when we were kids. But I noticed that a lot of people are doing it already so I changed my mind about the second option: “spaceship destroyer”. When I was a kid there was this well-known game in my community and among my friends, we called it “chicken.” In that game, there was this spaceship that was flying in the air and it was firing lasers at chickens while avoiding colliding with their eggs. Of course, it was way more advanced than that as it had multiple powerups and multiple levels and it seemed to have a story. However, I wanted to do something similar. And that’s when I decided to make the game I made. 

 

Challenges:

I think I experienced challenges in every step of coding that game. It all started with setting the size of the canvas. I think I overthought it as I was trying to find the perfect canvas size for the game. I ended up choosing a portrait-like canvas. 

Then I had a problem controlling the spaceship. The arrows were not doing the job. The spaceship’s movement was very weird. I tried multiple ways to make it smoother, but a lot of them didn’t work at first. I eventually found a good setup for the arrows. And I figured out a way to make it go to the right and appear from the left and vice versa to make the user experience smooth.

I think the biggest challenge was to make the bullets hit the rocks falling down. It was just going through it for hours without making any obvious thing at all. After hours of debugging, I figured out a way to make it the rock disappear when the laser hits it.

Code:

controlling the spaceship:

function keyPressed() {
  if(keyCode === ENTER){
     gamestatus = "running";
  }
  if (keyCode === UP_ARROW){
    makebullet(mainship.x,mainship.y);
  }
  if(keyCode === LEFT_ARROW){
    rate = -5;
  }
  if(keyCode === RIGHT_ARROW){
    rate = 5;
  }
  if(keyCode === BACKSPACE){
    rocks.splice(0,rocks.length);
    rocksctr = 0;
  }
  
  
}

function removeRocks(){
  rocks.splice(0,rocks.length);
  rocksctr = 0;
}


function keyReleased() 
{
  
  if (keyCode === RIGHT_ARROW || keyCode === LEFT_ARROW) 
  {
    rate = 0;
  }
  if(keyCode === ENTER){
     gamestatus = "running";
  }
  if(keyCode === BACKSPACE){
    rocks.splice(0,rocks.length);
    rocksctr = 0;
  }
  
}

Generating rocks:

function generaterocks(){
  let rand = int(random(0, 100));
  let rand2 = int(random(0, 100));
  if(rand % 7 == 0){
    if(rand2 % 3 == 0){
      if(rand2 % 2 == 0 && rand % 2 == 0){
          rocks[rocksctr] = new boulders();
          rocks[rocksctr].display();
          // console.log(rocksctr);
          rocksctr++;
        }
     }
  }
}

catching collisions and displaying rocks:

function displayrocks(){
  for(let i = 0; i < rocks.length; i++){
    rocks[i].display();
    // console.log(">",rocks.length);
    
    let temp = false;
    for(let j = 0; j < bullets.length; j++){
      if(bullets[j].didcollide(rocks[i])){
        temp = true;
        bullets.splice(i,1);
        numBullets--;
      }
    }
    
    if(mainship.didcollide(rocks[i])){
      rocks.splice(i,1);
      rocksctr--;
      gamestatus = "end";
      bomb.play();
    }else if(rocks[i].y > height || temp){
      rocks.splice(i,1);
      rocksctr--;
    }
  }
}

Main spaceship class:

class spaceship{
  constructor(){
    this.x = 200;
    this.y = 450;
    this.display();
  }
  
  display(){
    imageMode(CENTER);
    image(ship,this.x,this.y);

    this.move();
    this.checkboundries();


    imageMode(CORNER);
  }
  
  move(){
    this.x += rate;
  }
  
  checkboundries(){
    if(this.x > width){
      this.x = 0;
    }else if(this.x < 0){
      this.x = width;
    }
  }
  
  didcollide(other){
    if ( (this.x <= (other.x + other.width())) && (this.x >= other.x)) {
      if ((this.y <= (other.y + other.width())) && (this.y  >= other.y)){
        // print("Collision");
        return true;
      }      
      
    }
  }

}

The game:

 

Reflections:

Even though I faced several difficulties when creating the game and my original concept had to be modified, I am quite pleased with the outcome. Through making mistakes, I gained a lot of knowledge. I also discovered that it’s a pretty good approach to advance to break the problem into smaller challenges. I began the code with simple shapes before starting to add my assets, animation, point system, and other things. I examined the animation code independently and just inserted it once it began to move.

Assignment 3 – OOP

https://editor.p5js.org/merna.rakkad/full/fLiO5Qym8

Concept:

Coding using OOP was more difficult than I expected it to be, but with practice it ended up being as easy as the rest of the concepts. Learning OOP from scratch with no background in coding generally confused me a little because it was completely different and included many new functions and concepts, but doing this assignment helped me understand it; OOP felt very simple by the end of the assignment.

The concept of this program is simple, it is yet another artwork. I intended to make something that was visually pleasing and coordinated, and OOP helped me do that.

Using different creative names helps keep the code entertaining, for example when I used circir, that helped me store the different names and parts of the code in my head without being bored.

A problem I ran into was getting the constructors to work, my code kept crashing and the website would lag and I’d have to repeat the entire process again. After redoing the code though, I finally understood that my problem was with the syntax and I fixed it.

 

Midterm Project – Feed No Face!

Here’s the link the the editor and to the full screen game
Concept

My midterm project concept is based on a Studio Ghibli film called Spirited Away. The movie is about a girl named Chihiro who enters an abandoned amusement park because she lost her parents in the midst of moving homes, only to find her parents turned into pigs. There was one particular scene in the movie where No Face, a spirit side character, is fed by the workers, so I decided to use this scene as inspiration for my game.

No Face feasting

The concept is a game where you, as the character No Face from Spirited Away, have to eat all the food that appears on the screen. The trick is that you can only eat it when it reaches the height of the character, so clicking above will not count. If one food reaches the bottom of the canvas and you fail to click it, the game will end. Below are the three states of the game: the start/instruction screen, the actual game, and the game over screen.

How it Works
class Food {
  constructor() {
    this.xPos = random(50, width - 80);
    this.yPos = -20;
    this.xSize = 95;
    this.ySize = 70;
    this.xCenter = this.xPos + (this.xSize/2); // Midpoint formula
    this.yCenter = this.yPos + (this.ySize/2); 
    this.food = random(foods);
    this.speed = random(2,4);
  }
  
  rainingFood() {
    this.yPos += this.speed;
    this.yCenter += this.speed; // Since the y-position is moving down the screen, the center position also has to move in order for the distance to be accurate
  }
  
  // Mouse Interactions with Objects (The Coding Train):
  // https://www.youtube.com/watch?v=TaN5At5RWH8
  checkFoodEatenAt(mousePosX, mousePosY) {
    
    // Finds the distance between the mouse position and center of the food
    let d = dist(mousePosX, mousePosY, this.xCenter, this.yCenter);
    d = round(d);
    
    if(this.yPos >= 440) { // Can only eat when the food reaches the height of the character
      if(d < this.xSize/2 || d < this.ySize/2) { 
        eatSound.play();
        return true;
      }
    } else {
      return false;
    }
  }
  
  missedFood() {
    if(this.yPos > height) { // If it goes off the screen it's game over
      gameState = "end";
    }
  }
  
  show() {
    image(this.food, this.xPos, this.yPos, this.xSize, this.ySize);
    
    // For debugging the food click
    // noFill();
    // stroke(255);
    // strokeWeight(2);
    // rect(this.xPos, this.yPos, 95, 70);
    // stroke("Red");
    // strokeWeight(10);
    // point(this.xCenter, this.yCenter);
  }
}

The main part of the game is clicking on the food, essentially eating it. The food appearing and disappearing is done in a class called Food, which is assigned to an array. A new food is pushed into the array based on the frameCount remainder. The falling effect is done simply by adding to the y-position of the food with a speed variable.

The tricky part was figuring out how to remove the food and check if the mouse clicked on the food. Professor Shiloh suggested that I use a method that is specifically made for removing elements in an array, which I had not thought of at first. That got me thinking, so I searched for the method, which wonderfully enough, The Coding Train had videos on how to remove items in an array as well as how to check if the mouse clicked on an object.

Before watching the video, I knew I had to use dist() to figure out if the cursor is within the object, but I struggled a lot with that. It also didn’t help that since I scaled the images, the x and y position was all scaled as well (I put it in push() and pop(), but the numbers were still in the thousands). The Coding Train example used a circle to figure out the distance, but for my code I used a rectangle.

To walk through the whole process of figuring out the distance, I first drew a rectangle that was roughly the same size as the foods. I tried using the sizes to get the center of the rectangle, and to get that point I needed to use the midpoint formula. If I know the size, I only need one x-y point for the formula. After getting the center point, I can use dist() and do the if condition.

The first issue was the scaling, which I mentioned earlier. This made the x-y position insanely large, because I was multiplying it to account for the scale. So I ended up removing the scale and hard coded the size of the food. While I was lucky that the image didn’t get distorted, I feel like this isn’t really the best approach, but it works better than scaling.

The next issue I encountered was that even though my code should technically work, when I clicked on the food it didn’t disappear. So I drew a point at the center of the food “rectangles” to get a clearer picture. Lo and behold, turns out the points were just being drawn at the top and they don’t move down. This seemed like such a silly error because of course I should have realized that if the y-position is changing then I need to change the y-position of the center point as well.

All the center points (red) just stay at the top because I’m not adding the speed variable to it as well.

After figuring out how to click and remove the food, completing the rest of my project was mostly smooth sailing. All that was left was fine tuning the instruction and game over screens and implementing sound. I did, however, have another laughable problem while creating my instruction screen: basically, I wanted to create random ellipses in the background so it didn’t seem as empty. Since random changes constantly, I put noLoop() in my for loop, but I also surround it with a push() and pop() thinking that it would only noLoop() the for loop. So after finishing the instruction screen, I tested out the game, but realized that it no longer goes to the play mode. I spent a while trying to figure out why it wouldn’t go to the next screen anymore even though it registered me pressing “Enter”. I did eventually have a eureka moment and realized it was the noLoop(), which was a very trivial error that could have been avoid.

The ellipses that ended my program and made me confused for 30 minutes
Conclusion – What I’m Proud of and Future Directions

On a brighter note, I am quite proud of how the game turned out. My biggest struggle is honestly what I’m most proud of because I managed to make it work. I also really like how the play mode and game over screens turned out in terms of design (the instruction screen could still use some work). I actually took the No Face image in the play mode from an image that had a background, so I had to Photoshop it. For the food images it was all one image with a white background, so I also had to remove the background for that and crop into each food image. As for the music choices, Studio Ghibli films always have great music, but honestly the soundtrack for Spirited Away weren’t “game” material. So I decided to go for 8bit sounding music, even though the game isn’t 8bit, but I feel like it makes it sound more like a game soundtrack. Also a side note: the sound effect when you click on a food is basically the only sound No Face makes in the movie.

I did a few user tests and the main issue I ran into was people not reading the instructions. One of them has never played games, so she was very confused with what to do. The other user tester thought it was catching the food by moving the character, not clicking on the food. These are a few things that I need to consider if I continue to work on this in the future. Additionally, other things I want to work on in the future are fixing the instruction screen and adding lives instead of ending it at just one food missed.

Overall, I really love how my project turned out and it was super fun to create. Print() everything and drawing every detail is your best friend when it comes to debugging (but it’ll cause the program to lag if you do too much)!  And finally, I highly recommend watching Spirited Away, if you haven’t already : ).

 

Assignment 2 – Loops

https://editor.p5js.org/merna.rakkad/full/LpG1LkHo3

Concept:

I just started learning about loops and how to use them recently, and so, once I realized how they work and how I can make the most appealing projects with them, I started playing with the code and making different shapes and colors. In this project, I created art using shapes that are not really identifiable, but the way I did it was, I created circles that increased and decreases in size constantly, which resulted in the shape that came out.

I felt really proud after doing this following part of the code. As I’ve previously mentioned, I have not worked with loops or conditionals before, so getting this done and getting it to work was really a milestone for me and I am really proud ofit

while (x <= windowWidth) {
let r = random(255);
let g = 0;
let b = random(255);
fill(r, g, b);
ellipse(x, y, wed, hei);
wed += widinc;
hei += heiinc;
if (wed > 200 || wed < 100) {
widinc *= -1;
}
if (hei < 100 || hei > 200) {
heiinc *= -1;

Moving on, I feel very confident after this assignment that I will be able to implement concepts and ideas like this in bigger projects like the midterm. Mastering the art of loops and conditional statements opens the doors to many different creative opportunities and projects.

Midterm Daniel – Final Update

game concept

The idea from this game came from my love of music and rock songs, as well as me not being able to code that well to implement sprites. I made a trivia game for guessing songs as I sometimes enjoy guessing them when listening to them from a distance.

game phase

The game is a quiz style game, where a song will play for 5 to 10 seconds, and you choose one of the 4 album covers on screen. Wether you choose the right or wrong one, you will proceed to the next round. If you get a wrong answer you will see it on the strike section on the top-right side of the screen. If you get 3 strikes, you loose and have the end-screen, where it tells you the score a hint to getting the game’s surprise at the end.

I used the random function for the length of the song array and based on that pulled a song and the album cover from the arrays. The positions for the correct answer and the other images were confusing to find, but I found a way around it, generating the correct answer over one of the other pictures.

The game ends after 10 rounds or if you get 3 wrong answers, afterwards you will see the end screen, or if you get the 10 answers correctly, a special surprise.

challenges

The biggest challenge was making the album covers and songs be random, as it took a while to figure out an efficient way to make it work, specially for the positions. It took days to figure out but felt very rewarding at the end.

The other challenge was making the game flow, as I used a noLoop() without noticing it. The noLoop() made my code not work as it stopped all the draw functions to stop working as intended. I fixed it by making my code be function oriented. Instead of fitting everything into 1 function, I spread it around many different ones.

The last challenge was more of a tedious one, as the songs took some time to collect and write the code correctly, I think it could have been done in a much more efficient way, but I do enjoy the end result.

code

The code was based on game states, similar to the example of class:

function draw() {
  background(220);

//   Taken from gameState code in class, makes the game work cohesively 
   if (gameState == 'start') {
    drawInstructions();
    
  } else if (gameState == 'playing') {
    drawGame();
    
  } else if (gameState == 'end') {
    drawEndScreen();
  }
  
}

The draw parts of the game I tried to make them the most basic as possible, while adding custom functions to it.

function drawGame(){
  background('pink')
    
//Based on having a random result from a string  
  image(album_covers[wSong1], img1X, img1Y)
  image(album_covers[wSong2], img2X, img2Y)
  image(album_covers [wSong3], img3X, img3Y)
  image(album_covers [wSong4], img4X, img4Y)
  
// Strikes and strike counter
  push()
  strokeWeight (5)
  textSize(20)
  text('Strikes: ' + strike, 300, 30)
  stroke(255,0,0)
  pop()
    
//Correct song randomly placed over another picture
  image(album_covers[currentSong], goodX, goodY);  

  //Text for round and score
  text('Round ' + counter, 25, 25)
  text('Score: '+ score + '/10', 25, 40)
}


The way I transitioned from screens to the game itself, was by the mouse click function and adding more and more custom functions to it:

function mouseClicked(){
  console.log("gamestate is: ", gameState);
  if (gameState == 'start'){
//   Makes it so that the game can be looped and work properly when multiple games are played
    gameState = 'playing'; 
    randomize(); //the songs are randomized and in theory, don't loop
    counter++ // round increase
  }else if (gameState == 'playing'){
   if (mouse_is_over()) {  
    score ++ // whem you get an answer your socre increases
     nextRound() // refreshes the game 
   }else{
    strike ++
    console.log('strike');
    console.log(strike)
    nextRound()
    }
   }else if(gameState == 'end'){
    gameRestart() // game begins again and values reset
   }
}
  

function mouse_is_over(){ 
  // console.log (mouseX, goodX, mouseY, goodY) // This was for debugging
  
//   Makes it so that mouse is relative to the corredct answer
   if ((mouseX>= goodX && mouseX < goodX + imgSize) && (mouseY >= goodY && mouseY <goodY + imgSize)) {
     return true
   }else {
     return false
   }
}
 
// Game ends if 10+ rounds are reached
function rounds(){
  if(counter == 11){
   songs[currentSong].stop()
    rickRoll()
    gameState = 'end'
    // drawEndScreen()
  }
}

// makes the next round happen,randoized again
function nextRound(){
   songs[currentSong].stop()
    previousSongs.push(currentSong)
  counter++
  rounds ()  
  randomize()
    gameOver()
}

// makes it so songs don;t repeat
function noRepeat(){
  while (currentSong == previousSongs){
    currentSong = int(random(songs.length))
  } 
}

// functions and values reset
function gameRestart(){
  print('Resetting game state');
  strike = 0
  score = 0
  counter = 0
  previousSongs = [];
  gameState = 'start'
} 

// Makes it so the right song is in one of the 4 possible combinations
function currentSongPosition(){
  goodX = random(positionX)
  goodY = random(positionY)
  
}

//Game ends if you get 3 wrong answers
function gameOver(){
  if (strike > 3){
    gameState = 'end'
  }
}

//makes it so the album pictures don't repeat as much by using while statements
function randomize(){
    currentSong = int(random(songs.length))
  while(currentSong in previousSongs){
    currentSong = int(random(songs.length))
  }
  wSong1 = int(random(songs.length));
    while(wSong1 == currentSong){
    wSong1 = int(random(songs.length));
  }
  wSong2 = int(random(songs.length));
  while(wSong2 == currentSong || wSong2 == wSong1){
    wSong2 = int(random(songs.length));
  }
  wSong3 = int(random(songs.length));
    while(wSong3 == currentSong || wSong3 == wSong2 || wSong3 == currentSong){
    wSong3 = int(random(songs.length));
    }
  wSong4 = int(random(songs.length));
    while(wSong4 == currentSong || wSong4 == wSong3 || wSong4 == wSong2 || wSong4 == wSong1){
      wSong4 = int(random(songs.length))
    }
    songs[currentSong].play();

  currentSongPosition()
}

// special surprise
function rickRoll(){
  if (score == 10){
    gameState = 'end'
    window.open("https://www.youtube.com/watch?v=dQw4w9WgXcQ")
  }
}

future improvements

I would have liked to add the names of each song under the pictures, but wasn’t able to figure it out.

Another thing I would have liked to iron out would have been the issue of songs repeating after they are played one round, however I was never able to figure it out, same for the album covers and their positions, I feel it could’ve been more practical and simple than the way I did it.

Also, being able to show the songs that played at the end of the game, or after each round would have been good, in order for the player to look them up if they liked them.

reflection

It was very interesting and fun doing a project like this as it allowed me to get a lot of practice by challenging myself. Overall, I wish I could make more improvements like using hears instead of X’s, but it was very good.

Midterm project: Final game-Jump Pinkie!

Inspiration:

I came up with the theme of my game when I was looking for different sprite sheets, as I really wanted to learn how to animate sprites during the development of my game. I came across “My Little Pony” sprite sheets, and thought it would be fun and colorful to work with ponies. Initially, I wanted to create a platform jumping game, but due to some challenges(listed below), I changed the concept of my game to a jumping pony game resembling the Chrome Dino Game.

Game Phase:

PinkiePie one of the characters in the cartoon is running away from the small dragon, that’s why she has to jump over it. Each successful jump adds one point. Also, when Pinkie Pie collects the star, she also gets one more point. Some funny phrases from the actual cartoon play, when she collects a star. When she hits Draco, the game is over and a funny cartoon phrase plays.

Challenges:

Unfortunately, while I was trying to create platform classes, place them randomly, jump over them and check for collisions, my program did not work, and I could not figure out the solution. That’s why I decided to stick to the game without platforms. It led to the alterations of the whole project and the assets of the game.

Also, one of the biggest challenges was the animation of the sprite, therefore I am really happy with the result that my pony is running. However, I couldn’t do two consecutive animations. For example, when a pony is jumping do jumping animation, and then change to running animation immediately.

Code:

Parallax motion:

image(back1, x1, 0, width, height);
image(back1, x2, 0, width, height);

x1 -= scrollSpeed;
x2 -= scrollSpeed;

if (x1 < -width){
  x1 = width;
}
if (x2 < -width){
  x2 = width;
}

Create dracos and check for collisions, if yes the game is lost(same for the stars):

//creates dracos
if (millis() >= lastFrame + frameDelay) {
  dracos.push(new Draco());
  frameDelay = random(0.6, 1) * 2000;
  lastFrame = millis();
  score++;
}
//draw dracos and check for collision
for(let d of dracos){
  d.move();
  d.display();
  if(pinkiePie.hits(d)){
    gameState='lose';
    console.log("game over");
    gameLost=true;
    //noLoop();
  }
}

Class Pinkie Pie:

class PinkiePie{
  constructor(animation){
    this.size=80;
    this.x=40;
    this.y=300;
    this.vy=0;
    this.gravity=3;
    this.animation = animation;
    this.w = this.animation[0].width;
    this.len = this.animation.length;
    this.speed = 0.2;
    this.index = 0;
    
  }
  
  display(){
    let index = floor(this.index) % this.len;
    image(this.animation[index], this.x, this.y, this.size,this.size);
    
  }
  jump(){
    if (this.y==height-100){
      this.vy=-35;
    }
    
  }
  hits(elem){
    return collideCircleCircle (this.x,this.y,this.size,elem.x,elem.y,elem.size);
  }
  run(){
    this.index += this.speed;
    this.y+=this.vy;
    this.vy+=this.gravity;
    this.y=constrain(this.y, 0, height-100);
  }
}

Class Dracos/stars-aka obstacles:

class Draco{
  constructor(){
    this.size=40;
    this.x=width;
    this.y=height-70;

  }
  
  move(){
    this.x-=6;

  }
  display(){
    image(draco, this.x, this.y, this.size,this.size);
  }
}

Reflection:

Even though I had a lot of challenges when I was making the game and my initial concept was changed, I am really happy with my result.  I learned a lot during this process of mistakes. Also, I learned that breaking the problem into small problems is really great way of development. I started the code with primitive shapes and then started adding my assets and animation, point system and etc. I was checking the animation code separately and added it only when it was finally moving.

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.