Code Sketch


siddhi gandas
By: Mhalsakant School
cleari()
originBottomLeft()

// ============================================================
// STOP PLASTIC POLLUTION
// ADVANCED ENVIRONMENT ANIMATION
// ============================================================

var time = 0.0

var cleaning = false
var cleanAmount = 0.0

var flash = 0.0
var wave = 0.0

var messageIndex = 0
var messageTimer = 0

val message = "STOP PLASTIC POLLUTION"

// ------------------------------------------------------------
// PLASTIC PARTICLES
// ------------------------------------------------------------

case class PlasticPiece(
  var x: Double,
  var y: Double,
  var vx: Double,
  var vy: Double,
  var size: Double,
  var angle: Double,
  var rot: Double
)

val plastic =
  scala.collection.mutable.ArrayBuffer.empty[PlasticPiece]

for (i <- 0 until 130) {

  plastic.append(
    PlasticPiece(
      10.0 + math.random * (cwidth - 20.0),
      55.0 + math.random * 190.0,
      (math.random - 0.5) * 0.5,
      (math.random - 0.5) * 0.25,
      4.0 + math.random * 10.0,
      math.random * 3.14,
      (math.random - 0.5) * 0.08
    )
  )
}

// ------------------------------------------------------------
// BIRDS
// ------------------------------------------------------------

val birdX =
  Array(
    90.0,
    170.0,
    500.0,
    620.0
  )

val birdY =
  Array(
    330.0,
    365.0,
    345.0,
    380.0
  )

// ------------------------------------------------------------
// HELPERS
// ------------------------------------------------------------

def clamp(
    v: Double,
    lo: Double,
    hi: Double
): Double = {

  math.max(
    lo,
    math.min(hi, v)
  )
}

// ------------------------------------------------------------
// UPDATE PLASTIC
// ------------------------------------------------------------

def updatePlastic(): Unit = {

  plastic.foreach { p =>

    if (!cleaning) {

      p.x += p.vx
      p.y += p.vy

      if (p.x < 0)
        p.x = cwidth

      if (p.x > cwidth)
        p.x = 0

      if (p.y < 45)
        p.y = 45

      if (p.y > 260)
        p.y = 260

      p.angle += p.rot

    } else {

      p.x +=
        (p.x - cwidth / 2.0) * 0.010

      p.y +=
        2.5 + cleanAmount * 5.0

      p.angle += 0.08

      if (p.y > cheight + 20) {

        p.x =
          20 + math.random * (cwidth - 40)

        p.y =
          60 + math.random * 180

        if (cleanAmount < 0.90) {
          p.y = 300 + math.random * 100
        }
      }
    }
  }
}

// ------------------------------------------------------------
// BACKGROUND
// ------------------------------------------------------------

def drawBackground(
    canvas: CanvasDraw
): Unit = {

  canvas.background(
    205,
    225,
    235
  )

  // Sky
  canvas.fill(
    150,
    215,
    240
  )

  canvas.noStroke()

  canvas.rect(
    0,
    150,
    cwidth,
    cheight - 150
  )

  // Horizon
  canvas.fill(
    90,
    150,
    75
  )

  canvas.rect(
    0,
    125,
    cwidth,
    70
  )

  // Ground
  val green =
    70.0 +
    cleanAmount * 70.0

  val greenInt =
    clamp(
      green,
      60.0,
      150.0
    ).toInt

  canvas.fill(
    55,
    greenInt,
    55
  )

  canvas.rect(
    0,
    0,
    cwidth,
    145
  )

  // Dirty area
  val dirtyAlpha =
    clamp(
      255.0 - cleanAmount * 255.0,
      0.0,
      255.0
    ).toInt

  canvas.fill(
    70,
    65,
    55,
    dirtyAlpha
  )

  canvas.rect(
    0,
    45,
    cwidth,
    110
  )

  // Sun
  canvas.fill(
    255,
    225,
    110,
    230
  )

  canvas.ellipse(
    cwidth - 90,
    cheight - 75,
    70,
    70
  )
}

// ------------------------------------------------------------
// TREES
// ------------------------------------------------------------

def drawTree(
    canvas: CanvasDraw,
    x: Double,
    y: Double,
    scale: Double
): Unit = {

  val appear =
    clamp(
      cleanAmount * 1.7,
      0.0,
      1.0
    )

  if (appear <= 0)
    return

  val trunkH =
    75.0 * scale * appear

  canvas.fill(
    95,
    60,
    35
  )

  canvas.noStroke()

  canvas.rect(
    x - 9 * scale,
    y,
    18 * scale,
    trunkH
  )

  canvas.fill(
    40,
    135,
    55
  )

  canvas.ellipse(
    x,
    y + trunkH + 20 * scale,
    65 * scale * appear,
    55 * scale * appear
  )

  canvas.fill(
    70,
    165,
    60
  )

  canvas.ellipse(
    x - 20 * scale,
    y + trunkH + 5 * scale,
    50 * scale * appear,
    50 * scale * appear
  )

  canvas.ellipse(
    x + 20 * scale,
    y + trunkH + 8 * scale,
    50 * scale * appear,
    50 * scale * appear
  )
}

// ------------------------------------------------------------
// COW
// ------------------------------------------------------------

def drawCow(
    canvas: CanvasDraw,
    x: Double,
    y: Double,
    scale: Double,
    direction: Double
): Unit = {

  val bob =
    math.sin(time * 3.0 + x * 0.01) *
    2.0

  val bodyY =
    y + bob

  // Shadow
  canvas.fill(
    0,
    0,
    0,
    45
  )

  canvas.ellipse(
    x,
    y - 18,
    75 * scale,
    15 * scale
  )

  // Body
  canvas.fill(
    165,
    105,
    55
  )

  canvas.stroke(
    80,
    55,
    35
  )

  canvas.strokeWeight(2)

  canvas.ellipse(
    x,
    bodyY,
    72 * scale,
    43 * scale
  )

  // White patch
  canvas.fill(
    220,
    200,
    165
  )

  canvas.noStroke()

  canvas.ellipse(
    x - 8 * direction,
    bodyY + 4,
    28 * scale,
    23 * scale
  )

  // Head
  canvas.fill(
    150,
    90,
    48
  )

  canvas.ellipse(
    x + 38 * direction,
    bodyY + 12,
    28 * scale,
    25 * scale
  )

  // Ear
  canvas.fill(
    120,
    72,
    40
  )

  canvas.ellipse(
    x + 47 * direction,
    bodyY + 27,
    13 * scale,
    8 * scale
  )

  // Eye
  canvas.fill(
    20,
    20,
    20
  )

  canvas.ellipse(
    x + 45 * direction,
    bodyY + 15,
    4 * scale,
    4 * scale
  )

  // Legs
  val legMove =
    math.sin(time * 5.0 + x * 0.02) *
    4.0

  canvas.stroke(
    95,
    60,
    40
  )

  canvas.strokeWeight(
    6 * scale
  )

  canvas.line(
    x - 22 * scale,
    bodyY - 16,
    x - 24 * scale + legMove,
    bodyY - 38
  )

  canvas.line(
    x + 5 * scale,
    bodyY - 16,
    x + 6 * scale - legMove,
    bodyY - 38
  )

  // Horns
  canvas.stroke(
    220,
    205,
    175
  )

  canvas.strokeWeight(
    3 * scale
  )

  canvas.line(
    x + 45 * direction,
    bodyY + 24,
    x + 52 * direction,
    bodyY + 34
  )

  canvas.line(
    x + 38 * direction,
    bodyY + 24,
    x + 33 * direction,
    bodyY + 34
  )
}

// ------------------------------------------------------------
// BIRDS
// ------------------------------------------------------------

def drawBirds(
    canvas: CanvasDraw
): Unit = {

  canvas.stroke(
    35,
    55,
    65
  )

  canvas.strokeWeight(2)

  for (i <- birdX.indices) {

    val x =
      birdX(i) +
      math.sin(time + i) * 20

    val y =
      birdY(i) +
      math.cos(time * 2 + i) * 8

    canvas.noFill()

    canvas.arc(
      x - 8,
      y,
      16,
      10,
      math.Pi,
      math.Pi * 2
    )

    canvas.arc(
      x + 8,
      y,
      16,
      10,
      math.Pi,
      math.Pi * 2
    )
  }
}

// ------------------------------------------------------------
// PLASTIC
// ------------------------------------------------------------

def drawPlastic(
    canvas: CanvasDraw
): Unit = {

  val alpha =
    clamp(
      255.0 -
      cleanAmount * 255.0,
      0.0,
      255.0
    ).toInt

  plastic.foreach { p =>

    if (alpha > 0) {

      canvas.fill(
        150,
        160,
        165,
        alpha
      )

      canvas.stroke(
        100,
        105,
        110,
        alpha
      )

      canvas.strokeWeight(1)

      canvas.pushMatrix()

      canvas.translate(
        p.x,
        p.y
      )

      canvas.rotate(
        p.angle
      )

      canvas.rect(
        -p.size,
        -p.size * 0.5,
        p.size * 2.0,
        p.size
      )

      canvas.popMatrix()
    }
  }
}

// ------------------------------------------------------------
// CLEANUP WAVE
// ------------------------------------------------------------

def drawCleanupWave(
    canvas: CanvasDraw
): Unit = {

  if (!cleaning)
    return

  val r =
    40.0 +
    cleanAmount * 350.0

  canvas.noFill()

  canvas.stroke(
    70,
    230,
    170,
    150
  )

  canvas.strokeWeight(3)

  canvas.ellipse(
    cwidth / 2.0,
    115,
    r,
    r * 0.55
  )

  canvas.stroke(
    160,
    255,
    200,
    90
  )

  canvas.ellipse(
    cwidth / 2.0,
    115,
    r * 0.75,
    r * 0.40
  )
}

// ------------------------------------------------------------
// ECO BUTTON
// ------------------------------------------------------------

def drawButton(
    canvas: CanvasDraw
): Unit = {

  val bx =
    cwidth / 2.0 - 115.0

  val by =
    25.0

  canvas.fill(
    20,
    130,
    70
  )

  canvas.stroke(
    210,
    255,
    220
  )

  canvas.strokeWeight(2)

  canvas.rect(
    bx,
    by,
    230,
    38
  )

  canvas.fill(
    255,
    255,
    255
  )

  canvas.noStroke()

  if (!cleaning) {

    canvas.text(
      "START CLEANUP",
      bx + 70,
      by + 25
    )

  } else {

    canvas.text(
      "CLEANING PLASTIC...",
      bx + 55,
      by + 25
    )
  }
}

// ------------------------------------------------------------
// POLLUTION METER
// ------------------------------------------------------------

def drawMeter(
    canvas: CanvasDraw
): Unit = {

  val px =
    20.0

  val py =
    cheight - 55.0

  canvas.fill(
    15,
    25,
    30,
    220
  )

  canvas.stroke(
    230,
    240,
    240
  )

  canvas.strokeWeight(1.5)

  canvas.rect(
    px,
    py,
    210,
    25
  )

  val polluted =
    1.0 - cleanAmount

  canvas.fill(
    210,
    70,
    45
  )

  canvas.rect(
    px + 5,
    py + 5,
    200 * polluted,
    15
  )

  canvas.fill(
    20,
    90,
    55
  )

  canvas.rect(
    px + 5 +
    200 * polluted,
    py + 5,
    200 * cleanAmount,
    15
  )

  canvas.fill(
    255,
    255,
    255
  )

  canvas.noStroke()

  canvas.text(
    "ENVIRONMENT STATUS",
    px,
    py + 42
  )
}

// ------------------------------------------------------------
// MESSAGE
// ------------------------------------------------------------

def drawMessage(
    canvas: CanvasDraw
): Unit = {

  if (messageIndex <= 0)
    return

  val shown =
    message.substring(
      0,
      messageIndex
    )

  canvas.fill(
    255,
    255,
    255
  )

  canvas.stroke(
    10,
    80,
    60,
    120
  )

  canvas.strokeWeight(2)

  canvas.text(
    shown,
    cwidth / 2.0 - 125,
    cheight - 22
  )
}

// ------------------------------------------------------------
// COMPLETE SCENE
// ------------------------------------------------------------

def drawScene(
    canvas: CanvasDraw
): Unit = {

  drawBackground(canvas)

  drawBirds(canvas)

  drawTree(
    canvas,
    75,
    120,
    1.0
  )

  drawTree(
    canvas,
    cwidth - 75,
    120,
    1.0
  )

  drawCow(
    canvas,
    145,
    100,
    1.0,
    1.0
  )

  drawCow(
    canvas,
    cwidth - 170,
    145,
    0.75,
    -1.0
  )

  drawPlastic(canvas)

  drawCleanupWave(canvas)

  drawButton(canvas)

  drawMeter(canvas)

  drawMessage(canvas)
}

// ------------------------------------------------------------
// MAIN ANIMATION
// ------------------------------------------------------------

animateWithCanvasDraw { canvas =>

  time += 0.04
  wave += 0.08

  updatePlastic()

  if (cleaning) {

    cleanAmount += 0.0018

    if (cleanAmount >= 1.0) {
      cleanAmount = 1.0
    }

    flash =
      math.max(
        0.0,
        flash - 0.04
      )

  }

  messageTimer += 1

  if (
    cleaning &&
    messageTimer % 5 == 0 &&
    messageIndex < message.length
  ) {

    messageIndex += 1
  }

  drawScene(canvas)

  // Click detection
  if (
    isMousePressed &&
    mouseX >= cwidth / 2.0 - 115 &&
    mouseX <= cwidth / 2.0 + 115 &&
    mouseY >= 25 &&
    mouseY <= 63 &&
    !cleaning
  ) {

    cleaning = true
    flash = 1.0
    cleanAmount = 0.0
    messageIndex = 0
    messageTimer = 0
  }
}