Code Sketch
sare jaha se aacha
// --- SARE JAHAN SE ACHHA WITH ROTATING ASHOKA CHAKRA & STARBURSTS ---
cleari()
originBottomLeft()
// ?. "???? ???? ?? ?????" ?? ????? ????? (Midi Tune)
setNoteInstrument(Instrument.FLUTE)
val sareJahanTune = Array(
(60, 250), (62, 250), (64, 250), (65, 250), (64, 300), (62, 250), (60, 300), // ??-?? ?-??? ?? ?-????
(60, 250), (64, 250), (67, 300), (65, 300), (64, 400), // ????-????-??? ?-??-??
(65, 250), (67, 250), (69, 250), (69, 300), (67, 250), (65, 300), // ?? ???-??-?? ??? ??-??
(64, 250), (65, 250), (67, 300), (65, 250), (64, 250), (62, 250), (60, 400) // ?? ??-?-??-??? ?-??-??
)
var tuneIndex = 0
// "???? ???? ?? ?????" ?? ??????? (Letter by Letter)
val lyricsText =
"Sare Jahan Se Achha\n" +
"Hindostan Hamara!\n\n" +
"Hum Bulbule Hain Iski,\n" +
"Yeh Gulsitan Hamara!\n\n" +
"Gurbat Mein Ho Agar Hum,\n" +
"Rehta Hai Dil Watan Mein,\n\n" +
"Samjho Wahi Humen Bhi,\n" +
"Dil Ho Jahan Hamara!\n\n" +
"SARE JAHAN SE ACHHA..."
var charIndex = 0
def playSareJahanStep() {
if (tuneIndex < sareJahanTune.length) {
val (note, duration) = sareJahanTune(tuneIndex)
playNote(note, duration)
tuneIndex = (tuneIndex + 1) % sareJahanTune.length
}
}
val gravity = Vector2D(0, -0.08)
var waveAngle = 0.0
var chakraRotation = 0.0 // ???? ???? ???????????? ????
// ?. ?????? ????????????? ???
val tricolorPalette = Array(
cm.rgb(255, 153, 51), // ?????
cm.rgb(255, 255, 255), // ??????
cm.rgb(18, 136, 7) // ?????
)
class StarParticle(x0: Double, y0: Double, col: Color, seed: Boolean) {
var location = Vector2D(x0, y0)
private var velocity =
if (seed) Vector2D(0, random(5, 11))
else randomStarburstVector
private var acceleration = Vector2D(0, 0)
var lifespan = 255.0
private var exploded = false
def randomStarburstVector: Vector2D = {
val angle = randomDouble(0, 2 * math.Pi)
val speed = randomDouble(1.5, 4.5)
Vector2D(math.cos(angle) * speed, math.sin(angle) * speed)
}
def applyForce(force: Vector2D) {
acceleration += force
}
def shouldExplode: Boolean = !exploded && lifespan <= 0
def checkExplode() {
if (seed && velocity.y < 0) {
lifespan = 0
}
}
def isDead: Boolean = {
if (seed) exploded else lifespan <= 0
}
def explode() {
playSareJahanStep()
exploded = true
// ?????? ?-? ?????? ???? ???? ????
if (charIndex < lyricsText.length) {
charIndex = math.min(charIndex + 3, lyricsText.length)
}
}
def step() {
velocity += acceleration
location += velocity
if (!seed) {
lifespan -= 6
velocity *= 0.94
}
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 starColor = tricolorPalette(random(tricolorPalette.length))
private val firework = new StarParticle(random(cwidth), 0, starColor, true)
private val particles = ArrayBuffer.empty[StarParticle]
def done: Boolean = {
firework.isDead && particles.isEmpty
}
def step() {
particles.filterInPlace(p => !p.isDead)
if (!firework.isDead) {
firework.applyForce(gravity)
firework.step()
if (firework.shouldExplode) {
repeat(70) {
particles.append(
new StarParticle(firework.location.x, firework.location.y, starColor, false)
)
}
firework.explode()
}
}
repeatFor(particles) { p =>
p.applyForce(gravity)
p.step()
}
}
def view(canvas: CanvasDraw) {
firework.view(canvas)
repeatFor(particles) { p =>
p.view(canvas)
}
}
}
val fireworks = ArrayBuffer.empty[Firework]
def updateState() {
fireworks.filterInPlace(f => !f.done)
if (randomDouble(1) < 0.08) {
fireworks.append(new Firework())
}
repeatFor(fireworks) { f =>
f.step()
}
waveAngle += 0.08 // ??????? ???
chakraRotation += 0.05 // ???? ???? ????????? ?????
}
// ?. ??????? ???? + ??????? ?? ?????? ???? ????
def drawInteractiveFlag(canvas: CanvasDraw) {
val fw = 170.0
val fh = 30.0
val fx = (cwidth - fw) / 2.0 + 110.0
val fy = cheight / 2.0 - 20.0
// ????????? (Flag Pole)
canvas.stroke(200, 200, 200)
canvas.strokeWeight(5)
canvas.line(fx, fy + fh * 3 + 15, fx, fy - 140)
// ??????? ?????
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
}
// ??????? ???? ???? (Spinning Ashoka Chakra)
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 = 12.0
canvas.stroke(0, 0, 128)
canvas.strokeWeight(2)
canvas.noFill()
canvas.ellipse(chakraX, chakraY, radius * 2, radius * 2)
// ????????? ?? ??? (24 Rotating Spokes)
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 drawSareJahanLyrics(canvas: CanvasDraw) {
val visibleSubstring = lyricsText.substring(0, charIndex)
val lines = visibleSubstring.split("\n")
val startX = 25.0
var startY = cheight - 70.0
for (i <- lines.indices) {
if (i == lines.length - 1) {
canvas.fill(255, 153, 51) // ???? ?? ????? ?????
} else {
canvas.fill(230, 230, 230) // ??????? ??? ???????? ?????
}
canvas.text(lines(i), startX, startY)
startY -= 20.0
}
}
def viewState(canvas: CanvasDraw) {
// ??????? ??? ???????????
canvas.fill(10, 10, 25, 45)
canvas.noStroke()
canvas.rect(0, 0, cwidth, cheight)
// ?. ????????????? ?????
repeatFor(fireworks) { f =>
f.view(canvas)
}
// ?. ???? ???? ?? ????? ???????
drawSareJahanLyrics(canvas)
// ?. ??????? ?????? ???? ??? ??????? ????
drawInteractiveFlag(canvas)
}
animateWithCanvasDraw { canvas =>
updateState()
viewState(canvas)
}