Code Sketch


aaii8
By: Mhalsakant School
Category: Programming
// ============================================================
//        ULTRA AI ROBOT - ADVANCED KOJO EDITION
//        BLUE / CYAN FUTURISTIC ROBOT
// ============================================================

cleari()
originBottomLeft()

class Sketch {

  // ==========================================================
  // VARIABLES
  // ==========================================================

  var t = 0.0

  var robotX = cwidth / 2.0
  var robotY = 215.0

  var vx = 0.0
  var vy = 0.0

  var energy = 100.0

  var headTurn = 0.0
  var bob = 0.0
  var walkPhase = 0.0
  var scanPhase = 0.0
  var blinkPhase = 0.0
  var reactorPhase = 0.0
  var pulsePhase = 0.0

  var talking = true
  var scanning = false
  var boost = false
  var flash = false
  var wave = false

  var wavePhase = 0.0

  var targetX = cwidth / 2.0
  var targetY = 220.0

  var message = "AI ONLINE"
  var messageIndex = 0

  // ==========================================================
  // HELPERS
  // ==========================================================

  def clamp(v: Double, lo: Double, hi: Double): Double = {
    math.max(lo, math.min(hi, v))
  }

  def a(v: Double): Int = {
    clamp(v, 0.0, 255.0).toInt
  }

  // ==========================================================
  // SETUP
  // ==========================================================

  def setup(c: CanvasDraw): Unit = {
    c.background(5, 10, 20)
  }

  // ==========================================================
  // BACKGROUND
  // ==========================================================

  def background(c: CanvasDraw): Unit = {

    c.background(3, 8, 18)

    // blue floor
    c.noStroke()
    c.fill(5, 20, 35)

    c.rect(
      0,
      0,
      cwidth,
      65
    )

    // floor glow
    c.fill(0, 130, 255, 35)

    c.ellipse(
      robotX,
      55,
      500,
      60
    )

    // stars / particles
    for (i <- 0 until 45) {

      val px =
        ((i * 97 + 40) % (cwidth - 80)) + 40

      val py =
        80 + ((i * 53) % (cheight - 130))

      val pulse =
        1.0 + math.sin(t * 2.0 + i) * 0.6

      c.noStroke()

      c.fill(
        0,
        180,
        255,
        a(70 + pulse * 40)
      )

      c.ellipse(
        px,
        py,
        2 + pulse,
        2 + pulse
      )
    }

    // horizontal futuristic lines
    for (i <- 0 until 9) {

      val y = 80 + i * 55

      c.stroke(
        0,
        110,
        180,
        30
      )

      c.strokeWeight(1)

      c.line(
        0,
        y,
        cwidth,
        y
      )
    }
  }

  // ==========================================================
  // TV / AI SCREEN
  // ==========================================================

  def drawScreen(c: CanvasDraw): Unit = {

    val cx = cwidth / 2.0
    val cy = 205.0

    // shadow
    c.noStroke()
    c.fill(0, 0, 0, 90)

    c.ellipse(
      cx,
      50,
      650,
      55
    )

    // outer frame
    c.fill(8, 18, 30)

    c.stroke(
      0,
      110,
      180,
      220
    )

    c.strokeWeight(5)

    c.rect(
      cx - 320,
      cy - 150,
      640,
      330
    )

    // inner frame
    c.fill(2, 13, 25)

    c.stroke(
      0,
      200,
      255,
      180
    )

    c.strokeWeight(2)

    c.rect(
      cx - 300,
      cy - 130,
      600,
      290
    )

    // screen
    c.fill(
      3,
      18,
      30
    )

    c.noStroke()

    c.rect(
      cx - 280,
      cy - 110,
      560,
      250
    )

    // screen glow
    c.fill(
      0,
      180,
      255,
      15
    )

    c.ellipse(
      cx,
      cy + 10,
      500,
      220
    )

    // scanlines
    for (i <- 0 until 22) {

      val sy =
        cy - 105 + i * 11

      c.stroke(
        0,
        190,
        255,
        20
      )

      c.strokeWeight(1)

      c.line(
        cx - 275,
        sy,
        cx + 275,
        sy
      )
    }

    // moving scan beam
    val scanY =
      cy - 105 +
      ((scanPhase % 245.0))

    c.stroke(
      0,
      230,
      255,
      110
    )

    c.strokeWeight(2)

    c.line(
      cx - 275,
      scanY,
      cx + 275,
      scanY
    )
  }

  // ==========================================================
  // ROBOT BODY
  // ==========================================================

  def drawRobot(c: CanvasDraw): Unit = {

    val bx = robotX
    val by = robotY + bob

    val moving =
      math.abs(vx) > 0.1 ||
      math.abs(vy) > 0.1

    // --------------------------------------------------------
    // shadow
    // --------------------------------------------------------

    c.noStroke()

    c.fill(
      0,
      0,
      0,
      100
    )

    c.ellipse(
      bx,
      105,
      150,
      25
    )

    // --------------------------------------------------------
    // legs
    // --------------------------------------------------------

    val legMove =
      if (moving)
        math.sin(walkPhase) * 8
      else
        0.0

    c.stroke(
      190,
      215,
      225
    )

    c.strokeWeight(12)

    c.line(
      bx - 22,
      by - 50,
      bx - 25 + legMove,
      by - 82
    )

    c.line(
      bx + 22,
      by - 50,
      bx + 25 - legMove,
      by - 82
    )

    // feet
    c.fill(
      30,
      90,
      120
    )

    c.stroke(
      0,
      200,
      255
    )

    c.strokeWeight(2)

    c.ellipse(
      bx - 28 + legMove,
      by - 88,
      35,
      14
    )

    c.ellipse(
      bx + 28 - legMove,
      by - 88,
      35,
      14
    )

    // --------------------------------------------------------
    // torso
    // --------------------------------------------------------

    c.fill(
      175,
      195,
      210
    )

    c.stroke(
      40,
      70,
      90
    )

    c.strokeWeight(3)

    c.ellipse(
      bx,
      by,
      105,
      125
    )

    // blue armor
    c.fill(
      10,
      75,
      110
    )

    c.stroke(
      0,
      210,
      255
    )

    c.strokeWeight(2)

    c.ellipse(
      bx - 48,
      by + 40,
      28,
      35
    )

    c.ellipse(
      bx + 48,
      by + 40,
      28,
      35
    )

    // --------------------------------------------------------
    // reactor glow
    // --------------------------------------------------------

    val reactor =
      a(
        120 +
        math.sin(reactorPhase) * 100
      )

    c.fill(
      0,
      190,
      255,
      reactor
    )

    c.noStroke()

    c.ellipse(
      bx,
      by + 15,
      38,
      38
    )

    c.fill(
      190,
      250,
      255
    )

    c.ellipse(
      bx,
      by + 15,
      13,
      13
    )

    // reactor rings
    c.noFill()

    c.stroke(
      0,
      220,
      255,
      120
    )

    c.strokeWeight(2)

    c.ellipse(
      bx,
      by + 15,
      52,
      52
    )

    // --------------------------------------------------------
    // arms
    // --------------------------------------------------------

    val arm =
      if (wave)
        math.sin(wavePhase) * 20
      else if (moving)
        math.sin(walkPhase) * 7
      else
        math.sin(t * 1.5) * 2

    c.stroke(
      190,
      215,
      225
    )

    c.strokeWeight(12)

    c.line(
      bx - 48,
      by + 38,
      bx - 70,
      by + 5
    )

    c.line(
      bx + 48,
      by + 38,
      bx + 70,
      by + 5 + arm
    )

    // joints
    c.fill(
      15,
      90,
      125
    )

    c.stroke(
      0,
      210,
      255
    )

    c.strokeWeight(2)

    c.ellipse(
      bx - 70,
      by + 5,
      20,
      20
    )

    c.ellipse(
      bx + 70,
      by + 5 + arm,
      20,
      20
    )

    // hands
    c.fill(
      210,
      225,
      235
    )

    c.stroke(
      50,
      80,
      100
    )

    c.strokeWeight(2)

    c.ellipse(
      bx - 72,
      by - 12,
      23,
      25
    )

    c.ellipse(
      bx + 72,
      by - 12 + arm,
      23,
      25
    )

    // --------------------------------------------------------
    // HEAD
    // --------------------------------------------------------

    val hx =
      bx + headTurn

    val hy =
      by + 78

    // head glow
    c.fill(
      0,
      150,
      255,
      25
    )

    c.ellipse(
      hx,
      hy,
      110,
      90
    )

    // head
    c.fill(
      220,
      230,
      238
    )

    c.stroke(
      35,
      60,
      75
    )

    c.strokeWeight(3)

    c.rect(
      hx - 45,
      hy - 35,
      90,
      70
    )

    // face panel
    c.fill(
      2,
      25,
      40
    )

    c.stroke(
      0,
      200,
      255
    )

    c.strokeWeight(2)

    c.rect(
      hx - 38,
      hy - 25,
      76,
      50
    )

    // --------------------------------------------------------
    // EYES
    // --------------------------------------------------------

    val eyeH =
      if (math.sin(blinkPhase) > 0.985)
        2.0
      else
        11.0

    c.noStroke()

    c.fill(
      0,
      150,
      220,
      80
    )

    c.ellipse(
      hx - 17,
      hy + 2,
      20,
      20
    )

    c.ellipse(
      hx + 17,
      hy + 2,
      20,
      20
    )

    c.fill(
      0,
      240,
      255
    )

    c.ellipse(
      hx - 17,
      hy + 2,
      8,
      eyeH
    )

    c.ellipse(
      hx + 17,
      hy + 2,
      8,
      eyeH
    )

    // --------------------------------------------------------
    // mouth
    // --------------------------------------------------------

    c.noFill()

    c.stroke(
      0,
      210,
      255
    )

    c.strokeWeight(2)

    if (talking) {

      val mouth =
        5 +
        math.abs(math.sin(t * 8)) * 7

      c.ellipse(
        hx,
        hy - 15,
        20,
        mouth
      )

    } else {

      c.line(
        hx - 10,
        hy - 15,
        hx + 10,
        hy - 15
      )
    }

    // --------------------------------------------------------
    // antenna
    // --------------------------------------------------------

    c.stroke(
      120,
      160,
      180
    )

    c.strokeWeight(3)

    c.line(
      hx,
      hy + 35,
      hx,
      hy + 55
    )

    c.fill(
      0,
      240,
      255,
      a(
        140 +
        math.sin(pulsePhase) * 100
      )
    )

    c.noStroke()

    c.ellipse(
      hx,
      hy + 60,
      12,
      12
    )
  }

  // ==========================================================
  // AI INFORMATION BOX
  // ==========================================================

  def drawInfo(c: CanvasDraw): Unit = {

    val x = cwidth - 245.0
    val y = cheight / 2.0 - 70.0

    // box
    c.fill(
      2,
      18,
      32,
      235
    )

    c.stroke(
      0,
      190,
      255,
      220
    )

    c.strokeWeight(2)

    c.rect(
      x,
      y,
      215,
      170
    )

    // header
    c.fill(
      0,
      180,
      255
    )

    c.text(
      "AI SYSTEM",
      x + 18,
      y + 145
    )

    c.fill(
      255,
      255,
      255
    )

    c.text(
      "MODEL : AI ROBOT",
      x + 18,
      y + 120
    )

    c.text(
      "STATUS : ONLINE",
      x + 18,
      y + 100
    )

    c.text(
      "CORE : BLUE-X",
      x + 18,
      y + 80
    )

    c.text(
      "MODE : " +
      (if (scanning) "SCANNING" else "NORMAL"),
      x + 18,
      y + 60
    )

    // energy
    c.fill(
      120,
      140,
      150
    )

    c.rect(
      x + 18,
      y + 35,
      175,
      12
    )

    c.fill(
      0,
      210,
      255
    )

    c.rect(
      x + 18,
      y + 35,
      175 * energy / 100.0,
      12
    )

    c.fill(
      255,
      255,
      255
    )

    c.text(
      "ENERGY " +
      energy.toInt.toString +
      "%",
      x + 18,
      y + 20
    )
  }

  // ==========================================================
  // SPEECH BOX
  // ==========================================================

  def drawMessage(c: CanvasDraw): Unit = {

    val x = 30.0
    val y = cheight - 105.0

    c.fill(
      2,
      20,
      38,
      235
    )

    c.stroke(
      0,
      200,
      255
    )

    c.strokeWeight(2)

    c.rect(
      x,
      y,
      250,
      65
    )

    c.fill(
      0,
      220,
      255
    )

    c.text(
      "AI MESSAGE",
      x + 15,
      y + 45
    )

    c.fill(
      255,
      255,
      255
    )

    c.text(
      message,
      x + 15,
      y + 22
    )
  }

  // ==========================================================
  // RADAR
  // ==========================================================

  def drawRadar(c: CanvasDraw): Unit = {

    val rx = 100.0
    val ry = 115.0

    c.noFill()

    c.stroke(
      0,
      180,
      255,
      90
    )

    c.strokeWeight(1)

    c.ellipse(
      rx,
      ry,
      100,
      100
    )

    c.ellipse(
      rx,
      ry,
      65,
      65
    )

    c.line(
      rx - 50,
      ry,
      rx + 50,
      ry
    )

    c.line(
      rx,
      ry - 50,
      rx,
      ry + 50
    )

    val angle =
      t * 2.5

    val sx =
      rx + math.cos(angle) * 50

    val sy =
      ry + math.sin(angle) * 50

    c.stroke(
      0,
      255,
      255,
      180
    )

    c.line(
      rx,
      ry,
      sx,
      sy
    )

    c.fill(
      0,
      240,
      255
    )

    c.noStroke()

    c.ellipse(
      rx,
      ry,
      7,
      7
    )
  }

  // ==========================================================
  // SCANNING EFFECT
  // ==========================================================

  def drawScan(c: CanvasDraw): Unit = {

    if (scanning) {

      val sx =
        robotX +
        math.sin(t * 3) * 120

      c.stroke(
        0,
        255,
        255,
        100
      )

      c.strokeWeight(2)

      c.line(
        robotX,
        robotY + 60,
        sx,
        120
      )

      c.noFill()

      c.ellipse(
        robotX,
        robotY + 60,
        160 +
        math.sin(t * 4) * 20,
        160 +
        math.sin(t * 4) * 20
      )
    }
  }

  // ==========================================================
  // FLASH EFFECT
  // ==========================================================

  def drawFlash(c: CanvasDraw): Unit = {

    if (flash) {

      c.noStroke()

      c.fill(
        0,
        210,
        255,
        a(
          25 +
          math.abs(math.sin(t * 5)) * 30
        )
      )

      c.rect(
        0,
        0,
        cwidth,
        cheight
      )
    }
  }

  // ==========================================================
  // KEYBOARD CONTROL
  // ==========================================================

  def controls(): Unit = {

    var dx = 0.0
    var dy = 0.0

    // W / UP
    if (isKeyPressed(Kc.VK_W) ||
        isKeyPressed(Kc.VK_UP)) {
      dy += 1.0
    }

    // S / DOWN
    if (isKeyPressed(Kc.VK_S) ||
        isKeyPressed(Kc.VK_DOWN)) {
      dy -= 1.0
    }

    // A / LEFT
    if (isKeyPressed(Kc.VK_A) ||
        isKeyPressed(Kc.VK_LEFT)) {
      dx -= 1.0
    }

    // D / RIGHT
    if (isKeyPressed(Kc.VK_D) ||
        isKeyPressed(Kc.VK_RIGHT)) {
      dx += 1.0
    }

    // smooth acceleration
    vx += dx * 0.55
    vy += dy * 0.55

    // friction
    vx *= 0.82
    vy *= 0.82

    val maxSpeed =
      if (boost) 7.0 else 4.0

    vx =
      clamp(vx, -maxSpeed, maxSpeed)

    vy =
      clamp(vy, -maxSpeed, maxSpeed)

    robotX += vx
    robotY += vy

    // boundaries
    robotX =
      clamp(
        robotX,
        cwidth / 2.0 - 210,
        cwidth / 2.0 + 210
      )

    robotY =
      clamp(
        robotY,
        160,
        330
      )

    // movement animation
    if (math.abs(vx) > 0.1 ||
        math.abs(vy) > 0.1) {

      walkPhase += 0.35
      bob =
        math.sin(walkPhase * 2) * 3
    }
    else {

      bob =
        math.sin(t * 2) * 1.5
    }
  }

  // ==========================================================
  // SPECIAL CONTROLS
  // ==========================================================

  def specialControls(): Unit = {

    // SPACE = wave
    if (isKeyPressed(Kc.VK_SPACE)) {
      wave = true
    }

    if (wave) {

      wavePhase += 0.35

      if (wavePhase > 20) {
        wave = false
        wavePhase = 0
      }
    }

    // E = energy boost
    boost =
      isKeyPressed(Kc.VK_E)

    if (boost) {
      energy -= 0.25
    }
    else {
      energy += 0.08
    }

    energy =
      clamp(
        energy,
        0,
        100
      )

    // R = scanning
    scanning =
      isKeyPressed(Kc.VK_R)

    // F = flash
    flash =
      isKeyPressed(Kc.VK_F)
  }

  // ==========================================================
  // MOUSE
  // ==========================================================

  def mouseControl(): Unit = {

    if (isMousePressed) {

      targetX = mouseX.toDouble
      targetY = mouseY.toDouble

      message =
        "HELLO HUMAN!"
    }

    val tx =
      clamp(
        (targetX - robotX) * 0.025,
        -10,
        10
      )

    headTurn +=
      (tx - headTurn) * 0.08
  }

  // ==========================================================
  // MESSAGE SYSTEM
  // ==========================================================

  def updateMessage(): Unit = {

    val messages =
      Array(
        "AI ONLINE",
        "HELLO HUMAN!",
        "SYSTEM READY",
        "BLUE CORE ACTIVE",
        "SCANNING WORLD",
        "ENERGY STABLE",
        "I AM LEARNING",
        "MISSION ACTIVE"
      )

    if (
      math.sin(t * 0.8) > 0.999
    ) {

      messageIndex =
        (messageIndex + 1) %
        messages.length

      message =
        messages(messageIndex)
    }
  }

  // ==========================================================
  // TOP HUD
  // ==========================================================

  def drawHUD(c: CanvasDraw): Unit = {

    c.fill(
      0,
      210,
      255
    )

    c.text(
      "? BLUE AI ROBOT // ULTRA SYSTEM ?",
      cwidth / 2.0 - 150,
      cheight - 25
    )

    c.fill(
      255,
      255,
      255
    )

    c.text(
      "WASD / ARROWS = MOVE",
      25,
      30
    )

    c.text(
      "SPACE = WAVE   E = BOOST   R = SCAN   F = FLASH",
      25,
      15
    )
  }

  // ==========================================================
  // MAIN LOOP
  // ==========================================================

  def drawLoop(c: CanvasDraw): Unit = {

    t += 0.04
    scanPhase += 1.5
    blinkPhase += 0.025
    reactorPhase += 0.12
    pulsePhase += 0.15

    background(c)

    drawScreen(c)

    controls()

    specialControls()

    mouseControl()

    updateMessage()

    drawRobot(c)

    drawScan(c)

    drawRadar(c)

    drawInfo(c)

    drawMessage(c)

    drawFlash(c)

    drawHUD(c)
  }
}

// ============================================================
// START
// ============================================================

val sketch = new Sketch

canvasSketch(sketch)