Week 4 – ask the magic ball for your future

 

Overview

Honestly I have no idea where this idea came from. I’ve been scrolling a lot on Pinterest, and I saw a lot of these kinds of images, and also my mom just found recently our old Magic 8 Ball, so I thought why not combine the two?

I just wanted to create something fun as well. I have been having some pretty bad days, and making this not super serious helped a lot with my mood, and I really enjoyed coming up with all the responses for the Magic Ball. I also made some of my friends try it out once it was ready and they also really enjoyed it.

Process


Originally, I really wanted to make it look very cool, and make it 3D, but I saw that I can only draw a sphere in a WebGL mode, so I just stayed with circles and a triangle. I had to resize them a lot so that the text won’t be tiny, it is not that big like this either, but much better than originally.

I ALSO wanted it to have some magical background, BUT the preload function was not working here either. I have no idea what I did wrong, but it just wouldn’t work at all, so in the end I just stayed with this background.

The Code + a LOT of problems

Now, even though the code is short, I had the most amount of problems with it so far. The first thing I did, even before writing a CSV file was to draw the main object, so the Magic ball. This was really easy and I had some fun even by adding some shade to it:

function draw() {
  background(220);

  //the structure of the ball, drawing a bunch of circles, a triangle and the shadow to make it look fancier 
  fill('grey')
  noStroke();
  ellipse(300, 530, 500, 120);
  fill('black');
  circle(width / 2, height / 2, 500)
  fill('white');
  circle(width / 2, height /2, 400)
  fill('black');
  circle(width/2, height/2, 300);
  fill('white');
  triangle(300, 420, 200, 220, 400, 220);

After creating this, I strated on the actually challenging part of the code. This is how the start of the code looks like now:

let question; //inputfield
let submitQuestion; //button
let responses = []; //csv of possible responses
let currentResponse = ""; //store current response on the screen

//async_await, the code waits until the full CSV file is fully loaded, and only then continues and creates the canvas and everything below
async function setup() {

//try and catch, because I had SO many errors with loading the CSV, and could not figure out where it went wrong
  try {
    responses = await loadStrings('responses.csv');
  console.log('Loaded responses:', responses);
  } catch (error) {
    console.error('could not load', error);
  }
  
  createCanvas(600, 600);

Well it didn’t look like this always. After the drawings, I created a CSV file in p5.js for all the responses, and when I was done I made a preload function before setup, so I could preload that CSV. BUT. For some reason, I have no idea why, the text just wouldn’t appear. I tried to figure it out with a console.log, and it turns out that it was for some reason returning an empty array. I tried everything to make it work, I quadruple checked the came of the file, that my browser was allowing it to read it, I changed the loadStrings function to loadTable, but it just didn’t work. So, after some meditation to calm myself down, I asked ChatGPT, what I should do. It suggested to try the things I already tried, but it also mentioned the try and catch as well. I did learn some C# back in high school, and I remembered it slightly, but I decided to search it up just in case and try it out after. Previously, when I was searching for answers among the p5.js references, I also found the async_await function, so I combined the two together, AND IT WORKED. I was so happy, I didn’t dare touch it anymore.

The reason why I know it worked after, and only after that is because while I was waiting for the Javascript fairy to solve my problem, I made a little question field and a button for submission. Since the Magic Ball needs a question for it to answer, and for the user to be able to actually interact with it, I made this, directly below the previous code:

 //Create an input field to ask a question
  question = createInput('');
  question.attribute('placeholder', 'Ask a question from the Magic Ball!');
  question.position(170, 5);
  question.size(150, 30);

  submitQuestion = createButton('GOO!');
  submitQuestion.position(330, 5);
  submitQuestion.size(50, 36);
  
  //when the button is pressed it calls the giveAnswer function
  submitQuestion.mousePressed(giveResponse);
}

// if checks if there is any user input, and if there is it goes through the CSV file and choses a random response
function giveResponse(){
  let userQuestion = question.value().trim();

  if (userQuestion.length > 0) {
  currentResponse = random(responses);
  } 
}

The giveResponse function works with a simple if. I am not exactly sure of this is the most elegant way to do this, but it worked so I accepted it. As the last step to give my text a few attributes I added this in the draw function:

  //the reponses in the triangle
  fill('black');
  textStyle(BOLDITALIC);
  textAlign(CENTER, CENTER);
  textSize(12);
  text(currentResponse, 220, 230, 160, 120);
}

The piece if code I am the most proud of, however remains that little try and catch part, just because of the absolute misery it gave me.

And finally, here is the full code:

let question; //inputfield
let submitQuestion; //button
let responses = []; //csv of possible responses
let currentResponse = ""; //store current response on the screen

//async_await, the code waits until the full CSV file is fully loaded, and only then continues and creates the canvas and everything below
async function setup() {

//try and catch, because I had SO many errors with loading the CSV, and could not figure out where it went wrong
  try {
    responses = await loadStrings('responses.csv');
  console.log('Loaded responses:', responses);
  } catch (error) {
    console.error('could not load', error);
  }
  
  createCanvas(600, 600);
 
  //Create an input field to ask a question
  question = createInput('');
  question.attribute('placeholder', 'Ask a question from the Magic Ball!');
  question.position(170, 5);
  question.size(150, 30);

  submitQuestion = createButton('GOO!');
  submitQuestion.position(330, 5);
  submitQuestion.size(50, 36);
  
  //when the button is pressed it calls the giveAnswer function
  submitQuestion.mousePressed(giveResponse);
}

// if checks if there is any user input, and if there is it goes through the CSV file and choses a random response
function giveResponse(){
  let userQuestion = question.value().trim();

  if (userQuestion.length > 0) {
  currentResponse = random(responses);
  } 
}

function draw() {
  background(220);

  //the structure of the ball, drawing a bunch of circles, a triangle and the shadow to make it look fancier 
  fill('grey')
  noStroke();
  ellipse(300, 530, 500, 120);
  fill('black');
  circle(width / 2, height / 2, 500)
  fill('white');
  circle(width / 2, height /2, 400)
  fill('black');
  circle(width/2, height/2, 300);
  fill('white');
  triangle(300, 420, 200, 220, 400, 220);

  //the reponses in the triangle
  fill('black');
  textStyle(BOLDITALIC);
  textAlign(CENTER, CENTER);
  textSize(12);
  text(currentResponse, 220, 230, 160, 120);
}

 

For the future

I feel like I learnt a lot from this assignment, for some reason even more than from any previous one. I feel like I know a little more about how I have more ways to start a certain problem, but also that I am able to ask AI for help without asking it to solve it for me. Even though it was hard, I am proud to have finished it. In the future, I would love to make a more refined ball as well, but non of the images were loading in the preload function, so I ended up drawing it myself.

Resources

I took these as base for the responses:
https://magic-8ball.com/magic-8-ball-answers/

Creating the button and the question field:
https://p5js.org/reference/p5/createInput

https://editor.p5js.org/Samizdat/sketches/eUsieMk6j

The async_await function, after the preload() was not working:

https://p5js.org/reference/p5/setup/

https://p5js.org/reference/p5/async_await/

Text style:

https://p5js.org/reference/p5/textStyle/

Some help to debug the problem:

I asked ChatGPT to help me figure out what the problem was, after the preload() function kept returning my array as empty, and it suggested the try and catch solution, so I did some research on that:

https://www.w3schools.com/js/js_errors.asp

https://www.geeksforgeeks.org/javascript/javascript-errors-throw-and-try-to-catch/

The final code was written by me, the AI only helped in terms of suggetsing me this solution.

 

 

 

Leave a Reply