Code Sketch


Bixuu02
By: Mhalsakant School
Category: Programming
// ============================================================
// CRIME KILLER - REAL KILLER FIGHT & MEDKIT EDITION (KOJO)
// ============================================================

cleari()
originBottomLeft()

// ============================================================
// GAME STATES & VARIABLES
// ============================================================
var screen = -1 
// -1: Intro Mission Letter
//  0: Avatar Selection Screen
//  1: Gun Selection Screen
//  2: Air Jet Landing
//  3: Gameplay Screen (Real Fight with Killers)
//  4: Game Over Screen
//  5: Level Victory Screen (Earned Coins)
//  6: Final Mission Complete Letter

var selectedAvatar = 0 // 0: Harshal, 1: Fire, 2: Water, 3: Bixuu
var selectedGun = 0    // 0: Desert Eagle, 1: MP40, 2: Shotgun, 3: Sniper
var currentLevel = 1
var totalCoins = 100
var earnedCoinsThisLevel = 0
var killersKilledInLevel = 0
var targetKillersInLevel = 5

// Player Stats
var playerX = cwidth / 2.0
var playerY = 80.0
val playerRadius = 18.0
var playerHealth = 100.0
val maxPlayerHealth = 100.0

// Extremely Fast Gun Stats & One Shot Kill
var gunDamage = 999.0 // ONE SHOT KILL
var gunFireRate = 0.05 // SUPER FAST
var lastShotTime = 0.0

// Defense & VFX
var glooWallActive = false
var glooWallTimer = 0.0
var glooWallX = 0.0
var glooWallY = 0.0
var muzzleFlashTimer = 0.0

// Controls
var isW = false; var isS = false; var isA = false; var isD = false
var isFiring = false

// Unlocks
var isHarshalUnlocked = true
var isFireUnlocked = false
var isWaterUnlocked = false
var isBixuuUnlocked = false

val HARSHAL_PRICE = 200
val FIRE_PRICE = 200
val WATER_PRICE = 200
val BIXUU_PRICE = 500

var isFrozen = false
var freezeTimer = 0.0

// ============================================================
// GAME CLASSES: KILLERS & BULLETS
// ============================================================
class Killer(var x: Double, var y: Double, var speed: Double, var health: Double, var isBoss: Boolean = false) {
  var isAlive = true
  var attackTimer = 0.0
  val maxHealth = health

  def update(pX: Double, pY: Double) {
    if (isAlive) {
      if (!isFrozen) {
        // Killer player kade dhavat yenar
        val angle = math.atan2(pY - y, pX - x)
        x += math.cos(angle) * speed
        y += math.sin(angle) * speed
      }
      attackTimer += 0.016
    }
  }

  def draw(canvas: CanvasDraw) {
    if (isAlive) {
      canvas.noStroke()
      // Shadow
      canvas.fill(0, 0, 0, 90)
      canvas.ellipse(x, y - 18, if(isBoss) 60 else 32, 12)

      if (isBoss) {
        // BIXUU BOSS KILLER
        canvas.fill(110, 0, 180); canvas.rect(x - 22, y - 25, 44, 50)
        canvas.fill(255, 215, 0); canvas.ellipse(x, y + 25, 32, 32)
        canvas.fill(255, 0, 0); canvas.ellipse(x - 7, y + 27, 7, 7); canvas.ellipse(x + 7, y + 27, 7, 7)

        // Health Bar for Boss
        canvas.fill(40, 40, 40); canvas.rect(x - 35, y + 48, 70, 8)
        canvas.fill(255, 0, 0); canvas.rect(x - 35, y + 48, 70 * (math.max(0.0, health) / maxHealth), 8)
      } else {
        // RED DANGEROUS KILLERS
        if (isFrozen) canvas.fill(0, 200, 255) else canvas.fill(220, 20, 20)
        canvas.rect(x - 12, y - 18, 24, 32)
        canvas.fill(255, 220, 180); canvas.ellipse(x, y + 16, 18, 18)
        // Red Eyes
        canvas.fill(255, 0, 0); canvas.ellipse(x - 4, y + 18, 4, 4); canvas.ellipse(x + 4, y + 18, 4, 4)
        // Knife / Weapon
        canvas.fill(180, 180, 180); canvas.rect(x + 12, y - 5, 12, 4)
      }
    }
  }
}

class Bullet(var x: Double, var y: Double, var vx: Double, var vy: Double, var damage: Double, var isEnemyBullet: Boolean) {
  var active = true

  def update() {
    x += vx
    y += vy
    if (x < 0 || x > cwidth || y < 0 || y > cheight) active = false
  }

  def draw(canvas: CanvasDraw) {
    if (active) {
      canvas.noStroke()
      if (isEnemyBullet) {
        canvas.fill(255, 80, 0); canvas.ellipse(x, y, 8, 8)
      } else {
        canvas.fill(255, 255, 100); canvas.ellipse(x, y, 12, 12)
        canvas.fill(255, 180, 0, 180); canvas.ellipse(x - vx*0.4, y - vy*0.4, 8, 8)
      }
    }
  }
}

val killers = ArrayBuffer.empty[Killer]
val bullets = ArrayBuffer.empty[Bullet]

// ============================================================
// HELPER FUNCTIONS & SETUP
// ============================================================
def startLevel(lvl: Int) {
  currentLevel = lvl
  playerX = cwidth / 2.0
  playerY = 80.0
  playerHealth = 100.0
  glooWallActive = false
  killersKilledInLevel = 0
  earnedCoinsThisLevel = 0

  killers.clear()
  bullets.clear()

  // Target Killers per Level Part
  targetKillersInLevel = lvl match {
    case 1 => 5
    case 2 => 8
    case 3 => 10
    case 4 => 12
    case 5 => 15 // LAST PART: 15 KILLERS + BOSS
  }

  // Spawn Killers from 5 Parts of Jungle
  for (i <- 1 to targetKillersInLevel) {
    val spawnPart = i % 5
    val (kX, kY) = spawnPart match {
      case 0 => (50.0, cheight - 80.0)             // Top Left Jungle
      case 1 => (cwidth - 50.0, cheight - 80.0)    // Top Right Jungle
      case 2 => (50.0, 150.0)                      // Bottom Left
      case 3 => (cwidth - 50.0, 150.0)             // Bottom Right
      case 4 => (cwidth / 2.0, cheight - 60.0)     // Center Top Jungle
    }
    killers.append(new Killer(kX + (math.random() * 40 - 20), kY + (math.random() * 40 - 20), 1.2 + (lvl * 0.25), 50))
  }

  if (lvl == 5) {
    killers.append(new Killer(cwidth / 2, cheight / 2 + 100, 2.0, 500, isBoss = true))
  }

  screen = 2 // Air Jet Landing
}

def isColliding(x1: Double, y1: Double, r1: Double, x2: Double, y2: Double, r2: Double): Boolean = {
  val dx = x1 - x2; val dy = y1 - y2
  math.sqrt(dx * dx + dy * dy) < (r1 + r2)
}

def fireGun() {
  val currentTime = System.currentTimeMillis() / 1000.0
  if (currentTime - lastShotTime >= gunFireRate) {
    lastShotTime = currentTime
    muzzleFlashTimer = 0.05

    var targetX = playerX + 300.0
    var targetY = playerY

    val activeKillers = killers.filter(_.isAlive)
    if (activeKillers.nonEmpty) {
      val nearest = activeKillers.minBy(k => math.hypot(k.x - playerX, k.y - playerY))
      targetX = nearest.x
      targetY = nearest.y
    }

    val angle = math.atan2(targetY - playerY, targetX - playerX)
    val speed = 22.0 // Fast Bullet Speed

    bullets.append(new Bullet(playerX, playerY, math.cos(angle) * speed, math.sin(angle) * speed, gunDamage, false))
  }
}

def useMedkit() {
  playerHealth = (playerHealth + 50.0).min(maxPlayerHealth)
}

def useSpecialPower() {
  if (selectedAvatar == 1) {
    killers.foreach { k => if (k.isAlive) k.health -= 500.0 }
  } else if (selectedAvatar == 2) {
    isFrozen = true; freezeTimer = 5.0
  } else if (selectedAvatar == 3) {
    isFrozen = true; freezeTimer = 6.0
    killers.foreach { k => if (k.isAlive) k.health -= 999.0 }
  }
}

def drawPlayerAvatar(canvas: CanvasDraw, x: Double, y: Double, avatarType: Int) {
  canvas.noStroke()
  canvas.fill(0, 0, 0, 90); canvas.ellipse(x, y - 20, 32, 10)

  avatarType match {
    case 0 => canvas.fill(40, 180, 70); canvas.rect(x - 12, y - 20, 24, 30); canvas.fill(255, 220, 180); canvas.ellipse(x, y + 15, 18, 18)
    case 1 => canvas.fill(230, 60, 10); canvas.rect(x - 12, y - 20, 24, 30); canvas.fill(255, 200, 100); canvas.ellipse(x, y + 15, 18, 18)
    case 2 => canvas.fill(0, 130, 240); canvas.rect(x - 12, y - 20, 24, 30); canvas.fill(200, 240, 255); canvas.ellipse(x, y + 15, 18, 18)
    case 3 => canvas.fill(140, 0, 210); canvas.rect(x - 15, y - 22, 30, 34); canvas.fill(255, 215, 0); canvas.ellipse(x, y + 16, 22, 22)
  }

  canvas.fill(30, 30, 30); canvas.rect(x + 8, y - 2, 18, 6)
}

// ============================================================
// GAME SCREENS
// ============================================================

def drawIntroLetterScreen(canvas: CanvasDraw) {
  canvas.background(12, 14, 20)
  canvas.fill(25, 28, 40); canvas.stroke(255, 60, 60); canvas.strokeWeight(3)
  canvas.rect(cwidth/2 - 270, cheight/2 - 180, 540, 360)

  canvas.fill(255, 60, 60); canvas.text("--- MISSION BRIEFING: KILLER JUNGLE ---", cwidth/2 - 190, cheight/2 + 140)
  canvas.fill(230, 230, 230)
  canvas.text("?????? ?????? KILLERS ????????? ????? ?????!", cwidth/2 - 210, cheight/2 + 80)
  canvas.text("?????????: W, A, S, D = ????? | F = ??-??? ????? ???????", cwidth/2 - 220, cheight/2 + 40)
  canvas.text("????? ?% ????? ??? ???????? M ????? / ????? ???? Medkit ?????!", cwidth/2 - 240, cheight/2 + 10)

  canvas.fill(0, 200, 100); canvas.noStroke(); canvas.rect(cwidth/2 - 110, cheight/2 - 120, 220, 50)
  canvas.fill(255, 255, 255); canvas.text("START MISSION", cwidth/2 - 65, cheight/2 - 90)
}

def drawAvatarSelectionScreen(canvas: CanvasDraw) {
  canvas.background(15, 18, 30)
  canvas.fill(255, 255, 255); canvas.text("CHOOSE YOUR AVATAR (PART CLEAR REWARD)", cwidth/2 - 180, cheight - 50)
  canvas.fill(255, 215, 0); canvas.text(s"TOTAL COINS: $totalCoins", cwidth/2 - 75, cheight - 80)

  val boxW = 120.0; val boxH = 180.0; val startY = cheight/2 - 50.0

  // Harshal
  canvas.fill(30, 50, 30); canvas.stroke(0, 255, 0); canvas.rect(cwidth/2 - 270, startY, boxW, boxH)
  drawPlayerAvatar(canvas, cwidth/2 - 210, startY + 110, 0)
  canvas.fill(255, 255, 255); canvas.text("HARSHAL", cwidth/2 - 245, startY + 40)

  // Fire
  canvas.fill(50, 20, 10); canvas.stroke(255, 100, 0); canvas.rect(cwidth/2 - 130, startY, boxW, boxH)
  drawPlayerAvatar(canvas, cwidth/2 - 70, startY + 110, 1)
  canvas.fill(255, 255, 255); canvas.text("FIRE", cwidth/2 - 90, startY + 40)
  canvas.text(if(isFireUnlocked) "SELECT" else "200 COINS", cwidth/2 - 110, startY + 15)

  // Water
  canvas.fill(10, 30, 60); canvas.stroke(0, 150, 255); canvas.rect(cwidth/2 + 10, startY, boxW, boxH)
  drawPlayerAvatar(canvas, cwidth/2 + 70, startY + 110, 2)
  canvas.fill(255, 255, 255); canvas.text("WATER", cwidth/2 + 45, startY + 40)
  canvas.text(if(isWaterUnlocked) "SELECT" else "200 COINS", cwidth/2 + 25, startY + 15)

  // Bixuu
  canvas.fill(40, 10, 50); canvas.stroke(200, 0, 255); canvas.rect(cwidth/2 + 150, startY, boxW, boxH)
  drawPlayerAvatar(canvas, cwidth/2 + 210, startY + 110, 3)
  canvas.fill(255, 215, 0); canvas.text("BIXUU", cwidth/2 + 185, startY + 40)
  canvas.text(if(isBixuuUnlocked) "SELECT" else "500 COINS", cwidth/2 + 165, startY + 15)
}

def drawGunSelectionScreen(canvas: CanvasDraw) {
  canvas.background(20, 25, 35)
  canvas.fill(255, 215, 0); canvas.text("SELECT YOUR GUN SPEED", cwidth/2 - 100, cheight - 60)

  val boxW = 130.0; val boxH = 170.0; val startY = cheight/2 - 40.0

  canvas.fill(40, 45, 55); canvas.stroke(200, 200, 200); canvas.rect(cwidth/2 - 280, startY, boxW, boxH)
  canvas.fill(255, 255, 255); canvas.text("DESERT EAGLE", cwidth/2 - 275, startY + 100)

  canvas.fill(40, 45, 55); canvas.stroke(255, 150, 0); canvas.rect(cwidth/2 - 135, startY, boxW, boxH)
  canvas.fill(255, 255, 255); canvas.text("MP40 RAPID", cwidth/2 - 125, startY + 100)

  canvas.fill(40, 45, 55); canvas.stroke(255, 50, 50); canvas.rect(cwidth/2 + 10, startY, boxW, boxH)
  canvas.fill(255, 255, 255); canvas.text("SHOTGUN", cwidth/2 + 35, startY + 100)

  canvas.fill(40, 45, 55); canvas.stroke(0, 255, 200); canvas.rect(cwidth/2 + 155, startY, boxW, boxH)
  canvas.fill(0, 255, 200); canvas.text("AWM SNIPER", cwidth/2 + 170, startY + 100)
}

def drawLandingScreen(canvas: CanvasDraw) {
  canvas.background(30, 120, 220)
  canvas.fill(255, 255, 255); canvas.text("LANDING IN JUNGLE PARTS...", cwidth/2 - 100, cheight - 80)
  canvas.fill(190, 190, 200); canvas.ellipse(cwidth/2, cheight - 160, 160, 40)
  canvas.fill(255, 120, 0); canvas.rect(cwidth/2 - 170, cheight/2 - 50, 340, 60)
  canvas.fill(255, 255, 255); canvas.text("CLICK HERE TO FIGHT KILLERS", cwidth/2 - 110, cheight/2 - 15)
}

def drawGameplayScreen(canvas: CanvasDraw) {
  // Jungle Background
  canvas.background(25, 40, 25)

  if (glooWallActive) {
    canvas.fill(0, 200, 255, 180); canvas.rect(glooWallX - 10, glooWallY - 35, 20, 70)
    glooWallTimer -= 0.016
    if (glooWallTimer <= 0) glooWallActive = false
  }

  if (muzzleFlashTimer > 0) {
    canvas.fill(255, 240, 100); canvas.ellipse(playerX + 24, playerY - 2, 20, 20)
    muzzleFlashTimer -= 0.016
  }

  if (isFiring) fireGun()

  // Bullet Updating & Hit Detection
  bullets.foreach { b =>
    b.update(); b.draw(canvas)
    if (!b.isEnemyBullet && b.active) {
      killers.foreach { k =>
        if (k.isAlive && isColliding(b.x, b.y, 8, k.x, k.y, if(k.isBoss) 30 else 16)) {
          k.health -= b.damage
          b.active = false
          if (k.health <= 0) {
            k.isAlive = false
            killersKilledInLevel += 1
            // KILLER MARLYAVARACH COIN MILNAR!
            val reward = if(k.isBoss) 200 else 20
            totalCoins += reward
            earnedCoinsThisLevel += reward
          }
        }
      }
    }
  }

  // Killers Attack & Damage
  killers.foreach { k =>
    k.update(playerX, playerY)
    k.draw(canvas)

    if (k.isAlive) {
      // Direct Touch / Attack Damage to Player
      if (isColliding(k.x, k.y, 16, playerX, playerY, playerRadius)) {
        playerHealth -= 0.8 // Health drops continuously when killer touches
      }

      // Boss Shoots Fast Bullets
      if (k.isBoss && k.attackTimer > 0.6) {
        k.attackTimer = 0.0
        val angle = math.atan2(playerY - k.y, playerX - k.x)
        bullets.append(new Bullet(k.x, k.y, math.cos(angle) * 8, math.sin(angle) * 8, 15, true))
      }
    }
  }

  drawPlayerAvatar(canvas, playerX, playerY, selectedAvatar)

  // HUD & DISPLAY
  canvas.fill(15, 15, 20); canvas.rect(0, cheight - 50, cwidth, 50)
  canvas.fill(255, 255, 255); canvas.text(s"PART/LEVEL: $currentLevel/5", 15, cheight - 20)
  canvas.fill(255, 215, 0); canvas.text(s"COINS: $totalCoins", 140, cheight - 20)
  canvas.fill(255, 80, 80); canvas.text(s"KILLERS LEFT: ${killers.count(_.isAlive)}", 250, cheight - 20)

  // Health Bar
  canvas.fill(80, 0, 0); canvas.rect(400, cheight - 35, 120, 18)
  canvas.fill(0, 255, 0); canvas.rect(400, cheight - 35, 120 * (math.max(0.0, playerHealth) / maxPlayerHealth), 18)

  // CRITICAL HEALTH & MEDKIT OPTION (Triggered when health drops low)
  if (playerHealth <= 50.0 && playerHealth > 0) {
    canvas.fill(220, 30, 30); canvas.rect(535, cheight - 42, 180, 32)
    canvas.fill(255, 255, 255); canvas.text("? MEDKIT READY [M]", 545, cheight - 20)
  }

  // Game Status Checks
  if (playerHealth <= 0) {
    screen = 4 // Game Over
  } else if (killers.forall(!_.isAlive)) {
    if (currentLevel == 5) screen = 6 else screen = 5 // Victory Screen
  }
}

def drawGameOverScreen(canvas: CanvasDraw) {
  canvas.background(40, 10, 10)
  canvas.fill(255, 255, 255); canvas.text("KILLERS ELIMINATED YOU!", cwidth/2 - 100, cheight/2 + 40)
  canvas.fill(200, 30, 30); canvas.rect(cwidth/2 - 80, cheight/2 - 30, 160, 45)
  canvas.fill(255, 255, 255); canvas.text("RETRY PART", cwidth/2 - 40, cheight/2 - 2)
}

def drawLevelClearScreen(canvas: CanvasDraw) {
  canvas.background(15, 25, 20)
  canvas.fill(25, 45, 35); canvas.stroke(255, 215, 0); canvas.strokeWeight(3)
  canvas.rect(cwidth/2 - 200, cheight/2 - 120, 400, 240)

  canvas.fill(255, 215, 0); canvas.text(s"PART $currentLevel CLEARED!", cwidth/2 - 80, cheight/2 + 80)
  canvas.fill(255, 255, 255); canvas.text(s"EARNED $earnedCoinsThisLevel COINS FROM KILLERS!", cwidth/2 - 130, cheight/2 + 30)

  canvas.fill(0, 180, 80); canvas.noStroke()
  canvas.rect(cwidth/2 - 110, cheight/2 - 80, 220, 45)
  canvas.fill(255, 255, 255); canvas.text("SELECT AVATAR / NEXT PART", cwidth/2 - 100, cheight/2 - 52)
}

def drawFinalThankYouLetter(canvas: CanvasDraw) {
  canvas.background(20, 10, 35)
  canvas.fill(35, 20, 55); canvas.stroke(255, 215, 0); canvas.strokeWeight(4)
  canvas.rect(cwidth/2 - 260, cheight/2 - 160, 520, 320)

  canvas.fill(255, 215, 0); canvas.text("? ALL KILLERS DESTROYED! ?", cwidth/2 - 140, cheight/2 + 110)
  canvas.fill(255, 255, 255)
  canvas.text("???????? ?? KILLERS ?? ??? BIXUU ?? ?????? ????? ???!", cwidth/2 - 200, cheight/2 + 60)
  canvas.text("?????? ???? ? ???????? ????????? ??? ?????? ????!", cwidth/2 - 170, cheight/2 + 30)

  canvas.fill(0, 255, 150)
  canvas.text("Thank you! This completed the mission.", cwidth/2 - 160, cheight/2 - 20)
  canvas.text("Thank you! Thank you! Thank you!", cwidth/2 - 140, cheight/2 - 50)

  canvas.fill(220, 50, 50); canvas.noStroke(); canvas.rect(cwidth/2 - 90, cheight/2 - 130, 180, 45)
  canvas.fill(255, 255, 255); canvas.text("MAIN MENU", cwidth/2 - 40, cheight/2 - 102)
}

// ============================================================
// LISTENERS
// ============================================================

onKeyPress { key =>
  if (key == Kc.VK_W || key == 87) isW = true
  if (key == Kc.VK_S || key == 83) isS = true
  if (key == Kc.VK_A || key == 65) isA = true
  if (key == Kc.VK_D || key == 68) isD = true
  if (key == Kc.VK_F || key == 70) isFiring = true
  if (key == Kc.VK_M || key == 77) useMedkit() // MEDKIT KEY
  if (key == Kc.VK_G || key == 71) { glooWallActive = true; glooWallTimer = 3.5; glooWallX = playerX + 35; glooWallY = playerY }
  if (key == Kc.VK_E || key == 69) useSpecialPower()
}

onKeyRelease { key =>
  if (key == Kc.VK_W || key == 87) isW = false
  if (key == Kc.VK_S || key == 83) isS = false
  if (key == Kc.VK_A || key == 65) isA = false
  if (key == Kc.VK_D || key == 68) isD = false
  if (key == Kc.VK_F || key == 70) isFiring = false
}

onMouseClick { (x, y) =>
  if (screen == -1) {
    if (x >= cwidth/2 - 110 && x <= cwidth/2 + 110 && y >= cheight/2 - 120 && y <= cheight/2 - 70) screen = 0
  }
  else if (screen == 0) { // Avatar Select
    val startY = cheight/2 - 50.0
    if (y >= startY && y <= startY + 180) {
      if (x >= cwidth/2 - 270 && x <= cwidth/2 - 150) { selectedAvatar = 0; screen = 1 }
      else if (x >= cwidth/2 - 130 && x <= cwidth/2 - 10) {
        if (isFireUnlocked) { selectedAvatar = 1; screen = 1 }
        else if (totalCoins >= FIRE_PRICE) { totalCoins -= FIRE_PRICE; isFireUnlocked = true; selectedAvatar = 1; screen = 1 }
      }
      else if (x >= cwidth/2 + 10 && x <= cwidth/2 + 130) {
        if (isWaterUnlocked) { selectedAvatar = 2; screen = 1 }
        else if (totalCoins >= WATER_PRICE) { totalCoins -= WATER_PRICE; isWaterUnlocked = true; selectedAvatar = 2; screen = 1 }
      }
      else if (x >= cwidth/2 + 150 && x <= cwidth/2 + 270) {
        if (isBixuuUnlocked) { selectedAvatar = 3; screen = 1 }
        else if (totalCoins >= BIXUU_PRICE) { totalCoins -= BIXUU_PRICE; isBixuuUnlocked = true; selectedAvatar = 3; screen = 1 }
      }
    }
  }
  else if (screen == 1) {
    startLevel(currentLevel)
  }
  else if (screen == 2) {
    if (x >= cwidth/2 - 170 && x <= cwidth/2 + 170 && y >= cheight/2 - 50 && y <= cheight/2 + 10) screen = 3
  }
  else if (screen == 3) {
    // MEDKIT CLICK OPTION
    if (playerHealth <= 50.0 && x >= 535 && x <= 715 && y >= cheight - 42) useMedkit()
  }
  else if (screen == 4) {
    if (x >= cwidth/2 - 80 && x <= cwidth/2 + 80 && y >= cheight/2 - 30 && y <= cheight/2 + 15) startLevel(currentLevel)
  }
  else if (screen == 5) { // Next Level / Part
    if (x >= cwidth/2 - 110 && x <= cwidth/2 + 110 && y >= cheight/2 - 80 && y <= cheight/2 - 35) {
      currentLevel += 1
      screen = 0 // Show Avatar Selection Screen before starting next part
    }
  }
  else if (screen == 6) {
    if (x >= cwidth/2 - 90 && x <= cwidth/2 + 90 && y >= cheight/2 - 130 && y <= cheight/2 - 85) {
      currentLevel = 1
      screen = 0
    }
  }
}

// MAIN ANIMATION LOOP
animateWithCanvasDraw { canvas =>
  if (screen == -1) drawIntroLetterScreen(canvas)
  else if (screen == 0) drawAvatarSelectionScreen(canvas)
  else if (screen == 1) drawGunSelectionScreen(canvas)
  else if (screen == 2) drawLandingScreen(canvas)
  else if (screen == 3) {
    val moveSpeed = if (selectedAvatar == 0 || selectedAvatar == 3) 8.5 else 6.0
    if (isW && playerY < cheight - 70) playerY += moveSpeed
    if (isS && playerY > 40) playerY -= moveSpeed
    if (isA && playerX > 40) playerX -= moveSpeed
    if (isD && playerX < cwidth - 40) playerX += moveSpeed

    if (freezeTimer > 0) {
      freezeTimer -= 0.016
      if (freezeTimer <= 0) isFrozen = false
    }

    drawGameplayScreen(canvas)
  }
  else if (screen == 4) drawGameOverScreen(canvas)
  else if (screen == 5) drawLevelClearScreen(canvas)
  else if (screen == 6) drawFinalThankYouLetter(canvas)
}