Code Sketch
yadnesh shahare
Category: Programming
// --- ISRO MISSION: REALISTIC 3D PERSPECTIVE SOLAR SYSTEM ---
cleari()
originBottomLeft()
// ==================== JANA GANA MANA TUNE SETUP ====================
setNoteInstrument(Instrument.PIANO)
val fullJanaGanaTune = Array(
(53, 200), (55, 200), (57, 200), (57, 200), (57, 200), (57, 200), (57, 200),
(57, 200), (57, 200), (55, 200), (57, 200), (58, 200),
(57, 200), (57, 200), (57, 200), (55, 200), (55, 200), (55, 200), (53, 200), (55, 200), (53, 300),
(55, 200), (57, 200), (55, 200), (53, 300),
(53, 200), (60, 200), (60, 200), (60, 200), (60, 200), (60, 200), (60, 200),
(60, 200), (58, 200), (60, 200), (58, 200), (57, 200), (55, 200), (57, 200), (58, 300),
(57, 200), (57, 200), (57, 200), (57, 200), (55, 200), (58, 200), (57, 200),
(55, 200), (55, 200), (53, 200), (55, 200), (53, 300),
(53, 200), (55, 200), (57, 200), (57, 200), (57, 200), (55, 200), (57, 200), (58, 300),
(57, 200), (55, 200), (57, 200), (53, 200), (55, 200), (53, 300),
(53, 200), (55, 200), (57, 200), (57, 200), (57, 200), (57, 200), (57, 200),
(55, 200), (57, 200), (58, 200), (57, 200), (55, 200), (53, 300),
(60, 250), (58, 250), (60, 300),
(58, 250), (57, 250), (58, 300),
(57, 250), (55, 250), (57, 300),
(53, 200), (53, 200), (55, 200), (55, 200), (57, 200), (57, 200), (58, 400)
)
var tuneIndex = 0
val fullAnthemText =
"Jana Gana Mana Adhinayaka Jaya He\n" +
"Bharata Bhagya Vidhata\n" +
"Punjaba Sindhu Gujarata Maratha\n" +
"Dravida Utkala Banga\n" +
"Vindhya Himachala Yamuna Ganga\n" +
"Uchhala Jaladhi Taranga\n" +
"Tava Subha Name Jage\n" +
"Tava Subha Asisa Mange\n" +
"Gahe Tava Jaya Gatha\n" +
"Jana Gana Mangala Dayaka Jaya He\n" +
"Bharata Bhagya Vidhata\n" +
"Jaya He, Jaya He, Jaya He\n" +
"Jaya Jaya Jaya Jaya He!"
var charIndex = 0
def playJanaGanaStep() {
if (tuneIndex < fullJanaGanaTune.length) {
val (note, duration) = fullJanaGanaTune(tuneIndex)
playNote(note, duration)
tuneIndex = (tuneIndex + 1) % fullJanaGanaTune.length
}
}
// ==================== STARS & ANIMATION VARS ====================
val starCount = 180
val starX = Array.fill(starCount)(randomDouble(0, cwidth))
val starY = Array.fill(starCount)(randomDouble(0, cheight))
val starSize = Array.fill(starCount)(randomDouble(1.0, 2.5))
var waveAngle = 0.0
var chakraRotation = 0.0
var neonGlowPhase = 0.0
var planetSelfRotationAngle = 0.0
def drawStars(canvas: CanvasDraw) {
canvas.stroke(255, 255, 255)
for (i <- 0 until starCount) {
canvas.strokeWeight(starSize(i))
if (randomDouble(1) > 0.05) {
canvas.point(starX(i), starY(i))
}
}
}
// ==================== ALL PLANETS 3D CONFIGURATION ====================
case class PlanetConfig(name: String, radiusX: Double, radiusY: Double, speed: Double, baseSize: Double, col: Color)
val planetConfigs = Array(
PlanetConfig("Mercury", 70.0, 22.0, 0.035, 7.0, cm.rgb(180, 180, 180)),
PlanetConfig("Venus", 105.0, 32.0, 0.028, 11.0, cm.rgb(230, 190, 110)),
PlanetConfig("Earth", 145.0, 44.0, 0.022, 13.0, cm.rgb(50, 180, 255)),
PlanetConfig("Moon", 160.0, 48.0, 0.020, 5.0, cm.rgb(200, 200, 200)),
PlanetConfig("Mars", 195.0, 58.0, 0.017, 10.0, cm.rgb(230, 80, 50)),
PlanetConfig("Jupiter", 245.0, 72.0, 0.012, 22.0, cm.rgb(230, 160, 100)),
PlanetConfig("Saturn", 295.0, 88.0, 0.009, 18.0, cm.rgb(210, 190, 120)),
PlanetConfig("Uranus", 340.0, 102.0, 0.006, 15.0, cm.rgb(120, 220, 230)),
PlanetConfig("Neptune", 380.0, 114.0, 0.004, 14.0, cm.rgb(60, 100, 240))
)
val planetList = Array("Sun", "Mercury", "Venus", "Earth", "Moon", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune")
val planetAngles = Array.fill(planetConfigs.length)(randomDouble(0, math.Pi * 2))
var selectedPlanet = "Mars"
// LAUNCH STATES
var isTimerRunning = false
var countdownTimer = 10.0
var isLaunched = false
var isLanded = false
var astronautOut = false
// BLAST STATE FOR SUN
var isBlasted = false
var blastTimer = 0.0
var targetX = (cwidth / 2.0) + 120.0
var targetY = (cheight / 2.0) + 20.0
var rocketX = 80.0
var rocketY = 60.0
var rocketAngle = 0.0
var launchProgress = 0.0
// MINI-GAME & RETURN LAUNCH STATES
var isMiniGameActive = false
var readyToReturnEarth = false
var isReturnTimerRunning = false
var returnCountdownTimer = 5.0
var isReturnLaunched = false
var isTeleportedToEarth = false
var startAnthemPhase = false
// ASTRONAUT MINI GAME PHYSICS
var miniPlayerX = (cwidth / 2.0) - 180.0
var miniPlayerY = (cheight / 2.0) - 60.0
var miniPlayerVy = 0.0
var isGrounded = true
var isKeyPotionCollected = false
var isDoorUnlocked = false
val tricolorPalette = Array(
cm.rgb(255, 153, 51),
cm.rgb(255, 255, 255),
cm.rgb(18, 136, 7)
)
// RESET GAME FUNCTION
def resetGame() {
isTimerRunning = false
countdownTimer = 10.0
isLaunched = false
isLanded = false
astronautOut = false
isBlasted = false
blastTimer = 0.0
targetX = (cwidth / 2.0) + 120.0
targetY = (cheight / 2.0) + 20.0
rocketX = 80.0
rocketY = 60.0
rocketAngle = 0.0
launchProgress = 0.0
isMiniGameActive = false
readyToReturnEarth = false
isReturnTimerRunning = false
returnCountdownTimer = 5.0
isReturnLaunched = false
isTeleportedToEarth = false
startAnthemPhase = false
miniPlayerX = (cwidth / 2.0) - 180.0
miniPlayerY = (cheight / 2.0) - 60.0
miniPlayerVy = 0.0
isGrounded = true
isKeyPotionCollected = false
isDoorUnlocked = false
selectedPlanet = "Mars"
}
// ==================== FIREWORKS SYSTEM ====================
class Particle(x0: Double, y0: Double, col: Color, seed: Boolean) {
var location = Vector2D(x0, y0)
private var velocity = if (seed) Vector2D(0, randomDouble(5, 11)) else randomExplosionVector
private var acceleration = Vector2D(0, 0)
var lifespan = 255.0
private var exploded = false
def randomExplosionVector: Vector2D = {
val rv1 = Vector2D(randomNormalDouble, randomNormalDouble)
val r1 = randomDouble(2, 4)
rv1 * r1
}
def applyForce(force: Vector2D) { acceleration += force }
def shouldExplode: Boolean = !exploded && lifespan <= 0
def isDead: Boolean = if (seed) exploded else lifespan <= 0
def explode() {
exploded = true
if (startAnthemPhase) {
playJanaGanaStep()
if (charIndex < fullAnthemText.length) {
charIndex = math.min(charIndex + 4, fullAnthemText.length)
}
}
}
def checkExplode() { if (seed && velocity.y < 0) lifespan = 0 }
def step() {
velocity += acceleration
location += velocity
if (!seed) {
lifespan -= 5
velocity *= 0.95
}
acceleration *= 0
checkExplode()
}
def view(canvas: CanvasDraw) {
canvas.stroke(col)
if (seed) canvas.strokeWeight(4) else canvas.strokeWeight(2)
canvas.point(location.x, location.y)
}
}
class Firework() {
private val fireworkColor = tricolorPalette(random(tricolorPalette.length))
private val firework = new Particle(randomDouble(cwidth), 0, fireworkColor, true)
private val particles = ArrayBuffer.empty[Particle]
def done: Boolean = firework.isDead && particles.isEmpty
def step() {
particles.filterInPlace(p => !p.isDead)
if (!firework.isDead) {
firework.applyForce(Vector2D(0, -0.08))
firework.step()
if (firework.shouldExplode) {
repeat(80) {
particles.append(new Particle(firework.location.x, firework.location.y, fireworkColor, false))
}
firework.explode()
}
}
repeatFor(particles) { p =>
p.applyForce(Vector2D(0, -0.08))
p.step()
}
}
def view(canvas: CanvasDraw) {
firework.view(canvas)
repeatFor(particles) { p => p.view(canvas) }
}
}
val fireworks = ArrayBuffer.empty[Firework]
// ==================== UPDATE LOGIC ====================
def updateState() {
fireworks.filterInPlace(f => !f.done)
if (startAnthemPhase) {
if (randomDouble(1) < 0.08) fireworks.append(new Firework())
}
repeatFor(fireworks) { f => f.step() }
waveAngle += 0.08
chakraRotation += 0.05
neonGlowPhase += 0.06
planetSelfRotationAngle += 0.035
val sunX = cwidth / 2.0 + 40.0
val sunY = cheight / 2.0 - 10.0
// UPDATE ORBITING ANGLES FOR ALL 3D PLANETS
for (i <- planetConfigs.indices) {
planetAngles(i) += planetConfigs(i).speed
if (planetAngles(i) > math.Pi * 2) planetAngles(i) -= math.Pi * 2
if (selectedPlanet == planetConfigs(i).name) {
targetX = sunX + math.cos(planetAngles(i)) * planetConfigs(i).radiusX
targetY = sunY + math.sin(planetAngles(i)) * planetConfigs(i).radiusY
}
}
if (selectedPlanet == "Sun") {
targetX = sunX
targetY = sunY
}
// LAUNCH TIMER
if (isTimerRunning && countdownTimer > 0) {
countdownTimer -= 0.04
if (countdownTimer <= 0) {
countdownTimer = 0.0
isTimerRunning = false
isLaunched = true
launchProgress = 0.0
}
}
// ROCKET LAUNCH
if (isLaunched && !isLanded && !isBlasted) {
launchProgress += 0.008
if (launchProgress >= 1.0) {
launchProgress = 1.0
if (selectedPlanet == "Sun") {
isBlasted = true
blastTimer = 100.0
} else {
isLanded = true
rocketAngle = 0.0
rocketX = targetX
rocketY = targetY + 15
astronautOut = true
isMiniGameActive = true
}
} else {
val startX = 80.0
val startY = 60.0
val controlX = cwidth / 2.0 + 80.0
val controlY = cheight / 2.0 + 180.0
val u = launchProgress
val tt = u * u
val uu = (1.0 - u) * (1.0 - u)
val nextX = uu * startX + 2 * (1.0 - u) * u * controlX + tt * targetX
val nextY = uu * startY + 2 * (1.0 - u) * u * controlY + tt * (targetY + 15)
val dx = nextX - rocketX
val dy = nextY - rocketY
rocketAngle = math.atan2(dy, dx) - (math.Pi / 2.0)
rocketX = nextX
rocketY = nextY
}
}
// BLAST TIMER AND AUTO-RESTART
if (isBlasted) {
blastTimer -= 1.0
if (blastTimer <= 0) {
resetGame()
}
}
// ASTRONAUT MINI GAME CONTROLS
if (isMiniGameActive && !readyToReturnEarth) {
val gx = cwidth / 2.0 - 220.0
val gy = cheight / 2.0 - 100.0
val speed = 3.5
if (isKeyPressed(Kc.VK_RIGHT) && miniPlayerX < gx + 415) miniPlayerX += speed
if (isKeyPressed(Kc.VK_LEFT) && miniPlayerX > gx + 15) miniPlayerX -= speed
if (isKeyPressed(Kc.VK_UP) && isGrounded) {
miniPlayerVy = 8.5
isGrounded = false
}
miniPlayerY += miniPlayerVy
if (!isGrounded) miniPlayerVy -= 0.45
val groundLevel = gy + 35.0
if (miniPlayerY <= groundLevel) {
miniPlayerY = groundLevel
miniPlayerVy = 0.0
isGrounded = true
} else if (miniPlayerX >= gx + 160 && miniPlayerX <= gx + 280 && miniPlayerY >= gy + 80 && miniPlayerY <= gy + 95 && miniPlayerVy <= 0) {
miniPlayerY = gy + 85.0
miniPlayerVy = 0.0
isGrounded = true
} else if (miniPlayerX >= gx + 320 && miniPlayerX <= gx + 420 && miniPlayerY >= gy + 130 && miniPlayerY <= gy + 145 && miniPlayerVy <= 0) {
miniPlayerY = gy + 135.0
miniPlayerVy = 0.0
isGrounded = true
} else {
if (miniPlayerY > groundLevel) isGrounded = false
}
if (!isKeyPotionCollected && math.abs(miniPlayerX - (gx + 380)) < 25 && math.abs(miniPlayerY - (gy + 150)) < 25) {
isKeyPotionCollected = true
isDoorUnlocked = true
}
if (isDoorUnlocked && math.abs(miniPlayerX - (gx + 40)) < 35 && math.abs(miniPlayerY - (gy + 45)) < 35) {
isMiniGameActive = false
readyToReturnEarth = true
}
}
// RETURN LAUNCH TIMER
if (isReturnTimerRunning && returnCountdownTimer > 0) {
returnCountdownTimer -= 0.04
if (returnCountdownTimer <= 0) {
returnCountdownTimer = 0.0
isReturnTimerRunning = false
isReturnLaunched = true
launchProgress = 0.0
}
}
// RETURN LAUNCH TRAJECTORY
if (isReturnLaunched && !isTeleportedToEarth) {
launchProgress += 0.008
if (launchProgress >= 1.0) {
launchProgress = 1.0
isTeleportedToEarth = true
startAnthemPhase = true
} else {
val startX = targetX
val startY = targetY + 15
val destX = 80.0
val destY = 60.0
val controlX = cwidth / 2.0 - 100.0
val controlY = cheight / 2.0 + 200.0
val u = launchProgress
val tt = u * u
val uu = (1.0 - u) * (1.0 - u)
val nextX = uu * startX + 2 * (1.0 - u) * u * controlX + tt * destX
val nextY = uu * startY + 2 * (1.0 - u) * u * controlY + tt * destY
val dx = nextX - rocketX
val dy = nextY - rocketY
rocketAngle = math.atan2(dy, dx) - (math.Pi / 2.0)
rocketX = nextX
rocketY = nextY
}
}
}
// MOUSE CLICK INPUT
onMouseClick { (x, y) =>
if (x >= 15 && x <= 125 && y >= 15 && y <= 55) {
if (!isTimerRunning && !isLaunched) {
isTimerRunning = true
countdownTimer = 10.0
}
}
else if (readyToReturnEarth && !isReturnLaunched && x >= cwidth / 2.0 - 100 && x <= cwidth / 2.0 + 100 && y >= cheight - 80 && y <= cheight - 30) {
if (!isReturnTimerRunning) {
isReturnTimerRunning = true
returnCountdownTimer = 5.0
}
}
else if (x <= 130 && y >= cheight - 340 && y <= cheight - 20 && !isLaunched) {
val index = ((cheight - 40 - y) / 28).toInt
if (index >= 0 && index < planetList.length) {
selectedPlanet = planetList(index)
}
}
}
// ==================== ? REALISTIC 3D PERSPECTIVE SOLAR SYSTEM ====================
def drawOrbitingSolarSystem(canvas: CanvasDraw) {
val sunX = cwidth / 2.0 + 40.0
val sunY = cheight / 2.0 - 10.0
// 1. DRAW 3D ORBIT LINES (PERSPECTIVE TILT)
for (i <- planetConfigs.indices) {
val p = planetConfigs(i)
canvas.stroke(0, 200, 255, 30)
canvas.strokeWeight(1.5)
canvas.noFill()
canvas.ellipse(sunX, sunY, p.radiusX * 2, p.radiusY * 2)
}
// 2. DRAW SUN WITH 3D GLOW & FLARES
val glowAlpha = (math.sin(neonGlowPhase * 2) * 40 + 200).toInt
canvas.fill(255, 100, 0, glowAlpha)
canvas.stroke(255, 230, 0)
canvas.strokeWeight(5)
canvas.ellipse(sunX, sunY, 65, 65)
canvas.fill(255, 255, 150)
canvas.noStroke()
canvas.ellipse(sunX - 8, sunY + 8, 20, 20) // 3D Specular Highlight
// 3. DRAW PLANETS WITH REALISTIC 3D DEPTH (BEHIND AND IN FRONT OF SUN)
for (i <- planetConfigs.indices) {
val p = planetConfigs(i)
val angle = planetAngles(i)
val px = sunX + math.cos(angle) * p.radiusX
val py = sunY + math.sin(angle) * p.radiusY
// Depth Scaling Effect: Sine values determine if the planet is in front or behind
val sinVal = math.sin(angle) // -1 (behind) to +1 (in front)
val depthScale = 0.75 + (sinVal + 1.0) * 0.25 // Scale between 0.75x and 1.25x
val dynamicSize = p.baseSize * depthScale
// Dynamic Shadow Shading
val alphaVal = (160 + sinVal * 95).toInt // Darker in back, brighter in front
if (selectedPlanet == p.name) {
canvas.stroke(0, 255, 200, alphaVal)
canvas.strokeWeight(2)
canvas.noFill()
canvas.ellipse(px, py, dynamicSize + 12, dynamicSize + 6)
}
// Planet Base Fill with Depth Lighting
canvas.fill(p.col)
canvas.stroke(255, 255, 255, alphaVal)
canvas.strokeWeight(1)
canvas.ellipse(px, py, dynamicSize * 1.1, dynamicSize)
// Dynamic Shadow (Spherical Light Effect)
canvas.fill(0, 0, 0, 100)
canvas.noStroke()
canvas.ellipse(px + (depthScale * 3), py - (depthScale * 3), dynamicSize * 0.8, dynamicSize * 0.8)
// Saturn 3D Rings
if (p.name == "Saturn") {
canvas.stroke(210, 190, 120, alphaVal)
canvas.strokeWeight(3)
canvas.noFill()
canvas.ellipse(px, py, dynamicSize * 2.4, dynamicSize * 0.7)
}
}
}
// ==================== ? FULL ROTATING 3D PLANET VIEW ====================
def drawDetailedRotatingPlanet(canvas: CanvasDraw) {
val px = cwidth - 120.0
val py = cheight - 120.0
val r = 50.0
// Planet View Frame
canvas.stroke(0, 255, 255, 120)
canvas.strokeWeight(2)
canvas.fill(5, 10, 20, 210)
canvas.rect(cwidth - 195, cheight - 195, 180, 180)
canvas.fill(0, 255, 255)
canvas.text(s"3D VIEW: $selectedPlanet", cwidth - 180, cheight - 25)
// Base Sphere
if (selectedPlanet == "Sun") {
canvas.fill(255, 120, 0)
canvas.stroke(255, 220, 0)
canvas.strokeWeight(4)
canvas.ellipse(px, py, r * 2, r * 2)
canvas.stroke(255, 200, 50, 180)
canvas.strokeWeight(2)
for (i <- -3 to 3) {
val yOff = i * 12
val xW = math.sqrt(math.max(0.0, r * r - yOff * yOff))
val waveX = math.sin(planetSelfRotationAngle + i) * 10.0
canvas.line(px - xW + waveX, py + yOff, px + xW + waveX, py + yOff)
}
} else {
var col = cm.rgb(180, 180, 180)
repeatFor(planetConfigs) { p => if (p.name == selectedPlanet) col = p.col }
canvas.fill(col)
canvas.stroke(255, 255, 255, 150)
canvas.strokeWeight(1.5)
canvas.ellipse(px, py, r * 2, r * 2)
canvas.stroke(0, 0, 0, 90)
canvas.strokeWeight(2)
for (i <- -4 to 4) {
val yOff = i * 10.0
if (math.abs(yOff) < r) {
val xW = math.sqrt(r * r - yOff * yOff)
val rotX = (math.sin(planetSelfRotationAngle + (i * 0.4)) * (xW * 0.8))
canvas.line(px - xW, py + yOff, px + xW, py + yOff)
canvas.fill(255, 255, 255, 110)
canvas.ellipse(px + rotX, py + yOff, 6, 4)
}
}
if (selectedPlanet == "Saturn") {
canvas.stroke(210, 190, 120, 200)
canvas.strokeWeight(4)
canvas.noFill()
canvas.ellipse(px, py, r * 2.8, r * 0.8)
} else if (selectedPlanet == "Uranus") {
canvas.stroke(120, 220, 230, 180)
canvas.strokeWeight(3)
canvas.noFill()
canvas.ellipse(px, py, r * 0.8, r * 2.6)
}
canvas.stroke(0, 0, 0, 120)
canvas.strokeWeight(6)
canvas.noFill()
canvas.ellipse(px + 10, py - 10, r * 1.8, r * 1.8)
}
}
def drawPlanetList(canvas: CanvasDraw) {
val glowWidth = (math.sin(neonGlowPhase) * 2 + 3).toFloat
canvas.stroke(0, 255, 255, 180)
canvas.strokeWeight(glowWidth)
canvas.fill(10, 15, 30, 230)
canvas.rect(10, cheight - 340, 120, 300)
canvas.fill(0, 255, 255)
canvas.text("SELECT TARGET", 15, cheight - 48)
var yPos = cheight - 70.0
repeatFor(planetList) { pName =>
if (pName == selectedPlanet) {
if (pName == "Sun") canvas.fill(255, 50, 0) else canvas.fill(18, 136, 7)
canvas.stroke(0, 255, 200)
canvas.strokeWeight(1)
canvas.rect(12, yPos - 12, 116, 22)
canvas.fill(255, 255, 255)
} else {
if (pName == "Sun") canvas.fill(255, 100, 100) else canvas.fill(180, 220, 255)
}
val label = if (pName == "Sun") "? Sun ?" else s"? $pName"
canvas.text(label, 18, yPos)
yPos -= 28.0
}
}
def drawFullEarthScreen(canvas: CanvasDraw) {
val cx = cwidth / 2.0
val cy = cheight / 2.0
canvas.fill(20, 100, 220)
canvas.stroke(0, 255, 255)
canvas.strokeWeight(4)
canvas.ellipse(cx, cy - 20, 360, 360)
canvas.fill(40, 160, 60)
canvas.ellipse(cx - 40, cy + 30, 120, 90)
canvas.ellipse(cx + 60, cy - 50, 140, 80)
}
def drawWavingTricolorFlag(canvas: CanvasDraw) {
val fw = 160.0
val fh = 28.0
val fx = (cwidth - fw) / 2.0 + 110.0
val fy = cheight / 2.0 - 10.0
canvas.stroke(200, 200, 200)
canvas.strokeWeight(5)
canvas.line(fx, fy + fh * 3 + 15, fx, fy - 160)
val stepSize = 4.0
var x = 0.0
while (x < fw) {
val yOffset = math.sin(waveAngle + (x * 0.03)) * 8.0
canvas.stroke(255, 153, 51)
canvas.strokeWeight(stepSize + 1)
canvas.line(fx + x, fy + fh * 2 + yOffset, fx + x, fy + fh * 3 + yOffset)
canvas.stroke(255, 255, 255)
canvas.line(fx + x, fy + fh + yOffset, fx + x, fy + fh * 2 + yOffset)
canvas.stroke(18, 136, 7)
canvas.line(fx + x, fy + yOffset, fx + x, fy + fh + yOffset)
x += stepSize
}
val chakraX = fx + fw / 2.0
val chakraY = fy + fh + (fh / 2.0) + (math.sin(waveAngle + ((fw / 2.0) * 0.03)) * 8.0)
val radius = 11.0
canvas.stroke(0, 0, 128)
canvas.strokeWeight(2)
canvas.noFill()
canvas.ellipse(chakraX, chakraY, radius * 2, radius * 2)
canvas.strokeWeight(1)
for (i <- 0 until 24) {
val angle = chakraRotation + (i * (2 * math.Pi / 24))
val xEnd = chakraX + math.cos(angle) * radius
val yEnd = chakraY + math.sin(angle) * radius
canvas.line(chakraX, chakraY, xEnd, yEnd)
}
}
def drawSingleSoldier(canvas: CanvasDraw, sx: Double, sy: Double) {
canvas.fill(45, 80, 45)
canvas.stroke(20, 50, 20)
canvas.strokeWeight(1)
canvas.rect(sx - 12, sy, 24, 38)
canvas.fill(240, 195, 150)
canvas.rect(sx - 4, sy + 38, 8, 6)
canvas.ellipse(sx, sy + 52, 18, 18)
canvas.fill(30, 60, 30)
canvas.ellipse(sx, sy + 57, 22, 14)
canvas.stroke(45, 80, 45)
canvas.strokeWeight(5)
canvas.line(sx - 12, sy + 34, sx - 18, sy + 10)
canvas.line(sx + 12, sy + 34, sx + 22, sy + 48)
canvas.line(sx + 22, sy + 48, sx + 8, sy + 57)
canvas.stroke(240, 195, 150)
canvas.strokeWeight(3)
canvas.line(sx + 8, sy + 57, sx + 4, sy + 58)
canvas.stroke(30, 50, 30)
canvas.strokeWeight(6)
canvas.line(sx - 6, sy, sx - 6, sy - 25)
canvas.line(sx + 6, sy, sx + 6, sy - 25)
}
def drawSalutingAstronaut(canvas: CanvasDraw, ax: Double, ay: Double) {
canvas.pushMatrix()
canvas.translate(ax, ay)
canvas.fill(240, 240, 245)
canvas.stroke(80, 80, 90)
canvas.strokeWeight(1)
canvas.rect(-12, -4, 24, 38)
canvas.fill(255, 153, 51); canvas.rect(-5, 14, 10, 3)
canvas.fill(18, 136, 7); canvas.rect(-5, 10, 10, 3)
canvas.fill(80, 80, 90)
canvas.rect(-9, -25, 7, 20); canvas.rect(2, -25, 7, 20)
canvas.stroke(200, 200, 210)
canvas.strokeWeight(5)
canvas.line(-12, 28, -18, 10)
canvas.line(12, 28, 22, 42)
canvas.line(22, 42, 8, 50)
canvas.fill(255, 255, 255)
canvas.stroke(100, 100, 120)
canvas.ellipse(0, 48, 22, 22)
canvas.fill(20, 140, 220)
canvas.noStroke()
canvas.ellipse(1, 48, 14, 12)
canvas.popMatrix()
}
def drawSoldiersSquad(canvas: CanvasDraw) {
val baseX = (cwidth / 2.0) + 40.0
val baseY = (cheight / 2.0) - 130.0
drawSingleSoldier(canvas, baseX, baseY)
drawSingleSoldier(canvas, baseX + 35, baseY)
drawSingleSoldier(canvas, baseX + 70, baseY)
drawSalutingAstronaut(canvas, baseX - 40, baseY)
}
def drawEarthAndLaunchUI(canvas: CanvasDraw) {
if (!isTeleportedToEarth) {
canvas.fill(30, 120, 220)
canvas.stroke(0, 255, 255)
canvas.strokeWeight(2)
canvas.ellipse(50, -20, 180, 180)
}
if (!isLaunched && !isTimerRunning) {
canvas.fill(255, 50, 0)
canvas.stroke(255, 200, 0)
canvas.strokeWeight((math.sin(neonGlowPhase * 3) * 2 + 3).toFloat)
canvas.rect(15, 15, 110, 40)
canvas.fill(255, 255, 255)
canvas.text("? LAUNCH", 25, 30)
}
if (readyToReturnEarth && !isReturnLaunched) {
canvas.fill(18, 136, 7)
canvas.stroke(0, 255, 150)
canvas.strokeWeight((math.sin(neonGlowPhase * 3) * 2 + 4).toFloat)
canvas.rect(cwidth / 2.0 - 100, cheight - 75, 200, 45)
canvas.fill(255, 255, 255)
canvas.text("? RETURN TO EARTH", cwidth / 2.0 - 75, cheight - 48)
}
if (isTimerRunning) {
val sec = countdownTimer.toInt
canvas.fill(255, 215, 0)
canvas.text(s"COUNTDOWN TO LAUNCH: $sec s", 135, 35)
} else if (isReturnTimerRunning) {
val sec = returnCountdownTimer.toInt
canvas.fill(255, 215, 0)
canvas.text(s"RETURN LAUNCH COUNTDOWN: $sec s", cwidth / 2.0 - 110, cheight - 90)
}
}
// EXPLOSION & ROCKET DRAWING
def drawISRORocket(canvas: CanvasDraw) {
val rx = rocketX
val ry = rocketY
if (isBlasted) {
canvas.fill(255, randomDouble(50, 200).toInt, 0)
canvas.stroke(255, 255, 255)
canvas.strokeWeight(3)
canvas.ellipse(rx, ry, randomDouble(70, 110), randomDouble(70, 110))
canvas.fill(255, 0, 0)
canvas.ellipse(rx + randomDouble(-20, 20), ry + randomDouble(-20, 20), 40, 40)
canvas.fill(255, 255, 255)
canvas.text("? ROCKET DESTROYED BY SUN HEAT! RESTARTING...", rx - 140, ry + 70)
} else {
canvas.pushMatrix()
canvas.translate(rx, ry)
canvas.rotate(rocketAngle)
if ((isLaunched && !isLanded) || (isReturnLaunched && !isTeleportedToEarth)) {
canvas.fill(0, 255, 255, 150)
canvas.noStroke()
canvas.ellipse(0, -30, randomDouble(20, 30), randomDouble(20, 30))
canvas.fill(255, 100, 0)
canvas.ellipse(0, -18, 14, 28)
canvas.fill(255, 255, 200)
canvas.ellipse(0, -14, 8, 16)
}
canvas.fill(240, 240, 240)
canvas.stroke(0, 255, 255)
canvas.strokeWeight(1.5)
canvas.rect(-15, 0, 30, 45)
if (isLanded && astronautOut) {
canvas.fill(20, 20, 30)
canvas.rect(-8, 5, 16, 25)
} else {
canvas.fill(180, 180, 190)
canvas.rect(-8, 5, 16, 25)
}
canvas.fill(255, 153, 51)
canvas.line(-15, 45, 0, 60)
canvas.line(15, 45, 0, 60)
canvas.fill(0, 51, 102)
canvas.text("ISRO", -12, 35)
canvas.popMatrix()
}
}
def drawAstronautPlayer(canvas: CanvasDraw, ax: Double, ay: Double) {
canvas.pushMatrix()
canvas.translate(ax, ay)
canvas.fill(240, 240, 245)
canvas.stroke(50, 50, 60)
canvas.strokeWeight(1)
canvas.rect(-8, -10, 16, 22)
canvas.fill(255, 153, 51); canvas.rect(-4, 2, 8, 2)
canvas.fill(18, 136, 7); canvas.rect(-4, -2, 8, 2)
canvas.fill(200, 200, 210)
canvas.rect(-7, -22, 5, 12)
canvas.rect(2, -22, 5, 12)
canvas.fill(255, 255, 255)
canvas.stroke(80, 80, 100)
canvas.ellipse(0, 18, 18, 18)
canvas.fill(0, 180, 240)
canvas.noStroke()
canvas.ellipse(1, 18, 12, 9)
canvas.popMatrix()
}
def drawTricolorMiniGame(canvas: CanvasDraw) {
if (isMiniGameActive) {
val gx = cwidth / 2.0 - 220.0
val gy = cheight / 2.0 - 100.0
canvas.fill(10, 10, 25, 240)
canvas.stroke(255, 0, 200)
canvas.strokeWeight((math.sin(neonGlowPhase * 2) * 2 + 3).toFloat)
canvas.rect(gx, gy, 440, 220)
canvas.fill(255, 255, 255)
canvas.text("? Arrow Keys: Move/Jump! Get Potion & Enter Earth Door!", gx + 10, gy + 200)
canvas.fill(255, 153, 51); canvas.rect(gx + 20, gy + 20, 400, 15)
canvas.fill(255, 255, 255); canvas.rect(gx + 160, gy + 75, 120, 10)
canvas.fill(18, 136, 7); canvas.rect(gx + 320, gy + 125, 100, 10)
if (!isKeyPotionCollected) {
canvas.fill(255, 50, 50)
canvas.stroke(255, 255, 0)
canvas.strokeWeight(2)
canvas.ellipse(gx + 380, gy + 150, 18, 18)
canvas.fill(255, 255, 255)
canvas.text("Potion", gx + 360, gy + 168)
}
if (isDoorUnlocked) {
canvas.fill(0, 200, 255, 200)
canvas.stroke(255, 255, 255)
canvas.strokeWeight(3)
canvas.ellipse(gx + 40, gy + 55, 30, 50)
canvas.fill(255, 255, 255)
canvas.text("EARTH DOOR", gx + 5, gy + 90)
}
drawAstronautPlayer(canvas, miniPlayerX, miniPlayerY)
}
}
def drawLetterByLetterAnthem(canvas: CanvasDraw) {
if (charIndex > 0) {
val visibleSubstring = fullAnthemText.substring(0, charIndex)
val lines = visibleSubstring.split("\n")
val startX = 20.0
var startY = cheight - 60.0
for (i <- lines.indices) {
canvas.fill(255, 255, 255)
canvas.text(lines(i), startX, startY)
startY -= 22.0
}
}
}
def viewState(canvas: CanvasDraw) {
canvas.fill(5, 5, 15, 55)
canvas.noStroke()
canvas.rect(0, 0, cwidth, cheight)
drawStars(canvas)
repeatFor(fireworks) { f => f.view(canvas) }
if (isTeleportedToEarth) {
drawFullEarthScreen(canvas)
drawWavingTricolorFlag(canvas)
drawSoldiersSquad(canvas)
drawLetterByLetterAnthem(canvas)
} else {
drawOrbitingSolarSystem(canvas)
drawPlanetList(canvas)
drawDetailedRotatingPlanet(canvas)
drawEarthAndLaunchUI(canvas)
drawISRORocket(canvas)
}
if (isMiniGameActive) {
drawTricolorMiniGame(canvas)
}
}
animateWithCanvasDraw { canvas =>
updateState()
viewState(canvas)
}