Code Sketch


bhavesh
By: Mhalsakant School
Category: Programming
// ============================================================
// BIXUU GAMING
// JUNGLE OF AMIGO
// AVATAR + AI ROBOT + 20 ENERGY DRONES
// FICTIONAL ARCADE GAME
// ============================================================

cleari()
originBottomLeft()

// ============================================================
// GAME STATES
// ============================================================

var screen = 0
// 0 = avatar selection
// 1 = robot briefing
// 2 = mission
// 3 = complete

var selectedAvatar = 0
var score = 0
var destroyed = 0

var launcherX = cwidth / 2.0
var launcherY = 100.0
var launcherAngle = math.Pi / 2.0

var messageTimer = 0

// ============================================================
// AVATAR DATA
// ============================================================

val avatarNames = Array(
    "STONE AI",
    "FIRE AI",
    "WATER AI",
    "AIR AI",
    "SMART CRYSTAL AI"
)

val avatarR = Array(
    130, 255, 40, 180, 220
)

val avatarG = Array(
    130, 80, 150, 230, 80
)

val avatarB = Array(
    140, 20, 255, 255, 255
)

// ============================================================
// DRONE
// ============================================================

class EnergyDrone(
    var x: Double,
    var y: Double,
    val id: Int
) {

    var active = true
    var pulse = randomDouble(6.28)
    var direction = 1.0

    def step() {

        pulse += 0.06

        x += math.sin(pulse) * 0.8 * direction

        if (x < 70) {
            direction = 1.0
        }

        if (x > cwidth - 70) {
            direction = -1.0
        }
    }

    def view(canvas: CanvasDraw) {

        if (active) {

            // Drone glow

            canvas.noStroke()

            canvas.fill(
                255,
                80,
                80,
                35
            )

            canvas.ellipse(
                x,
                y,
                60,
                60
            )

            // Drone body

            canvas.fill(
                55,
                65,
                80
            )

            canvas.stroke(
                180,
                190,
                210
            )

            canvas.strokeWeight(2)

            canvas.ellipse(
                x,
                y,
                34,
                34
            )

            // Drone core

            canvas.noStroke()

            canvas.fill(
                255,
                80,
                80
            )

            canvas.ellipse(
                x,
                y,
                12,
                12
            )

            // Drone arms

            canvas.stroke(
                130,
                140,
                160
            )

            canvas.strokeWeight(4)

            canvas.line(
                x - 22,
                y + 18,
                x + 22,
                y - 18
            )

            canvas.line(
                x - 22,
                y - 18,
                x + 22,
                y + 18
            )

            // ID

            canvas.noStroke()

            canvas.fill(
                255,
                255,
                255
            )

            canvas.text(
                "D" + id.toString,
                x - 8,
                y + 32
            )
        }
    }
}

val drones =
    ArrayBuffer.empty[EnergyDrone]

// ============================================================
// CREATE 20 DRONES
// ============================================================

for (i <- 0 until 20) {

    val row = i / 5
    val column = i % 5

    drones.append(
        new EnergyDrone(
            100.0 + column * 120.0,
            cheight - 180.0 - row * 75.0,
            i + 1
        )
    )
}

// ============================================================
// ENERGY PULSE
// ============================================================

class EnergyPulse(
    var x: Double,
    var y: Double,
    val angle: Double,
    val r: Int,
    val g: Int,
    val b: Int
) {

    var active = true

    val trail =
        ArrayBuffer.empty[Vector2D]

    def step() {

        val speed = 9.0

        x += math.cos(angle) * speed
        y += math.sin(angle) * speed

        trail.append(
            Vector2D(x, y)
        )

        if (trail.length > 12) {
            trail.remove(0)
        }

        if (
            x < -50 ||
            x > cwidth + 50 ||
            y < -50 ||
            y > cheight + 50
        ) {
            active = false
        }
    }

    def view(canvas: CanvasDraw) {

        canvas.noStroke()

        for (i <- 0 until trail.length) {

            val a =
                ((i.toDouble / trail.length) * 180).toInt

            canvas.fill(
                r,
                g,
                b,
                a
            )

            canvas.ellipse(
                trail(i).x,
                trail(i).y,
                7,
                7
            )
        }

        canvas.fill(
            255,
            255,
            255
        )

        canvas.ellipse(
            x,
            y,
            18,
            18
        )

        canvas.fill(
            r,
            g,
            b
        )

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

val pulses =
    ArrayBuffer.empty[EnergyPulse]

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

class Particle(
    var x: Double,
    var y: Double,
    val r: Int,
    val g: Int,
    val b: Int
) {

    var life = 35

    def step() {

        y += 1.5

        life -= 1
    }

    def view(canvas: CanvasDraw) {

        if (life > 0) {

            canvas.noStroke()

            canvas.fill(
                r,
                g,
                b,
                life * 6
            )

            canvas.ellipse(
                x,
                y,
                8,
                8
            )
        }
    }
}

val particles =
    ArrayBuffer.empty[Particle]

// ============================================================
// STARS
// ============================================================

class Star(
    val x: Double,
    val y: Double,
    val size: Double
) {

    var phase =
        randomDouble(6.28)

    def step() {
        phase += 0.04
    }

    def view(canvas: CanvasDraw) {

        val brightness =
            130 +
            (math.sin(phase) * 80).toInt

        canvas.noStroke()

        canvas.fill(
            brightness,
            brightness,
            255,
            200
        )

        canvas.ellipse(
            x,
            y,
            size,
            size
        )
    }
}

val stars =
    ArrayBuffer.empty[Star]

for (i <- 0 until 80) {

    stars.append(
        new Star(
            randomDouble(cwidth),
            randomDouble(cheight),
            1.0 + randomDouble(3.0)
        )
    )
}

// ============================================================
// AVATAR ROBOT
// ============================================================

def drawAvatarRobot(
    canvas: CanvasDraw,
    x: Double,
    y: Double,
    avatar: Int,
    scale: Double
) {

    val r = avatarR(avatar)
    val g = avatarG(avatar)
    val b = avatarB(avatar)

    // Glow

    canvas.noStroke()

    canvas.fill(
        r,
        g,
        b,
        35
    )

    canvas.ellipse(
        x,
        y,
        120 * scale,
        120 * scale
    )

    // Body

    canvas.fill(
        45,
        50,
        65
    )

    canvas.stroke(
        r,
        g,
        b
    )

    canvas.strokeWeight(3)

    canvas.rect(
        x - 32 * scale,
        y - 42 * scale,
        64 * scale,
        70 * scale
    )

    // Head

    canvas.fill(
        65,
        70,
        90
    )

    canvas.ellipse(
        x,
        y + 45 * scale,
        70 * scale,
        55 * scale
    )

    // Eyes

    canvas.noStroke()

    canvas.fill(
        r,
        g,
        b
    )

    canvas.ellipse(
        x - 15 * scale,
        y + 47 * scale,
        10 * scale,
        14 * scale
    )

    canvas.ellipse(
        x + 15 * scale,
        y + 47 * scale,
        10 * scale,
        14 * scale
    )

    // Core

    canvas.fill(
        255,
        255,
        255
    )

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

    canvas.fill(
        r,
        g,
        b
    )

    canvas.ellipse(
        x,
        y - 8 * scale,
        8 * scale,
        8 * scale
    )

    // Arms

    canvas.stroke(
        r,
        g,
        b
    )

    canvas.strokeWeight(
        8 * scale
    )

    canvas.line(
        x - 32 * scale,
        y + 5 * scale,
        x - 55 * scale,
        y - 25 * scale
    )

    canvas.line(
        x + 32 * scale,
        y + 5 * scale,
        x + 55 * scale,
        y - 25 * scale
    )
}

// ============================================================
// JUNGLE BACKGROUND
// ============================================================

def drawJungle(
    canvas: CanvasDraw
) {

    // Ground

    canvas.fill(
        20,
        90,
        45
    )

    canvas.noStroke()

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

    // Trees

    for (i <- 0 until 8) {

        val tx =
            30.0 + i * 100.0

        canvas.fill(
            90,
            55,
            25
        )

        canvas.rect(
            tx,
            80,
            22,
            160
        )

        canvas.fill(
            20,
            150,
            55
        )

        canvas.ellipse(
            tx + 10,
            240,
            100,
            100
        )
    }
}

// ============================================================
// LAUNCHER
// ============================================================

def drawLauncher(
    canvas: CanvasDraw
) {

    canvas.fill(
        30,
        35,
        50
    )

    canvas.stroke(
        150,
        170,
        190
    )

    canvas.strokeWeight(2)

    canvas.ellipse(
        launcherX,
        launcherY,
        80,
        80
    )

    canvas.pushMatrix()

    canvas.translate(
        launcherX,
        launcherY
    )

    canvas.rotate(
        launcherAngle
    )

    canvas.fill(
        55,
        65,
        90
    )

    canvas.rect(
        -15,
        -18,
        75,
        36
    )

    canvas.fill(
        avatarR(selectedAvatar),
        avatarG(selectedAvatar),
        avatarB(selectedAvatar)
    )

    canvas.ellipse(
        52,
        0,
        26,
        26
    )

    canvas.fill(
        255,
        255,
        255
    )

    canvas.ellipse(
        52,
        0,
        9,
        9
    )

    canvas.popMatrix()
}

// ============================================================
// CONTROL BUTTON
// ============================================================

def button(
    canvas: CanvasDraw,
    x: Double,
    label: String,
    r: Int,
    g: Int,
    b: Int
) {

    canvas.fill(
        r,
        g,
        b,
        230
    )

    canvas.stroke(
        220,
        220,
        230
    )

    canvas.strokeWeight(2)

    canvas.rect(
        x,
        15,
        70,
        40
    )

    canvas.fill(
        255,
        255,
        255
    )

    canvas.text(
        label,
        x + 12,
        30
    )
}

// ============================================================
// MISSION CONTROLS
// ============================================================

def drawMissionControls(
    canvas: CanvasDraw
) {

    canvas.fill(
        8,
        12,
        25,
        235
    )

    canvas.noStroke()

    canvas.rect(
        5,
        5,
        cwidth - 10,
        70
    )

    button(
        canvas,
        15,
        "<-",
        40,
        80,
        130
    )

    button(
        canvas,
        95,
        "->",
        40,
        80,
        130
    )

    button(
        canvas,
        175,
        "UP",
        50,
        80,
        150
    )

    button(
        canvas,
        255,
        "DOWN",
        50,
        80,
        150
    )

    button(
        canvas,
        335,
        "ROT-L",
        130,
        50,
        150
    )

    button(
        canvas,
        415,
        "ROT-R",
        130,
        50,
        150
    )

    button(
        canvas,
        495,
        "ENERGY",
        180,
        0,
        170
    )
}

// ============================================================
// AVATAR SELECTION
// ============================================================

def drawAvatarSelection(
    canvas: CanvasDraw
) {

    canvas.background(
        5,
        8,
        20
    )

    repeatFor(stars) { s =>
        s.view(canvas)
    }

    canvas.fill(
        0,
        220,
        255
    )

    canvas.text(
        "SELECT YOUR AVATAR",
        cwidth / 2.0 - 130,
        cheight - 55
    )

    val startX = 90.0

    for (i <- 0 until 5) {

        val x =
            startX + i * 120.0

        val y =
            cheight / 2.0

        drawAvatarRobot(
            canvas,
            x,
            y,
            i,
            0.75
        )

        canvas.fill(
            255,
            255,
            255
        )

        canvas.text(
            avatarNames(i),
            x - 50,
            y - 80
        )

        canvas.stroke(
            avatarR(i),
            avatarG(i),
            avatarB(i)
        )

        canvas.strokeWeight(2)

        canvas.noFill()

        canvas.rect(
            x - 55,
            y - 110,
            110,
            150
        )
    }

    canvas.fill(
        255,
        255,
        255
    )

    canvas.text(
        "STONE ? FIRE ? WATER ? AIR ? SMART CRYSTAL",
        cwidth / 2.0 - 210,
        80
    )
}

// ============================================================
// ROBOT BRIEFING
// ============================================================

def drawBriefing(
    canvas: CanvasDraw
) {

    canvas.background(
        5,
        8,
        20
    )

    repeatFor(stars) { s =>
        s.view(canvas)
    }

    drawAvatarRobot(
        canvas,
        110,
        cheight / 2.0,
        selectedAvatar,
        1.15
    )

    canvas.fill(
        8,
        15,
        30,
        235
    )

    canvas.stroke(
        avatarR(selectedAvatar),
        avatarG(selectedAvatar),
        avatarB(selectedAvatar)
    )

    canvas.strokeWeight(3)

    canvas.rect(
        210,
        125,
        cwidth - 245,
        300
    )

    canvas.fill(
        avatarR(selectedAvatar),
        avatarG(selectedAvatar),
        avatarB(selectedAvatar)
    )

    canvas.text(
        "BIXUU AI ROBOT",
        240,
        390
    )

    canvas.fill(
        255,
        255,
        255
    )

    canvas.text(
        "WELCOME! YOUR MISSION STARTS NOW.",
        240,
        350
    )

    canvas.text(
        "We received a letter from",
        240,
        320
    )

    canvas.text(
        "JUNGLE OF AMIGO.",
        240,
        290
    )

    canvas.text(
        "The jungle animals need your help.",
        240,
        255
    )

    canvas.text(
        "Protect the animals from the",
        240,
        225
    )

    canvas.text(
        "fictional energy drones.",
        240,
        195
    )

    canvas.fill(
        0,
        220,
        255
    )

    canvas.text(
        "CLICK START MISSION",
        280,
        150
    )
}

// ============================================================
// COMPLETE SCREEN
// ============================================================

def drawComplete(
    canvas: CanvasDraw
) {

    canvas.background(
        5,
        8,
        20
    )

    repeatFor(stars) { s =>
        s.view(canvas)
    }

    canvas.fill(
        0,
        220,
        255
    )

    canvas.text(
        "BIXUU GAMING",
        cwidth / 2.0 - 100,
        cheight - 60
    )

    canvas.fill(
        255,
        255,
        255
    )

    canvas.text(
        "MISSION COMPLETE!",
        cwidth / 2.0 - 120,
        cheight / 2.0 + 90
    )

    canvas.fill(
        255,
        220,
        0
    )

    canvas.text(
        "VEER AWARD",
        cwidth / 2.0 - 80,
        cheight / 2.0 + 45
    )

    canvas.fill(
        255,
        255,
        255
    )

    canvas.text(
        "20 / 20 DRONES CLEARED",
        cwidth / 2.0 - 110,
        cheight / 2.0
    )

    canvas.text(
        "SCORE: " + score.toString,
        cwidth / 2.0 - 55,
        cheight / 2.0 - 40
    )

    canvas.fill(
        0,
        220,
        120
    )

    canvas.text(
        "THANK YOU FOR PLAYING BIXUU GAMING!",
        cwidth / 2.0 - 170,
        cheight / 2.0 - 100
    )

    canvas.fill(
        0,
        255,
        120
    )

    canvas.text(
        "SAVE ANIMALS",
        cwidth / 2.0 - 65,
        110
    )

    canvas.text(
        "SAVE NATURE",
        cwidth / 2.0 - 60,
        80
    )

    canvas.text(
        "SAVE CULTURE",
        cwidth / 2.0 - 65,
        50
    )
}

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

def updateGame() {

    repeatFor(stars) { s =>
        s.step()
    }

    if (screen == 2) {

        repeatFor(drones) { d =>
            if (d.active) {
                d.step()
            }
        }

        pulses.filterInPlace(
            _.active
        )

        repeatFor(pulses) { p =>
            p.step()
        }

        particles.filterInPlace(
            _.life > 0
        )

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

        // Drone collision

        repeatFor(pulses) { p =>

            if (p.active) {

                repeatFor(drones) { d =>

                    if (
                        d.active &&
                        math.abs(p.x - d.x) < 30 &&
                        math.abs(p.y - d.y) < 30
                    ) {

                        d.active = false

                        p.active = false

                        destroyed += 1

                        score += 50

                        // Energy particles

                        for (k <- 0 until 15) {

                            particles.append(
                                new Particle(
                                    d.x,
                                    d.y,
                                    avatarR(selectedAvatar),
                                    avatarG(selectedAvatar),
                                    avatarB(selectedAvatar)
                                )
                            )
                        }

                        if (destroyed >= 20) {

                            screen = 3
                        }
                    }
                }
            }
        }
    }
}

// ============================================================
// MOUSE CONTROL
// ============================================================

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

    // ========================================================
    // AVATAR SELECTION
    // ========================================================

    if (screen == 0) {

        for (i <- 0 until 5) {

            val left =
                35.0 + i * 120.0

            val right =
                left + 110.0

            if (
                x >= left &&
                x <= right &&
                y >= 100 &&
                y <= 420
            ) {

                selectedAvatar = i

                screen = 1
            }
        }
    }

    // ========================================================
    // BRIEFING
    // ========================================================

    else if (screen == 1) {

        if (
            x > 230 &&
            y > 120 &&
            y < 190
        ) {

            screen = 2
        }
    }

    // ========================================================
    // MISSION
    // ========================================================

    else if (screen == 2) {

        // LEFT

        if (
            x >= 15 &&
            x <= 85 &&
            y >= 15 &&
            y <= 55
        ) {

            launcherX -= 8
        }

        // RIGHT

        else if (
            x >= 95 &&
            x <= 165 &&
            y >= 15 &&
            y <= 55
        ) {

            launcherX += 8
        }

        // UP

        else if (
            x >= 175 &&
            x <= 245 &&
            y >= 15 &&
            y <= 55
        ) {

            launcherY += 8
        }

        // DOWN

        else if (
            x >= 255 &&
            x <= 325 &&
            y >= 15 &&
            y <= 55
        ) {

            launcherY -= 8
        }

        // ROTATE LEFT

        else if (
            x >= 335 &&
            x <= 405 &&
            y >= 15 &&
            y <= 55
        ) {

            launcherAngle -= 0.15
        }

        // ROTATE RIGHT

        else if (
            x >= 415 &&
            x <= 485 &&
            y >= 15 &&
            y <= 55
        ) {

            launcherAngle += 0.15
        }

        // ENERGY

        else if (
            x >= 495 &&
            x <= 565 &&
            y >= 15 &&
            y <= 55
        ) {

            val px =
                launcherX +
                math.cos(launcherAngle) * 65.0

            val py =
                launcherY +
                math.sin(launcherAngle) * 65.0

            pulses.append(
                new EnergyPulse(
                    px,
                    py,
                    launcherAngle,
                    avatarR(selectedAvatar),
                    avatarG(selectedAvatar),
                    avatarB(selectedAvatar)
                )
            )
        }
    }
}

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

def viewGame(
    canvas: CanvasDraw
) {

    if (screen == 0) {

        drawAvatarSelection(canvas)
    }

    else if (screen == 1) {

        drawBriefing(canvas)
    }

    else if (screen == 2) {

        canvas.background(
            8,
            30,
            20
        )

        drawJungle(canvas)

        repeatFor(stars) { s =>
            s.view(canvas)
        }

        repeatFor(drones) { d =>
            d.view(canvas)
        }

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

        repeatFor(pulses) { p =>
            p.view(canvas)
        }

        drawLauncher(canvas)

        drawMissionControls(canvas)

        canvas.fill(
            255,
            255,
            255
        )

        canvas.text(
            "JUNGLE OF AMIGO",
            20,
            cheight - 35
        )

        canvas.fill(
            255,
            220,
            0
        )

        canvas.text(
            "DRONES: " +
            destroyed.toString +
            " / 20",
            cwidth - 130,
            cheight - 35
        )
    }

    else if (screen == 3) {

        drawComplete(canvas)
    }
}

// ============================================================
// CLICK EVENT
// ============================================================

onMouseClick { (x, y) =>

    handleClick(
        x,
        y
    )
}

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

animateWithCanvasDraw { canvas =>

    updateGame()

    viewGame(canvas)
}