Code Sketch


Navya Tembhurne
By: Mhalsakant School
Category: Art
// ============================================================
// ? AI ROBOT ? ENERGY RUN
// NO QUESTIONS ? NO QUIZ
// ============================================================

cleari()
originBottomLeft()

// ============================================================
// GAME VARIABLES
// ============================================================

var robotX = 100.0
var robotY = 120.0

var velocityY = 0.0
var grounded = true

var score = 0
var energy = 100

var gameOver = false
var victory = false

var time = 0.0
var pulse = 0.0

// ============================================================
// ENERGY ORBS
// ============================================================

val orbX = Array(
    180.0,
    330.0,
    470.0,
    610.0,
    760.0,
    250.0,
    540.0,
    700.0
)

val orbY = Array(
    120.0,
    190.0,
    120.0,
    220.0,
    120.0,
    300.0,
    350.0,
    280.0
)

val collected =
    Array.fill(orbX.length)(false)

// ============================================================
// OBSTACLES
// ============================================================

val obstacleX = Array(
    280.0,
    430.0,
    580.0,
    720.0
)

val obstacleY = Array(
    100.0,
    100.0,
    100.0,
    100.0
)

// ============================================================
// BACKGROUND STARS
// ============================================================

val starCount = 120

val starsX =
    Array.fill(starCount)(
        randomDouble(0, cwidth)
    )

val starsY =
    Array.fill(starCount)(
        randomDouble(0, cheight)
    )

// ============================================================
// PARTICLES
// ============================================================

class Particle(
    x0: Double,
    y0: Double
) {

    var x = x0
    var y = y0

    var vx =
        randomDouble(-3, 3)

    var vy =
        randomDouble(2, 6)

    var life = 255.0

    def update() {

        x += vx
        y += vy

        vy -= 0.15

        life -= 5
    }

    def draw(canvas: CanvasDraw) {

        canvas.stroke(
            0,
            255,
            255,
            life.toInt
        )

        canvas.strokeWeight(3)

        canvas.point(
            x,
            y
        )
    }
}

val particles =
    ArrayBuffer.empty[Particle]

// ============================================================
// EXPLOSION
// ============================================================

def explosion(
    x: Double,
    y: Double
) {

    repeat(25) {

        particles.append(
            new Particle(
                x,
                y
            )
        )
    }
}

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

def drawBackground(
    canvas: CanvasDraw
) {

    canvas.fill(
        2,
        5,
        20
    )

    canvas.noStroke()

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

    // Stars

    canvas.stroke(
        120,
        200,
        255
    )

    for (i <- 0 until starCount) {

        canvas.strokeWeight(
            randomDouble(1, 2)
        )

        canvas.point(
            starsX(i),
            starsY(i)
        )
    }

    // Ground

    canvas.fill(
        8,
        20,
        35
    )

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

    // Neon ground

    canvas.stroke(
        0,
        255,
        255
    )

    canvas.strokeWeight(2)

    canvas.line(
        0,
        105,
        cwidth,
        105
    )
}

// ============================================================
// ENERGY ORBS
// ============================================================

def drawOrbs(
    canvas: CanvasDraw
) {

    for (i <- orbX.indices) {

        if (!collected(i)) {

            val glow =
                math.sin(
                    pulse + i
                ) * 7

            // Glow

            canvas.fill(
                0,
                255,
                255,
                25
            )

            canvas.noStroke()

            canvas.ellipse(
                orbX(i),
                orbY(i),
                40 + glow,
                40 + glow
            )

            // Orb

            canvas.fill(
                0,
                240,
                255
            )

            canvas.stroke(
                200,
                255,
                255
            )

            canvas.strokeWeight(2)

            canvas.ellipse(
                orbX(i),
                orbY(i),
                18,
                18
            )

            // Center

            canvas.fill(
                255,
                255,
                255
            )

            canvas.noStroke()

            canvas.ellipse(
                orbX(i),
                orbY(i),
                6,
                6
            )
        }
    }
}

// ============================================================
// OBSTACLES
// ============================================================

def drawObstacles(
    canvas: CanvasDraw
) {

    for (i <- obstacleX.indices) {

        canvas.fill(
            100,
            10,
            60
        )

        canvas.stroke(
            255,
            0,
            100
        )

        canvas.strokeWeight(3)

        canvas.rect(
            obstacleX(i),
            obstacleY(i),
            35,
            55
        )

        // Warning light

        canvas.fill(
            255,
            50,
            50
        )

        canvas.ellipse(
            obstacleX(i) + 17,
            obstacleY(i) + 42,
            8,
            8
        )
    }
}

// ============================================================
// AI ROBOT
// ============================================================

def drawRobot(
    canvas: CanvasDraw
) {

    val bob =
        math.sin(time * 5) * 3

    val x =
        robotX

    val y =
        robotY + bob

    // Aura

    canvas.fill(
        0,
        255,
        255,
        20
    )

    canvas.noStroke()

    canvas.ellipse(
        x,
        y + 30,
        80,
        100
    )

    // Legs

    canvas.stroke(
        70,
        120,
        150
    )

    canvas.strokeWeight(7)

    canvas.line(
        x - 12,
        y,
        x - 12,
        y - 25
    )

    canvas.line(
        x + 12,
        y,
        x + 12,
        y - 25
    )

    // Body

    canvas.fill(
        35,
        50,
        75
    )

    canvas.stroke(
        0,
        230,
        255
    )

    canvas.strokeWeight(3)

    canvas.rect(
        x - 27,
        y,
        54,
        55
    )

    // Chest core

    canvas.fill(
        0,
        220,
        255
    )

    canvas.ellipse(
        x,
        y + 27,
        20,
        20
    )

    canvas.fill(
        255,
        255,
        255
    )

    canvas.ellipse(
        x,
        y + 27,
        7,
        7
    )

    // Head

    canvas.fill(
        55,
        70,
        95
    )

    canvas.stroke(
        0,
        255,
        255
    )

    canvas.strokeWeight(3)

    canvas.rect(
        x - 35,
        y + 55,
        70,
        48
    )

    // Face

    canvas.fill(
        2,
        15,
        30
    )

    canvas.rect(
        x - 27,
        y + 65,
        54,
        28
    )

    // Eyes

    canvas.fill(
        0,
        255,
        255
    )

    canvas.ellipse(
        x - 14,
        y + 79,
        10,
        7
    )

    canvas.ellipse(
        x + 14,
        y + 79,
        10,
        7
    )

    // Antenna

    canvas.stroke(
        0,
        220,
        255
    )

    canvas.strokeWeight(3)

    canvas.line(
        x,
        y + 103,
        x,
        y + 125
    )

    canvas.fill(
        255,
        0,
        180
    )

    canvas.ellipse(
        x,
        y + 130,
        10,
        10
    )
}

// ============================================================
// COLLISION WITH ORBS
// ============================================================

def collectOrbs() {

    for (i <- orbX.indices) {

        if (!collected(i)) {

            val dx =
                robotX - orbX(i)

            val dy =
                robotY - orbY(i)

            val distance =
                math.sqrt(
                    dx * dx +
                    dy * dy
                )

            if (distance < 35) {

                collected(i) = true

                score += 100

                energy =
                    math.min(
                        100,
                        energy + 10
                    )

                explosion(
                    orbX(i),
                    orbY(i)
                )
            }
        }
    }
}

// ============================================================
// OBSTACLE COLLISION
// ============================================================

def checkObstacles() {

    for (i <- obstacleX.indices) {

        if (
            math.abs(
                robotX -
                (obstacleX(i) + 17)
            ) < 30 &&
            robotY < obstacleY(i) + 60 &&
            robotY > obstacleY(i) - 10
        ) {

            energy -= 1

            robotX -= 5

            if (energy <= 0) {

                gameOver = true
            }
        }
    }
}

// ============================================================
// WIN CHECK
// ============================================================

def checkVictory() {

    var allCollected = true

    for (i <- collected.indices) {

        if (!collected(i))
            allCollected = false
    }

    if (allCollected) {

        victory = true

        explosion(
            robotX,
            robotY
        )
    }
}

// ============================================================
// PARTICLES UPDATE
// ============================================================

def updateParticles() {

    particles.filterInPlace(
        p => p.life > 0
    )

    repeatFor(particles) { p =>
        p.update()
    }
}

// ============================================================
// UPDATE
// ============================================================

def updateState() {

    time += 0.05

    pulse += 0.08

    updateParticles()

    if (
        !gameOver &&
        !victory
    ) {

        // Gravity

        if (!grounded) {

            velocityY -= 0.45

            robotY += velocityY
        }

        // Ground

        if (robotY <= 120) {

            robotY = 120

            velocityY = 0

            grounded = true
        }

        collectOrbs()

        checkObstacles()

        checkVictory()
    }
}

// ============================================================
// KEYBOARD
// ============================================================

onKeyPress { key =>

    if (
        !gameOver &&
        !victory
    ) {

        if (
            key == Kc.VK_RIGHT
        ) {

            robotX += 12
        }

        if (
            key == Kc.VK_LEFT
        ) {

            robotX -= 12
        }

        if (
            key == Kc.VK_UP &&
            grounded
        ) {

            velocityY = 11

            grounded = false
        }

        robotX =
            math.max(
                40,
                math.min(
                    cwidth - 320,
                    robotX
                )
            )
    }
}

// ============================================================
// UI
// ============================================================

def drawUI(
    canvas: CanvasDraw
) {

    canvas.fill(
        5,
        12,
        30,
        220
    )

    canvas.stroke(
        0,
        220,
        255
    )

    canvas.strokeWeight(2)

    canvas.rect(
        20,
        cheight - 100,
        250,
        70
    )

    canvas.fill(
        0,
        255,
        255
    )

    canvas.text(
        "? AI ENERGY RUN",
        35,
        cheight - 50
    )

    canvas.fill(
        255,
        255,
        255
    )

    canvas.text(
        s"ENERGY: $energy%",
        35,
        cheight - 75
    )

    canvas.text(
        s"SCORE: $score",
        155,
        cheight - 75
    )

    canvas.fill(
        100,
        120,
        140
    )

    canvas.text(
        "? ? MOVE     ? JUMP",
        cwidth - 220,
        35
    )
}

// ============================================================
// GAME OVER
// ============================================================

def drawGameOver(
    canvas: CanvasDraw
) {

    canvas.fill(
        5,
        5,
        20,
        240
    )

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

    canvas.fill(
        255,
        40,
        80
    )

    canvas.text(
        "SYSTEM OFFLINE",
        cwidth / 2 - 65,
        cheight / 2 + 40
    )

    canvas.fill(
        255,
        255,
        255
    )

    canvas.text(
        s"SCORE: $score",
        cwidth / 2 - 40,
        cheight / 2
    )

    canvas.text(
        "Refresh to restart",
        cwidth / 2 - 55,
        cheight / 2 - 40
    )
}

// ============================================================
// VICTORY
// ============================================================

def drawVictory(
    canvas: CanvasDraw
) {

    canvas.fill(
        5,
        10,
        25,
        240
    )

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

    canvas.fill(
        0,
        255,
        220
    )

    canvas.text(
        "? AI FULLY CHARGED ?",
        cwidth / 2 - 100,
        cheight / 2 + 60
    )

    canvas.fill(
        255,
        255,
        255
    )

    canvas.text(
        s"FINAL SCORE: $score",
        cwidth / 2 - 55,
        cheight / 2 + 20
    )

    canvas.text(
        "MISSION COMPLETE!",
        cwidth / 2 - 65,
        cheight / 2 - 20
    )
}

// ============================================================
// VIEW
// ============================================================

def viewState(
    canvas: CanvasDraw
) {

    drawBackground(canvas)

    if (
        !gameOver &&
        !victory
    ) {

        drawOrbs(canvas)

        drawObstacles(canvas)

        drawRobot(canvas)

        drawUI(canvas)

    } else if (gameOver) {

        drawGameOver(canvas)

    } else {

        drawVictory(canvas)
    }

    repeatFor(particles) { p =>
        p.draw(canvas)
    }
}

// ============================================================
// GAME LOOP
// ============================================================

animateWithCanvasDraw { canvas =>

    updateState()

    viewState(canvas)
}