Code Sketch
dolly 24
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)
}
}