Midterm Progress – The Boy Who Cried Wolf

Concept

For my midterm project, I decided to make a game based on one of my favorite fables, The Boy Who Cried Wolf! The story goes that the boy, a shepherd, gave a false alarm to a village about a wolf coming to attack their sheep. Having done it two times, the third time, when a wolf was actually coming, the villagers did not believe him, leaving the sheep dead. There is a valuable lesson in this story, but as a child, I always wished they had saved the sheep. Why not believe the third time, you know, just in case? So, I decided to create a game in which a shepherd needs to collect his sheep into a pen before the wolf arrives to eat them.

Progress

For now, I have created the sheep and shepherd graphics and shapes which are underneath the images. The shepherd moves the sheep as he gets close to them and the sheep move around each other if they get too close. What is left is the sheep pen and the interactions concerning it. As for the graphics that are left, I intend on making the wolf, start and end screens, all pixelated as that is what I aim for the game to look like. I have also created the tree graphics which I will place around the screen.

Challenge

The most challenging part as of now is the sheep and pen interactions. Since the sheep move by 15 pixels as the shepherd approaches, it will take some thinking and logic to stop them from moving through the fence. I have experimented a bit and some solutions worked to a certain extent while others failed miserably. Since that is the last part of the game that needs to be implemented, I will put in some work to make it as smooth as possible. I have imported a library that makes shape interactions easier to handle.

The game might not be extremely complex at its core, but I have limited myself to only one or two libraries. The rest I wish to finish using pure JS. If possible, I also wish to create a second phase of the game where the shepherd and the wolf fight if the sheep are placed in the pen on time. If I have time left, I will try and make this possible or simplify the fight in order to incorporate it into the final version.

 

Midterm Progress

For the midterm, I decided to recreate one of my favorite childhood games, Doodle Jump. The user will be able to play the game using either WASD or arrows. The goal of the game is to score as many points as possible. The higher you get, the harder it will be to survive.

As you can see on the sketch, the game already has the intro page, the user selects which doodler he wants to use; the main page, the game itself with platforms, boosters, and hazards; and the game over the page, a meme about how you lost.

The hardest part of this project is the animation of a doodler. There are so many cases such as trampoline, jetpack, hat, shooting and etc. For each one of them, there is a different doodler. Hence, I had to upload more than 20 images and use each one of them accordingly. I already implemented this part, which makes my life much easier.

However, there are a few things that do not work right now. The sounds get collapsed. Only one platform is shown. The Jetpack is shown instead of the appropriate booster. These are the bugs I have to fix before spring break.

 

Week 4 – Global Temperature Anomaly Visualization

Concept & Idea

This visualization shows the change in global temperature anomaly (the difference between the actual temperature and the long-term average temperature) over time, based on publicly available data. The visualization uses a line chart to represent the data, with the x-axis representing the years from 1753 to 2015 and the y-axis representing the temperature anomaly in degrees Celsius.

 

Implementation

The chart is generated using the p5.js library for drawing and the d3.js library for data manipulation. The code first loads the JSON data from a publicly available URL and extracts the necessary data. It then draws the x-axis and y-axis of the chart, with tick marks and labels indicating the years and temperature values. Finally, it draws the data points as small circles with color representing the temperature anomaly value, and connects them with lines to form the line chart.

let data; // variable to hold the JSON data
let minYear, maxYear, minTemp, maxTemp;

function preload() {
  // load the JSON data from a publicly available URL
  let url = 'https://raw.githubusercontent.com/freeCodeCamp/ProjectReferenceData/master/global-temperature.json';
  data = loadJSON(url);
}

function setup() {
  createCanvas(800, 400);
  textAlign(CENTER);
  textSize(16);
  noLoop();

  // extract the necessary data from the JSON
  let monthlyData = data.monthlyVariance;
  minYear = monthlyData[0].year;
  maxYear = monthlyData[monthlyData.length - 1].year;
  minTemp = data.baseTemperature + d3.min(monthlyData, d => d.variance);
  maxTemp = data.baseTemperature + d3.max(monthlyData, d => d.variance);
}

function draw() {
  background(255);

  // draw the x-axis
  stroke(0);
  line(50, height - 50, width - 50, height - 50);
  for (let year = minYear; year <= maxYear; year += 10) {
    let x = map(year, minYear, maxYear, 50, width - 50);
    textAlign(CENTER);
    text(year, x, height - 30);
    stroke(200);
    line(x, height - 50, x, 60);
    stroke(0);
  }

  // draw the y-axis
  line(50, height - 50, 50, 60);
  textAlign(CENTER);
  push();
  translate(30, height / 2);
  rotate(-HALF_PI);
  text("Temperature Anomaly (°C)", 0, -15);
  pop();
  for (let temp = Math.floor(minTemp); temp <= Math.ceil(maxTemp); temp += 1) {
    let y = map(temp, minTemp, maxTemp, height - 50, 60);
    textAlign(RIGHT);
    text(temp, 40, y + 5);
    stroke(200);
    line(50, y, width - 50, y);
    stroke(0);
  }

  // draw the data points and connecting lines
  noFill();
  beginShape();
  for (let i = 0; i < data.monthlyVariance.length; i++) {
    let x = map(data.monthlyVariance[i].year, minYear, maxYear, 50, width - 50);
    let y = map(data.baseTemperature + data.monthlyVariance[i].variance, minTemp, maxTemp, height - 50, 60);
    stroke(255 - map(data.monthlyVariance[i].variance, -7, 7, 0, 255), 0, map(data.monthlyVariance[i].variance, -7, 7, 0, 255));
    ellipse(x, y, 4, 4);
    vertex(x, y);
  }
  endShape();
  
  // add the title and data source
  textAlign(CENTER);
  text("Global Temperature Anomaly (°C) " + minYear + " - " + maxYear, width / 2, 30);
}

Reflection & Future Improvements

This visualization allows users to easily see the trend in global temperature anomaly over time, as well as the magnitude of the variation in temperature from year to year. The color-coded data points also highlight areas of particularly high or low temperature anomalies, drawing attention to potentially significant events or trends in global climate. There are several potential improvements that could be made to this visualization. For instance, the visualization could be made more interactive by allowing users to hover over data points to see the exact temperature anomaly value and the year, or to zoom in on specific areas of the chart to see more detail. Users could also be given the ability to adjust the time frame shown on the chart or to select specific temperature ranges to focus on.

 

Assignment 4 – FIFA World Cup Data Visualization

The Concept

This piece is to provide a data visualization of all the countries that have won the FIFA world cup since the start of the tournament in 1930. I used a pre existing map of the world in p5js, and added the data about the world cups from kaggle. By combining the two, I was able to have all the data I needed to create the visual representation.

The Sketch

Link for the full screen sketch: https://editor.p5js.org/mhh410/full/3e1QPs51S

<

The design of the sketch itself is something I spent a lot of time on. I tried various combinations of world map lay outs, color combinations and even explored the Mappa library. At the end, the most practical thing to use was a preexisting p5js sketch [link: https://editor.p5js.org/Kumu-Paul/sketches/8awPJGZQ4] as the structure of my data visualization. The preexisting sketch gave me access to a complex array of vertices that layout the border of every single country in the world.

Now with the dataset for all the countries locations as vertices, I needed a dataset of all the Fifa World Cups that have taken place. I found a great resource of Kaggle, but it only went up to 2014, so I had to manually add the relevant data to make it up to date.

Then to combine everything, I first started by making the whole map black. I wanted to highlight the countries that won the world cup as gold, and the countries that were runner ups as silver, so adding any different color in the background didn’t seem to make sense aesthetically. I added a slider functionality to build on the interactivity of the sketch. The slider represents the date starting from 1930, when the first world cup was hosted, and the user can slide it all the way till 2022. As the world cup happens every 4 years, the slider has a step of 4.

The next step was to extract data from the World Cup csv about the date, the winner and the runner up. To do this, I iterated over the csv table and saved the winners and the runner ups in separate arrays. There was one issue here, which was what happens if a country already won the cup and then were runner ups in later years. If a country had won the world cup, but then became runner ups later on, I wanted them to stay with the gold color. To do this I had to make sure I create the winners array first and then cross check the winners array before pushing to the runner ups array.

Finally, the last functionality I wanted to add is that if a country won the world cup several times, I wanted there to be some distinction when compared to the rest. Todo so, I added a variable which counted the number of wins, and then decreased the rgb value of the shade of gold by a factor of the number of wins. This allowed me to create a representation for the number of wins of each country, as the countries that had won more cups now were represented by a darker shade of gold

 

Improvements

I would have liked to change the color of the slider, but unfortunately I can’t do that on p5js

HW4: Generative Text

CONCEPT

I was inspired by the Stroop text I learned about from the intro to psychology class I am currently taking. The test requires its participants to name the colors of the words on the grid as fast as possible. The trick is that the words on the grid are actually the names of colors different from the ones they are colored in. This test allows for measuring a person’s selective attention capacity and executive processing skills. In my assignment submission, I am making this test into a written game.

Taking the Stroop Test | Musings of an Aspie

IMPLEMENTATION

The most challenging part of the idea implementation for me was to make the time counter work. I couldn’t figure out how to make it count the seconds since the beginning of the game as opposed to every frame since the beginning of the game. My mistake was that I didn’t divide it by 60, which sounds silly but took me lots of time to notice. Besides that, I didn’t have any other issues while figuring out the game design. Below is attached a snippet of my time counter:

//update and display time since the beggining of the game
function updateTime() {
  //check if 30sec passed
  if (timeLeft > 0) {
    //count seconds passed since start
    let alltime = floor((frameCount - startTime) / 60);
    //count time left
    timeLeft = 30 - alltime;
    //display time left
    textSize(14);
    text("time: " + timeLeft, width / 1.25, 270);
  }
  //if 30sec passed -> end game
  else {
    gameOver(false);
  }
}

ASPECTS TO WORK ON

I feel like my code could have been written more beautifully (neater and more concise). I have also tried assembling it as a class but I couldn’t figure out how to make it work, so I turned it back into a bunch of functions. Perhaps, I could have actually displayed the words in a grid as opposed to one word at a time to make it more challenging to focus for the user.

 

Week 4 Generative Text

The concept behind this project is to create a colorful, dynamic, and mesmerizing generative artwork that combines vibrant colors, fluid shapes, and intriguing phrases. To achieve this, we use a combination of randomization and user-defined variables to create unique color schemes, shapes, and phrases.

 

 

The program is structured around a group of arrays that describe the nouns, adjectives, and colors that make up the sentences. The random() method is then used to pick a color from the color array, an adjective from the adjective array, and a noun from the noun array, resulting in a sentence that vividly describes a scene using a wide variety of colors and adjectives.

My use of a gradient background is one of the code snippets I am most pleased with. To make a background that is both visually pleasing and easy on the eyes, I used the createLinearGradient() function to make a linear gradient.

 

Adding user controls to this project would be a great way to improve it and give people more interactivity in shaping the final product. Also, I would use other shapes and phrases, adding additional components to the artwork to increase its visual complexity and intrigue.

 

 

 

 

Generative Text with p5js

For this homework, I chose to work with generative text and produce a simple program that will output a poem of my choice in some chaotic fashion. The poem I chose ‘The night, the pharmacy, the street’ is one of quite famous poems in Russian by Alexander Blok, and it is one of very few I can fully recite in Russian. Personally, while this poem has a meaning, it always comes to my mind first when I think of something quite random in literature.

To select which words are going to be displayed in canvas, I use the following function. It first filters poem from double spaces and then randomly selects the first word to display as well as the last word.

function drawWords(x, y) {

  let corpus = poem.split(' ').filter(y => y!="");

  let first_word = floor(random(corpus.length));
  let last_word = first_word + random(2, 8);

  fill(255,233,0);
  text(corpus.slice(first_word, last_word).join(' ').trim(), x, y);

}

The sketch of my final program is shown below:

I chose yellow and black to better match with the scene described: the street in the night with the bright lamppost. For future improvement, I would like to add more complexity to implementation and to make it more random. It feels chaotic as of now, but with addition of randomness in the position and more controlled randomness in the selection of words it should be more accurate in my vision. Also, I wanted to work on graphics a bit and add a lamp with options to turn on and off to match the theme. Overall, this was a fun experience with generative text and I hope future projects are going to be fun as well =)

 

Link: https://editor.p5js.org/ds6058/sketches/GHtAW9-XW

References:

https://sites.google.com/site/poetryandtranslations/alexander-blok/-the-night-the-pharmacy-the-street-a-blok

https://p5js.org/examples/typography-words.html

Assignment 4 – Data Visualization

In this assignment, I represent the countries of the world and their population growth over the years on a world map.

To start off, I downloaded the dataset from https://data.worldbank.org/indicator/SP.POP.TOTL. The dataset shows the countries of the world, and the respective populations of each year from 1960 to 2021. As the dataset only contained the country names and not their latitudes and longitudes, I used the Google Sheets extension “Geocode by Awesome Table” to generate the lats and lons of each country. I cleaned up the data by removing all rows where the longitudes and latitudes could not be generated.

Once the data was ready, I read through the csv and generated points for each longitude and latitude. I then added a map of the earth in the background and adjusted the lans and lats to match the borders of the countries as accurately as possible. To ensure this was successful, I also printed the names of all the countries along with their points to give me a better idea about where to place the dots approximately. Initially, I mapped the population of 2021 for all countries only for making sure the program runs fine.

After this was implemented, I used the map() function to change the size of the ellipses and their colors based on the population of the country. This was done by initially finding the min and the max population from the entire dataset along with min and max latitudes and longitudes.

Once I had the basic functioning code for the year 2021, I edited the code to run for all years. As the code was too slow when the years were only incrementing by 1, I changed it to make the years increment by 10 each time.

Reflection

I found it quite challenging to update the canvas without removing the ellipses which represented the population for the previous year. If I updated the background image each time the draw function was run, all ellipses was erased. And, if I only updated it every time the year was incremented, all the previous ellipses were erased due to which it was difficult to estimate population growth over the years. To solve this problem, I went through P5 references to understand multiple functions which may help me to solve the problem such as erase() and clear() but none of them helped. Eventually, I settled on only initializing the background once in setup but adding a black rectangle behind the text so I can update it every time without the years being overwritten on top of each. One aspect in which I believe this piece could have been further improved is by showing the growth of all the circles more dynamically instead of one being drawn over another.

Assignment 4: Generative Text

Concept & Inspiration

Aaron Sherwood’s portfolio website had me impressed since the past 2 years, and it had been on my to-do list of things to learn just because of how addictive its animations were. Therefore, I decided to pursue this assignment in p5js to produce something similar and learn something new.

The website I took inspiration from is linked here

Embedded Canvas

The assignment outcome is attached as an embedded sketch as follows:

Code

The methodology to convert the text to points:

function setup() {
  createCanvas(600, 400);
  textSize(64);
  textFont(font);

  for (let i = 0; i < texts.length; i++) {
    let points = font.textToPoints(texts[i], 50 + i * 150, height / 2,50, {sampleFactor: 0.75, simplifyThreshold: 0 });
    for (let j = 0; j < points.length; j++) {
      let p = new Particle(points[j].x, points[j].y);
      particles.push(p);
    }
  }
}

Object Oriented Nature of the Particles!

class Particle {
  constructor(x, y) {
    this.pos = createVector(x, y);
    this.vel = createVector(random(-1, 1), random(-1, 1));
    this.acc = createVector(0, 0);
    this.target = createVector(x, y);
    this.size = 2;
    this.maxSpeed = 2;
    this.maxForce = 0.1;
    this.attractRadius = 50;
    this.attractForce = 0.1;
    this.color = color(255, 255, 255);

  }

  behaviors() {
    let arrive = this.arrive(this.target);
    this.applyForce(arrive);
    this.repel();
  }

  repel() {
    let mouse = createVector(mouseX, mouseY);
    let distance = p5.Vector.dist(this.pos, mouse);
    if (distance < this.attractRadius) {
      let repelForce = p5.Vector.sub(this.pos, mouse).normalize().mult(this.attractForce);
      this.applyForce(repelForce);
    }
  }
    attract() {
    let mouse = createVector(mouseX, mouseY);
    let distance = p5.Vector.dist(this.pos, mouse);
    if (distance < this.attractRadius) {
      let attractForce = p5.Vector.sub(mouse, this.pos).normalize().mult(this.attractForce);
      this.applyForce(attractForce);
    }
  }

  applyForce(f) {
    this.acc.add(f);
  }

  arrive(target) {
    let desired = p5.Vector.sub(target, this.pos);
    let d = desired.mag();
    let speed = this.maxSpeed;
    if (d < 100) {
      speed = map(d, 0, 100, 0, this.maxSpeed);
    }
    desired.setMag(speed);
    let steer = p5.Vector.sub(desired, this.vel);
    steer.limit(this.maxForce);
    return steer;
  }

  update() {
    this.pos.add(this.vel);
    this.vel.add(this.acc);
    this.acc.mult(0);
  }

  show() {
    // Set the fill color based on the velocity of the particle
    let vel = this.vel.mag();
    if (vel < 0.5) {
      this.color = color(255, 0, 0); // red
    } else if (vel < 1) {
      this.color = color(255, 255, 0); // yellow
    } else {
      this.color = color(255, 255, 255); // white
    }

    fill(this.color);
    noStroke();
    ellipse(this.pos.x, this.pos.y, this.size, this.size);
  }
}

 

Problems

The primary issue I faced was to discover the font.textToPoints() function and its complex usage. The other difficult bits was to repel or attract the points and adjust the speed and colors of it!

Assignment 4 – Generative Text

Concept

For this project, I decided to go for the Generative Text option, because I felt that way I could get some experience both with manipulating text and implementing csv files as well. I really wanted to use particle systems to generate text and do some fun stuff with them so I went ahead and explored a little on how to implement a particle system in p5.js and use it to generate text.

Implementation

I started off by making a Particle class. This class essentially contains all the attributes that are related to the particles that are generated. For instance, it contains their velocity, acceleration, maximum speed, and whether they have left the canvas yet or not, or in other words, if they are alive. I thought it would be a great idea to use vectors for this scenario since velocity and acceleration basically are defined by a magnitude and direction (which in essence is a vector). So I went ahead and made unit vectors for both of them.

// creating the class for the particles
class Particle {
  // the x and y positions where the particle would appear
  constructor(x, y) {
    this.pos = createVector(x, y);
    this.vel = createVector(random(-1, 1), random(-1, 1)); // to include all directions (360 deg)
    this.acc = createVector(random(-1, 1), random(-1, 1)); // to include all directions (360 deg)
    this.maxSpeed = 20; // limiting max speed of the particle
    this.prevPos = this.pos.copy(); // will use this as a starting point to create a line 
    this.alive = true; // to check if the particle has left the canvas
  }

As for the methods, the update method would add acceleration to the velocity vector and increase the acceleration at the same time as well. The particles are displayed as lines by using the current and previous positions of the particles in every frame. This really makes the particles look as though they are flying off like shooting stars when the ENTER key is pressed.

// to make the particle move
update() {
  this.vel.add(this.acc); // to make the particles move with increasing speed
  this.vel.limit(this.maxSpeed); // limiting them to a max speed
  this.pos.add(this.vel); // making them move by changing their position
  this.acc.mult(2); // increasing acc on every update so the lines become longer
}

// making lines to make particles appear
show() {
  stroke(random(255), random(255), random(255));
  // using previous pos and updated pos to make a line for the travelling particle
  line(this.pos.x, this.pos.y, this.prevPos.x, this.prevPos.y);
  // updating the prev position
  this.prevPos = this.pos.copy();
}

Another interesting method I used was the one that allowed the pixels to wrap around the text. I did this by looping over all the pixels in the canvas and checking if the pixel was white or 255. If it was then I would place a particle at that pixel. I didn’t display the text itself, it only appeared for a split second in one of the frames of the draw() function and during that time the particles would stick to that text. The nested for loops I used were as follows:

// the nested for loop traverses over the whole canvas and finds where the 
// white pixels of the text are located
for (let x = 0; x < width; x += 2) { // number after += indicates density of particles
  for (let y = 0; y < height; y += 2) { // lesser number = more performance problems
    let index = (x + y * width) * 4;
    if (pixels[index] == 255) { // checking if the text is present at the current pixel
      let p = new Particle(x, y); // if yes then make a particle at that position
      particles.push(p); // and add it to the array
    }
  }
}

Reflection

I really enjoyed working with text and particles during this assignment and I feel I learned a lot about particle movement, vectors, and pixels; all of which were new concepts for me. I did notice a strange bug however while I was working on this assignment and I wasn’t quite able to fix it. I was initially working on my monitor for this assignment and it was working just fine, but as soon as I opened the p5.js file on my laptop screen, the particles that made up the word were not aligned at their correct positions on the screen. I really tried to dig deep into this issue but I couldn’t understand why it was happening. Due to this, I had to fix the position of the random particle text on the center of the screen instead of using the mousePos  to generate it. I would love to explore more on how I could resolve this bug as I have never encountered a bug like this before in p5.