Your browser does not support the canvas tag.

previous        Show / Hide Source        Download        next
// FLOWER GARDEN DISCOVERY SUPREME //
// by Peter Francis //
// Just hold the mouse to water your beloved garden.
// Wow! Plants grow so fast!
// What wonders will you uncover???

color bgColour=color(185, 232, 245);
boolean watering; 

//Sets the  watering can's spout point to follow the mouse
PVector spoutPoint= new PVector(mouseX+52, mouseY-27); 

//defines the array 'water' which stores all the individual droplets
Droplet[] water = new Droplet[250];
Flower[] blooms = new Flower[20];

// defining some clouds
Cloud cloud1;
Cloud cloud2;
Cloud cloud3;
Cloud cloud4;
Cloud cloud5;
Cloud cloud6;


void setup() {
  size(800, 400);

  // INITIALIZING ARRAYS

  //...for water droplets...
  for (int i=0; i<water.length; i++) {
    water[i] = new Droplet();
  }

  //... and for our randomized flowers!
  for (int i=0; i<blooms.length; i++) {
    blooms[i] = new Flower();
  }

  //INITIALIZING THE CLOUDS
  cloud1 = new Cloud();
  cloud2= new Cloud();
  cloud3= new Cloud();
  cloud4 = new Cloud();
  cloud5= new Cloud();
  cloud6= new Cloud();
}

void draw() {

  //Every frame, the "spout point" is reset according to the mouse
  spoutPoint.x= mouseX+52;
  spoutPoint.y= mouseY-27; 

  //UPDATES

  //updating clouds
  cloud1.updateCloud();
  cloud2.updateCloud();
  cloud3.updateCloud();
  cloud4.updateCloud();  
  cloud5.updateCloud();
  cloud6.updateCloud();

  // going through the arrays and drawing/updating each drop 
  for (int i=0; i<water.length; i++) {
    water[i].updateDroplet();
  }

  //updating each flower
  for (int i=0; i<blooms.length; i++) {
    blooms[i].updateFlower();
  }

  //DRAWS

  //Background Drawings
  background(bgColour);

  //drawing clouds
  cloud1.drawCloud();
  cloud2.drawCloud();
  cloud3.drawCloud();

  drawHillsNTrees();

  //some clouds are in the foreground
  cloud4.drawCloud();  
  cloud5.drawCloud();
  cloud6.drawCloud();

  drawBackgroundSoil();

  // an array of draw functions for each water droplet
  for (int i=0; i<water.length; i++) {
    water[i].drawDroplet();
  }

  drawWateringCan(mouseX, mouseY);

  // an array of draw functions for each flower
  for (int i=0; i<blooms.length; i++) {
    blooms[i].drawLeaves();
    blooms[i].drawFlower();
  }

  drawForegroundSoil(); 

  // Establish that when the mouse is held, the WATERING variable is true
  if (mousePressed) {
    watering=true;
  } else {
    watering = false;
  }
}

// The function for drawing the background scenery
void drawHillsNTrees() {
  fill(193, 222, 175);
  ellipse(780, 380, 320, 560);  
  ellipse(20, 380, 320, 560);  
  fill(163, 206, 135); 
  ellipse(800, 400, 560, 320);
  ellipse(0, 400, 560, 320);
}

// The function for drawing the cursor watering can
void drawWateringCan(float centerX, float centerY) {
  colorMode(RGB); 
  stroke(54+100, 134-100, 79+20);
  strokeWeight(7); 
  noFill();
  ellipse(centerX-20, centerY-5, 40, 40); 
  noStroke();
  fill(54+100, 134-100, 79+20); 

  rectMode(CENTER);
  rect(centerX, centerY-5, 40, 50, 10);
  ellipse(centerX, centerY+15, 40, 20); 
  quad(centerX+15, centerY, centerX+20, centerY+15, centerX+50, centerY-20, centerX+40, centerY-20);
  bezier(centerX+40, centerY-30, centerX+43, centerY-13, centerX+50, centerY-17, centerX+60, centerY-20);
  fill(24+100, 104-100, 49+20); 
  bezier(centerX-15, centerY-25, centerX-14, centerY-15, centerX-5, centerY-15, centerX+10, centerY-25);
  strokeWeight(5); 
  stroke(24+100, 104-100, 49+20); 
  line(centerX+40, centerY-32, centerX+60, centerY-20);
}

// The function for drawing the soil
void drawForegroundSoil() {
  fill(118, 75, 48); 
  rectMode(CENTER);
  noStroke();
  float dirtLumpPosition=20;
  for (int i=0; i<20; i++) {
    ellipse(dirtLumpPosition, 380, 40, 40);
    rect(dirtLumpPosition, 390, 40, 20); 
    dirtLumpPosition+=40;
  }
}

// The function for drawing even more soil
void drawBackgroundSoil() {
  fill(85, 54, 34); 
  rectMode(CENTER);
  noStroke();
  float dirtLumpPosition=0;
  for (int i=0; i<21; i++) {
    ellipse(dirtLumpPosition, 360, 40, 40);
    rect(dirtLumpPosition, 370, 40, 20); 
    dirtLumpPosition+=40;
  }
}
class Cloud {

  //I chose not to use a PVector here since clouds only move on the X axis.
  float cloudplaceY;
  float cloudPositionX;
  float cloudSpeed;
  float cloudWidth;
  float cloudHeight;
  
  Cloud() {
    cloudplaceY=random(40, 240);
    cloudSpeed=random(0.25, 1); 
    cloudWidth=random(80, 400); 
    cloudHeight=random(30, 80);
    cloudPositionX=random(-500,800); 
  }

// Updates clouds' random movement
  void updateCloud() {
    cloudPositionX+= cloudSpeed;
    if (cloudPositionX>1000) {
      cloudplaceY=random(40, 280);
      cloudSpeed=random(0.25, 1); 
      cloudWidth=random(80, 400); 
      cloudHeight=random(30, 80);
      cloudPositionX= -200;
    }
  }

  void drawCloud() {
    rectMode(CENTER);
    fill(255, 100); 
    rect(cloudPositionX, cloudplaceY, cloudWidth, cloudHeight, 10);
    rect(cloudPositionX+5, cloudplaceY-5, cloudWidth-10, cloudHeight-10, 10);
  }
}
class Droplet {

  float dropletColour;
  float dropletSize;
  PVector dropletPosition = new PVector();
  PVector dropletSpeed = new PVector();
  PVector dropletAcc = new PVector();

  Droplet() {
    //When the drop initially spawns, it's offscreen 
    // so the user doesn't see it until they click
    dropletPosition.x=850;
    dropletPosition.y=spoutPoint.y;

    dropletSpeed.x=random(3.5, 5.5);
    dropletSpeed.y=random(-2.5, -.75);

    dropletAcc.x= random(-0.25, -0.05);
    dropletAcc.y= random(0.5, 1.5);

    dropletSize= random(3, 6); 
    dropletColour= random(220, 255);
  }

  //Updates droplets on their random path towards the thirsty soil
  void updateDroplet() {
    dropletPosition.x+= dropletSpeed.x;
    dropletPosition.y+= dropletSpeed.y;

    dropletSpeed.x+= dropletAcc.x;
    dropletSpeed.y+= dropletAcc.y;

// Droplets are re-randomized and jump back to the spout of the watering can
// when they fall of screen - but only if the player is still watering!

    if (dropletPosition.y>400) {
      if (watering==true) {
        dropletPosition.x=spoutPoint.x;
        dropletPosition.y=spoutPoint.y;

        dropletSpeed.x=random(3.0, 5.5);
        dropletSpeed.y=random(-2.5, -.75);

        dropletAcc.x= random(-0.25, -0.05);
        dropletAcc.y= random(0.5, 1.5);

        dropletSize= random(3, 6); 
        dropletColour= random(220, 255);
      }
    }
  }

  void drawDroplet() {
    colorMode(HSB);
    noStroke();
    fill(150, 85, dropletColour);
    ellipse(dropletPosition.x, dropletPosition.y, dropletSize, dropletSize);
  }
}
class Flower {

  float stemLength;
  float flowerPosition;
  float flowerMaxHeight;
  float stemColor; 

  float leafVisibility; 
  float leafDeterminer;
  float leafSpacing;

  float flowerBloomSize;
  float flowerMaxBloomSize;
  float flowerHue;

  int bloomType;


  Flower() {
    stemLength=10;
    flowerPosition=random(20, 780);
    flowerMaxHeight=random(100, 500); 
    leafVisibility=(0); 
    stemColor=random(100, 200);
    leafDeterminer=1; 
    leafSpacing= random(15, 45);

    //flower variables
    flowerMaxBloomSize=random(25, 45); 
    flowerBloomSize=0;
    flowerHue=random(0, 255);
    bloomType=int(random(0,2));
  }

  void drawFlower() {
    rectMode(CENTER);
    colorMode(HSB);
    fill(93, 170, stemColor); 
    noStroke(); 
    rect(flowerPosition, 360, 5, stemLength);

    //Bloom-related stuff
    // There are a few types of flower blooms; the variable bloomType
    // decides which one is drawn 
    fill(flowerHue, 200, 230); 

    if (bloomType==0) {
      strokeWeight(2);
      stroke(flowerHue, 220, 200); 
      ellipse(flowerPosition, 350-flowerMaxHeight/2, flowerBloomSize, flowerBloomSize);
      float stamenSize=flowerBloomSize-15;
      fill(0, 70);
      while (stamenSize>5) {
        ellipse(flowerPosition, 350-flowerMaxHeight/2, stamenSize, stamenSize);
        stamenSize-=10;
      }
    } else if (bloomType==1) {
      fill(flowerHue, 220, 180); 
      ellipse(flowerPosition+flowerBloomSize*.3, (350-flowerMaxHeight/2), flowerBloomSize*.5, flowerBloomSize*.7);
      ellipse(flowerPosition-flowerBloomSize*.3, (350-flowerMaxHeight/2), flowerBloomSize*.5, flowerBloomSize*.7);
      fill(flowerHue, 200, 230); 
      ellipse(flowerPosition, (350-flowerMaxHeight/2)-flowerBloomSize*.3, flowerBloomSize*.7, flowerBloomSize*.5);
      ellipse(flowerPosition, (350-flowerMaxHeight/2)+flowerBloomSize*.3, flowerBloomSize*.7, flowerBloomSize*.5);

      fill(flowerHue+130, 100, 250);
      ellipse(flowerPosition, 350-flowerMaxHeight/2, flowerBloomSize*.3, flowerBloomSize*.3);
    }
    colorMode(RGB);
  }

  void updateFlower() {

    //this if statement makes flower grow when the watering can is
    //spraying water over them. 
    if (mouseX<flowerPosition-70 && mouseX>flowerPosition-140 && watering==true) {
      stemLength+=1;
      leafVisibility+=3; 
      stemLength=constrain(stemLength, 0, flowerMaxHeight);
    }

    // Update the Bloom
    // This if statement makes the flower bloom grow to a point when the stalk is 
    // at its max height. 
    if (stemLength==flowerMaxHeight && flowerBloomSize<flowerMaxBloomSize) {
      flowerBloomSize++;
    }
  }

  void drawLeaves() {
    colorMode(HSB);
    float leafHeight=360;
    float leafSide=leafDeterminer; 

    // This variable means each higher leaf appears later
    int leafVisibilityModifier=0;
    strokeWeight(3);  
    for (int i=0; i<(flowerMaxHeight/(leafSpacing*2)); i++) {
      fill(93, 170, stemColor, leafVisibility-leafVisibilityModifier);
      stroke(93, 170, stemColor, leafVisibility-leafVisibilityModifier);
      bezier(flowerPosition, leafHeight, flowerPosition-(2)*leafSide, leafHeight-13, flowerPosition-(10)*leafSide, leafHeight-15, flowerPosition-(20)*leafSide, leafHeight-20);
      bezier(flowerPosition, leafHeight, flowerPosition-(13)*leafSide, leafHeight-2, flowerPosition-(15)*leafSide, leafHeight-10, flowerPosition-(20)*leafSide, leafHeight-20);
      leafHeight-=leafSpacing; 
      leafVisibilityModifier+=130+leafSpacing*2; 
      leafSide= leafSide*-1;
    }
    colorMode(RGB);
  }
}