xxxxxxxxxx
781
// stuff that manages sounds
let sounds = []; // array to store music sound objects
let currentsound; // to keep track of current music playing
let currentsoundIndex; // currentsound index in sounds[]
let knocking; // to store knocking sound
let dooropen; // door opening sound
let canKnock = true; // to prevent continuous knocking while on door
let canStartMusic = true; // to prevent music playing on top whenever we enter
// stuff that manages text
quotefile = []; // contains entire lines of the csv as arrays
quotes = []; // 2D array that stores the split-up pieces of text
selectedquotes = []; // stores 3 random quotes to be displayed by the books
let book1quote = false;
let book2quote = false;
let book3quote = false;
// global variables for the Japanese Tree
let onFrame1 = false; // for detecting mouse hover over objetcs
let leafColors = ["#963990", "#4B2454"];
let leaves = []; // array to store all the leaf objects
let numLeaves = 600; // setting number of leaves of the tree
function preload() {
// loading the csv file into an array
quotefile = loadStrings("quotes.csv");
// storing paths of soundfiles in an array
soundFiles = [
"/sounds/music1.mp3",
"/sounds/music2.mp3",
"/sounds/music3.mp3",
];
// loop through the sound files and load each one as objects into the sounds[] array
for (let i = 0; i < soundFiles.length; i++) {
sounds[i] = loadSound(soundFiles[i]);
}
// preloading all images
knocking = loadSound("/sounds/knocking.mp3");
dooropen = loadSound("/sounds/door-open.mp3");
cafeoutside = loadImage("photos/outside.png");
cafeinside = loadImage("photos/inside.png");
board = loadImage("photos/board.png");
smallboombox = loadImage("photos/boombox-small.png");
bigboombox = loadImage("photos/boomzoom.png");
boomboxwhite = loadImage("photos/boombox-white.png");
boomplay = loadImage("photos/boomplay.png");
boompause = loadImage("photos/boompause.png");
boomnext = loadImage("photos/boomnext.png");
boomback = loadImage("photos/boomback.png");
frame1 = loadImage("photos/frame1.png");
frame2 = loadImage("photos/frame2.png");
frame3 = loadImage("photos/frame3.png");
frame1white = loadImage("photos/frame1-white.png");
frame2white = loadImage("photos/frame2-white.png");
frame3white = loadImage("photos/frame3-white.png");
bookzoom = loadImage("photos/bookzoom.png");
bookzoomwhite = loadImage("photos/bookzoom-white.png");
book1white = loadImage("photos/book1-white.png");
book2white = loadImage("photos/book2-white.png");
book3white = loadImage("photos/book3-white.png");
boardwhite = loadImage("photos/board-white.png");
doorwhite = loadImage("photos/door-white.png");
bgimage = loadImage("photos/background.png");
previousbutton = loadImage("photos/previousbutton.png");
previousbuttonwhite = loadImage("photos/previousbutton-white.png");
frame1zoom = loadImage("photos/frame1zoom.png");
frame2zoom = loadImage("photos/frame2zoom.png");
frame3zoom = loadImage("photos/frame3zoom.png");
}
function setup() {
createCanvas(1000, 600);
rectMode(CENTER);
// creating the scene manager object for managing layers
scene = new SceneManager();
// creating an array of quotes with authors and genres
for (let i = 0; i < quotefile.length; i++) {
quotes[i] = quotefile[i].split(";");
}
// selecting 3 random quotes
for (let i = 0; i < 3; i++) {
selectedquotes[i] = quotes[Math.floor(random(1, quotes.length))];
}
// creating leaves for the Japanese Tree
// populating the array with leaf objects
// cluster 1: topmost
for (let i = 0; i < numLeaves - 400; i++) {
leaves[i] = new Leaf(170, 220, 80, 30);
}
// cluster 2: bottom-most
for (let i = numLeaves - 400; i < numLeaves - 200; i++) {
leaves[i] = new Leaf(200, 380, 90, 30);
}
// cluster3: rightmost
for (let i = numLeaves - 200; i < numLeaves; i++) {
leaves[i] = new Leaf(420, 280, 100, 40);
}
}
// for displaying the japanese Tree upon clicking frame1
function zoomedFrame1() {
background("#F8EDE2");
drawTrunk();
// drawing all the leaves and removing the ones which have reached the bottom of the canvas
for (let i = leaves.length - 1; i >= 0; i--) {
leaves[i].move();
leaves[i].draw();
leaves[i].checkForCollisions();
if (!leaves[i].alive) {
leaves.splice(i, 1);
}
}
// choosing a random leaf to fall every 20 frames
// if the leaves[] array becomes empty, it causes an error because the length is 0 but
// the 0th element doesn't exist anymore so we provide a check for that as well
if (frameCount % 25 == 0 && leaves.length != 0) {
// choosing a random leaf index to make it fall from the tree
index = int(random(0, leaves.length));
// check if the leaf at the random index is alive and present inside the array
if (leaves[index].alive) {
// if yes then make the leaf fall
leaves[index].fall = true;
}
}
// to confirm if the array objects are being deleted
console.log(leaves.length);
// to translate the back button back to its original position
translate(-200, 0);
if (!scene.onOutsideButton) {
image(previousbutton, 0, 0);
} else if (scene.onOutsideButton) {
image(previousbuttonwhite, 0, 0);
}
}
function draw() {
background(220);
// displaying scene images according to the layer
scene.display();
if (scene.layer4) {
// draw japanese tree
zoomedFrame1();
}
// this was to assist with finding coordinates to detect clicks on objects
// showPoint();
}
function mouseClicked() {
// checking which object the user has clicked on and then displaying the relevant layer
if (scene.onDoor) {
console.log("Door clicked!");
// if yes move inside the cafe
scene.layer1 = false;
scene.layer2 = true;
// start playing the music
dooropen.play();
if (canStartMusic) {
sounds[0].play();
canStartMusic = false; // to prtevent music playing on top whenever the door is clicked
}
currentsound = sounds[0];
currentsoundIndex = 0;
}
if (scene.onSmallBoombox) {
console.log("boombox clicked!");
// if yes zoom into boombox
// layer 1 is already false as we're in layer 2
scene.layer2 = false;
scene.layer3 = true;
}
if (scene.onFrame1) {
console.log("frame1 clicked!");
// if yes zoom into japanese tree
scene.layer2 = false;
scene.layer4 = true;
}
if (scene.onFrame2) {
console.log("frame2 clicked!");
// if yes zoom into frame2
scene.layer2 = false;
scene.layer5 = true;
}
if (scene.onFrame3) {
console.log("frame3 clicked!");
// if yes zoom into frame3
scene.layer2 = false;
scene.layer6 = true;
}
if (scene.onMenu) {
console.log("menu clicked!");
scene.layer2 = false;
scene.layer8 = true;
}
if (scene.onBook1) {
console.log("book1 clicked!");
// if yes zoom into book
scene.layer2 = false;
scene.layer7 = true;
book2quote = false;
book3quote = false;
book1quote = true;
}
if (scene.onBook2) {
console.log("book2 clicked!");
// if yes zoom into book
scene.layer2 = false;
scene.layer7 = true;
book1quote = false;
book3quote = false;
book2quote = true;
}
if (scene.onBook3) {
console.log("book3 clicked!");
// if yes zoom into book
scene.layer2 = false;
scene.layer7 = true;
book1quote = false;
book2quote = false;
book3quote = true;
}
if (scene.onPlayButton) {
// play the sound
console.log("play clicked!");
if (currentsound.isPaused()) {
currentsound.play();
}
}
if (scene.onPauseButton) {
// pause the sound
console.log("pause clicked!");
if (currentsound.isPlaying()) {
currentsound.pause();
}
}
if (scene.onNextButton) {
// play the next song
console.log("next clicked!");
if (currentsound.isPlaying()) {
currentsound.pause(); // stop the current music that's playing
sounds[(currentsoundIndex + 1) % sounds.length].play(); // start the music that's next in line
// update the current sound index and current sound
currentsoundIndex = (currentsoundIndex + 1) % sounds.length;
currentsound = sounds[currentsoundIndex];
} else if (currentsound.isPaused) {
sounds[(currentsoundIndex + 1) % sounds.length].play(); // if it's already paused then play the next sound
// update the current sound index and current sound
currentsoundIndex = (currentsoundIndex + 1) % sounds.length;
currentsound = sounds[currentsoundIndex];
}
}
if (scene.onBackButton) {
// play the previous song
console.log("back clicked!");
// same as in next sound but the only difference is we have to take care of index 0
if (currentsound.isPlaying()) {
currentsound.pause(); // if the current sound is playing, pause it first
if (currentsoundIndex == 0) {
sounds[sounds.length - 1].play(); // if we're at index 0, play the last song in the list
currentsoundIndex = sounds.length - 1;
currentsound = sounds[currentsoundIndex];
} else {
sounds[(currentsoundIndex - 1) % sounds.length].play(); // otherwise play the previous one
currentsoundIndex = (currentsoundIndex - 1) % sounds.length;
currentsound = sounds[currentsoundIndex];
}
} else if (currentsound.isPaused) {
// if it's paused already, repaet the steps without the pausing step
if (currentsoundIndex == 0) {
sounds[sounds.length - 1].play();
currentsoundIndex = sounds.length - 1;
currentsound = sounds[currentsoundIndex];
} else {
sounds[(currentsoundIndex - 1) % sounds.length].play();
currentsoundIndex = (currentsoundIndex - 1) % sounds.length;
currentsound = sounds[currentsoundIndex];
}
}
}
// the following conditions check if the back button is pressed in any layer
// if it is, we move back to the previous layer
if (scene.onOutsideButton && scene.layer2) {
scene.layer1 = true;
scene.layer2 = false;
}
if (scene.onOutsideButton && scene.layer3) {
scene.layer2 = true;
scene.layer3 = false;
}
if (scene.onOutsideButton && scene.layer4) {
scene.layer2 = true;
scene.layer4 = false;
}
if (scene.onOutsideButton && scene.layer5) {
scene.layer2 = true;
scene.layer5 = false;
}
if (scene.onOutsideButton && scene.layer6) {
scene.layer2 = true;
scene.layer6 = false;
}
if (scene.onOutsideButton && scene.layer7) {
scene.layer2 = true;
scene.layer7 = false;
}
if (scene.onOutsideButton && scene.layer8) {
scene.layer2 = true;
scene.layer8 = false;
}
}
// function to help seeing canvas coordinates
function showPoint() {
text(mouseX, 10, 20);
text(mouseY, 10, 40);
}
// leaf class for the Japanese tree
class Leaf {
// x0 and y0 specify the center of the cluster of leaves (one of the 3 clusters)
constructor(x0, y0, clusterWidth, clusterHeight) {
// using a separate variable for the initial position of x since xPos will
// always be changing in draw() and this will cause abrupt behavior in the
// leaf's x-movement if used along with noise inside move()
// positioning initialX, xPos, and yPos within the cluster
this.initialX = random(x0 - clusterWidth, x0 + clusterWidth);
this.xPos = random(x0 - clusterWidth, x0 + clusterWidth);
this.yPos = random(y0 - clusterHeight, y0 + clusterHeight);
// random width and height for the leaves
this.width = random(10, 20);
this.height = random(10, 15);
// random y speed
this.ySpeed = random(0.5, 2);
// variables for x-noise
this.xoff = 0.0;
this.xincrement = 0.01;
// to check if the leaf has fallen beneath the canvas
this.alive = true;
// leaf only falls when this is true
this.fall = false;
// choosing a random shade of purple from the two specified in the global array
this.color = leafColors[int(random(0, 2))];
}
// for the leaf's falling movement
move() {
// only make the leaf fall if the fall attribute of the object is true
if (this.fall) {
// giving some noise in the x direction to give a natural feel while falling
this.xPos = this.initialX + noise(this.xoff) * 100;
this.xoff += this.xincrement;
// incrementing y to make the leaf fall vertically
this.yPos += this.ySpeed;
}
}
// to check for collisions of leaves with the bottom of the canvas
checkForCollisions() {
// check if the leaf has fallen beneath the canvas
if (
this.xPos <= -15 ||
this.xPos >= width + 15 ||
this.yPos >= height + 15
) {
this.alive = false;
}
// attempting to make the leaf stop when it hits the pot
// it does stop but the noise at the end causes it to end on a slightly abrupt position
// if (this.yPos >= 535 && this.xPos <= 425 && this.xPos >= 175) {
// this.ySpeed = 0;
// this.xoff = 0;
// }
}
// drawing the leaf
draw() {
noStroke();
fill(this.color);
ellipse(this.xPos, this.yPos, this.width, this.height);
}
}
// drawing the window frame
function drawWindow() {
noStroke();
fill("#130F26");
rect(50, 250, 20, 500);
rect(180, 250, 20, 500);
rect(420, 250, 20, 500);
rect(300, 150, 500, 20);
rect(550, 250, 20, 500);
rect(300, 500, 520, 100);
fill(50);
rect(300, 550, 250, 40);
}
// drawing the beautiful moon
function drawMoon() {
noStroke();
fill("#B88CAA");
circle(300, 120, 420);
fill("#FCDCDA");
circle(300, 120, 350);
}
// aesthetic light purple sky
function drawSky() {
fill("#9675A7");
rect(300, 200, 500, 500);
}
// beziers for the Japanese tree trunk
function drawTrunk() {
noFill();
stroke("#301822");
strokeWeight(25);
translate(200, 0);
bezier(300, 550, 200, 400, 450, 450, 350, 300);
bezier(320, 420, 100, 300, 300, 450, 150, 220);
// drawing pot over the trunk
fill("#584B42");
noStroke();
rect(300, 550, 250, 40);
rect(300, 730, 150, 400);
fill(255);
}
// scene manager class to help with navigating between layers
class SceneManager {
constructor() {
// different layers of the cafe, like the outside, inside, zoomed-in boombox
this.layer1 = true;
this.layer2 = false;
this.layer3 = false;
this.layer4 = false;
this.layer5 = false;
this.layer6 = false;
this.layer7 = false;
this.layer8 = false;
this.layer9 = false;
// checking mouse hover over the interactable objects
this.onDoor = false;
this.onSmallBoombox = false;
this.onFrame1 = false;
this.onFrame2 = false;
this.onFrame3 = false;
this.onMenu = false;
this.onBook1 = false;
this.onBook2 = false;
this.onBook3 = false;
// boombox controls
this.onPlayButton = false;
this.onPauseButton = false;
this.onNextButton = false;
this.onBackButton = false;
this.onOutsideButton = false; // back button for previous layers
}
// checks for mouse hover over interactables
checkInteractions() {
// need to make everything false back again before we check for hover
// else they stay true
this.onDoor = false;
this.onSmallBoombox = false;
this.onFrame1 = false;
this.onFrame2 = false;
this.onFrame3 = false;
this.onMenu = false;
this.onBook1 = false;
this.onBook2 = false;
this.onBook3 = false;
this.onPlayButton = false;
this.onPauseButton = false;
this.onNextButton = false;
this.onBackButton = false;
this.onOutsideButton = false;
// setting the interactable objects to true when the mouse hovers over them
if (
mouseX > 308 &&
mouseX < 430 &&
mouseY > 305 &&
mouseY < 495 &&
this.layer1
) {
this.onDoor = true;
} else if (
mouseX > 638 &&
mouseX < 689 &&
mouseY > 278 &&
mouseY < 307 &&
this.layer2
) {
this.onSmallBoombox = true;
} else if (
mouseX > 244 &&
mouseX < 281 &&
mouseY > 213 &&
mouseY < 262 &&
this.layer2
) {
this.onFrame1 = true;
} else if (
mouseX > 289 &&
mouseX < 328 &&
mouseY > 183 &&
mouseY < 235 &&
this.layer2
) {
this.onFrame2 = true;
} else if (
mouseX > 310 &&
mouseX < 363 &&
mouseY > 245 &&
mouseY < 279 &&
this.layer2
) {
this.onFrame3 = true;
}
// else if (mouseX > 429 && mouseX < 482 && mouseY > 385 && mouseY < 441 && this.layer2) {
// this.onMenu = true;
// }
else if (
mouseX > 688 &&
mouseX < 698 &&
mouseY > 171 &&
mouseY < 204 &&
this.layer2
) {
this.onBook1 = true;
} else if (
mouseX > 701 &&
mouseX < 711 &&
mouseY > 171 &&
mouseY < 204 &&
this.layer2
) {
this.onBook2 = true;
} else if (
mouseX > 714 &&
mouseX < 725 &&
mouseY > 179 &&
mouseY < 204 &&
this.layer2
) {
this.onBook3 = true;
} else if (
mouseX > 507 &&
mouseX < 526 &&
mouseY > 310 &&
mouseY < 321 &&
this.layer3
) {
this.onPlayButton = true;
} else if (
mouseX > 483 &&
mouseX < 500 &&
mouseY > 304 &&
mouseY < 327 &&
this.layer3
) {
this.onPauseButton = true;
} else if (
mouseX > 507 &&
mouseX < 527 &&
mouseY > 355 &&
mouseY < 367 &&
this.layer3
) {
this.onNextButton = true;
} else if (
mouseX > 479 &&
mouseX < 501 &&
mouseY > 355 &&
mouseY < 367 &&
this.layer3
) {
this.onBackButton = true;
} else if (
mouseX > 34 &&
mouseX < 87 &&
mouseY > 547 &&
mouseY < 572 &&
(this.layer2 ||
this.layer3 ||
this.layer4 ||
this.layer5 ||
this.layer6 ||
this.layer7 ||
this.layer8)
) {
this.onOutsideButton = true;
}
}
// displaying cafe exterior
cafeExterior() {
if (this.onDoor) {
image(doorwhite, 0, 0);
} else {
image(cafeoutside, 0, 0);
}
}
// displaying cafe interior
cafeInterior() {
image(bgimage, 0, 0);
if (!this.onOutsideButton) {
image(previousbutton, 0, 0);
} else if (this.onOutsideButton) {
image(previousbuttonwhite, 0, 0);
}
if (this.onFrame1) {
image(frame1white, 0, 0);
} else if (this.onFrame2) {
image(frame2white, 0, 0);
} else if (this.onFrame3) {
image(frame3white, 0, 0);
} else if (this.onBook1) {
image(book1white, 0, 0);
} else if (this.onBook2) {
image(book2white, 0, 0);
} else if (this.onBook3) {
image(book3white, 0, 0);
} else if (this.onMenu) {
image(boardwhite, 0, 0);
} else if (this.onSmallBoombox) {
image(boomboxwhite, 0, 0);
} else {
image(cafeinside, 0, 0);
}
}
// displaying zoomed boombox with controls
zoomedBoombox() {
if (this.onPlayButton) {
image(boomplay, 0, 0);
} else if (this.onPauseButton) {
image(boompause, 0, 0);
} else if (this.onNextButton) {
image(boomnext, 0, 0);
} else if (this.onBackButton) {
image(boomback, 0, 0);
} else {
image(bigboombox, 0, 0);
}
if (!this.onOutsideButton) {
image(previousbutton, 0, 0);
} else if (this.onOutsideButton) {
image(previousbuttonwhite, 0, 0);
}
}
// displaying zoomed book with quote
zoomedBook() {
image(bookzoom, 0, 0);
if (!this.onOutsideButton) {
image(bookzoom, 0, 0);
} else if (this.onOutsideButton) {
image(bookzoomwhite, 0, 0);
}
// quote text for each book
textSize(16);
textFont("Arial");
textAlign(CENTER, CENTER);
fill(0);
// positioning the quote text
let x1 = 500;
let y1 = 300;
let x2 = 520;
let y2 = 350;
// displaying different quotes for each book
if (book1quote) {
let txt1 = '"' + selectedquotes[0][0] + '"';
text(txt1, x1, y1, x2, y2);
text(selectedquotes[0][1], x1, 500, x2, y2);
}
if (book2quote) {
let txt2 = '"' + selectedquotes[1][0] + '"';
text(txt2, x1, y1, x2, y2);
text(selectedquotes[1][1], x1, 500, x2, y2);
}
if (book3quote) {
let txt3 = '"' + selectedquotes[2][0] + '"';
text(txt3, x1, y1, x2, y2);
text(selectedquotes[2][1], x1, 500, x2, y2);
}
}
// displaying zoomed frame2
zoomedFrame2() {
image(frame2zoom, 0, 0);
if (!this.onOutsideButton) {
image(previousbutton, 0, 0);
} else if (this.onOutsideButton) {
image(previousbuttonwhite, 0, 0);
}
}
// displaying zoomed frame3
zoomedFrame3() {
image(frame3zoom, 0, 0);
if (!this.onOutsideButton) {
image(previousbutton, 0, 0);
} else if (this.onOutsideButton) {
image(previousbuttonwhite, 0, 0);
}
}
// display function to be called inside draw()
display() {
// checking for mouse hover over interactables
this.checkInteractions();
// displaying layers and changing them when needed
if (this.layer1) {
this.cafeExterior();
} else if (this.layer2) {
this.cafeInterior();
} else if (this.layer3) {
this.zoomedBoombox();
} else if (this.layer5) {
this.zoomedFrame2();
} else if (this.layer6) {
this.zoomedFrame3();
} else if (this.layer7) {
this.zoomedBook();
}
// playing knocking sound when mouse is over the door
if (this.onDoor) {
if (!knocking.isPlaying() && canKnock) {
console.log("inside if");
knocking.play();
canKnock = false; // so that we don't repeatedly knock while the mouse hovers over the door
}
} else if (!this.onDoor) {
// making it true back again since we moved the mouse away from the door
canKnock = true;
}
}
}