Code Sketch


dolly 24
By: Mhalsakant School

cleari()
originBottomLeft()

// ========================================
// ROBOT ENERGY RUN - UPDATED EDITION
// ========================================

var robotX = 100.0
var robotY = 100.0
var velocityY = 0.0
var grounded = true

var score = 0
var energy = 100
var tick = 0
var level = 1
var gameOver = false

var obstacleX = 700.0
var obstacle2X = 1100.0
var crystalX = 400.0
var crystalY = 140.0
var crystalTaken = false

var bonusX = 850.0
var bonusTaken = false

def resetRun() {
    robotX = 100.0
    robotY = 100.0
    velocityY = 0.0
    grounded = true

    score = 0
    energy = 100
    tick = 0
    level = 1
    gameOver = false

    obstacleX = 700.0
    obstacle2X = 1100.0
    crystalX = 400.0
    crystalY = 140.0
    crystalTaken = false

    bonusX = 850.0
    bonusTaken = false
}

onKeyPress { key =>
    if (key == Kc.VK_R) {
        resetRun()
    }

    if (!gameOver) {
        if (key == Kc.VK_SPACE && grounded) {
            velocityY = 17.0
            grounded = false
        }

        if (key == Kc.VK_LEFT) {
            robotX = math.max(35.0, robotX - 25.0)
        }

        if (key == Kc.VK_RIGHT) {
            robotX = math.min(cwidth - 35.0, robotX + 25.0)
        }
    }
}

// BACKGROUND

def drawWorld(c: CanvasDraw) {
    c.fill(5, 8, 30)
    c.noStroke()
    c.rect(0, 0, cwidth, cheight)

    for (i <- 0 until 60) {
        val x = (i * 137) % cwidth.toInt
        val y = (i * 97) % cheight.toInt

        c.fill(100, 180, 255)
        c.ellipse(x.toDouble, y.toDouble, 3, 3)
    }

    c.fill(15, 25, 55)
    c.rect(0, 70, cwidth, 100)

    c.fill(0, 220, 180)
    c.rect(0, 70, cwidth, 5)

    c.fill(30, 40, 75)
    c.rect(0, 0, cwidth, 70)

    // Futuristic buildings

    for (i <- 0 until 12) {
        val bx = i * 75
        val bh = 30 + (i * 17) % 60

        c.fill(20, 35, 75)
        c.rect(bx, 75, 45, bh)

        c.fill(0, 180, 255)
        c.rect(bx + 10, 85, 5, 5)
        c.rect(bx + 25, 100, 5, 5)
    }
}

// ROBOT

def drawRobot(c: CanvasDraw) {
    c.stroke(255, 255, 255)
    c.strokeWeight(2)

    // Legs

    c.fill(40, 100, 220)
    c.rect(robotX - 14, robotY - 20, 10, 12)
    c.rect(robotX + 4, robotY - 20, 10, 12)

    // Body

    c.fill(0, 210, 255)
    c.rect(robotX - 18, robotY - 8, 36, 32)

    // Head

    c.fill(50, 80, 150)
    c.rect(robotX - 16, robotY + 24, 32, 20)

    // Eyes

    c.fill(255, 255, 0)
    c.noStroke()
    c.ellipse(robotX - 7, robotY + 34, 6, 6)
    c.ellipse(robotX + 7, robotY + 34, 6, 6)

    // Energy core

    c.fill(0, 255, 150)
    c.ellipse(robotX, robotY + 7, 12, 12)
}

// OBSTACLES

def drawObstacles(c: CanvasDraw) {
    c.fill(255, 50, 70)
    c.stroke(255, 140, 100)
    c.strokeWeight(2)
    c.rect(obstacleX - 18, 75, 36, 42)
    c.rect(obstacle2X - 18, 75, 36, 42)

    c.fill(255, 180, 0)
    c.noStroke()
    c.ellipse(obstacleX, 115, 12, 12)
    c.ellipse(obstacle2X, 115, 12, 12)
}

// ENERGY CRYSTAL

def drawCrystal(c: CanvasDraw) {
    if (!crystalTaken) {
        c.fill(255, 220, 0)
        c.stroke(255, 255, 180)
        c.strokeWeight(2)
        c.ellipse(crystalX, crystalY, 22, 28)

        c.fill(255, 255, 255)
        c.noStroke()
        c.ellipse(crystalX, crystalY, 7, 12)
    }

    if (!bonusTaken) {
        c.fill(255, 50, 220)
        c.ellipse(bonusX, 145, 25, 25)
        c.fill(255, 255, 255)
        c.ellipse(bonusX, 145, 10, 10)
    }
}

// SCOREBOARD

def drawHUD(c: CanvasDraw) {
    c.fill(255, 255, 255)
    c.noStroke()

    c.text("ROBOT ENERGY RUN", cwidth / 2 - 65, cheight - 30)
    c.text(s"SCORE: $score", 20, cheight - 30)
    c.text(s"LEVEL: $level", 20, cheight - 55)
    c.text(s"ENERGY: $energy", 20, cheight - 80)

    // Energy bar

    c.fill(70, 70, 90)
    c.rect(cwidth - 160, cheight - 55, 120, 15)

    c.fill(0, 240, 120)
    c.rect(
        cwidth - 160,
        cheight - 55,
        120.0 * energy / 100.0,
        15
    )

    c.fill(200, 220, 255)
    c.text("SPACE = JUMP", cwidth - 160, cheight - 80)
    c.text("R = RESTART", cwidth - 160, cheight - 105)
}

// UPDATE GAME

def updateRun() {
    if (!gameOver) {
        tick += 1

        // Gravity

        velocityY -= 0.8
        robotY += velocityY

        if (robotY <= 100) {
            robotY = 100
            velocityY = 0
            grounded = true
        }

        // Difficulty

        level = 1 + score / 100
        val speed = 5.0 + level * 0.5

        // Move obstacles

        obstacleX -= speed
        obstacle2X -= speed

        if (obstacleX < -30) {
            obstacleX = cwidth + 100
            score += 5
        }

        if (obstacle2X < -30) {
            obstacle2X = cwidth + 200
            score += 5
        }

        // Move crystal

        crystalX -= speed

        if (crystalX < -30) {
            crystalX = cwidth + 150
            crystalY = 120.0 + (tick % 4) * 35.0
            crystalTaken = false
        }

        // Move bonus

        bonusX -= speed

        if (bonusX < -30) {
            bonusX = cwidth + 300
            bonusTaken = false
        }

        // Obstacle collision

        if (
            math.abs(robotX - obstacleX) < 30 &&
            robotY < 140
        ) {
            energy -= 25
            obstacleX = cwidth + 150
        }

        if (
            math.abs(robotX - obstacle2X) < 30 &&
            robotY < 140
        ) {
            energy -= 25
            obstacle2X = cwidth + 200
        }

        // Collect crystal

        if (
            !crystalTaken &&
            math.abs(robotX - crystalX) < 25 &&
            math.abs(robotY - crystalY) < 35
        ) {
            crystalTaken = true
            score += 10
            energy = math.min(100, energy + 10)
        }

        // Collect bonus

        if (
            !bonusTaken &&
            math.abs(robotX - bonusX) < 25 &&
            math.abs(robotY - 145) < 35
        ) {
            bonusTaken = true
            score += 25
            energy = math.min(100, energy + 20)
        }

        // Survival bonus

        if (tick % 100 == 0) {
            score += 5
        }       

        if (energy <= 0) {
            energy = 0
            gameOver = true
        }
    }
}

// GAME OVER

def drawEnd(c: CanvasDraw) {
    c.fill(5, 8, 30)
    c.noStroke()
    c.rect(0, 0, cwidth, cheight)

    c.fill(255, 60, 80)
    c.text("GAME OVER!", cwidth / 2 - 45, cheight / 2 + 40)

    c.fill(255, 255, 255)
    c.text(s"FINAL SCORE: $score", cwidth / 2 - 55, cheight / 2)
    c.text(s"LEVEL REACHED: $level", cwidth / 2 - 60, cheight / 2 - 30)
    c.text("Press R to Play Again", cwidth / 2 - 75, cheight / 2 - 65)
}

// GAME LOOP

animateWithCanvasDraw { c =>
    updateRun()

    if (!gameOver) {
        drawWorld(c)
        drawCrystal(c)
        drawObstacles(c)
        drawRobot(c)
        drawHUD(c)
    } else {
           drawEnd(c)
    }
}