Code Sketch
siddhi sabale
Category: Programming
cleari()
originBottomLeft()
// ============================================================
// ?? ISRO MARS EXPLORER - ULTIMATE 3D GAME
// Robot + Mars + Moon + Earth + Vikram Lander
// Keyboard Movement + Scanner + Sample Collection + Welding
// Energy + Health + Score + Missions + Footprints + Particles
// ============================================================
// ============================================================
// GAME VARIABLES
// ============================================================
var robotX = 220.0
var robotY = 150.0
var robotWalk = 0.0
var robotBob = 0.0
var robotGlow = 0.0
var robotTime = 0.0
var robotHeadTurn = 0.0
var robotArmWave = 0.0
var robotFacing = 1.0
var robotState = 0
// 0 = FREE
// 1 = SCANNING
// 2 = COLLECTING
// 3 = WELDING
var stateTimer = 0.0
var scanAngle = 0.0
var armBend = 0.0
var energy = 100.0
var health = 100.0
var score = 0
var samples = 0
var repairs = 0
var flashlight = false
var paused = false
var messageTimer = 0.0
var missionText = "SEARCH FOR MARS SAMPLE"
var cameraShake = 0.0
// ============================================================
// ROCK
// ============================================================
var rockX = 500.0
var rockY = 145.0
var rockScanned = false
var rockCollected = false
// ============================================================
// VIKRAM LANDER
// ============================================================
val landerX = 130.0
val landerY = 155.0
// ============================================================
// METEOR
// ============================================================
var meteorX = cwidth + 50.0
var meteorY = cheight - 60.0
var meteorActive = false
var meteorTimer = 0.0
// ============================================================
// FOOTPRINTS
// ============================================================
val maxFootprints = 30
val fpX =
Array.fill(maxFootprints)(-100.0)
val fpY =
Array.fill(maxFootprints)(140.0)
var fpIndex = 0
var lastStepX = robotX
// ============================================================
// DUST PARTICLES
// ============================================================
val particleCount = 80
val particleX =
Array.fill(particleCount)(
randomDouble(0, cwidth)
)
val particleY =
Array.fill(particleCount)(
randomDouble(145, cheight)
)
val particleSpeed =
Array.fill(particleCount)(
randomDouble(0.15, 0.65)
)
// ============================================================
// COLORS
// ============================================================
val whiteRobot =
cm.rgb(245, 248, 250)
val whiteShadow =
cm.rgb(170, 185, 195)
val greenMain =
cm.rgb(0, 210, 80)
val greenDark =
cm.rgb(0, 105, 45)
val greenGlow =
cm.rgb(40, 255, 120)
val blackScreen =
cm.rgb(5, 8, 18)
val marsDark =
cm.rgb(90, 28, 22)
val marsMid =
cm.rgb(135, 43, 28)
val marsLight =
cm.rgb(175, 65, 38)
// ============================================================
// MESSAGE
// ============================================================
def showMessage(txt: String) {
missionText = txt
messageTimer = 3.0
}
// ============================================================
// KEYBOARD CONTROLS
// ============================================================
// One-time action keys
onKeyPress { k =>
k match {
// SPACE = SCAN
case Kc.VK_SPACE =>
if (!paused) {
robotState = 1
stateTimer = 0.0
scanAngle = 0.0
showMessage("LASER SCANNING STARTED")
}
// E = COLLECT
case Kc.VK_E =>
if (!paused && rockScanned && !rockCollected) {
robotState = 2
stateTimer = 0.0
showMessage("COLLECTING MARS SAMPLE")
}
// R = WELD / REPAIR
case Kc.VK_R =>
if (!paused) {
robotState = 3
stateTimer = 0.0
showMessage("WELDING / REPAIR SYSTEM ACTIVE")
}
// F = FLASHLIGHT
case Kc.VK_F =>
flashlight = !flashlight
if (flashlight)
showMessage("FLASHLIGHT ON")
else
showMessage("FLASHLIGHT OFF")
// Q = STOP TASK
case Kc.VK_Q =>
robotState = 0
stateTimer = 0.0
showMessage("TASK STOPPED")
// P = PAUSE
case Kc.VK_P =>
paused = !paused
if (paused)
showMessage("MISSION PAUSED")
else
showMessage("MISSION RESUMED")
// H = HELP
case Kc.VK_H =>
showMessage(
"WASD/ARROWS MOVE | SPACE SCAN | E COLLECT | R WELD"
)
case _ =>
}
}
// ============================================================
// MOVEMENT
// ============================================================
def updateMovement() {
if (paused)
return
// Movement allowed during FREE state
if (robotState == 0) {
var dx = 0.0
var dy = 0.0
// --------------------------------------------------------
// LEFT / RIGHT
// --------------------------------------------------------
if (
isKeyPressed(Kc.VK_A) ||
isKeyPressed(Kc.VK_LEFT)
) {
dx -= 1.0
robotFacing = -1.0
}
if (
isKeyPressed(Kc.VK_D) ||
isKeyPressed(Kc.VK_RIGHT)
) {
dx += 1.0
robotFacing = 1.0
}
// --------------------------------------------------------
// UP / DOWN
// --------------------------------------------------------
if (
isKeyPressed(Kc.VK_W) ||
isKeyPressed(Kc.VK_UP)
) {
dy += 1.0
}
if (
isKeyPressed(Kc.VK_S) ||
isKeyPressed(Kc.VK_DOWN)
) {
dy -= 1.0
}
// --------------------------------------------------------
// SPEED
// --------------------------------------------------------
var speed = 2.2
if (isKeyPressed(Kc.VK_SHIFT)) {
speed = 4.8
energy -= 0.05
if (energy < 0)
energy = 0
}
// --------------------------------------------------------
// APPLY MOVEMENT
// --------------------------------------------------------
robotX += dx * speed
robotY += dy * speed
// --------------------------------------------------------
// BOUNDARIES
// --------------------------------------------------------
if (robotX < 80)
robotX = 80
if (robotX > cwidth - 80)
robotX = cwidth - 80
if (robotY < 150)
robotY = 150
if (robotY > cheight - 160)
robotY = cheight - 160
// --------------------------------------------------------
// WALK ANIMATION
// --------------------------------------------------------
if (dx != 0 || dy != 0) {
robotWalk += 0.16
robotBob =
math.sin(robotWalk * 2.0) * 3.5
robotArmWave =
math.sin(robotWalk) * 18.0
// footprints
if (
math.abs(robotX - lastStepX) > 24
) {
fpX(fpIndex) =
robotX - 15.0 * robotFacing
fpY(fpIndex) =
142.0
fpIndex =
(fpIndex + 1) % maxFootprints
lastStepX = robotX
}
} else {
robotBob =
math.sin(robotTime * 2) * 1.2
robotArmWave = 0
}
}
}
// ============================================================
// GAME UPDATE
// ============================================================
def updateRobot() {
if (paused)
return
robotTime += 0.018
robotGlow += 0.08
stateTimer += 0.018
// ==========================================================
// MOVEMENT
// ==========================================================
updateMovement()
// ==========================================================
// STATE 1 - SCANNING
// ==========================================================
if (robotState == 1) {
robotBob =
math.sin(robotTime * 3) * 1.5
robotHeadTurn =
math.sin(robotTime * 3) * 8
scanAngle =
math.sin(robotTime * 5) * 55
// energy consumption
energy -= 0.035
if (energy < 0)
energy = 0
// Scan complete
if (stateTimer > 3.0) {
rockScanned = true
robotState = 0
score += 100
showMessage(
"ROCK SCANNED! PRESS E TO COLLECT"
)
}
}
// ==========================================================
// STATE 2 - COLLECTION
// ==========================================================
if (robotState == 2) {
robotBob = -6
armBend =
math.sin(robotTime * 5) * 18
robotHeadTurn =
-12 * robotFacing
energy -= 0.045
if (energy < 0)
energy = 0
if (stateTimer > 3.0) {
rockCollected = true
samples += 1
score += 250
robotState = 0
showMessage(
"MARS SAMPLE COLLECTED!"
)
}
}
// ==========================================================
// STATE 3 - WELDING
// ==========================================================
if (robotState == 3) {
robotBob =
math.sin(robotTime * 7) * 1.5
armBend =
math.sin(robotTime * 9) * 20
energy -= 0.04
if (energy < 0)
energy = 0
if (stateTimer > 3.5) {
repairs += 1
score += 150
health += 25
if (health > 100)
health = 100
robotState = 0
showMessage(
"WELDING COMPLETE! ROBOT REPAIRED"
)
}
}
// ==========================================================
// ENERGY RECOVERY
// ==========================================================
if (robotState == 0) {
energy += 0.015
if (energy > 100)
energy = 100
}
// ==========================================================
// MESSAGE TIMER
// ==========================================================
if (messageTimer > 0)
messageTimer -= 0.018
// ==========================================================
// METEOR
// ==========================================================
meteorTimer += 0.018
if (
!meteorActive &&
meteorTimer > 4.0
) {
meteorActive = true
meteorX =
randomDouble(
cwidth * 0.5,
cwidth + 100
)
meteorY =
randomDouble(
cheight - 80,
cheight
)
meteorTimer = 0
}
if (meteorActive) {
meteorX -= 10
meteorY -= 5
if (
meteorX < -80 ||
meteorY < 180
) {
meteorActive = false
}
}
// ==========================================================
// PARTICLES
// ==========================================================
for (i <- 0 until particleCount) {
particleY(i) += particleSpeed(i)
if (particleY(i) > cheight) {
particleY(i) = 145
particleX(i) =
randomDouble(0, cwidth)
}
}
}
// ============================================================
// VIKRAM LANDER
// ============================================================
def drawVikramLander(
canvas: CanvasDraw,
lx: Double,
ly: Double
) {
// shadow
canvas.fill(30, 10, 10, 100)
canvas.noStroke()
canvas.ellipse(
lx,
ly - 23,
100,
15
)
// legs
canvas.stroke(190, 190, 200)
canvas.strokeWeight(3)
canvas.line(
lx - 25,
ly,
lx - 45,
ly - 25
)
canvas.line(
lx + 25,
ly,
lx + 45,
ly - 25
)
canvas.line(
lx - 10,
ly,
lx - 20,
ly - 25
)
canvas.line(
lx + 10,
ly,
lx + 20,
ly - 25
)
// pads
canvas.fill(100, 105, 110)
canvas.noStroke()
canvas.ellipse(
lx - 45,
ly - 25,
16,
6
)
canvas.ellipse(
lx + 45,
ly - 25,
16,
6
)
// main body
canvas.fill(220, 165, 30)
canvas.stroke(180, 125, 15)
canvas.strokeWeight(2)
canvas.rect(
lx - 30,
ly,
60,
35
)
// 3D side
canvas.fill(170, 115, 15)
canvas.rect(
lx + 20,
ly,
10,
35
)
// top
canvas.fill(195, 140, 20)
canvas.rect(
lx - 20,
ly + 35,
40,
12
)
// solar panels
canvas.fill(15, 55, 140)
canvas.stroke(60, 120, 210)
canvas.strokeWeight(1)
canvas.rect(
lx - 52,
ly + 5,
18,
28
)
canvas.rect(
lx + 34,
ly + 5,
18,
28
)
// panel lines
canvas.stroke(100, 170, 230)
canvas.line(
lx - 43,
ly + 5,
lx - 43,
ly + 33
)
canvas.line(
lx + 43,
ly + 5,
lx + 43,
ly + 33
)
// antenna
canvas.stroke(210, 210, 220)
canvas.strokeWeight(2)
canvas.line(
lx,
ly + 47,
lx,
ly + 60
)
canvas.fill(220, 220, 225)
canvas.noStroke()
canvas.ellipse(
lx,
ly + 62,
18,
10
)
// Indian badge
canvas.fill(255, 153, 51)
canvas.rect(
lx - 11,
ly + 22,
22,
4
)
canvas.fill(255, 255, 255)
canvas.rect(
lx - 11,
ly + 18,
22,
4
)
canvas.fill(19, 136, 8)
canvas.rect(
lx - 11,
ly + 14,
22,
4
)
}
// ============================================================
// INDIAN FLAG
// ============================================================
def drawIndianFlag(
canvas: CanvasDraw,
fx: Double,
fy: Double
) {
canvas.stroke(220, 220, 220)
canvas.strokeWeight(3)
canvas.line(
fx,
fy,
fx,
fy + 85
)
canvas.fill(255, 210, 0)
canvas.noStroke()
canvas.ellipse(
fx,
fy + 88,
7,
7
)
val wave =
math.sin(robotTime * 4) * 3
// green
canvas.fill(19, 136, 8)
canvas.rect(
fx,
fy + 36 + wave,
48,
11
)
// white
canvas.fill(255, 255, 255)
canvas.rect(
fx,
fy + 47 + wave,
48,
11
)
// saffron
canvas.fill(255, 153, 51)
canvas.rect(
fx,
fy + 58 + wave,
48,
11
)
// chakra
canvas.stroke(0, 0, 128)
canvas.strokeWeight(1.5)
canvas.ellipse(
fx + 24,
fy + 52 + wave,
8,
8
)
}
// ============================================================
// MARS BACKGROUND
// ============================================================
def drawBackground(
canvas: CanvasDraw
) {
// ==========================================================
// SPACE
// ==========================================================
canvas.fill(8, 4, 12)
canvas.noStroke()
canvas.rect(
0,
0,
cwidth,
cheight
)
// purple/red atmosphere
canvas.fill(65, 18, 25)
canvas.rect(
0,
150,
cwidth,
cheight - 150
)
// ==========================================================
// STARS
// ==========================================================
canvas.fill(255, 245, 225)
for (i <- 0 until 55) {
val sx =
(i * 53) % cwidth
val sy =
280 +
((i * 47) % (cheight - 280))
val starSize =
if (i % 5 == 0) 3 else 2
canvas.ellipse(
sx,
sy,
starSize,
starSize
)
}
// ==========================================================
// MOON
// ==========================================================
val mx =
cwidth - 135
val my =
cheight - 105
canvas.fill(255, 235, 210, 35)
canvas.ellipse(
mx,
my,
125,
125
)
canvas.fill(255, 240, 220, 65)
canvas.ellipse(
mx,
my,
100,
100
)
canvas.fill(235, 230, 215)
canvas.ellipse(
mx,
my,
72,
72
)
// moon craters
canvas.fill(195, 190, 180)
canvas.ellipse(
mx - 15,
my + 12,
16,
12
)
canvas.ellipse(
mx + 15,
my - 15,
20,
15
)
canvas.ellipse(
mx + 5,
my + 20,
11,
10
)
// ==========================================================
// EARTH
// ==========================================================
canvas.fill(40, 100, 210, 180)
canvas.ellipse(
90,
cheight - 80,
30,
30
)
canvas.fill(60, 170, 100, 170)
canvas.ellipse(
95,
cheight - 75,
12,
7
)
// ==========================================================
// DISTANT MOUNTAINS
// ==========================================================
canvas.fill(80, 25, 25)
canvas.ellipse(
100,
145,
350,
130
)
canvas.ellipse(
390,
145,
430,
150
)
canvas.ellipse(
720,
145,
380,
140
)
// ==========================================================
// LANDER
// ==========================================================
drawVikramLander(
canvas,
landerX,
landerY
)
// ==========================================================
// MID MOUNTAINS
// ==========================================================
canvas.fill(125, 42, 29)
canvas.ellipse(
250,
145,
300,
110
)
canvas.ellipse(
570,
145,
350,
120
)
// ==========================================================
// MARS GROUND
// ==========================================================
canvas.fill(marsLight)
canvas.rect(
0,
0,
cwidth,
145
)
// ==========================================================
// FLAG
// ==========================================================
drawIndianFlag(
canvas,
205,
145
)
// ==========================================================
// CRATERS
// ==========================================================
canvas.fill(110, 35, 23)
canvas.ellipse(
70,
60,
100,
28
)
canvas.ellipse(
350,
45,
135,
32
)
canvas.ellipse(
650,
75,
120,
30
)
// ==========================================================
// TARGET ROCK
// ==========================================================
if (!rockCollected) {
canvas.fill(60, 20, 13)
canvas.ellipse(
rockX,
rockY,
40,
24
)
canvas.fill(100, 32, 18)
canvas.ellipse(
rockX - 5,
rockY + 3,
24,
12
)
// scanned glow
if (rockScanned) {
canvas.fill(
0,
255,
100,
70
)
canvas.ellipse(
rockX,
rockY,
55,
35
)
}
}
// ==========================================================
// FOOTPRINTS
// ==========================================================
canvas.fill(
90,
28,
20,
170
)
canvas.noStroke()
for (i <- 0 until maxFootprints) {
if (fpX(i) > 0) {
canvas.ellipse(
fpX(i),
fpY(i),
15,
7
)
}
}
// ==========================================================
// GROUND LINES
// ==========================================================
canvas.stroke(
195,
78,
48
)
canvas.strokeWeight(1)
for (i <- 0 until 8) {
canvas.line(
0,
15 + i * 16,
cwidth,
15 + i * 16
)
}
// ==========================================================
// DUST
// ==========================================================
canvas.noStroke()
for (i <- 0 until particleCount) {
val glow =
(
math.sin(
robotTime * 3 + i
) * 2 + 3
).toFloat
canvas.fill(
255,
150,
100,
130
)
canvas.ellipse(
particleX(i),
particleY(i),
glow,
glow
)
}
// ==========================================================
// METEOR
// ==========================================================
if (meteorActive) {
canvas.stroke(
255,
235,
170,
220
)
canvas.strokeWeight(3)
canvas.line(
meteorX,
meteorY,
meteorX + 45,
meteorY + 27
)
canvas.fill(
255,
255,
255
)
canvas.noStroke()
canvas.ellipse(
meteorX,
meteorY,
7,
7
)
}
}
// ============================================================
// FLASHLIGHT
// ============================================================
def drawFlashlight(
canvas: CanvasDraw
) {
if (flashlight) {
val hx =
robotX + robotFacing * 55
val hy =
robotY + robotBob + 185
canvas.fill(
150,
255,
180,
25
)
canvas.noStroke()
canvas.ellipse(
hx + robotFacing * 65,
hy - 30,
150,
80
)
canvas.stroke(
150,
255,
180,
120
)
canvas.strokeWeight(2)
canvas.line(
hx,
hy,
hx + robotFacing * 130,
hy - 35
)
}
}
// ============================================================
// LASER SCANNER
// ============================================================
def drawScanner(
canvas: CanvasDraw
) {
if (robotState == 1) {
val hx =
robotX + robotHeadTurn
val hy =
robotY +
robotBob +
198
val targetX =
rockX + scanAngle * 0.35
// outer beam
canvas.stroke(
0,
255,
100,
50
)
canvas.strokeWeight(8)
canvas.line(
hx,
hy,
targetX,
rockY
)
// laser
canvas.stroke(
0,
255,
120,
230
)
canvas.strokeWeight(2.5)
canvas.line(
hx,
hy,
targetX,
rockY
)
// scanner circle
canvas.fill(
0,
255,
120,
70
)
canvas.noStroke()
canvas.ellipse(
targetX,
rockY,
35,
35
)
canvas.fill(
255,
255,
255
)
canvas.ellipse(
targetX,
rockY,
7,
7
)
}
}
// ============================================================
// WELDING EFFECT
// ============================================================
def drawWelding(
canvas: CanvasDraw
) {
if (robotState == 3) {
val wx =
robotX +
robotFacing * 75
val wy =
robotY +
robotBob +
105
canvas.fill(
255,
210,
40,
80
)
canvas.noStroke()
canvas.ellipse(
wx,
wy,
35,
35
)
canvas.fill(
255,
255,
255
)
canvas.ellipse(
wx,
wy,
12,
12
)
// sparks
canvas.stroke(
255,
180,
40
)
canvas.strokeWeight(2)
for (i <- 0 until 8) {
val sx =
wx +
math.sin(
robotTime * 10 + i
) * 22
val sy =
wy +
math.cos(
robotTime * 11 + i
) * 22
canvas.line(
wx,
wy,
sx,
sy
)
}
}
}
// ============================================================
// ROBOT SHADOW
// ============================================================
def drawRobotShadow(
canvas: CanvasDraw
) {
canvas.fill(
30,
10,
10,
110
)
canvas.noStroke()
canvas.ellipse(
robotX,
145,
135,
22
)
}
// ============================================================
// ROBOT FOOT
// ============================================================
def drawRobotFoot(
canvas: CanvasDraw,
px: Double,
py: Double,
angle: Double
) {
canvas.pushMatrix()
canvas.translate(
px,
py
)
canvas.rotate(angle)
// glow
canvas.fill(
0,
255,
100,
35
)
canvas.noStroke()
canvas.ellipse(
0,
0,
64,
32
)
// foot
canvas.fill(
whiteRobot
)
canvas.stroke(
whiteShadow
)
canvas.strokeWeight(2)
canvas.ellipse(
0,
0,
60,
32
)
// green strip
canvas.fill(
greenMain
)
canvas.noStroke()
canvas.rect(
-25,
-5,
50,
8
)
// metallic side
canvas.fill(
215,
220,
225
)
canvas.ellipse(
18,
3,
24,
17
)
canvas.popMatrix()
}
// ============================================================
// ROBOT LEG
// ============================================================
def drawRobotLeg(
canvas: CanvasDraw,
px: Double,
py: Double,
angle: Double
) {
canvas.pushMatrix()
canvas.translate(
px,
py
)
canvas.rotate(angle)
// upper leg
canvas.fill(
whiteRobot
)
canvas.stroke(
whiteShadow
)
canvas.strokeWeight(2)
canvas.rect(
-13,
-45,
26,
48
)
// joint
canvas.fill(
greenMain
)
canvas.stroke(
greenGlow
)
canvas.strokeWeight(2)
canvas.ellipse(
0,
-48,
22,
22
)
// lower leg
canvas.fill(
whiteRobot
)
canvas.stroke(
whiteShadow
)
canvas.strokeWeight(2)
canvas.rect(
-15,
-92,
30,
45
)
// green armor
canvas.fill(
greenMain
)
canvas.noStroke()
canvas.rect(
-15,
-88,
7,
35
)
canvas.popMatrix()
}
// ============================================================
// ROBOT ARM
// ============================================================
def drawRobotArm(
canvas: CanvasDraw,
px: Double,
py: Double,
armAngle: Double,
flip: Boolean
) {
canvas.pushMatrix()
canvas.translate(
px,
py
)
if (flip)
canvas.scale(-1, 1)
canvas.rotate(
armAngle
)
// shoulder
canvas.fill(
greenMain
)
canvas.stroke(
greenGlow
)
canvas.strokeWeight(2)
canvas.ellipse(
0,
0,
30,
30
)
// upper arm
canvas.fill(
whiteRobot
)
canvas.stroke(
whiteShadow
)
canvas.strokeWeight(2)
canvas.rect(
-12,
-48,
24,
48
)
// elbow
canvas.fill(
greenMain
)
canvas.noStroke()
canvas.ellipse(
0,
-50,
19,
19
)
// forearm
canvas.fill(
whiteRobot
)
canvas.stroke(
whiteShadow
)
canvas.strokeWeight(2)
canvas.rect(
-11,
-92,
22,
42
)
// green panel
canvas.fill(
greenMain
)
canvas.noStroke()
canvas.rect(
-11,
-84,
6,
25
)
// hand
canvas.fill(
whiteRobot
)
canvas.stroke(
whiteShadow
)
canvas.strokeWeight(2)
canvas.ellipse(
0,
-101,
25,
22
)
canvas.fill(
greenMain
)
canvas.noStroke()
canvas.ellipse(
0,
-103,
13,
10
)
// sample
if (
robotState == 2 &&
flip
) {
canvas.fill(
220,
150,
30
)
canvas.ellipse(
0,
-113,
13,
13
)
}
canvas.popMatrix()
}
// ============================================================
// ROBOT BODY
// ============================================================
def drawRobotBody(
canvas: CanvasDraw
) {
val bx =
robotX
val by =
robotY + robotBob
// energy aura
canvas.fill(
0,
255,
100,
25
)
canvas.noStroke()
canvas.ellipse(
bx,
by + 65,
120,
140
)
// body shadow side
canvas.fill(
190,
200,
205
)
canvas.rect(
bx - 48,
by + 20,
96,
105
)
// main body
canvas.fill(
whiteRobot
)
canvas.stroke(
whiteShadow
)
canvas.strokeWeight(2.5)
canvas.rect(
bx - 48,
by + 20,
88,
105
)
// green armor
canvas.fill(
greenMain
)
canvas.noStroke()
canvas.rect(
bx - 48,
by + 28,
96,
13
)
// reactor outer
canvas.fill(
235,
240,
242
)
canvas.stroke(
180,
190,
195
)
canvas.strokeWeight(1.5)
canvas.ellipse(
bx,
by + 90,
40,
40
)
// reactor glow
val rg =
(
math.sin(robotGlow * 2) * 5 + 18
).toFloat
canvas.fill(
0,
255,
100,
60
)
canvas.noStroke()
canvas.ellipse(
bx,
by + 90,
40 + rg,
40 + rg
)
canvas.fill(
0,
220,
80
)
canvas.ellipse(
bx,
by + 90,
19,
19
)
canvas.fill(
220,
255,
230
)
canvas.ellipse(
bx - 4,
by + 94,
6,
6
)
// ISRO
canvas.fill(
20,
30,
30
)
canvas.text(
"ISRO",
bx - 18,
by + 115
)
// shoulder plate
canvas.fill(
greenMain
)
canvas.noStroke()
canvas.rect(
bx - 38,
by + 15,
76,
15
)
canvas.fill(
whiteRobot
)
canvas.stroke(
whiteShadow
)
canvas.strokeWeight(2)
canvas.ellipse(
bx,
by + 10,
35,
22
)
}
// ============================================================
// ROBOT HEAD
// ============================================================
def drawRobotHead(
canvas: CanvasDraw
) {
val hx =
robotX + robotHeadTurn
val hy =
robotY +
robotBob +
170
// antenna
canvas.stroke(
180,
190,
200
)
canvas.strokeWeight(2.5)
canvas.line(
hx,
hy + 60,
hx,
hy + 88
)
// beacon
val blink =
math.sin(
robotTime * 12
)
if (
blink > 0 ||
robotState != 0
) {
canvas.fill(
255,
40,
40,
100
)
canvas.noStroke()
canvas.ellipse(
hx,
hy + 88,
20,
20
)
canvas.fill(
255,
50,
50
)
canvas.ellipse(
hx,
hy + 88,
9,
9
)
} else {
canvas.fill(
40,
255,
120,
100
)
canvas.noStroke()
canvas.ellipse(
hx,
hy + 88,
20,
20
)
canvas.fill(
0,
255,
100
)
canvas.ellipse(
hx,
hy + 88,
9,
9
)
}
// head glow
canvas.fill(
0,
255,
120,
25
)
canvas.noStroke()
canvas.ellipse(
hx,
hy,
105,
80
)
// neck
canvas.fill(
greenDark
)
canvas.stroke(
greenMain
)
canvas.strokeWeight(2)
canvas.rect(
hx - 15,
hy - 43,
30,
25
)
// head
canvas.fill(
whiteRobot
)
canvas.stroke(
whiteShadow
)
canvas.strokeWeight(2.5)
canvas.rect(
hx - 45,
hy - 5,
90,
65
)
// screen
canvas.fill(
blackScreen
)
canvas.stroke(
20,
40,
50
)
canvas.strokeWeight(3)
canvas.rect(
hx - 35,
hy + 5,
70,
42
)
// side sensor
canvas.fill(
greenMain
)
canvas.stroke(
greenGlow
)
canvas.strokeWeight(2)
canvas.ellipse(
hx + 45,
hy + 28,
17,
30
)
// eyes
val eyeMove =
if (robotState == 1)
scanAngle * 0.12
else
math.sin(
robotTime * 2
) * 2
canvas.fill(
40,
180,
255
)
canvas.ellipse(
hx - 17,
hy + 28 + eyeMove,
7,
7
)
canvas.ellipse(
hx + 17,
hy + 28 + eyeMove,
7,
7
)
// face line
canvas.stroke(
40,
180,
255
)
canvas.strokeWeight(2)
canvas.line(
hx - 15,
hy + 15,
hx + 15,
hy + 15
)
for (i <- 0 until 5) {
canvas.line(
hx - 25 + i * 12,
hy + 48,
hx - 20 + i * 12,
hy + 48
)
}
}
// ============================================================
// ROBOT
// ============================================================
def drawRobot(
canvas: CanvasDraw
) {
val by =
robotY + robotBob
var leftArm =
robotArmWave
var rightArm =
-robotArmWave
if (robotState == 1) {
leftArm = -20
rightArm = 45
}
if (robotState == 2) {
leftArm = 30
rightArm =
75 + armBend
}
if (robotState == 3) {
leftArm = -10
rightArm =
65 + armBend
}
// arms
drawRobotArm(
canvas,
robotX - 48,
by + 105,
leftArm,
false
)
drawRobotArm(
canvas,
robotX + 48,
by + 105,
rightArm,
true
)
// legs
val leftLeg =
if (robotState == 0)
math.sin(robotWalk) * 15
else
0.0
val rightLeg =
if (robotState == 0)
-math.sin(robotWalk) * 15
else
0.0
drawRobotLeg(
canvas,
robotX - 23,
by + 10,
leftLeg
)
drawRobotLeg(
canvas,
robotX + 23,
by + 10,
rightLeg
)
// feet
drawRobotFoot(
canvas,
robotX -
30 +
math.sin(robotWalk) * 8,
150,
leftLeg
)
drawRobotFoot(
canvas,
robotX +
30 -
math.sin(robotWalk) * 8,
150,
rightLeg
)
// body
drawRobotBody(canvas)
// head
drawRobotHead(canvas)
}
// ============================================================
// HUD
// ============================================================
def drawHUD(
canvas: CanvasDraw
) {
// top mission panel
canvas.fill(
5,
12,
20,
210
)
canvas.stroke(
0,
255,
120,
160
)
canvas.strokeWeight(2)
canvas.rect(
15,
cheight - 115,
360,
90
)
canvas.fill(
255,
255,
255
)
canvas.text(
"?? ISRO MARS EXPLORER",
30,
cheight - 48
)
canvas.fill(
greenGlow
)
canvas.text(
"MISSION: " + missionText,
30,
cheight - 72
)
canvas.fill(
255,
220,
100
)
canvas.text(
"SCORE: " + score +
" SAMPLES: " + samples,
30,
cheight - 95
)
// ==========================================================
// ENERGY
// ==========================================================
canvas.fill(
30,
40,
45
)
canvas.stroke(
0,
255,
120
)
canvas.strokeWeight(2)
canvas.rect(
cwidth - 220,
cheight - 55,
180,
18
)
canvas.fill(
0,
230,
90
)
canvas.rect(
cwidth - 216,
cheight - 51,
1.72 * energy,
10
)
canvas.fill(
255,
255,
255
)
canvas.text(
"ENERGY " +
energy.toInt +
"%",
cwidth - 210,
cheight - 67
)
// ==========================================================
// HEALTH
// ==========================================================
canvas.fill(
30,
40,
45
)
canvas.stroke(
255,
70,
70
)
canvas.strokeWeight(2)
canvas.rect(
cwidth - 220,
cheight - 90,
180,
18
)
canvas.fill(
230,
50,
50
)
canvas.rect(
cwidth - 216,
cheight - 86,
1.72 * health,
10
)
canvas.fill(
255,
255,
255
)
canvas.text(
"HEALTH " +
health.toInt +
"%",
cwidth - 210,
cheight - 102
)
// ==========================================================
// CONTROLS
// ==========================================================
canvas.fill(
5,
10,
18,
190
)
canvas.stroke(
80,
180,
255,
130
)
canvas.strokeWeight(1.5)
canvas.rect(
15,
15,
270,
85
)
canvas.fill(
200,
230,
255
)
canvas.text(
"WASD / ARROWS : MOVE",
28,
32
)
canvas.text(
"SHIFT : TURBO",
28,
50
)
canvas.text(
"SPACE : SCAN",
28,
68
)
canvas.text(
"E : COLLECT R : WELD",
28,
86
)
canvas.text(
"F : LIGHT P : PAUSE",
300,
32
)
// ==========================================================
// PAUSE
// ==========================================================
if (paused) {
canvas.fill(
0,
0,
0,
180
)
canvas.noStroke()
canvas.rect(
0,
0,
cwidth,
cheight
)
canvas.fill(
255,
255,
255
)
canvas.text(
"MISSION PAUSED",
cwidth / 2 - 70,
cheight / 2
)
canvas.text(
"PRESS P TO RESUME",
cwidth / 2 - 80,
cheight / 2 - 30
)
}
}
// ============================================================
// MAIN DRAW
// ============================================================
def viewGame(
canvas: CanvasDraw
) {
canvas.fill(
0,
0,
0
)
canvas.noStroke()
canvas.rect(
0,
0,
cwidth,
cheight
)
drawBackground(canvas)
drawRobotShadow(canvas)
drawFlashlight(canvas)
drawScanner(canvas)
drawWelding(canvas)
drawRobot(canvas)
drawHUD(canvas)
// ==========================================================
// CENTER MESSAGE
// ==========================================================
if (messageTimer > 0) {
canvas.fill(
0,
0,
0,
170
)
canvas.noStroke()
canvas.rect(
cwidth / 2 - 220,
cheight - 145,
440,
35
)
canvas.fill(
greenGlow
)
canvas.text(
missionText,
cwidth / 2 - 190,
cheight - 122
)
}
}
// ============================================================
// START GAME
// ============================================================
activateCanvas()
animateWithCanvasDraw { canvas =>
updateRobot()
viewGame(canvas)
}