xxxxxxxxxx
720
/*
Hana Selmani
06/03/2023
Zen Garden
Intro to IM - Midterm Project
*/
// global variables
let bgs = [];
let seeds = [];
let plants = [];
let seedsX = [];
let seedsY = [];
let clickedSeed = -1;
let currentBg = 0;
let planterX = [];
let planterY = [];
let plantObjects = [];
let seedInHand = false;
let drops = [];
let start = false;
let myFont;
let titleIMG;
let butterflyIMG;
let buttonPressed = false;
let restartbutton;
let cx, cy;
let minutesRadius;
let hoursRadius;
let clockDiameter;
let minute = 0;
let hour = 6;
let filledPlanters = [];
let planttext = false;
let planttextctr = 0;
let frame = 0;
let mybutterfly = [];
let animalframe;
let dirt;
let frameSinceStart = 0;
let rainSound;
let clickSound;
let sparkleSound;
let plantSound;
let bgMusic;
let isWatering = false;
index = 0;
// Define the Plant class
class Plant {
constructor(planter, plantchoice) {
this.planter = planter; // Set the planter ID
this.plantchoice = plantchoice; // Set the plant choice ID
this.progress = []; // Create an array to store the plant's growth stages
this.currentStage = 0; // Set the current stage to 0
this.getSprites(); // Load the sprites for the plant growth stages
}
// Get the planter ID
getPlanter() {
return this.planter;
}
// Load the sprites for the plant growth stages
getSprites() {
let counter = 0;
for (let j = 0; j < 4; j++) {
for (let i = 0; i < 2; i++) {
this.progress[counter] = plants[this.plantchoice].get(
i * 32,
j * 32,
32,
32
);
counter++;
}
}
}
// Display the current stage of the plant
display() {
image(
this.progress[this.currentStage],
planterX[this.planter] - 16,
planterY[this.planter] - 28
);
}
// Increment the plant's growth stage
incrementStage() {
if (this.currentStage < 6) {
this.currentStage++;
} else {
sparkleSound.play();
}
}
}
// Define the Water class
class Water {
constructor(x, y, lowerlimit, upperlimit) {
this.x = x + random(-15, 15); // Set the x position with random deviation
this.y = y; // Set the y position
this.initialY = y; // Store the initial y position
this.upperlimit = upperlimit; // Set the upper limit for the water droplet
this.lowerlimit = lowerlimit; // Set the lower limit for the water droplet
this.ySpeed = random(1, 5); // Set the y speed with random deviation
this.fell = false; // Set the "fell" flag to false
}
// Display the water droplet
display() {
if (this.y > this.lowerlimit) {
strokeWeight(1);
stroke(66, 173, 255);
line(this.x, this.y, this.x, this.y + random(1, 5));
}
}
// Apply gravity to the water droplet
gravity() {
this.y += this.ySpeed;
if (this.y > this.upperlimit) {
this.fell = true;
}
}
// Check if the water droplet has fallen
isDead() {
return this.fell;
}
}
// Define a class called Butterfly
class Butterfly {
// Constructor function with parameters for direction, x position, and y position
constructor(direction, x, y) {
this.direction = direction; // Set the direction property to the direction parameter
this.x = x; // Set the x property to the x parameter
this.y = y; // Set the y property to the y parameter
this.xSpeed; // Initialize the xSpeed property
this.ySpeed; // Initialize the ySpeed property
this.sprites = []; // Initialize the sprites array property
this.getSprites(); // Call the getSprites method to populate the sprites array
}
// Method to populate the sprites array based on the direction property
getSprites() {
let row;
if (this.direction == 0) {
row = 0;
this.xSpeed = 0;
this.ySpeed = -1;
} else if (this.direction == 1) {
row = 32;
this.xSpeed = 1;
this.ySpeed = 0;
} else if (this.direction == 2) {
row = 64;
this.xSpeed = 0;
this.ySpeed = 1;
} else {
row = 96;
this.xSpeed = -1;
this.ySpeed = 0;
}
let counter = 0;
for (let i = 0; i < 3; i++) {
this.sprites[counter] = butterflyIMG.get(i * 16, row, 16, 16);
counter++;
}
this.sprites.push(this.sprites[1]);
}
// Method to display the butterfly on the canvas
display(frame) {
frame = int(frame);
image(this.sprites[frame], this.x, this.y);
this.x += this.xSpeed;
this.y += this.ySpeed;
}
// Method to check if the butterfly is out of bounds
isDead() {
if (this.x > 567) {
return true;
} else if (this.x < -16) {
return true;
} else if (this.y > 324) {
return true;
} else if (this.y < -16) {
return true;
} else {
return false;
}
}
}
// Preload function that loads all the necessary images and sounds
function preload() {
// Background images
bgs[0] = loadImage("8.png");
bgs[1] = loadImage("1.png");
bgs[2] = loadImage("2.png");
bgs[3] = loadImage("3.png");
bgs[4] = loadImage("4.png");
bgs[5] = loadImage("6.png");
bgs[6] = loadImage("7.png");
bgs[7] = loadImage("5.png");
// Seeds image
seedsimg = loadImage("seeds.png");
// Plant images
plants[0] = loadImage("000.png");
plants[1] = loadImage("001.png");
plants[2] = loadImage("002.png");
plants[3] = loadImage("003.png");
plants[4] = loadImage("004.png");
plants[5] = loadImage("005.png");
plants[6] = loadImage("006.png");
plants[7] = loadImage("007.png");
// Font
myFont = loadFont("zx-spectrum.ttf");
// Title image
titleIMG = loadImage("Zen Garden.png");
// Butterfly image
butterflyIMG = loadImage("butterfly_0.png");
// Restart button image
restartbutton = loadImage("restartbutton.png");
// Dirt image
dirt = loadImage("dirt.png");
// Sound formats
soundFormats("mp3");
// Rain sound
rainSound = loadSound("river-stream-05-99181.mp3");
// Click sound
clickSound = loadSound("lclick-13694.mp3");
// Sparkle sound
sparkleSound = loadSound("sound-effect-twinklesparkle-115095.mp3");
// Plant sound
plantSound = loadSound("water_drop-6707.mp3");
// Background music
bgMusic = loadSound("just-relax-11157 (mp3cut.net).mp3");
}
// Function that gets the seed images from the seeds image
function getSeeds() {
let counter = 0;
for (let i = 0; i < 4; i++) {
for (let j = 0; j < 2; j++) {
seeds[counter] = seedsimg.get(i * 16, j * 16, 16, 16);
counter++;
}
}
}
function displaySeeds() {
// set the space between seeds
let spacebetween = 15;
// set the space from the top of the canvas
let spacefromtop = 100;
// loop through the seeds array
for (let i = 0; i < 8; i += 2) {
// display the first seed in the pair
image(seeds[i], 17, i * spacebetween + spacefromtop);
// display the second seed in the pair
image(seeds[i + 1], 44, i * spacebetween + spacefromtop);
// store the x-coordinate of the first seed in the pair
seedsX[i] = 17 + 4;
// store the y-coordinate of the first seed in the pair
seedsY[i] = i * spacebetween + spacefromtop + 4;
// store the x-coordinate of the second seed in the pair
seedsX[i + 1] = 44 + 4;
// store the y-coordinate of the second seed in the pair
seedsY[i + 1] = i * spacebetween + spacefromtop + 4;
}
}
function getPlanters() {
// calculate the total x distance for each planter
let diff = 510 - 130;
// set the number of planters per row
let num = 6;
// the quotient is the total surface divided by number of planters
let quotient = int(diff / num);
let counter = 0;
// loop through the rows of planters
for (let j = 0; j < 3; j++) {
// loop through the planters in each row
for (let i = 0; i < num; i++) {
// store the x-coordinate of the planter
planterX[counter] = 130 + quotient / 2 + i * quotient;
// store the y-coordinate of the planter
planterY[counter] = 70 + j * 100;
// increment the counter
counter++;
}
}
}
function setup() {
createCanvas(567, 324); // create a canvas with dimensions 567 x 324
image(bgs[0], 0, 0); // display the first image in the bgs array at coordinates (0, 0) on the canvas
getPlanters(); // call the getPlanters() function to set planter coordinates
let radius = 30; // set the radius of the clock to 30
minutesRadius = radius * 0.6; // set the radius for the minutes indicator
hoursRadius = radius * 0.5; // set the radius for the hours indicator
clockDiameter = radius * 1.7; // set the diameter of the clock
cx = 40; // set the x-coordinate of the clock center
cy = 50; // set the y-coordinate of the clock center
animalframe = int(random(1200, 1400)); // set a random value for animalframe between 1200 and 1400
dirt.resize(419, 235); // resize the dirt image to fit the canvas
bgMusic.setVolume(0.2); // set the volume for the background music
bgMusic.loop(); // loop the background music
plantSound.setVolume(0.7); // set the volume for the plant sound effect
rainSound.setVolume(0.5); // set the volume for the rain sound effect
}
// display dirt planters
function displayDirt() {
// provide white backgrounds so the plants are more visible and the planters noticable
for (let x = 0; x < 18; x++) {
noStroke();
fill(255, 255, 255, 150);
rect(planterX[x] - 25, planterY[x] - 50, 50, 50, 10);
}
// image of the land
image(dirt, 110, 70);
}
function draw() {
// if game has started - if the player has clicked play
if (start) {
// frame counter since game has started
frameSinceStart++;
// display seeds and background
getSeeds();
redrawBg();
// change background every 980 frames
if (frameSinceStart % 980 == 0) {
changeBG();
}
// display restart button
restartbutton.resize(40, 40);
image(restartbutton, 20, 240);
// draw clock
strokeWeight(5);
stroke(237, 34, 93);
fill(244, 122, 158);
ellipse(cx, cy, clockDiameter, clockDiameter);
//for smoother animation the below numbers were chosen
//every 240 frames an hour passes
minute += 0.5;
if (minute % 120 == 0) {
hour++;
}
// helpers for the cosine angles
let m = map(minute, 0, 120, 0, TWO_PI) - HALF_PI;
let h = map(hour, 0, 24, 0, TWO_PI * 2) - HALF_PI;
// Draw the hands of the clock
stroke(255);
strokeWeight(1);
line(cx, cy, cx + cos(m) * minutesRadius, cy + sin(m) * minutesRadius);
strokeWeight(2);
line(cx, cy, cx + cos(h) * hoursRadius, cy + sin(h) * hoursRadius);
// if a seed is clicked, make it so that the mouse is dragging and image of the seed
for (let i = 0; i < seeds.length; i++) {
if (clickedSeed == i) {
image(seeds[clickedSeed], mouseX - 10, mouseY - 10);
}
}
// display all plants which have been planted
for (let i = 0; i < plantObjects.length; i++) {
plantObjects[i].display();
}
// helper to add sound to the restart button
// check mouseClicked() for the rest
let distance3 = dist(mouseX, mouseY, 40, 260);
if (distance3 < 20) {
cursor(HAND);
} else {
cursor(ARROW);
}
// only one butterfly at a time
if (mybutterfly.length < 1) {
// animal frame is a timer which randomly chooses from a range when the next butterfly will appear
if (frameCount % animalframe == 0) {
// choose butterfly direction
let butterflychoice = int(random(0, 5));
if (butterflychoice == 0) {
//down up
// create butterfly with the appropriate direction and coordinates
mybutterfly.push(
new Butterfly(butterflychoice, random(100, 450), 324)
);
} else if (butterflychoice == 1) {
//left right
// create butterfly with the appropriate direction and coordinates
mybutterfly.push(new Butterfly(butterflychoice, 0, random(60, 300)));
} else if (butterflychoice == 2) {
//up down
// create butterfly with the appropriate direction and coordinates
mybutterfly.push(new Butterfly(butterflychoice, random(100, 450), 0));
} else {
//right left
// create butterfly with the appropriate direction and coordinates
mybutterfly.push(
new Butterfly(butterflychoice, 567, random(60, 300))
);
}
// console.log(mybutterfly.length);
}
} else {
// if butterfly is still in frame
if (!mybutterfly[0].isDead()) {
// display butterfly
// the frame which is passed helps with the sprite choice
mybutterfly[0].display(frame % 4);
frame += 0.2;
if (frame > 4) {
frame = 0;
}
} else {
// if butterfly is out of bounds erase it and reset the animal frame to a new number
mybutterfly.splice(0, mybutterfly.length);
animalframe = int(1200, 1400);
}
}
// if trying to add a plant to a filled up planter
if (planttext) {
// add text to let the player know
noStroke();
fill("red");
textFont(myFont);
textSize(8);
text("THERE IS ALREADY A PLANT IN THERE!", 170, 300);
planttextctr += 1;
// let it stay on screen for 200 frames
if (planttextctr > 200) {
planttextctr = 0;
planttext = false;
}
}
if (mouseIsPressed) {
// if not planting
if (!seedInHand) {
// determine the bounds
if (mouseX > 110) {
if (mouseY > 14 && mouseY < 70) {
// add sounds and add water drops
if (!isWatering) {
rainSound.loop();
}
for (let i = 0; i < 3; i++) {
drops.push(new Water(mouseX, mouseY, 14, 70));
}
} else if (mouseY > 114 && mouseY < 170) {
// add sounds and add water drops
if (!isWatering) {
rainSound.loop();
}
for (let i = 0; i < 3; i++) {
drops.push(new Water(mouseX, mouseY, 114, 170));
}
} else if (mouseY > 214 && mouseY < 270) {
// add sounds and add water drops
if (!isWatering) {
rainSound.loop();
}
for (let i = 0; i < 3; i++) {
drops.push(new Water(mouseX, mouseY, 214, 270));
}
}
}
// check for all existing plants
for (let i = 0; i < plantObjects.length; i++) {
let Xcoor = planterX[plantObjects[i].getPlanter()];
let Ycoor = planterY[plantObjects[i].getPlanter()] - 28;
let distance = dist(mouseX, mouseY, Xcoor, Ycoor);
// if cursor is in the right location then increment the stages of growth every 70 frames
if (distance < 28) {
if (frameCount % 70 == 0) {
plantObjects[i].incrementStage();
}
}
}
// display watering
for (let i = 0; i < drops.length; i++) {
isWatering = true;
drops[i].display();
drops[i].gravity();
// erase water drops when theyre out of bounds
if (drops[i].isDead()) {
drops.splice(i, 1);
}
}
}
} else {
// stops from layering the sounds on top of each other
isWatering = false;
rainSound.stop();
}
} else {
// if game hasnt started yet
// display background and title
image(bgs[0], 0, 0);
titleIMG.resize(570, 400);
image(titleIMG, 0, -40);
// play button
strokeWeight(5);
stroke("#8A61DB");
fill("#AB86F5");
circle(280, 230, 65);
noStroke();
fill(255);
triangle(270, 215, 295, 230, 270, 245);
// help button instructions
// if user hovers they pop up
let distance = dist(mouseX, mouseY, 30, 30);
if (distance < 15) {
noStroke();
fill(254, 210, 198, 230);
rect(50, 50, width - 100, 140, 10);
// setting up color font and size
fill("#584665");
textFont(myFont);
textSize(8);
getSeeds();
// add icons and text
image(seeds[0], 70, 60);
text("PICK A SEED AND DRAG IT FROM THE LEFT ONTO", 90, 70);
text("THE LAND TO THE RIGHT TO PLANT IT.", 60, 90);
let plantimg = plants[0].get(0, 96, 32, 32);
plantimg.resize(24, 24);
image(plantimg, 65, 92);
text("TO WATER THE PLANT, HOLD YOUR MOUSE DOWN OVER", 90, 110);
text("THE NEAR PLANT AREA.", 60, 130);
image(butterflyIMG.get(0, 0, 16, 16), 70, 140);
text("CREATE THE GARDEN OF YOUR DREAMS, AND ENJOY", 90, 150);
text("LITTLE VISITS ALONG THE WAY.", 60, 170);
}
if (mouseIsPressed) {
// if user clicks on the play button
let distance2 = dist(mouseX, mouseY, 280, 230);
if (distance2 < 32) {
// add effect to the button which changes colors
strokeWeight(5);
stroke("#5E17EB");
fill("#5E17EB");
circle(280, 230, 65);
noStroke();
fill("#AB86F5");
triangle(270, 215, 295, 230, 270, 245);
// helps with starting game
// see mouseRelease() for the rest
buttonPressed = true;
// helps with adding sound
// see mouseClick() for the rest
cursor(HAND);
} else {
cursor(ARROW);
}
}
}
}
// function which changes the background each time it is called
function changeBG() {
// incrementing the array index
index = (index + 1) % 8;
currentBg = index;
// adding menu rectangle
noStroke();
fill(255, 255, 255, 150);
rect(10, 10, 60, 304, 10);
}
function mousePressed() {
// if game has started
if (start) {
for (let i = 0; i < seeds.length; i++) {
let distance = dist(mouseX, mouseY, seedsX[i], seedsY[i]);
// if distance is less than seed radius, the mouse was pressed on the seed
if (distance < 8) {
seedInHand = true;
clickedSeed = i;
}
}
// if reset button is pressed
let distance2 = dist(mouseX, mouseY, 40, 260);
if (distance2 < 20) {
// erase everything in the planters and plant lists
filledPlanters.splice(0, filledPlanters.length);
plantObjects.splice(0, plantObjects.length);
}
}
}
function mouseReleased() {
if (!start && buttonPressed) {
// if game has not started yet, and the play button is pressed, start game
start = true;
}
// if currently watering and release mouse, stop the rain sounds
if (isWatering) {
rainSound.stop();
isWatering = false;
}
// erase remaining water drops when mouse released
drops.splice(0, drops.length);
// if user is dragging a seed
if (seedInHand) {
for (let i = 0; i < planterX.length; i++) {
let distance = dist(mouseX, mouseY, planterX[i], planterY[i]);
// if the seed is dropped off at the correct planter loacation
if (distance < 28) {
let planterfound = false;
// if garden isnt empty
if (filledPlanters.length > 0) {
for (let j = 0; j < filledPlanters.length; j++) {
// if there is already a plant, let the user know
if (i == filledPlanters[j]) {
planttext = true;
planterfound = true;
}
}
}
// if the chosen planter is free
if (!planterfound) {
// create plant object
let myplant = new Plant(i, clickedSeed);
// add to plant list
plantObjects.push(myplant);
// mark the planter as filled
filledPlanters.push(i);
// play planting sound
plantSound.play();
}
}
}
}
clickedSeed = -1; // reset the clicked seed when the mouse is released
seedInHand = false; // dropped seed
}
function redrawBg() {
// redraw background image
image(bgs[currentBg], 0, 0);
// add menu rect
noStroke();
fill(255, 255, 255, 150);
rect(10, 10, 60, 304, 10);
// display seeds and land
displaySeeds();
displayDirt();
}
function mouseClicked() {
// for play button
let distance = dist(mouseX, mouseY, 280, 230);
// if correct distance
if (distance < 32) {
// play the click sound
clickSound.play();
}
// for reset button
let distance2 = dist(mouseX, mouseY, 40, 260);
// if correct distance
if (distance2 < 20) {
// play the click sound
clickSound.play();
}
}