Code Sketch
YADNESH
Category: Art
// --- ISRO ULTIMATE 3D ANIMATED MISSION: SHARP ROCKET & 3D PLANETS ---
cleari()
originBottomLeft()
// ==================== FULL 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
var anthemFinished = false
var finalCreditsTimer = 0.0
val patrioticInfoText =
"?? BHARAT MATA KI JAI! ??\n" +
"Jana Gana Mana Adhinayaka Jaya He...\n" +
"Bharata Bhagya Vidhata!"
var charIndex = 0
def playJanaGanaStep() {
if (tuneIndex < fullJanaGanaTune.length) {
val (note, duration) = fullJanaGanaTune(tuneIndex)
playNote(note, duration)
tuneIndex += 1
if (tuneIndex >= fullJanaGanaTune.length) {
anthemFinished = true
}
}
}
// ==================== PLANET DETAILS & 3D COLORS ====================
case class PlanetDetail(name: String, surfaceCol: Color, darkSurfCol: Color, accent3D: Color, infoLine1: String, dayNightStatus: String, gravityVal: String, alienHumanStatus: String, atmosphere: String, coreTemp: String, funFact: String, quizQuestion: String, quizOptions: Array[String], correctOpt: Int)
val planetDetailsMap = Array(
PlanetDetail("Sun", cm.rgb(255, 140, 0), cm.rgb(120, 60, 0), cm.rgb(255, 220, 100), "Solar Plasma Surface", "Day: Perpetual Bright", "274.0 m/s� (27.9g)", "Aliens: No | Humans: No", "Hydrogen & Helium", "15 Million �C", "Generates energy via nuclear fusion.", "What is the core temperature of Sun?", Array("A) 1 million �C", "B) 15 million �C", "C) 100,000 �C"), 1),
PlanetDetail("Mercury", cm.rgb(120, 120, 120), cm.rgb(60, 60, 60), cm.rgb(200, 200, 200), "Rocky Cratered Surface", "Day/Night: 58 Earth Days", "3.7 m/s� (0.38g)", "Aliens: No | Humans: No", "Minimal (Oxygen, Sodium)", "430�C / -180�C", "Closest planet to the Sun.", "Does Mercury have any moons?", Array("A) Yes (2 moons)", "B) No moons", "C) Yes (1 moon)"), 1),
PlanetDetail("Venus", cm.rgb(210, 150, 80), cm.rgb(100, 70, 30), cm.rgb(255, 200, 130), "Volcanic Sulfuric Plains", "Day/Night: 243 Earth Days", "8.87 m/s� (0.90g)", "Aliens: No | Humans: No", "Carbon Dioxide", "462�C (Hottest)", "Hottest planet in solar system.", "Which gas makes Venus extremely hot?", Array("A) Oxygen", "B) Carbon Dioxide", "C) Nitrogen"), 1),
PlanetDetail("Earth", cm.rgb(40, 130, 240), cm.rgb(20, 60, 120), cm.rgb(100, 200, 255), "Blue Terrestrial Crust", "Day & Night (24 Hours)", "9.8 m/s� (1.0g)", "Aliens: Unproven | Humans: Yes", "Nitrogen, Oxygen", "5,500�C", "Only planet supporting life.", "What percentage of Earth's surface is water?", Array("A) 50%", "B) 71%", "C) 90%"), 1),
PlanetDetail("Mars", cm.rgb(200, 70, 40), cm.rgb(100, 30, 15), cm.rgb(255, 130, 100), "Red Dusty Iron Oxide Desert", "Day/Night: 24h 39m (Sol)", "3.72 m/s� (0.38g)", "Aliens: Microbial (Suspected)", "Carbon Dioxide", "-60�C Average", "Home to Olympus Mons volcano.", "Why does Mars appear red?", Array("A) Iron Oxide (Rust)", "B) Red Sandstorms", "C) Lava oceans"), 0),
PlanetDetail("Jupiter", cm.rgb(210, 140, 90), cm.rgb(100, 60, 40), cm.rgb(255, 190, 140), "Gaseous Stormy Surface", "Day/Night: 10 Hours", "24.79 m/s� (2.53g)", "Aliens: No | Humans: No", "Hydrogen & Helium", "24,000�C", "Largest planet with Great Red Spot.", "What is Jupiter's Great Red Spot?", Array("A) A giant volcano", "B) A massive storm", "C) A crater"), 1),
PlanetDetail("Saturn", cm.rgb(190, 170, 110), cm.rgb(90, 80, 50), cm.rgb(240, 230, 160), "Icy Ringed Gas Plains", "Day/Night: 10.7 Hours", "10.44 m/s� (1.07g)", "Aliens: No | Humans: No", "Hydrogen & Helium", "11,700�C", "Famous for complex ring system.", "What are Saturn's rings primarily made of?", Array("A) Solid rock slabs", "B) Ice and dust particles", "C) Burning gas"), 1),
PlanetDetail("Uranus", cm.rgb(100, 200, 220), cm.rgb(40, 90, 100), cm.rgb(180, 240, 255), "Cold Methane Ice Crust", "Day/Night: Extreme Tilt", "8.69 m/s� (0.89g)", "Aliens: No | Humans: No", "Hydrogen, Helium, Methane", "-197�C", "Rotates completely on its side.", "How does Uranus rotate on its axis?", Array("A) Normally", "B) Completely on its side", "C) Backwards"), 1),
PlanetDetail("Neptune", cm.rgb(50, 90, 220), cm.rgb(20, 40, 100), cm.rgb(130, 170, 255), "Supersonic Stormy Ice Crust", "Day/Night: 16 Hours", "11.15 m/s� (1.14g)", "Aliens: No | Humans: No", "Hydrogen, Helium, Methane", "-201�C", "Windiest planet with supersonic winds.", "What gives Neptune its blue appearance?", Array("A) Deep oceans", "B) Methane in atmosphere", "C) Blue rocks"), 1),
PlanetDetail("Maha-Prithvi", cm.rgb(30, 190, 130), cm.rgb(15, 90, 60), cm.rgb(120, 255, 190), "Super-Earth Habitable Crust", "Day/Night: ~290 Days Orbit", "14.2 m/s� (1.45g)", "Aliens: Unknown | Humans: Future", "Oxygen rich", "Unknown", "A promising exoplanet candidate.", "Is Maha-Prithvi a real discovery?", Array("A) Yes (Kepler-22b)", "B) No, purely fictional", "C) Mars moon"), 0)
)
// ==================== STARS & SOLAR SYSTEM SETUP ====================
val starCount = 300
val starX = Array.fill(starCount)(randomDouble(0, cwidth))
val starY = Array.fill(starCount)(randomDouble(0, cheight))
val starSize = Array.fill(starCount)(randomDouble(1.0, 3.5))
var waveAngle = 0.0
var chakraRotation = 0.0
var neonGlowPhase = 0.0
var globalTime = 0.0
val planetList = Array("Sun", "Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune", "Maha-Prithvi")
var selectedPlanet = "Mars"
var earthNotificationTimer = 0.0
// GAME & MISSION STATES
var isTimerRunning = false
var countdownTimer = 10.0
var isLaunched = false
var isLanded = false
// TOP SURFACE LANDING & INFO STATES
var rocketSurfaceY = 160.0
var doorOpeningProgress = 0.0
var astronautOut = false
var infoPanelShown = false
var infoPageNumber = 1
// QUIZ STATES
var quizActive = false
var quizFeedback = ""
// MINI GAME STATES
var activeMiniGameType = 0
var isMiniGameActive = false
var readyToReturnEarth = false
var gameCountdownTimer = 15.0
var isGameTimerRunning = false
// THANK YOU & RETURN STATES
var thankYouShown = false
var thankYouTimer = 4.0
var isReturnTimerRunning = false
var returnCountdownTimer = 5.0
var isReturnLaunched = false
var isTeleportedToEarth = false
var startAnthemPhase = false
// MINI-GAME PLAYER & OBJECT PHYSICS
var miniPlayerX = (cwidth / 2.0) - 100.0
var miniPlayerY = 220.0
var miniPlayerVy = 0.0
var modifierGrounded = true
var isKeyPotionCollected = false
var isDoorUnlocked = false
var starsCaughtCount = 0
var targetStarsToCatch = 5
var fallingStarX = Array.fill(5)(randomDouble(120, cwidth - 120))
var fallingStarY = Array.fill(5)(randomDouble(150, cheight - 80))
var asteroidX = Array.fill(4)(cwidth + randomDouble(50, 150))
var asteroidY = Array.fill(4)(randomDouble(150, cheight - 80))
val tricolorPalette = Array(cm.rgb(255, 153, 51), cm.rgb(255, 255, 255), cm.rgb(18, 136, 7))
// ==================== 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(6, 12)) 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, 5)
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 && !anthemFinished) {
playJanaGanaStep()
if (charIndex < patrioticInfoText.length) {
charIndex = math.min(charIndex + 4, patrioticInfoText.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(5) else canvas.strokeWeight(2.5)
canvas.point(location.x, location.y)
}
}
class Firework() {
private val fireworkColor = tricolorPalette(random(tricolorPalette.length))
private val firework = new Particle(randomDouble(cwidth), cheight, 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(90) {
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 && !anthemFinished) {
if (randomDouble(1) < 0.1) fireworks.append(new Firework())
} else if (anthemFinished) {
finalCreditsTimer += 0.04
}
repeatFor(fireworks) { f => f.step() }
waveAngle += 0.1
chakraRotation += 0.08
neonGlowPhase += 0.08
globalTime += 0.025
if (earthNotificationTimer > 0) earthNotificationTimer -= 0.04
if (thankYouTimer > 0 && thankYouShown) {
thankYouTimer -= 0.04
if (thankYouTimer <= 0) {
thankYouShown = false
astronautOut = false
readyToReturnEarth = true
}
}
if (isTimerRunning && countdownTimer > 0) {
countdownTimer -= 0.04
if (countdownTimer <= 0) {
countdownTimer = 0.0
isTimerRunning = false
quizActive = true
}
}
if (isLaunched && !isLanded) {
rocketSurfaceY += 4.5
val targetLandingY = 150.0
if (rocketSurfaceY >= targetLandingY) {
rocketSurfaceY = targetLandingY
isLanded = true
}
}
if (isLanded && !isReturnLaunched) {
if (!thankYouShown && !readyToReturnEarth && !infoPanelShown) {
if (doorOpeningProgress < 1.0) {
doorOpeningProgress += 0.02
} else {
astronautOut = true
infoPanelShown = true
}
}
}
if (isGameTimerRunning && gameCountdownTimer > 0 && !thankYouShown && !readyToReturnEarth) {
gameCountdownTimer -= 0.04
if (gameCountdownTimer <= 0) {
gameCountdownTimer = 15.0
isGameTimerRunning = false
isMiniGameActive = false
infoPanelShown = true
isKeyPotionCollected = false
isDoorUnlocked = false
starsCaughtCount = 0
}
}
// MINI-GAME 1
if (isMiniGameActive && activeMiniGameType == 0 && !thankYouShown) {
val gx = cwidth / 2.0 - 220.0
val gy = cheight / 2.0 - 100.0
val speed = 4.0
if (isKeyPressed(Kc.VK_RIGHT) && miniPlayerX < gx + 410) miniPlayerX += speed
if (isKeyPressed(Kc.VK_LEFT) && miniPlayerX > gx + 15) miniPlayerX -= speed
if (isKeyPressed(Kc.VK_UP) && modifierGrounded) {
miniPlayerVy = -8.0
modifierGrounded = false
}
miniPlayerY -= miniPlayerVy
if (!modifierGrounded) miniPlayerVy += 0.4
val floorLevel = gy + 175.0
if (miniPlayerY >= floorLevel) {
miniPlayerY = floorLevel
miniPlayerVy = 0.0
modifierGrounded = true
} else {
if (miniPlayerY < floorLevel) modifierGrounded = false
}
if (!isKeyPotionCollected && math.abs(miniPlayerX - (gx + 350)) < 25 && math.abs(miniPlayerY - (gy + 110)) < 25) {
isKeyPotionCollected = true
isDoorUnlocked = true
}
if (isDoorUnlocked && math.abs(miniPlayerX - (gx + 50)) < 30 && math.abs(miniPlayerY - (gy + 120)) < 30) {
isMiniGameActive = false
isGameTimerRunning = false
thankYouShown = true
thankYouTimer = 4.0
}
}
// MINI-GAME 2
if (isMiniGameActive && activeMiniGameType == 1 && !thankYouShown) {
val gx = cwidth / 2.0 - 220.0
val gy = cheight / 2.0 - 100.0
val speed = 4.5
if (isKeyPressed(Kc.VK_RIGHT) && miniPlayerX < gx + 410) miniPlayerX += speed
if (isKeyPressed(Kc.VK_LEFT) && miniPlayerX > gx + 15) miniPlayerX -= speed
if (isKeyPressed(Kc.VK_UP) && miniPlayerY > gy + 30) miniPlayerY -= speed
if (isKeyPressed(Kc.VK_DOWN) && miniPlayerY < gy + 175) miniPlayerY += speed
for (i <- 0 until fallingStarX.length) {
fallingStarY(i) += 1.5
if (fallingStarY(i) > gy + 185) {
fallingStarY(i) = gy + 30.0
fallingStarX(i) = gx + randomDouble(30, 380)
}
if (math.abs(miniPlayerX - fallingStarX(i)) < 25 && math.abs(miniPlayerY - fallingStarY(i)) < 25) {
starsCaughtCount += 1
fallingStarY(i) = gy + 30.0
fallingStarX(i) = gx + randomDouble(30, 380)
}
}
if (starsCaughtCount >= targetStarsToCatch) {
isMiniGameActive = false
isGameTimerRunning = false
thankYouShown = true
thankYouTimer = 4.0
}
}
// MINI-GAME 3
if (isMiniGameActive && activeMiniGameType == 2 && !thankYouShown) {
val gx = cwidth / 2.0 - 220.0
val gy = cheight / 2.0 - 100.0
val speed = 4.5
if (isKeyPressed(Kc.VK_UP) && miniPlayerY > gy + 30) miniPlayerY -= speed
if (isKeyPressed(Kc.VK_DOWN) && miniPlayerY < gy + 175) miniPlayerY += speed
for (i <- 0 until asteroidX.length) {
asteroidX(i) -= 3.5
if (asteroidX(i) < gx) {
asteroidX(i) = gx + 430.0
asteroidY(i) = gy + randomDouble(30, 170)
}
}
if (randomDouble(1) < 0.003) {
isMiniGameActive = false
isGameTimerRunning = false
thankYouShown = true
thankYouTimer = 4.0
}
}
if (isReturnTimerRunning && returnCountdownTimer > 0) {
returnCountdownTimer -= 0.04
if (returnCountdownTimer <= 0) {
returnCountdownTimer = 0.0
isReturnTimerRunning = false
isReturnLaunched = true
}
}
if (isReturnLaunched && !isTeleportedToEarth) {
rocketSurfaceY -= 6.0
if (rocketSurfaceY < -100.0) {
isTeleportedToEarth = true
startAnthemPhase = true
}
}
}
// MOUSE CLICK INPUT
onMouseClick { (x, y) =>
if (x >= 15 && x <= 125 && y >= 15 && y <= 55) {
if (!isTimerRunning && !isLaunched && !quizActive) {
isTimerRunning = true
countdownTimer = 10.0
}
}
else if (quizActive) {
var qCorrect = 1
repeatFor(planetDetailsMap) { pd =>
if (pd.name == selectedPlanet) qCorrect = pd.correctOpt
}
val boxY = cheight / 2.0 - 10.0
if (x >= cwidth / 2.0 - 190 && x <= cwidth / 2.0 + 190 && y >= boxY && y <= boxY + 25) {
if (qCorrect == 0) { quizActive = false; isLaunched = true; rocketSurfaceY = -60.0 }
else { quizFeedback = "? Wrong Answer! Try again." }
}
else if (x >= cwidth / 2.0 - 190 && x <= cwidth / 2.0 + 190 && y >= boxY + 30 && y <= boxY + 55) {
if (qCorrect == 1) { quizActive = false; isLaunched = true; rocketSurfaceY = -60.0 }
else { quizFeedback = "? Wrong Answer! Try again." }
}
else if (x >= cwidth / 2.0 - 190 && x <= cwidth / 2.0 + 190 && y >= boxY + 60 && y <= boxY + 85) {
if (qCorrect == 2) { quizActive = false; isLaunched = true; rocketSurfaceY = -60.0 }
else { quizFeedback = "? Wrong Answer! Try again." }
}
}
else if (infoPanelShown && !isMiniGameActive) {
if (x >= cwidth / 2.0 + 80 && x <= cwidth / 2.0 + 210 && y >= cheight / 2.0 + 45 && y <= cheight / 2.0 + 80) {
if (infoPageNumber < 3) {
infoPageNumber += 1
} else {
infoPanelShown = false
astronautOut = false
isMiniGameActive = true
isGameTimerRunning = true
gameCountdownTimer = 15.0
activeMiniGameType = random(3)
starsCaughtCount = 0
miniPlayerX = cwidth / 2.0 - 150.0
miniPlayerY = cheight / 2.0 + 40.0
}
}
else if (x >= cwidth / 2.0 - 210 && x <= cwidth / 2.0 - 80 && y >= cheight / 2.0 + 45 && y <= cheight / 2.0 + 80) {
if (infoPageNumber > 1) {
infoPageNumber -= 1
}
}
}
else if (readyToReturnEarth && !isReturnLaunched && x >= cwidth / 2.0 - 120 && x <= cwidth / 2.0 + 120 && y >= cheight - 80 && y <= cheight - 30) {
if (!isReturnTimerRunning) {
isReturnTimerRunning = true
returnCountdownTimer = 5.0
}
}
else if (x <= 145 && y >= cheight - 400 && y <= cheight - 20 && !isLaunched && !quizActive) {
val index = ((cheight - 30 - y) / 25).toInt
if (index >= 0 && index < planetList.length) {
val chosen = planetList(index)
if (chosen == "Earth") {
earthNotificationTimer = 4.0
} else {
selectedPlanet = chosen
infoPageNumber = 1
}
}
}
}
// ==================== RENDERING UI & GRAPHICS ====================
def drawPlanetList(canvas: CanvasDraw) {
val glowWidth = (math.sin(neonGlowPhase) * 2 + 3).toFloat
canvas.stroke(0, 255, 255, 200)
canvas.strokeWeight(glowWidth)
canvas.fill(10, 15, 30, 245)
canvas.rect(10, cheight - 405, 140, 375)
canvas.fill(0, 255, 255)
canvas.text("SELECT TARGET", 18, cheight - 42)
var yPos = cheight - 65.0
var pBaseCol = cm.rgb(255, 255, 255)
var pAccentCol = cm.rgb(200, 200, 200)
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.5)
canvas.rect(12, yPos - 12, 136, 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 if (pName == "Maha-Prithvi") "? Maha-Prithvi" else s"? $pName"
canvas.text(label, 16, yPos)
if (pName == selectedPlanet) {
repeatFor(planetDetailsMap) { pd =>
if (pd.name == pName) {
pBaseCol = pd.surfaceCol
pAccentCol = pd.accent3D
}
}
}
yPos -= 25.0
}
// DRAW 3D ANIMATED SPHERE LIVE PREVIEW NEXT TO MENU
canvas.fill(10, 15, 30, 245)
canvas.stroke(255, 215, 0)
canvas.strokeWeight(2)
canvas.rect(155, cheight - 210, 120, 120)
canvas.fill(255, 255, 255)
canvas.text("3D LIVE VIEW:", 162, cheight - 185)
// 3D Animated Shading Sphere with rotating highlight ring
val sphereX = 215.0
val sphereY = cheight - 130.0
val radius = 35.0
canvas.fill(pBaseCol)
canvas.stroke(pAccentCol)
canvas.strokeWeight(2)
canvas.ellipse(sphereX, sphereY, radius * 2, radius * 2)
// 3D Curved Highlights (Simulating Rotation)
canvas.noFill()
canvas.stroke(255, 255, 255, 180)
canvas.strokeWeight(1.5)
val animOffset = math.sin(globalTime * 3) * 15.0
canvas.ellipse(sphereX + (animOffset * 0.2), sphereY, radius * 0.8, radius * 1.9)
canvas.ellipse(sphereX, sphereY + (animOffset * 0.2), radius * 1.9, radius * 0.8)
// Glowing core specular reflection
canvas.fill(255, 255, 255, 220)
canvas.noStroke()
canvas.ellipse(sphereX - 10, sphereY - 10, 8, 8)
if (earthNotificationTimer > 0) {
canvas.fill(255, 50, 50, 240)
canvas.stroke(255, 255, 255)
canvas.strokeWeight(2)
canvas.rect(155, cheight - 265, 260, 42)
canvas.fill(255, 255, 255)
canvas.text("? Already on Earth! Choose another.", 165, cheight - 239)
}
}
// ZOOMED OUT SOLAR SYSTEM WITH DIFFERENT CUSTOM SPEEDS
def drawFullSolarSystem(canvas: CanvasDraw) {
val centerX = cwidth / 2.0 + 80.0
val centerY = cheight / 2.0
canvas.fill(255, 140, 0)
canvas.stroke(255, 200, 0)
canvas.strokeWeight(2)
canvas.ellipse(centerX, centerY, 45, 45)
val orbits = Array(50.0, 80.0, 110.0, 145.0, 185.0, 225.0, 265.0, 305.0)
val orbitalSpeeds = Array(2.2, 1.6, 1.2, 1.0, 0.8, 0.5, 0.35, 0.25)
val planetColors = Array(
cm.rgb(150, 150, 150),
cm.rgb(220, 180, 100),
cm.rgb(40, 130, 240),
cm.rgb(200, 70, 40),
cm.rgb(210, 140, 90),
cm.rgb(190, 170, 110),
cm.rgb(100, 200, 220),
cm.rgb(50, 90, 220)
)
for (i <- orbits.indices) {
canvas.noFill()
canvas.stroke(255, 255, 255, 35)
canvas.strokeWeight(1)
canvas.ellipse(centerX, centerY, orbits(i) * 2, orbits(i) * 2)
val angle = globalTime * orbitalSpeeds(i) + (i * 1.5)
val px = centerX + math.cos(angle) * orbits(i)
val py = centerY + math.sin(angle) * orbits(i)
canvas.fill(planetColors(i))
canvas.noStroke()
canvas.ellipse(px, py, 10, 10)
}
}
def drawPlanetSurfaceBackground(canvas: CanvasDraw) {
var surfColor = cm.rgb(50, 50, 80)
var darkSurfColor = cm.rgb(25, 25, 40)
repeatFor(planetDetailsMap) { pd =>
if (pd.name == selectedPlanet) {
surfColor = pd.surfaceCol
darkSurfColor = pd.darkSurfCol
}
}
canvas.fill(surfColor)
canvas.noStroke()
canvas.rect(0, 0, cwidth, 150)
canvas.fill(darkSurfColor)
canvas.rect(0, 115, cwidth, 35)
}
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(220, 220, 220)
canvas.strokeWeight(6)
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.04)) * 9.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.04)) * 9.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 drawLaunchAndUI(canvas: CanvasDraw) {
if (!isLaunched && !isTimerRunning && !quizActive) {
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 - 120, cheight - 75, 240, 45)
canvas.fill(255, 255, 255)
canvas.text("? RETURN TO EARTH", cwidth / 2.0 - 95, cheight - 48)
}
if (isTimerRunning) {
val sec = countdownTimer.toInt
canvas.fill(255, 215, 0)
canvas.text(s"COUNTDOWN: $sec s", 135, 35)
} else if (isReturnTimerRunning) {
val sec = returnCountdownTimer.toInt
canvas.fill(255, 215, 0)
canvas.text(s"RETURN COUNTDOWN: $sec s", cwidth / 2.0 - 110, cheight - 90)
}
}
// ==================== ULTRA-SHARP DETAILED ISRO ROCKET ====================
def drawISRORocketTopSurface(canvas: CanvasDraw) {
val rx = cwidth / 2.0
val ry = rocketSurfaceY
canvas.pushMatrix()
canvas.translate(rx, ry)
// Powerful Rocket Exhaust Fire & Thruster Glow
if ((isLaunched && !isLanded) || (isReturnLaunched && !isTeleportedToEarth)) {
canvas.fill(255, 120, 0)
canvas.noStroke()
canvas.ellipse(0, -55, randomDouble(26, 38), randomDouble(35, 50))
canvas.fill(255, 255, 220)
canvas.ellipse(0, -45, 14, 25)
}
// Rocket Body - Main Fuselage (High Aerodynamic Details)
canvas.fill(245, 245, 250)
canvas.stroke(0, 255, 255)
canvas.strokeWeight(2)
canvas.rect(-12, -45, 24, 45)
// Ultra-Sharp Nose Cone (Using lines instead of triangle)
canvas.fill(255, 60, 60)
canvas.stroke(255, 200, 200)
canvas.strokeWeight(1.5)
canvas.beginShape()
canvas.vertex(0, -68)
canvas.vertex(-12, -45)
canvas.vertex(12, -45)
canvas.endShape()
// Side Boosters / Strap-on Motors (Detailed ISRO design)
canvas.fill(220, 220, 230)
canvas.stroke(100, 100, 120)
canvas.rect(-20, -35, 7, 35)
canvas.rect(13, -35, 7, 35)
// Booster pointy tips
canvas.beginShape(); canvas.vertex(-16.5, -45); canvas.vertex(-20, -35); canvas.vertex(-13, -35); canvas.endShape()
canvas.beginShape(); canvas.vertex(16.5, -45); canvas.vertex(-13, -35); canvas.vertex(20, -35); canvas.endShape()
// Aerodynamic Fins at bottom
canvas.fill(255, 153, 51)
canvas.beginShape(); canvas.vertex(-12, 0); canvas.vertex(-22, 10); canvas.vertex(-12, 5); canvas.endShape()
canvas.beginShape(); canvas.vertex(12, 0); canvas.vertex(22, 10); canvas.vertex(12, 5); canvas.endShape()
// Door / Airlock compartment
if (isLanded && !thankYouShown) {
canvas.fill(20, 20, 40)
val doorWidth = 14.0 * doorOpeningProgress
canvas.rect(-7, -25, doorWidth, 22)
} else {
canvas.fill(160, 160, 175)
canvas.rect(-7, -25, 14, 22)
}
// ISRO Branding Stamp
canvas.fill(0, 51, 102)
canvas.text("ISRO", -10, -12)
if (astronautOut && !isMiniGameActive && !thankYouShown) {
canvas.fill(240, 240, 245)
canvas.stroke(50, 50, 60)
canvas.strokeWeight(1)
canvas.rect(22, -22, 16, 22)
canvas.fill(255, 255, 255)
canvas.stroke(80, 80, 100)
canvas.ellipse(30, -17, 14, 14)
canvas.fill(0, 180, 240)
canvas.noStroke()
canvas.ellipse(31, -17, 9, 7)
}
canvas.popMatrix()
}
def drawQuizPopup(canvas: CanvasDraw) {
if (quizActive) {
var qText = ""
var opts = Array("", "", "")
repeatFor(planetDetailsMap) { pd =>
if (pd.name == selectedPlanet) {
qText = pd.quizQuestion
opts = pd.quizOptions
}
}
canvas.fill(10, 15, 30, 250)
canvas.stroke(255, 215, 0)
canvas.strokeWeight(3)
canvas.rect(cwidth / 2.0 - 210, cheight / 2.0 - 90, 420, 180)
canvas.fill(255, 255, 255)
canvas.text(s"? MISSION QUESTION FOR $selectedPlanet:", cwidth / 2.0 - 195, cheight / 2.0 - 65)
canvas.text(qText, cwidth / 2.0 - 195, cheight / 2.0 - 40)
val boxY = cheight / 2.0 - 10.0
canvas.fill(30, 40, 70)
canvas.stroke(0, 255, 255)
canvas.strokeWeight(1.5)
canvas.rect(cwidth / 2.0 - 190, boxY, 380, 25)
canvas.rect(cwidth / 2.0 - 190, boxY + 30, 380, 25)
canvas.rect(cwidth / 2.0 - 190, boxY + 60, 380, 25)
canvas.fill(255, 255, 255)
canvas.text(opts(0), cwidth / 2.0 - 180, boxY + 17)
canvas.text(opts(1), cwidth / 2.0 - 180, boxY + 47)
canvas.text(opts(2), cwidth / 2.0 - 180, boxY + 77)
if (quizFeedback != "") {
canvas.fill(255, 50, 50)
canvas.text(quizFeedback, cwidth / 2.0 - 100, boxY + 105)
}
}
}
def drawPlanetInfoPopup(canvas: CanvasDraw) {
if (infoPanelShown && !isMiniGameActive) {
var dLine = ""
var dnInfo = ""
var gInfo = ""
var alienInfo = ""
var atmInfo = ""
var coreInfo = ""
var factInfo = ""
repeatFor(planetDetailsMap) { pd =>
if (pd.name == selectedPlanet) {
dLine = pd.infoLine1
dnInfo = pd.dayNightStatus
gInfo = pd.gravityVal
alienInfo = pd.alienHumanStatus
atmInfo = pd.atmosphere
coreInfo = pd.coreTemp
factInfo = pd.funFact
}
}
canvas.fill(10, 15, 30, 250)
canvas.stroke(0, 255, 255)
canvas.strokeWeight(3)
canvas.rect(cwidth / 2.0 - 230, cheight / 2.0 - 110, 460, 215)
canvas.fill(255, 255, 255)
canvas.text(s"? ASTRO-REPORT ($selectedPlanet) - Page $infoPageNumber/3", cwidth / 2.0 - 215, cheight / 2.0 - 85)
if (infoPageNumber == 1) {
canvas.text(s"? Surface: $dLine", cwidth / 2.0 - 215, cheight / 2.0 - 50)
canvas.text(s"? $dnInfo", cwidth / 2.0 - 215, cheight / 2.0 - 20)
canvas.text(s"? Gravity: $gInfo", cwidth / 2.0 - 215, cheight / 2.0 + 10)
} else if (infoPageNumber == 2) {
canvas.text(s"? Atmosphere: $atmInfo", cwidth / 2.0 - 215, cheight / 2.0 - 50)
canvas.text(s"? Core Temp: $coreInfo", cwidth / 2.0 - 215, cheight / 2.0 - 20)
canvas.text(s"? $alienInfo", cwidth / 2.0 - 215, cheight / 2.0 + 10)
} else {
canvas.text(s"? Fun Fact: $factInfo", cwidth / 2.0 - 215, cheight / 2.0 - 35)
canvas.text("? Mission Ready: Proceed to Game!", cwidth / 2.0 - 215, cheight / 2.0 + 5)
}
if (infoPageNumber > 1) {
canvas.fill(100, 100, 150)
canvas.stroke(255, 255, 255)
canvas.strokeWeight(1.5)
canvas.rect(cwidth / 2.0 - 210, cheight / 2.0 + 45, 120, 32)
canvas.fill(255, 255, 255)
canvas.text("? PREV PAGE", cwidth / 2.0 - 200, cheight / 2.0 + 66)
}
canvas.fill(255, 153, 51)
canvas.stroke(255, 255, 255)
canvas.strokeWeight(2)
canvas.rect(cwidth / 2.0 + 80, cheight / 2.0 + 45, 130, 32)
canvas.fill(255, 255, 255)
val nextBtnText = if (infoPageNumber < 3) "NEXT PAGE ?" else "PLAY GAME ?"
canvas.text(nextBtnText, cwidth / 2.0 + 90, cheight / 2.0 + 66)
}
if (thankYouShown) {
canvas.fill(10, 15, 30, 245)
canvas.stroke(0, 255, 100)
canvas.strokeWeight(3)
canvas.rect(cwidth / 2.0 - 210, cheight / 2.0 - 60, 420, 120)
canvas.fill(50, 255, 50)
canvas.text("? FANTASTIC! GAME COMPLETED!", cwidth / 2.0 - 165, cheight / 2.0 - 25)
canvas.fill(255, 255, 255)
canvas.text("??? Astronaut: 'Thank you! Re-entering spaceship...'", cwidth / 2.0 - 195, cheight / 2.0 + 15)
}
}
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(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 drawMiniGames(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(3)
canvas.rect(gx, gy, 440, 210)
val gSec = gameCountdownTimer.toInt
canvas.fill(255, 50, 50)
canvas.text(s"? Time Left: ${gSec}s", gx + 310, gy + 20)
if (activeMiniGameType == 0) {
canvas.fill(255, 255, 255)
canvas.text("? Mini-Game 1: Platform Potion Hunt!", gx + 15, gy + 190)
canvas.fill(255, 153, 51); canvas.rect(gx + 20, gy + 175, 400, 12)
canvas.fill(255, 255, 255); canvas.rect(gx + 140, gy + 120, 120, 10)
canvas.fill(18, 136, 7); canvas.rect(gx + 280, gy + 75, 100, 10)
if (!isKeyPotionCollected) {
canvas.fill(255, 50, 50)
canvas.ellipse(gx + 350, gy + 110, 16, 16)
}
if (isDoorUnlocked) {
canvas.fill(0, 200, 255, 200)
canvas.ellipse(gx + 50, gy + 120, 25, 40)
}
drawAstronautPlayer(canvas, miniPlayerX, miniPlayerY)
} else if (activeMiniGameType == 1) {
canvas.fill(255, 255, 255)
canvas.text(s"? Mini-Game 2: Catch Stars ($starsCaughtCount/$targetStarsToCatch)", gx + 15, gy + 190)
for (i <- 0 until fallingStarX.length) {
canvas.fill(255, 255, 0)
canvas.ellipse(fallingStarX(i), fallingStarY(i), 14, 14)
}
drawAstronautPlayer(canvas, miniPlayerX, miniPlayerY)
} else {
canvas.fill(255, 255, 255)
canvas.text("?? Mini-Game 3: Asteroid Dodge (Up/Down)", gx + 15, gy + 190)
for (i <- 0 until asteroidX.length) {
canvas.fill(200, 50, 50)
canvas.ellipse(asteroidX(i), asteroidY(i), 20, 20)
}
drawAstronautPlayer(canvas, miniPlayerX, miniPlayerY)
}
}
}
def drawPatrioticInfoText(canvas: CanvasDraw) {
if (charIndex > 0) {
val visibleSubstring = patrioticInfoText.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) {
if (anthemFinished) {
canvas.fill(0, 0, 0, 255)
canvas.noStroke()
canvas.rect(0, 0, cwidth, cheight)
canvas.fill(255, 255, 255)
canvas.text("THE END", cwidth / 2.0 - 50.0, cheight / 2.0 - 20.0)
canvas.fill(255, 153, 51)
canvas.text("Made by Yadnesh Shahare and Bhavesh Shahare", cwidth / 2.0 - 180.0, cheight / 2.0 + 20.0)
return
}
canvas.fill(0, 0, 0, 255)
canvas.noStroke()
canvas.rect(0, 0, cwidth, cheight)
for (i <- 0 until starCount) {
canvas.stroke(255, 255, 255)
canvas.strokeWeight(starSize(i))
canvas.point(starX(i), starY(i))
}
repeatFor(fireworks) { f => f.view(canvas) }
if (isTeleportedToEarth) {
drawWavingTricolorFlag(canvas)
drawSoldiersSquad(canvas)
drawPatrioticInfoText(canvas)
} else {
if (isLaunched) {
drawPlanetSurfaceBackground(canvas)
} else {
drawFullSolarSystem(canvas)
drawPlanetList(canvas)
}
drawLaunchAndUI(canvas)
drawISRORocketTopSurface(canvas)
}
drawQuizPopup(canvas)
drawPlanetInfoPopup(canvas)
drawMiniGames(canvas)
}
animateWithCanvasDraw { canvas =>
updateState()
viewState(canvas)
}