Code Sketch
SIDDHI SABALE
Category: Art
cleari()
originBottomLeft()
// ============================================================
// ISRO MARS EXPLORER GAME
// COMPLETE WORKING VERSION
// ============================================================
// ============================================================
// ROBOT POSITION / ANIMATION
// ============================================================
var robotX = 220.0 //> var robotX: Double = 220.0
var robotY = 145.0 //> var robotY: Double = 145.0
var robotWalk = 0.0 //> var robotWalk: Double = 0.0
var robotBob = 0.0 //> var robotBob: Double = 0.0
var robotGlow = 0.0 //> var robotGlow: Double = 0.0
var robotHeadTurn = 0.0 //> var robotHeadTurn: Double = 0.0
var robotArmWave = 0.0 //> var robotArmWave: Double = 0.0
var robotTime = 0.0 //> var robotTime: Double = 0.0
var robotFacing = 1.0 //> var robotFacing: Double = 1.0
// ============================================================
// GAME STATE
// 0 = WALK
// 1 = SCAN
// 2 = COLLECT
// 3 = WELD
// ============================================================
var robotState = 0 //> var robotState: Int = 0
var stateTimer = 0.0 //> var stateTimer: Double = 0.0
var scanAngle = 0.0 //> var scanAngle: Double = 0.0
var armBend = 0.0 //> var armBend: Double = 0.0
// ============================================================
// GAME VARIABLES
// ============================================================
var energy = 100 //> var energy: Int = 100
var samples = 0 //> var samples: Int = 0
var score = 0 //> var score: Int = 0
var missionComplete = false //> var missionComplete: Boolean = false
var gamePaused = false //> var gamePaused: Boolean = false
var weldProgress = 0.0 //> var weldProgress: Double = 0.0
// ============================================================
// KEYBOARD SPEED
// ============================================================
val moveSpeed = 2.8 //> val moveSpeed: Double = 2.8
// ============================================================
// METEOR
// ============================================================
var meteorX = cwidth + 50.0 //> var meteorX: Double = 825.0
var meteorY = cheight - 50.0 //> var meteorY: Double = 477.0
var meteorActive = false //> var meteorActive: Boolean = false
var meteorTimer = 0.0 //> var meteorTimer: Double = 0.0
// ============================================================
// FOOTPRINTS
// ============================================================
val maxFootprints = 16 //> val maxFootprints: Int = 16
val fpX =
Array.fill(maxFootprints)(-100.0) //> val fpX: Array[Double] = Array(-100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0)
val fpY =
Array.fill(maxFootprints)(140.0) //> val fpY: Array[Double] = Array(140.0, 140.0, 140.0, 140.0, 140.0, 140.0, 140.0, 140.0, 140.0, 140.0, 140.0, 140.0, 140.0, 140.0, 140.0, 140.0)
var fpIndex = 0 //> var fpIndex: Int = 0
var lastStepX = robotX //> var lastStepX: Double = 220.0
// ============================================================
// DUST PARTICLES
// ============================================================
val particleCount = 70 //> val particleCount: Int = 70
val particleX =
Array.fill(particleCount)(
randomDouble(0, cwidth)
) //> val particleX: Array[Double] = Array(633.0222040349222, 563.9013373845515, 132.56695372892983, 9.593878398617425, 73.33847570466203, 640.0859123675743, 56.77278082067481, 145.06253277405074, 704.5754059142043, 407.87416443543634, 138.0105136450392, 692.6899878231916, 464.58019251765063, 599.5101848063889, 62.470728037223104, 103.07445582192115, 364.96465882877, 573.4385607981977, 644.1169072635299, 20.382347027016046, 371.4385490727127, 135.64123211985313, 132.5517042956706, 253.73490182906795, 369.312651022744, 137.89850346838787, 749.1432218132743, 736.5385232193136, 749.2717591624647, 145.9547362223835, 693.6285225316487, 532.7425849370943, 79.74419510579159, 486.7550446448635, 375.49672488190544, 630.4291542207974, 168.88785145882233, 224.32539216130687, 729.5073732076905, 256.27890...
val particleY =
Array.fill(particleCount)(
randomDouble(145, cheight)
) //> val particleY: Array[Double] = Array(319.37214709701504, 236.76898889522164, 407.2518070359643, 159.2601606614719, 344.1626398855843, 290.4468086196124, 391.91659904188, 397.9843940064643, 513.0679525134594, 422.3153607487331, 268.1195175064586, 308.08190032404184, 214.89127724539847, 347.17682153509253, 159.27900400524325, 378.02649762197086, 238.4912823383441, 210.49193231613984, 397.95597224413814, 289.6710477648246, 450.33629290889377, 314.8377490175859, 317.36550354019687, 347.43123427045884, 482.8384966144226, 283.301012287448, 410.40048763003034, 326.92669313374233, 422.5253830640566, 462.8930923125327, 430.02802572386696, 322.0549311482906, 331.82217156376913, 179.33597524481124, 461.6049514879606, 222.45621193504365, 154.3733784503408, 475.770072196142, 394.7818083696882, 270.2...
val particleSpeed =
Array.fill(particleCount)(
randomDouble(0.15, 0.6)
) //> val particleSpeed: Array[Double] = Array(0.40520587267413877, 0.34349348026815496, 0.27947998349015846, 0.2610259096583358, 0.5320772198561498, 0.17333446581047302, 0.5096845676245629, 0.37060313430793035, 0.5114895059981269, 0.32115431500185787, 0.561891355726905, 0.3359884498883521, 0.458767346455196, 0.17837210224483965, 0.15577343139941038, 0.2936608065453644, 0.5748209054435249, 0.1995301158942573, 0.4362194575752104, 0.17449372043934755, 0.5285188890697406, 0.5357156861386225, 0.3768481789941092, 0.3791614076939395, 0.3986056118646021, 0.5528462984589374, 0.5442944509838047, 0.2598813168736669, 0.5517504475019707, 0.39301053432488814, 0.3061297818695923, 0.537998715528694, 0.5900078246869098, 0.21444978324043584, 0.1665008761797808, 0.5400933132257997, 0.15921722778023745, 0.28722...
// ============================================================
// COLORS
// ============================================================
val whiteRobot =
cm.rgb(245, 248, 250) //> val whiteRobot: net.kogics.kojo.doodle.Color = RGBA(UnsignedByte(117),UnsignedByte(120),UnsignedByte(122),Normalized(1.0))
val whiteShadow =
cm.rgb(190, 200, 205) //> val whiteShadow: net.kogics.kojo.doodle.Color = RGBA(UnsignedByte(62),UnsignedByte(72),UnsignedByte(77),Normalized(1.0))
val greenMain =
cm.rgb(0, 210, 80) //> val greenMain: net.kogics.kojo.doodle.Color = RGBA(UnsignedByte(-128),UnsignedByte(82),UnsignedByte(-48),Normalized(1.0))
val greenDark =
cm.rgb(0, 105, 45) //> val greenDark: net.kogics.kojo.doodle.Color = RGBA(UnsignedByte(-128),UnsignedByte(-23),UnsignedByte(-83),Normalized(1.0))
val greenGlow =
cm.rgb(40, 255, 120) //> val greenGlow: net.kogics.kojo.doodle.Color = RGBA(UnsignedByte(-88),UnsignedByte(127),UnsignedByte(-8),Normalized(1.0))
val blackScreen =
cm.rgb(5, 8, 18) //> val blackScreen: net.kogics.kojo.doodle.Color = RGBA(UnsignedByte(-123),UnsignedByte(-120),UnsignedByte(-110),Normalized(1.0))
// ============================================================
// TARGET ROCK
// ============================================================
var targetRockX = 520.0 //> var targetRockX: Double = 520.0
val targetRockY = 130.0 //> val targetRockY: Double = 130.0
// ============================================================
// KEYBOARD HELP
// ============================================================
onKeyPress { k =>
// ----------------------------------------------------------
// SPACE = SCAN
// ----------------------------------------------------------
if (k == Kc.VK_SPACE && !gamePaused) {
if (robotState == 0) {
robotState = 1
stateTimer = 0.0
scanAngle = 0.0
}
}
// ----------------------------------------------------------
// E = COLLECT
// ----------------------------------------------------------
if (k == Kc.VK_E && !gamePaused) {
if (robotState == 1 || robotState == 0) {
robotState = 2
stateTimer = 0.0
}
}
// ----------------------------------------------------------
// F = WELD
// ----------------------------------------------------------
if (k == Kc.VK_F && !gamePaused) {
robotState = 3
stateTimer = 0.0
}
// ----------------------------------------------------------
// NUMBER MODES
// ----------------------------------------------------------
if (k == Kc.VK_1) {
robotState = 0
stateTimer = 0.0
}
if (k == Kc.VK_2) {
robotState = 1
stateTimer = 0.0
}
if (k == Kc.VK_3) {
robotState = 2
stateTimer = 0.0
}
if (k == Kc.VK_4) {
robotState = 3
stateTimer = 0.0
}
// ----------------------------------------------------------
// P = PAUSE
// ----------------------------------------------------------
if (k == Kc.VK_P) {
gamePaused = !gamePaused
}
// ----------------------------------------------------------
// R = RESET
// ----------------------------------------------------------
if (k == Kc.VK_R) {
robotX = 220.0
robotY = 145.0
energy = 100
samples = 0
score = 0
weldProgress = 0.0
robotState = 0
stateTimer = 0.0
missionComplete = false
gamePaused = false
}
}
// ============================================================
// UPDATE ROBOT
// ============================================================
def updateRobot() {
if (gamePaused) {
return
}
robotTime += 0.018
robotGlow += 0.08
stateTimer += 0.018
// ----------------------------------------------------------
// KEYBOARD MOVEMENT
// ----------------------------------------------------------
var moving = false
if (
isKeyPressed(Kc.VK_LEFT) ||
isKeyPressed(Kc.VK_A)
) {
robotX -= moveSpeed
robotFacing = -1.0
moving = true
}
if (
isKeyPressed(Kc.VK_RIGHT) ||
isKeyPressed(Kc.VK_D)
) {
robotX += moveSpeed
robotFacing = 1.0
moving = true
}
if (
isKeyPressed(Kc.VK_UP) ||
isKeyPressed(Kc.VK_W)
) {
robotY += moveSpeed * 0.7
if (robotY > 190) {
robotY = 190
}
}
if (
isKeyPressed(Kc.VK_DOWN) ||
isKeyPressed(Kc.VK_S)
) {
robotY -= moveSpeed * 0.7
if (robotY < 145) {
robotY = 145
}
}
// ----------------------------------------------------------
// SCREEN BOUNDARY
// ----------------------------------------------------------
if (robotX < 80) {
robotX = 80
}
if (robotX > cwidth - 80) {
robotX = cwidth - 80
}
// ----------------------------------------------------------
// WALK ANIMATION
// ----------------------------------------------------------
if (moving && robotState == 0) {
robotWalk += 0.16
robotBob =
math.sin(robotWalk * 2.0) * 3.5
robotArmWave =
math.sin(robotWalk) * 22.0
// Footprints
if (
math.abs(robotX - lastStepX) > 22.0
) {
fpX(fpIndex) =
robotX - (15.0 * robotFacing)
fpY(fpIndex) =
142.0 + randomDouble(-2, 2)
fpIndex =
(fpIndex + 1) % maxFootprints
lastStepX = robotX
}
}
else {
robotBob =
math.sin(robotTime * 2.0) * 1.5
robotArmWave =
math.sin(robotTime) * 5.0
}
// ----------------------------------------------------------
// SCAN MODE
// ----------------------------------------------------------
if (robotState == 1) {
robotBob =
math.sin(robotTime * 3.0) * 1.5
scanAngle =
math.sin(robotTime * 4.0) * 30.0
robotHeadTurn =
-8.0 * robotFacing
robotArmWave = 5.0
if (stateTimer > 5.0) {
robotState = 0
stateTimer = 0.0
score += 10
}
}
// ----------------------------------------------------------
// COLLECT MODE
// ----------------------------------------------------------
if (robotState == 2) {
robotBob = -5.0
armBend =
math.sin(robotTime * 4.0) * 18.0
robotHeadTurn =
-12.0 * robotFacing
if (stateTimer > 3.5) {
samples += 1
score += 25
robotState = 0
stateTimer = 0.0
energy -= 5
if (energy < 0) {
energy = 0
}
}
}
// ----------------------------------------------------------
// WELD MODE
// ----------------------------------------------------------
if (robotState == 3) {
robotBob = -2.0
armBend =
math.sin(robotTime * 8.0) * 12.0
robotHeadTurn =
8.0 * robotFacing
weldProgress += 0.8
if (weldProgress > 100) {
weldProgress = 100
}
if (stateTimer > 5.0) {
score += 50
energy -= 8
if (energy < 0) {
energy = 0
}
robotState = 0
stateTimer = 0.0
weldProgress = 0.0
}
}
// ----------------------------------------------------------
// MISSION CHECK
// ----------------------------------------------------------
if (samples >= 3 && score >= 75) {
missionComplete = true
}
// ----------------------------------------------------------
// METEOR
// ----------------------------------------------------------
meteorTimer += 0.018
if (
!meteorActive &&
meteorTimer > 4.0
) {
meteorActive = true
meteorX =
randomDouble(
cwidth * 0.4,
cwidth + 50
)
meteorY =
randomDouble(
cheight - 80,
cheight + 20
)
meteorTimer = 0.0
}
if (meteorActive) {
meteorX -= 9.0
meteorY -= 5.5
if (
meteorY < 180 ||
meteorX < -50
) {
meteorActive = false
}
}
// ----------------------------------------------------------
// DUST
// ----------------------------------------------------------
for (i <- 0 until particleCount) {
particleY(i) += particleSpeed(i)
if (particleY(i) > cheight) {
particleY(i) = 145
particleX(i) =
randomDouble(0, cwidth)
}
}
} //> def updateRobot(): Unit
// ============================================================
// VIKRAM LANDER
// ============================================================
def drawVikramLander(
canvas: CanvasDraw,
lx: Double,
ly: Double
) {
canvas.stroke(180, 180, 190)
canvas.strokeWeight(3.0)
canvas.line(
lx - 25,
ly,
lx - 45,
ly - 22
)
canvas.line(
lx + 25,
ly,
lx + 45,
ly - 22
)
canvas.line(
lx - 12,
ly,
lx - 20,
ly - 22
)
canvas.line(
lx + 12,
ly,
lx + 20,
ly - 22
)
// Landing pads
canvas.fill(120, 120, 130)
canvas.noStroke()
canvas.ellipse(
lx - 45,
ly - 22,
12,
5
)
canvas.ellipse(
lx + 45,
ly - 22,
12,
5
)
// Body
canvas.fill(220, 165, 30)
canvas.stroke(180, 130, 20)
canvas.strokeWeight(1.5)
canvas.rect(
lx - 28,
ly,
56,
32
)
// Top
canvas.fill(190, 140, 20)
canvas.rect(
lx - 20,
ly + 32,
40,
14
)
// Solar panels
canvas.fill(20, 70, 160)
canvas.stroke(40, 100, 200)
canvas.strokeWeight(1)
canvas.rect(
lx - 48,
ly + 6,
18,
26
)
canvas.rect(
lx + 30,
ly + 6,
18,
26
)
// Antenna
canvas.fill(210, 215, 220)
canvas.noStroke()
canvas.ellipse(
lx,
ly + 52,
16,
10
)
canvas.stroke(200, 200, 210)
canvas.strokeWeight(2)
canvas.line(
lx,
ly + 46,
lx,
ly + 52
)
// Indian badge
canvas.fill(255, 153, 51)
canvas.noStroke()
canvas.rect(
lx - 10,
ly + 20,
20,
3
)
canvas.fill(255, 255, 255)
canvas.rect(
lx - 10,
ly + 17,
20,
3
)
canvas.fill(19, 136, 8)
canvas.rect(
lx - 10,
ly + 14,
20,
3
)
} //> def drawVikramLander(canvas: builtins.CanvasDraw, lx: Double, ly: Double): Unit
// ============================================================
// INDIAN FLAG
// ============================================================
def drawIndianFlag(
canvas: CanvasDraw,
fx: Double,
fy: Double
) {
canvas.stroke(210, 215, 220)
canvas.strokeWeight(3.5)
canvas.line(
fx,
fy,
fx,
fy + 80
)
canvas.fill(255, 215, 0)
canvas.noStroke()
canvas.ellipse(
fx,
fy + 81,
7,
7
)
val wave =
math.sin(robotTime * 4.0) * 3.0
// Saffron
canvas.fill(255, 153, 51)
canvas.rect(
fx,
fy + 58 + wave,
44,
11
)
// White
canvas.fill(255, 255, 255)
canvas.rect(
fx,
fy + 47 + wave,
44,
11
)
// Chakra
canvas.stroke(0, 0, 128)
canvas.strokeWeight(1.2)
canvas.ellipse(
fx + 22,
fy + 52.5 + wave,
7.5,
7.5
)
// Green
canvas.fill(19, 136, 8)
canvas.noStroke()
canvas.rect(
fx,
fy + 36 + wave,
44,
11
)
} //> def drawIndianFlag(canvas: builtins.CanvasDraw, fx: Double, fy: Double): Unit
// ============================================================
// BACKGROUND
// ============================================================
def drawRobotBackground(
canvas: CanvasDraw
) {
// Sky
canvas.fill(20, 5, 12)
canvas.noStroke()
canvas.rect(
0,
0,
cwidth,
cheight
)
canvas.fill(80, 25, 20)
canvas.rect(
0,
0,
cwidth,
180
)
// Stars
canvas.fill(255, 230, 220)
for (i <- 0 until 40) {
val sx =
(i * 37) % cwidth
val sy =
160 +
((i * 53) % (cheight - 160))
canvas.ellipse(
sx,
sy,
2,
2
)
}
// Meteor
if (meteorActive) {
canvas.stroke(
255,
240,
180,
220
)
canvas.strokeWeight(2.5)
canvas.line(
meteorX,
meteorY,
meteorX + 35,
meteorY + 22
)
canvas.fill(255, 255, 255)
canvas.noStroke()
canvas.ellipse(
meteorX,
meteorY,
4,
4
)
}
// Moon
val mx =
cwidth - 130
val my =
cheight - 100
canvas.fill(
255,
230,
200,
30
)
canvas.ellipse(
mx,
my,
110,
110
)
canvas.fill(
255,
240,
220,
60
)
canvas.ellipse(
mx,
my,
85,
85
)
canvas.fill(240, 235, 220)
canvas.ellipse(
mx,
my,
65,
65
)
// Moon craters
canvas.fill(200, 195, 180)
canvas.ellipse(
mx - 10,
my + 8,
14,
12
)
canvas.ellipse(
mx + 12,
my - 10,
18,
15
)
canvas.ellipse(
mx + 5,
my + 15,
10,
10
)
// Earth
canvas.fill(
70,
130,
200,
180
)
canvas.ellipse(
100,
cheight - 70,
20,
20
)
// Mountains
canvas.fill(90, 30, 25)
canvas.ellipse(
100,
145,
320,
120
)
canvas.ellipse(
350,
145,
450,
160
)
canvas.ellipse(
650,
145,
380,
140
)
// Lander
drawVikramLander(
canvas,
130,
155
)
// Mid mountains
canvas.fill(130, 45, 30)
canvas.ellipse(
220,
145,
280,
100
)
canvas.ellipse(
550,
145,
320,
110
)
// Mars ground
canvas.fill(160, 55, 35)
canvas.rect(
0,
0,
cwidth,
145
)
// Flag
drawIndianFlag(
canvas,
210,
145
)
// Craters
canvas.fill(120, 40, 25)
canvas.ellipse(
80,
60,
90,
25
)
canvas.ellipse(
340,
40,
130,
30
)
canvas.ellipse(
620,
80,
110,
28
)
// Target rock
canvas.fill(80, 25, 15)
canvas.ellipse(
targetRockX,
targetRockY,
32,
18
)
canvas.fill(110, 35, 20)
canvas.ellipse(
targetRockX - 3,
targetRockY + 2,
18,
10
)
// Target marker
if (robotState == 1) {
canvas.stroke(
0,
255,
120
)
canvas.strokeWeight(2)
canvas.noFill()
canvas.ellipse(
targetRockX,
targetRockY,
45,
28
)
}
// Footprints
canvas.fill(
100,
30,
20,
160
)
canvas.noStroke()
for (i <- 0 until maxFootprints) {
if (fpX(i) > 0) {
canvas.ellipse(
fpX(i),
fpY(i),
14,
6
)
}
}
// Ground lines
canvas.stroke(
180,
70,
45
)
canvas.strokeWeight(1.0)
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,
140,
90,
160
)
canvas.ellipse(
particleX(i),
particleY(i),
glow,
glow
)
}
} //> def drawRobotBackground(canvas: builtins.CanvasDraw): Unit
// ============================================================
// ROBOT SHADOW
// ============================================================
def drawRobotShadow(
canvas: CanvasDraw
) {
canvas.fill(
30,
10,
10,
120
)
canvas.noStroke()
canvas.ellipse(
robotX,
145,
125,
22
)
} //> def drawRobotShadow(canvas: builtins.CanvasDraw): Unit
// ============================================================
// ROBOT FOOT
// ============================================================
def drawRobotFoot(
canvas: CanvasDraw,
px: Double,
py: Double,
angle: Double
) {
canvas.pushMatrix()
canvas.translate(
px,
py
)
canvas.rotate(angle)
canvas.fill(
0,
255,
100,
35
)
canvas.noStroke()
canvas.ellipse(
0,
0,
58,
28
)
canvas.fill(whiteRobot)
canvas.stroke(whiteShadow)
canvas.strokeWeight(2.0)
canvas.ellipse(
0,
0,
60,
32
)
canvas.fill(greenMain)
canvas.noStroke()
canvas.rect(
-25,
-5,
50,
8
)
canvas.fill(
220,
225,
230
)
canvas.ellipse(
18,
3,
25,
18
)
canvas.popMatrix()
} //> def drawRobotFoot(canvas: builtins.CanvasDraw, px: Double, py: Double, angle: Double): Unit
// ============================================================
// ROBOT LEG
// ============================================================
def drawRobotLeg(
canvas: CanvasDraw,
px: Double,
py: Double,
legAngle: Double
) {
canvas.pushMatrix()
canvas.translate(
px,
py
)
canvas.rotate(
legAngle
)
canvas.fill(whiteRobot)
canvas.stroke(whiteShadow)
canvas.strokeWeight(2.0)
canvas.rect(
-13,
-45,
26,
48
)
canvas.fill(greenMain)
canvas.stroke(greenGlow)
canvas.strokeWeight(1.5)
canvas.ellipse(
0,
-48,
22,
22
)
canvas.fill(whiteRobot)
canvas.stroke(whiteShadow)
canvas.strokeWeight(2.0)
canvas.rect(
-15,
-92,
30,
45
)
canvas.fill(greenMain)
canvas.noStroke()
canvas.rect(
-15,
-88,
7,
35
)
canvas.popMatrix()
} //> def drawRobotLeg(canvas: builtins.CanvasDraw, px: Double, py: Double, legAngle: Double): Unit
// ============================================================
// 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
)
// Joint
canvas.fill(greenMain)
canvas.noStroke()
canvas.ellipse(
0,
-50,
19,
19
)
// Lower arm
canvas.fill(whiteRobot)
canvas.stroke(whiteShadow)
canvas.strokeWeight(2)
canvas.rect(
-11,
-92,
22,
42
)
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 container
if (
robotState == 2 &&
flip
) {
canvas.fill(
220,
150,
30
)
canvas.ellipse(
0,
-110,
10,
10
)
}
// Welding sparks
if (
robotState == 3 &&
flip
) {
canvas.fill(
255,
220,
40
)
canvas.ellipse(
8,
-108,
5,
5
)
canvas.fill(
255,
120,
20
)
canvas.ellipse(
-7,
-112,
4,
4
)
canvas.ellipse(
6,
-118,
3,
3
)
}
canvas.popMatrix()
} //> def drawRobotArm(canvas: builtins.CanvasDraw, px: Double, py: Double, armAngle: Double, flip: Boolean): Unit
// ============================================================
// ROBOT BODY
// ============================================================
def drawRobotBody(
canvas: CanvasDraw
) {
val bx = robotX
val by =
robotY + robotBob
// Glow
canvas.fill(
0,
255,
100,
25
)
canvas.noStroke()
canvas.ellipse(
bx,
by + 65,
105,
125
)
// Body
canvas.fill(whiteRobot)
canvas.stroke(whiteShadow)
canvas.strokeWeight(2.5)
canvas.rect(
bx - 48,
by + 20,
96,
105
)
// Green stripe
canvas.fill(greenMain)
canvas.noStroke()
canvas.rect(
bx - 48,
by + 28,
96,
13
)
// Reactor
canvas.fill(
235,
240,
242
)
canvas.stroke(
180,
190,
195
)
canvas.strokeWeight(1.5)
canvas.ellipse(
bx,
by + 90,
38,
38
)
val reactorGlow =
(
math.sin(robotGlow * 2) * 5 + 18
).toFloat
canvas.fill(
0,
255,
100,
60
)
canvas.noStroke()
canvas.ellipse(
bx,
by + 90,
38 + reactorGlow,
38 + reactorGlow
)
canvas.fill(
0,
220,
80
)
canvas.ellipse(
bx,
by + 90,
18,
18
)
// ISRO
canvas.fill(
20,
30,
30
)
canvas.text(
"ISRO",
bx - 18,
by + 115
)
// Chest stripe
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
)
} //> def drawRobotBody(canvas: builtins.CanvasDraw): Unit
// ============================================================
// 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
if (
math.sin(robotTime * 12.0) > 0 ||
robotState != 0
) {
canvas.fill(
255,
40,
40,
100
)
canvas.noStroke()
canvas.ellipse(
hx,
hy + 88,
18,
18
)
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,
18,
18
)
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,
100,
75
)
// 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 LED
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.2
}
else {
math.sin(robotTime * 2) * 2.0
}
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
)
} //> def drawRobotHead(canvas: builtins.CanvasDraw): Unit
// ============================================================
// LASER SCANNER
// ============================================================
def drawLaserScan(
canvas: CanvasDraw
) {
if (robotState == 1) {
val hx =
robotX + robotHeadTurn
val hy =
robotY +
robotBob +
198
val targetX =
targetRockX + scanAngle
// Beam
canvas.stroke(
0,
255,
100,
200
)
canvas.strokeWeight(3.0)
canvas.line(
hx,
hy,
targetX,
targetRockY
)
// Glow
canvas.fill(
0,
255,
120,
40
)
canvas.noStroke()
canvas.ellipse(
targetX,
targetRockY,
35,
12
)
// Dot
canvas.fill(
255,
255,
255
)
canvas.ellipse(
targetX,
targetRockY,
6,
6
)
}
} //> def drawLaserScan(canvas: builtins.CanvasDraw): Unit
// ============================================================
// WELDING EFFECT
// ============================================================
def drawWelding(
canvas: CanvasDraw
) {
if (robotState == 3) {
val wx =
robotX +
(55.0 * robotFacing)
val wy =
robotY + 135
canvas.stroke(
255,
180,
30,
180
)
canvas.strokeWeight(2)
canvas.line(
wx,
wy,
wx + 25,
wy - 10
)
canvas.line(
wx,
wy,
wx - 20,
wy - 15
)
canvas.fill(
255,
230,
60
)
canvas.noStroke()
canvas.ellipse(
wx,
wy,
14,
14
)
}
} //> def drawWelding(canvas: builtins.CanvasDraw): Unit
// ============================================================
// ROBOT DRAW
// ============================================================
def drawFuturisticRobot(
canvas: CanvasDraw
) {
val by =
robotY + robotBob
var rightArmAngle =
-robotArmWave
var leftArmAngle =
robotArmWave
if (robotState == 1) {
rightArmAngle = 45.0
leftArmAngle = -20.0
}
if (robotState == 2) {
rightArmAngle =
75.0 + armBend
leftArmAngle = 30.0
}
if (robotState == 3) {
rightArmAngle =
60.0 + armBend
leftArmAngle = -10.0
}
drawRobotArm(
canvas,
robotX - 48,
by + 105,
leftArmAngle,
false
)
drawRobotArm(
canvas,
robotX + 48,
by + 105,
rightArmAngle,
true
)
val leftLegAngle =
if (robotState == 0) {
math.sin(robotWalk) * 15.0
}
else {
0.0
}
val rightLegAngle =
if (robotState == 0) {
-math.sin(robotWalk) * 15.0
}
else {
0.0
}
drawRobotLeg(
canvas,
robotX - 23,
by + 10,
leftLegAngle
)
drawRobotLeg(
canvas,
robotX + 23,
by + 10,
rightLegAngle
)
drawRobotFoot(
canvas,
robotX - 30 +
math.sin(robotWalk) * 8,
150,
leftLegAngle
)
drawRobotFoot(
canvas,
robotX + 30 -
math.sin(robotWalk) * 8,
150,
rightLegAngle
)
drawRobotBody(canvas)
drawRobotHead(canvas)
drawLaserScan(canvas)
drawWelding(canvas)
} //> def drawFuturisticRobot(canvas: builtins.CanvasDraw): Unit
// ============================================================
// HUD
// ============================================================
def drawRobotHUD(
canvas: CanvasDraw
) {
// Title
canvas.fill(
255,
220,
200
)
canvas.text(
"ISRO MARS EXPLORER",
25,
cheight - 30
)
// Status
canvas.fill(
0,
255,
120
)
if (robotState == 0) {
canvas.text(
"WALKING / EXPLORING",
25,
cheight - 55
)
}
if (robotState == 1) {
canvas.fill(
255,
220,
0
)
canvas.text(
"SCANNING ROCK...",
25,
cheight - 55
)
}
if (robotState == 2) {
canvas.fill(
0,
220,
255
)
canvas.text(
"COLLECTING MARS SAMPLE...",
25,
cheight - 55
)
}
if (robotState == 3) {
canvas.fill(
255,
150,
20
)
canvas.text(
"WELDING / REPAIRING...",
25,
cheight - 55
)
}
// Energy bar
canvas.fill(
30,
40,
45
)
canvas.stroke(
0,
255,
120
)
canvas.strokeWeight(2)
canvas.rect(
cwidth - 190,
cheight - 65,
150,
18
)
canvas.fill(
0,
230,
90
)
canvas.rect(
cwidth - 186,
cheight - 61,
energy * 1.35,
10
)
canvas.fill(
255,
255,
255
)
// IMPORTANT:
// energy is already Int.
// NO energy.toInt()
canvas.text(
"ENERGY " + energy + "%",
cwidth - 180,
cheight - 72
)
// Samples
canvas.fill(
255,
220,
80
)
canvas.text(
"SAMPLES: " + samples,
cwidth - 180,
cheight - 100
)
// Score
canvas.fill(
100,
220,
255
)
canvas.text(
"SCORE: " + score,
cwidth - 180,
cheight - 125
)
// Controls
canvas.fill(
230,
230,
230
)
canvas.text(
"A/D or <- -> MOVE",
20,
35
)
canvas.text(
"SPACE SCAN | E COLLECT | F WELD",
20,
52
)
canvas.text(
"1 WALK | 2 SCAN | 3 COLLECT | 4 WELD | P PAUSE | R RESET",
20,
69
)
// Pause
if (gamePaused) {
canvas.fill(
255,
255,
255
)
canvas.text(
"=== GAME PAUSED ===",
cwidth / 2 - 70,
cheight / 2
)
}
// Mission complete
if (missionComplete) {
canvas.fill(
0,
255,
120
)
canvas.text(
"MISSION COMPLETE!",
cwidth / 2 - 70,
cheight / 2 + 50
)
canvas.fill(
255,
255,
255
)
canvas.text(
"MARS SAMPLES COLLECTED",
cwidth / 2 - 80,
cheight / 2 + 30
)
}
} //> def drawRobotHUD(canvas: builtins.CanvasDraw): Unit
// ============================================================
// MAIN VIEW
// ============================================================
def viewRobot(
canvas: CanvasDraw
) {
canvas.fill(
0,
0,
0
)
canvas.noStroke()
canvas.rect(
0,
0,
cwidth,
cheight
)
drawRobotBackground(canvas)
drawRobotShadow(canvas)
drawFuturisticRobot(canvas)
drawRobotHUD(canvas)
} //> def viewRobot(canvas: builtins.CanvasDraw): Unit
// ============================================================
// START GAME
// ============================================================
activateCanvas()
animateWithCanvasDraw { canvas =>
updateRobot()
viewRobot(canvas)
}