Code Sketch


Bixuu02
By: Mhalsakant School
Category: Programming
// ============================================================
// RAKSHABANDHAN ANIMATED DELIVERY MISSION GAME
// SCALA SCRIPT FOR KOJO / SCALA CANVAS
// ============================================================

cleari()
originBottomLeft()

// ============================================================
// GAME STATES & ANIMATION VARIABLES
// 0 = Letter Order
// 1 = Avatar Selection (Woman / Man)
// 2 = Rakhi Creation (Shapes + Thread)
// 3 = Interactive Delivery Animation Scene
// 4 = Final Mission Completion Screen
// ============================================================
var screen = 0
var selectedAvatar = "MAN"
var selectedShape = ""
var threadAttached = false

// Delivery Animation State Variables
var carX = -120.0
var carY = 100.0
var deliveryManX = 0.0
var deliveryManY = 0.0
var womanDoorX = 0.0
var isDoorOpen = false
var hasGivenBox = false

// Delivery Sub-states: 
// 0 = Car driving to house
// 1 = Delivery man walking to door
// 2 = Pressing doorbell & Woman opens door
// 3 = Handing over Rakhi Gift Box & Dialogue
// 4 = Animation complete (Show continue button)
var deliverySubState = 0 
var animationTimer = 0

class Star(val x: Double, val y: Double, val size: Double) {
    var phase = randomDouble(6.28)
    def step() { phase += 0.04 }
    def view(canvas: CanvasDraw) {
        val brightness = 150 + (math.sin(phase) * 80).toInt
        canvas.noStroke()
        canvas.fill(brightness, brightness, 255, 200)
        canvas.ellipse(x, y, size, size)
    }
}

val stars = ArrayBuffer.empty[Star]
for (i <- 0 until 60) {
    stars.append(new Star(randomDouble(cwidth), randomDouble(cheight), 1.0 + randomDouble(3.0)))
}

// ============================================================
// DRAW DETAILED AVATARS (WOMAN & MAN)
// ============================================================
def drawDetailedAvatar(canvas: CanvasDraw, x: Double, y: Double, gender: String, scale: Double) {
    canvas.noStroke()
    
    if (gender == "WOMAN") {
        // Hair (Back)
        canvas.fill(30, 20, 15)
        canvas.ellipse(x, y + 20 * scale, 75 * scale, 85 * scale)
        
        // Face
        canvas.fill(255, 220, 180)
        canvas.ellipse(x, y + 25 * scale, 55 * scale, 60 * scale)
        
        // Traditional Saree & Jewelry
        canvas.fill(210, 30, 90) // Pink/Red Saree
        canvas.rect(x - 30 * scale, y - 60 * scale, 60 * scale, 70 * scale)
        canvas.fill(255, 215, 0) // Gold Pallu & Jewelry
        canvas.line(x - 30 * scale, y - 60 * scale, x + 20 * scale, y + 5 * scale)
        canvas.ellipse(x - 30 * scale, y + 25 * scale, 10 * scale, 12 * scale) // Earring Left
        canvas.ellipse(x + 30 * scale, y + 25 * scale, 10 * scale, 12 * scale) // Earring Right
        
        // Bindi
        canvas.fill(220, 0, 0)
        canvas.ellipse(x, y + 33 * scale, 8 * scale, 8 * scale)
    } else {
        // Feta / Cap
        canvas.fill(230, 100, 30)
        canvas.ellipse(x, y + 45 * scale, 65 * scale, 35 * scale)
        
        // Face
        canvas.fill(255, 220, 180)
        canvas.ellipse(x, y + 20 * scale, 55 * scale, 55 * scale)
        
        // Kurta & Vest
        canvas.fill(240, 240, 240)
        canvas.rect(x - 30 * scale, y - 60 * scale, 60 * scale, 70 * scale)
        canvas.fill(40, 90, 180)
        canvas.rect(x - 25 * scale, y - 60 * scale, 50 * scale, 60 * scale)
    }

    // Eyes & Smile
    canvas.fill(0, 0, 0)
    canvas.ellipse(x - 12 * scale, y + 22 * scale, 6 * scale, 8 * scale)
    canvas.ellipse(x + 12 * scale, y + 22 * scale, 6 * scale, 8 * scale)
    canvas.stroke(180, 50, 50)
    canvas.strokeWeight(2 * scale)
    canvas.line(x - 10 * scale, y + 8 * scale, x + 10 * scale, y + 8 * scale)
}

// ============================================================
// DETAILED CAR DRAWING
// ============================================================
def drawDetailedCar(canvas: CanvasDraw, x: Double, y: Double) {
    // Car Body Shadow
    canvas.noStroke()
    canvas.fill(50, 50, 50, 100)
    canvas.ellipse(x + 75, y - 5, 160, 20)

    // Main Body
    canvas.fill(220, 30, 30)
    canvas.rect(x, y + 10, 150, 45)
    canvas.rect(x + 30, y + 55, 85, 35)

    // Windows (Glass Details)
    canvas.fill(180, 220, 255)
    canvas.rect(x + 35, y + 58, 35, 28)
    canvas.rect(x + 75, y + 58, 35, 28)

    // Headlights & Taillights
    canvas.fill(255, 230, 0) // Front Light
    canvas.rect(x + 145, y + 25, 8, 15)
    canvas.fill(180, 0, 0) // Tail Light
    canvas.rect(x - 3, y + 25, 6, 15)

    // Side Door Handles & Stripes
    canvas.stroke(255, 255, 255)
    canvas.strokeWeight(2)
    canvas.line(x, y + 35, x + 150, y + 35)
    canvas.fill(50, 50, 50)
    canvas.rect(x + 55, y + 42, 10, 4)
    canvas.rect(x + 95, y + 42, 10, 4)

    // Detailed Wheels (Tires + Alloys)
    canvas.noStroke()
    val wheelPositions = Array(x + 35, x + 115)
    for (wx <- wheelPositions) {
        canvas.fill(20, 20, 20)
        canvas.ellipse(wx, y + 8, 36, 36) // Outer Tire
        canvas.fill(200, 200, 200)
        canvas.ellipse(wx, y + 8, 20, 20) // Alloy Rim
        canvas.fill(50, 50, 50)
        canvas.ellipse(wx, y + 8, 8, 8) // Center
    }
}

// ============================================================
// DRAW RAKHI DESIGN
// ============================================================
def drawRakhi(canvas: CanvasDraw, x: Double, y: Double, shape: String, showThread: Boolean) {
    if (showThread) {
        canvas.stroke(220, 30, 30)
        canvas.strokeWeight(10)
        canvas.line(x - 160, y, x + 160, y)
        canvas.stroke(255, 215, 0)
        canvas.strokeWeight(4)
        canvas.line(x - 160, y, x + 160, y)
    }

    canvas.noStroke()
    canvas.fill(255, 215, 0) // Gold Base
    canvas.ellipse(x, y, 95, 95)

    canvas.fill(220, 20, 60)
    if (shape == "CIRCLE") {
        canvas.ellipse(x, y, 65, 65)
        canvas.fill(255, 255, 255)
        canvas.ellipse(x, y, 35, 35)
    } else if (shape == "TRIANGLE") {
        canvas.rect(x - 28, y - 25, 56, 56)
    } else if (shape == "STAR") {
        canvas.ellipse(x, y, 75, 35)
        canvas.ellipse(x, y, 35, 75)
        canvas.fill(255, 215, 0)
        canvas.ellipse(x, y, 30, 30)
    }
}

// ============================================================
// DELIVERY ANIMATION SCENE
// ============================================================
def drawDeliveryAnimationScene(canvas: CanvasDraw) {
    canvas.background(135, 206, 235) // Sky

    // Road & Environment
    canvas.noStroke()
    canvas.fill(40, 160, 60)
    canvas.rect(0, 0, cwidth, 160)
    canvas.fill(70, 70, 75)
    canvas.rect(0, 80, cwidth, 70) // Road
    canvas.fill(255, 255, 255)
    for (i <- 0 until 10) {
        canvas.rect(i * 70, 110, 40, 8)
    }

    // House at Gokuldham
    val houseX = cwidth - 190.0
    val houseY = 140.0
    canvas.fill(255, 230, 180) // Wall
    canvas.rect(houseX, houseY, 160, 130)
    canvas.fill(180, 50, 40) // Roof
    canvas.rect(houseX - 10, houseY + 130, 180, 45)

    // Doorway
    canvas.fill(80, 40, 20)
    canvas.rect(houseX + 60, houseY, 50, 80) // Open Door Frame

    // Doorbell Switch
    canvas.fill(220, 220, 220)
    canvas.rect(houseX + 45, houseY + 45, 8, 12)
    canvas.fill(200, 30, 30)
    canvas.ellipse(houseX + 49, houseY + 51, 4, 4)

    // Gokuldham Title Board
    canvas.fill(0, 100, 180)
    canvas.rect(houseX + 15, houseY + 100, 130, 25)
    canvas.fill(255, 255, 255)
    canvas.text("GOKULDHAM", houseX + 30, houseY + 107)

    // Draw Detailed Car
    drawDetailedCar(canvas, carX, carY)

    // Woman Appearing from Door
    if (isDoorOpen) {
        drawDetailedAvatar(canvas, houseX + 85, houseY + 20, "WOMAN", 0.55)
    }

    // Delivery Person
    if (deliverySubState >= 1) {
        drawDetailedAvatar(canvas, deliveryManX, deliveryManY, selectedAvatar, 0.55)

        // Delivery Box (Holding in Hand or Handed over)
        if (!hasGivenBox) {
            canvas.fill(200, 140, 60)
            canvas.rect(deliveryManX + 10, deliveryManY, 22, 18) // Box in hands
            canvas.fill(220, 30, 30)
            canvas.rect(deliveryManX + 18, deliveryManY, 6, 18) // Red Ribbon
        } else {
            // Box Handed to Woman
            canvas.fill(200, 140, 60)
            canvas.rect(houseX + 70, houseY + 15, 22, 18)
            canvas.fill(220, 30, 30)
            canvas.rect(houseX + 78, houseY + 15, 6, 18)
        }
    }

    // Doorbell Visual Sound Effect
    if (deliverySubState == 2 && animationTimer < 30) {
        canvas.fill(255, 215, 0)
        canvas.text("DING DONG!", houseX + 10, houseY + 65)
    }

    // Dialogues & Speech Bubbles
    if (deliverySubState >= 3) {
        // Speech Bubble from Woman
        canvas.fill(255, 255, 255)
        canvas.stroke(0, 0, 0)
        canvas.strokeWeight(2)
        canvas.rect(houseX - 190, houseY + 70, 220, 65)
        canvas.fill(0, 0, 0)
        canvas.text("Thank you for the delivery!", houseX - 180, houseY + 110)
        canvas.text("Please visit again!", houseX - 180, houseY + 92)
        canvas.fill(180, 0, 60)
        canvas.text("Happy Rakshabandhan!", houseX - 180, houseY + 76)

        // Continue Button
        canvas.fill(0, 180, 80)
        canvas.noStroke()
        canvas.rect(cwidth / 2 - 90, 20, 180, 45)
        canvas.fill(255, 255, 255)
        canvas.text("CLICK TO COMPLETE", cwidth / 2 - 75, 38)
    }
}

// ============================================================
// OTHER GAME SCREENS
// ============================================================
def drawLetterScreen(canvas: CanvasDraw) {
    canvas.background(40, 20, 50)
    repeatFor(stars) { s => s.view(canvas) }

    canvas.fill(255, 248, 220)
    canvas.stroke(212, 175, 55)
    canvas.strokeWeight(4)
    canvas.rect(cwidth/2 - 200, cheight/2 - 160, 400, 320)

    canvas.fill(180, 0, 0)
    canvas.text("RAKSHABANDHAN ORDER LETTER", cwidth/2 - 150, cheight/2 + 120)

    canvas.fill(50, 50, 50)
    canvas.text("Dear Creator,", cwidth/2 - 170, cheight/2 + 80)
    canvas.text("Please create a Rakhi and deliver it to:", cwidth/2 - 170, cheight/2 + 50)
    
    canvas.fill(0, 100, 0)
    canvas.text("Address: Gokuldham Society,", cwidth/2 - 170, cheight/2 + 10)
    canvas.text("Powder Galli, Goregaon East.", cwidth/2 - 170, cheight/2 - 15)

    canvas.fill(220, 50, 50)
    canvas.rect(cwidth/2 - 90, cheight/2 - 120, 180, 50)
    canvas.fill(255, 255, 255)
    canvas.text("Accept the Order", cwidth/2 - 65, cheight/2 - 90)
}

def drawAvatarSelection(canvas: CanvasDraw) {
    canvas.background(30, 30, 60)
    canvas.fill(255, 215, 0)
    canvas.text("SELECT YOUR AVATAR", cwidth/2 - 100, cheight - 50)

    drawDetailedAvatar(canvas, cwidth/2 - 120, cheight/2, "WOMAN", 1.0)
    canvas.fill(255, 255, 255)
    canvas.text("WOMAN", cwidth/2 - 150, cheight/2 - 100)

    drawDetailedAvatar(canvas, cwidth/2 + 120, cheight/2, "MAN", 1.0)
    canvas.fill(255, 255, 255)
    canvas.text("MAN", cwidth/2 + 105, cheight/2 - 100)
}

def drawCreateRakhiScreen(canvas: CanvasDraw) {
    canvas.background(20, 50, 40)
    canvas.fill(255, 255, 255)
    canvas.text("DRAW / CREATE THE RAKHI", cwidth/2 - 120, cheight - 50)

    val shapes = Array("CIRCLE", "TRIANGLE", "STAR")
    for (i <- 0 until 3) {
        val bx = 100 + i * 160
        canvas.fill(240, 240, 240)
        canvas.rect(bx, cheight/2 - 30, 120, 60)
        canvas.fill(0, 0, 0)
        canvas.text(shapes(i), bx + 25, cheight/2 + 5)
    }

    if (selectedShape != "") {
        drawRakhi(canvas, cwidth/2, 130, selectedShape, threadAttached)

        if (!threadAttached) {
            canvas.fill(220, 50, 50)
            canvas.rect(cwidth/2 - 100, 30, 200, 45)
            canvas.fill(255, 255, 255)
            canvas.text("Attach Thread (Dhaga)", cwidth/2 - 80, 55)
        } else {
            canvas.fill(0, 180, 80)
            canvas.rect(cwidth/2 - 100, 30, 200, 45)
            canvas.fill(255, 255, 255)
            canvas.text("Click to Deliver", cwidth/2 - 60, 55)
        }
    }
}

def drawCompletionScreen(canvas: CanvasDraw) {
    canvas.background(20, 60, 30)
    repeatFor(stars) { s => s.view(canvas) }

    canvas.fill(255, 215, 0)
    canvas.text("HAPPY RAKSHABANDHAN!", cwidth/2 - 120, cheight/2 + 80)

    canvas.fill(255, 255, 255)
    canvas.text("Thank you for completing the mission!", cwidth/2 - 150, cheight/2 + 25)

    canvas.fill(200, 220, 255)
    canvas.text("Mission Accomplished at Gokuldham Society!", cwidth/2 - 165, cheight/2 - 35)
}

// ============================================================
// ANIMATION STEP UPDATER
// ============================================================
def updateDeliveryAnimation() {
    if (screen == 3) {
        if (deliverySubState == 0) { // Car Driving
            carX += 3.5
            if (carX >= cwidth - 360) {
                deliverySubState = 1
                deliveryManX = carX + 60
                deliveryManY = carY + 15
            }
        } else if (deliverySubState == 1) { // Delivery Man Walking
            deliveryManX += 1.5
            deliveryManY += 0.4
            if (deliveryManX >= cwidth - 150) {
                deliverySubState = 2
                animationTimer = 0
            }
        } else if (deliverySubState == 2) { // Ringing Bell & Opening Door
            animationTimer += 1
            if (animationTimer > 35) {
                isDoorOpen = true
                deliverySubState = 3
            }
        } else if (deliverySubState == 3) { // Handing over Box
            hasGivenBox = true
        }
    }
}

// ============================================================
// CLICK HANDLER
// ============================================================
def handleClick(x: Double, y: Double) {
    if (screen == 0) {
        if (x >= cwidth/2 - 90 && x <= cwidth/2 + 90 && y >= cheight/2 - 120 && y <= cheight/2 - 70) {
            screen = 1
        }
    } else if (screen == 1) {
        if (x >= cwidth/2 - 170 && x <= cwidth/2 - 70) {
            selectedAvatar = "WOMAN"
            screen = 2
        } else if (x >= cwidth/2 + 70 && x <= cwidth/2 + 170) {
            selectedAvatar = "MAN"
            screen = 2
        }
    } else if (screen == 2) {
        if (y >= cheight/2 - 30 && y <= cheight/2 + 30) {
            if (x >= 100 && x <= 220) selectedShape = "CIRCLE"
            if (x >= 260 && x <= 380) selectedShape = "TRIANGLE"
            if (x >= 420 && x <= 540) selectedShape = "STAR"
        }

        if (selectedShape != "" && x >= cwidth/2 - 100 && x <= cwidth/2 + 100 && y >= 30 && y <= 75) {
            if (!threadAttached) {
                threadAttached = true
            } else {
                screen = 3 // Start Delivery Animation Scene
            }
        }
    } else if (screen == 3 && deliverySubState >= 3) {
        if (x >= cwidth / 2 - 90 && x <= cwidth / 2 + 90 && y >= 20 && y <= 65) {
            screen = 4 // Show Final Completion Screen
        }
    }
}

onMouseClick { (x, y) => handleClick(x, y) }

// ============================================================
// MAIN LOOP
// ============================================================
animateWithCanvasDraw { canvas =>
    repeatFor(stars) { s => s.step() }
    updateDeliveryAnimation()

    if (screen == 0) drawLetterScreen(canvas)
    else if (screen == 1) drawAvatarSelection(canvas)
    else if (screen == 2) drawCreateRakhiScreen(canvas)
    else if (screen == 3) drawDeliveryAnimationScene(canvas)
    else if (screen == 4) drawCompletionScreen(canvas)
}