Code Sketch


Bixuu spring season event 9
By: Mhalsakant School
Category: Programming
import java.awt.{AlphaComposite, BasicStroke, Color, Dimension, Font, GradientPaint, Graphics, Graphics2D, Polygon, RenderingHints}
import java.awt.event.{ActionEvent, ActionListener, KeyEvent, KeyListener, MouseEvent, MouseListener, MouseMotionListener}
import java.io.{File, FileInputStream, FileOutputStream}
import java.util.Properties
import javax.swing.{JFrame, JOptionPane, JPanel, SwingUtilities, Timer}
import scala.collection.mutable.ArrayBuffer
import scala.util.Random

object CosmicEclipseEvent8 {
  def main(args: Array[String]): Unit = {
    SwingUtilities.invokeLater(new Runnable {
      override def run(): Unit = {
        var chosenName = "STAR EXPLORER"
        try {
          val answer = JOptionPane.showInputDialog(null, "Enter your explorer name:", "COSMIC ECLIPSE - EVENT 8", JOptionPane.QUESTION_MESSAGE)
          if (answer != null && answer.trim.length > 0) chosenName = answer.trim.take(16)
        } catch {
          case _: Throwable => chosenName = "STAR EXPLORER"
        }
        val frame = new JFrame("SPRING SEASON EVENT 8 - COSMIC ECLIPSE")
        val game = new CosmicEclipsePanel(chosenName)
        
        frame.setContentPane(game)
        frame.pack()
        frame.setResizable(false)
        frame.setLocationRelativeTo(null)
        frame.setVisible(true)
        game.requestFocusInWindow()
      }
    })
  }
}

class EclipseShard(var x: Double, var y: Double, val phase: Double, var taken: Boolean)
class EclipseComet(var x: Double, var y: Double, val radius: Int, val speed: Double, val drift: Double)

class CosmicEclipsePanel(val playerName: String)
  extends JPanel with KeyListener with MouseListener with MouseMotionListener {

  private val screenWidth = 1000
  private val screenHeight = 700
  private val random = new Random()
  private val backgroundStars: Array[(Int, Int, Int, Int)] = Array.tabulate(150) { i =>
    (random.nextInt(screenWidth), random.nextInt(screenHeight), 1 + random.nextInt(3), 100 + random.nextInt(156))
  }
  private val saveFile = new File(System.getProperty("user.home"), ".cosmic_eclipse_event8.properties")

  private var screen = "MENU"
  private var tick = 0
  private var level = 1
  private var unlockedLevel = 1
  private var coins = 120
  private var totalCrystals = 0
  private var bestScore = 0
  private var score = 0
  private var lives = 3
  private var collected = 0
  private var target = 5
  private var energy = 100.0
  private var shieldFrames = 0
  private var dashFrames = 0
  private var hitCooldown = 0
  private var pulseFrames = 0
  private var shieldUpgrade = 0
  private var magnetUpgrade = 0
  private var dashUpgrade = 0
  private var playerX = 500.0
  private var playerY = 530.0
  private var mouseX = 500
  private var mouseY = 350
  private val pressedKeys = scala.collection.mutable.Set[Int]()
  private val shards = ArrayBuffer[EclipseShard]()
  private val comets = ArrayBuffer[EclipseComet]()

  setPreferredSize(new Dimension(screenWidth, screenHeight))
  setFocusable(true)
  setFocusTraversalKeysEnabled(false)
  addKeyListener(this)
  addMouseListener(this)
  addMouseMotionListener(this)
  setBackground(new Color(5, 7, 25))

  loadProgress()

  private val animationTimer = new Timer(16, new ActionListener {
    override def actionPerformed(e: ActionEvent): Unit = updateGame()
  })
  animationTimer.start()

  private def loadProgress(): Unit = {
    if (saveFile.exists()) {
      val props = new Properties()
      var in: FileInputStream = null
      try {
        in = new FileInputStream(saveFile)
        props.load(in)
        coins = math.max(0, props.getProperty("coins", "120").toInt)
        totalCrystals = math.max(0, props.getProperty("crystals", "0").toInt)
        bestScore = math.max(0, props.getProperty("bestScore", "0").toInt)
        unlockedLevel = math.max(1, math.min(12, props.getProperty("unlockedLevel", "1").toInt))
        shieldUpgrade = math.max(0, math.min(3, props.getProperty("shieldUpgrade", "0").toInt))
        magnetUpgrade = math.max(0, math.min(3, props.getProperty("magnetUpgrade", "0").toInt))
        dashUpgrade = math.max(0, math.min(3, props.getProperty("dashUpgrade", "0").toInt))
      } catch {
        case _: Throwable => ()
      } finally {
        if (in != null) {
          try { in.close() } catch { case _: Throwable => () }
        }
      }
    }
  }

  private def saveProgress(): Unit = {
    val props = new Properties()
    props.setProperty("player", playerName)
    props.setProperty("coins", coins.toString)
    props.setProperty("crystals", totalCrystals.toString)
    props.setProperty("bestScore", bestScore.toString)
    props.setProperty("unlockedLevel", unlockedLevel.toString)
    props.setProperty("shieldUpgrade", shieldUpgrade.toString)
    props.setProperty("magnetUpgrade", magnetUpgrade.toString)
    props.setProperty("dashUpgrade", dashUpgrade.toString)
    var out: FileOutputStream = null
    try {
      out = new FileOutputStream(saveFile)
      props.store(out, "Cosmic Eclipse Event 8 progress")
    } catch {
      case _: Throwable => ()
    } finally {
      if (out != null) {
        try { out.close() } catch { case _: Throwable => () }
      }
    }
  }

  private def startLevel(number: Int): Unit = {
    level = math.max(1, math.min(12, number))
    score = 0
    lives = 3
    collected = 0
    target = 4 + level
    energy = 100.0
    shieldFrames = 0
    dashFrames = 0
    hitCooldown = 0
    pulseFrames = 0
    playerX = screenWidth / 2.0
    playerY = screenHeight - 115.0
    shards.clear()
    comets.clear()
    var i = 0
    while (i < target + 3) {
      val sx = 55 + random.nextInt(screenWidth - 110)
      val sy = 100 + random.nextInt(screenHeight - 220)
      shards += new EclipseShard(sx.toDouble, sy.toDouble, random.nextDouble() * 6.28, false)
      i += 1
    }
    val cometCount = math.min(12, 2 + level)
    i = 0
    while (i < cometCount) {
      val cx = 45 + random.nextInt(screenWidth - 90)
      val cy = -random.nextInt(screenHeight)
      val radius = 14 + random.nextInt(13)
      val speed = 1.25 + level * 0.18 + random.nextDouble() * 0.8
      val drift = -0.8 + random.nextDouble() * 1.6
      comets += new EclipseComet(cx.toDouble, cy.toDouble, radius, speed, drift)
      i += 1
    }
    screen = "PLAY"
    requestFocusInWindow()
  }

  private def updateGame(): Unit = {
    tick += 1
    if (screen == "PLAY") {
      updatePlayer()
      updateShards()
      updateComets()
      if (energy < 100.0) energy = math.min(100.0, energy + 0.10)
      if (shieldFrames > 0) shieldFrames -= 1
      if (dashFrames > 0) dashFrames -= 1
      if (hitCooldown > 0) hitCooldown -= 1
      if (pulseFrames > 0) pulseFrames -= 1
      if (screen == "PLAY" && collected >= target) completeLevel()
    }
    repaint()
  }

  private def updatePlayer(): Unit = {
    var speed = 4.0 + dashUpgrade * 0.45
    if (dashFrames > 0) speed = speed + 3.2
    if (pressedKeys.contains(KeyEvent.VK_W) || pressedKeys.contains(KeyEvent.VK_UP)) playerY -= speed
    if (pressedKeys.contains(KeyEvent.VK_S) || pressedKeys.contains(KeyEvent.VK_DOWN)) playerY += speed
    if (pressedKeys.contains(KeyEvent.VK_A) || pressedKeys.contains(KeyEvent.VK_LEFT)) playerX -= speed
    if (pressedKeys.contains(KeyEvent.VK_D) || pressedKeys.contains(KeyEvent.VK_RIGHT)) playerX += speed
    playerX = math.max(28.0, math.min(screenWidth - 28.0, playerX))
    playerY = math.max(92.0, math.min(screenHeight - 45.0, playerY))
  }

  private def updateShards(): Unit = {
    val magnetRange = 22.0 + magnetUpgrade * 22.0
    var i = 0
    while (i < shards.length) {
      val shard = shards(i)
      if (!shard.taken) {
        val dx = playerX - shard.x
        val dy = playerY - shard.y
        val distance = math.sqrt(dx * dx + dy * dy)
        if (magnetUpgrade > 0 && distance < magnetRange && distance > 0.1) {
          shard.x += dx / distance * 1.8
          shard.y += dy / distance * 1.8
        }
        if (distance < 29.0) {
          shard.taken = true
          collected += 1
          totalCrystals += 1
          score += 100 + level * 10
          coins += 8 + level
          energy = math.min(100.0, energy + 8.0)
        }
      }
      i += 1
    }
  }

  private def updateComets(): Unit = {
    var i = 0
    while (i < comets.length) {
      val comet = comets(i)
      comet.y += comet.speed
      comet.x += math.sin((tick + i * 19) / 35.0) * comet.drift
      if (comet.y > screenHeight + 40) {
        comet.y = -comet.radius.toDouble - random.nextInt(160)
        comet.x = 35 + random.nextInt(screenWidth - 70)
      }
      val dx = playerX - comet.x
      val dy = playerY - comet.y
      val hitDistance = comet.radius + 17.0
      if (dx * dx + dy * dy < hitDistance * hitDistance && hitCooldown <= 0) {
        if (shieldFrames <= 0) {
          lives -= 1
          hitCooldown = 65
          energy = math.max(0.0, energy - 12.0)
          if (lives <= 0) {
            screen = "GAMEOVER"
            if (score > bestScore) bestScore = score
            saveProgress()
          }
        } else {
          comet.y = screenHeight + 80.0
        }
      }
      i += 1
    }
  }

  private def completeLevel(): Unit = {
    val reward = 80 + level * 20
    coins += reward
    score += reward
    if (score > bestScore) bestScore = score
    if (level < 12) unlockedLevel = math.max(unlockedLevel, level + 1)
    saveProgress()
    screen = "COMPLETE"
  }

  private def usePulse(): Unit = {
    if (screen == "PLAY" && energy >= 25.0) {
      energy -= 25.0
      pulseFrames = 18
      var i = 0
      while (i < comets.length) {
        val comet = comets(i)
        val dx = mouseX - comet.x
        val dy = mouseY - comet.y
        if (dx * dx + dy * dy < 150.0 * 150.0) {
          comet.y = screenHeight + 100.0
          score += 25
        }
        i += 1
      }
    }
  }

  private def activateShield(): Unit = {
    if (screen == "PLAY" && energy >= 35.0 && shieldFrames <= 0) {
      energy -= 35.0
      shieldFrames = 150 + shieldUpgrade * 45
    }
  }

  private def activateDash(): Unit = {
    if (screen == "PLAY" && energy >= 12.0 && dashFrames <= 0) {
      energy -= 12.0
      dashFrames = 22
    }
  }

  private def isInside(x: Int, y: Int, left: Int, top: Int, width: Int, height: Int): Boolean = {
    x >= left && x <= left + width && y >= top && y <= top + height
  }

  private def buyUpgrade(which: Int): Unit = {
    val current = if (which == 0) shieldUpgrade else if (which == 1) magnetUpgrade else dashUpgrade
    val cost = 100 + current * 100
    if (current < 3 && coins >= cost) {
      coins -= cost
      if (which == 0) shieldUpgrade += 1
      else if (which == 1) magnetUpgrade += 1
      else dashUpgrade += 1
      saveProgress()
    }
  }

  private def handleMouse(x: Int, y: Int): Unit = {
    mouseX = x
    mouseY = y
    if (screen == "MENU") {
      if (isInside(x, y, 370, 300, 260, 54)) startLevel(unlockedLevel)
      else if (isInside(x, y, 370, 366, 260, 54)) screen = "LEVELS"
      else if (isInside(x, y, 370, 432, 260, 54)) screen = "SHOP"
      else if (isInside(x, y, 370, 498, 260, 54)) screen = "CONTROLS"
    } else if (screen == "LEVELS") {
      if (isInside(x, y, 35, 610, 145, 48)) screen = "MENU"
      else if (x >= 205 && x <= 795 && y >= 190 && y <= 535) {
        val column = (x - 205) / 200
        val row = (y - 190) / 86
        val chosen = row * 3 + column + 1
        if (chosen >= 1 && chosen <= 12 && chosen <= unlockedLevel) startLevel(chosen)
      }
    } else if (screen == "SHOP") {
      if (isInside(x, y, 35, 610, 145, 48)) screen = "MENU"
      else if (isInside(x, y, 202, 385, 166, 48)) buyUpgrade(0)
      else if (isInside(x, y, 417, 385, 166, 48)) buyUpgrade(1)
      else if (isInside(x, y, 632, 385, 166, 48)) buyUpgrade(2)
    } else if (screen == "CONTROLS") {
      if (isInside(x, y, 35, 610, 145, 48)) screen = "MENU"
    } else if (screen == "PLAY") {
      usePulse()
    } else if (screen == "PAUSE") {
      if (isInside(x, y, 370, 340, 260, 54)) screen = "PLAY"
      else if (isInside(x, y, 370, 406, 260, 54)) screen = "MENU"
    } else if (screen == "COMPLETE") {
      if (isInside(x, y, 370, 390, 260, 54)) {
        if (level < 12) startLevel(level + 1) else screen = "MENU"
      } else if (isInside(x, y, 370, 456, 260, 54)) screen = "MENU"
    } else if (screen == "GAMEOVER") {
      if (isInside(x, y, 370, 390, 260, 54)) startLevel(level)
      else if (isInside(x, y, 370, 456, 260, 54)) screen = "MENU"
    }
    requestFocusInWindow()
    repaint()
  }

  private def centerText(g: Graphics2D, text: String, y: Int, size: Int, color: Color): Unit = {
    g.setFont(new Font("SansSerif", Font.BOLD, size))
    g.setColor(color)
    val metrics = g.getFontMetrics
    g.drawString(text, (screenWidth - metrics.stringWidth(text)) / 2, y)
  }

  private def drawButton(g: Graphics2D, text: String, x: Int, y: Int, width: Int, height: Int, enabled: Boolean): Unit = {
    val base = if (enabled) new Color(39, 91, 151, 220) else new Color(55, 61, 82, 190)
    g.setColor(base)
    g.fillRoundRect(x, y, width, height, 18, 18)
    g.setColor(if (enabled) new Color(112, 224, 255) else new Color(115, 120, 140))
    g.setStroke(new BasicStroke(2.0f))
    g.drawRoundRect(x, y, width, height, 18, 18)
    g.setFont(new Font("SansSerif", Font.BOLD, 18))
    val metrics = g.getFontMetrics
    g.setColor(if (enabled) Color.WHITE else new Color(170, 173, 188))
    g.drawString(text, x + (width - metrics.stringWidth(text)) / 2, y + height / 2 + 6)
  }

  private def drawSpaceBackground(g: Graphics2D): Unit = {
    g.setPaint(new GradientPaint(0.0f, 0.0f, new Color(5, 7, 28), 0.0f, screenHeight.toFloat, new Color(22, 11, 58)))
    g.fillRect(0, 0, screenWidth, screenHeight)
    var i = 0
    while (i < backgroundStars.length) {
      val star = backgroundStars(i)
      val twinkle = 100 + ((Math.sin((tick + i * 13) / 17.0) + 1.0) * 70.0).toInt
      g.setColor(new Color(180, 210, 255, math.min(255, twinkle)))
      g.fillOval(star._1, star._2, star._3, star._3)
      i += 1
    }
    val glow = 75 + ((Math.sin(tick / 80.0) + 1.0) * 35.0).toInt
    g.setColor(new Color(91, 62, 190, glow))
    g.fillOval(615, 75, 255, 255)
    g.setColor(new Color(33, 25, 91))
    g.fillOval(640, 92, 220, 220)
    g.setColor(new Color(113, 91, 196, 170))
    g.setStroke(new BasicStroke(4.0f))
    g.drawOval(625, 76, 250, 250)
    val eclipseSize = 92 + ((Math.sin(tick / 95.0) + 1.0) * 18.0).toInt
    g.setColor(new Color(255, 172, 89, 80))
    g.fillOval(145, 105, 190, 190)
    g.setColor(new Color(255, 209, 123, 220))
    g.drawOval(150, 110, 180, 180)
    g.setColor(new Color(11, 9, 36))
    g.fillOval(190 + (eclipseSize - 92) / 2, 130, eclipseSize, eclipseSize)
    g.setColor(new Color(93, 75, 149, 90))
    g.fillRect(0, 0, screenWidth, screenHeight)
  }

  private def drawTitle(g: Graphics2D): Unit = {
    centerText(g, "SPRING SEASON EVENT 8", 82, 19, new Color(157, 220, 255))
    centerText(g, "COSMIC ECLIPSE", 155, 50, new Color(255, 222, 153))
    centerText(g, "A JOURNEY THROUGH THE SHADOW OF STARS", 190, 15, new Color(198, 190, 245))
  }

  private def drawMenu(g: Graphics2D): Unit = {
    drawTitle(g)
    centerText(g, "WELCOME, " + playerName.toUpperCase, 255, 18, Color.WHITE)
    centerText(g, "CRYSTALS " + totalCrystals + "     COINS " + coins + "     UNLOCKED LEVEL " + unlockedLevel, 280, 15, new Color(255, 220, 140))
    drawButton(g, "START JOURNEY", 370, 300, 260, 54, true)
    drawButton(g, "LEVEL SELECT", 370, 366, 260, 54, true)
    drawButton(g, "COSMIC SHOP", 370, 432, 260, 54, true)
    drawButton(g, "HOW TO PLAY", 370, 498, 260, 54, true)
    centerText(g, "Collect Star Shards. Dodge Comets. Restore the Eclipse Core!", 600, 15, new Color(188, 205, 255))
  }

  private def drawLevels(g: Graphics2D): Unit = {
    drawTitle(g)
    centerText(g, "CHOOSE YOUR DESTINATION", 145, 23, Color.WHITE)
    var i = 1
    while (i <= 12) {
      val column = (i - 1) % 3
      val row = (i - 1) / 3
      val x = 205 + column * 200
      val y = 190 + row * 86
      val available = i <= unlockedLevel
      val label = if (available) "LEVEL " + i else "LOCKED " + i
      drawButton(g, label, x, y, 175, 58, available)
      i += 1
    }
    drawButton(g, "BACK (B)", 35, 610, 145, 48, true)
  }

  private def drawShop(g: Graphics2D): Unit = {
    drawTitle(g)
    centerText(g, "COSMIC UPGRADE STATION", 150, 24, Color.WHITE)
    centerText(g, "YOUR COINS: " + coins, 195, 19, new Color(255, 220, 125))
    val labels = Array("AURA SHIELD", "STAR MAGNET", "LIGHT DASH")
    val descriptions = Array("Longer shield time", "Pull shards closer", "Faster dash movement")
    val levels = Array(shieldUpgrade, magnetUpgrade, dashUpgrade)
    var i = 0
    while (i < 3) {
      val x = 190 + i * 215
      g.setColor(new Color(22, 32, 75, 225))
      g.fillRoundRect(x, 260, 190, 190, 22, 22)
      g.setColor(new Color(109, 200, 255))
      g.drawRoundRect(x, 260, 190, 190, 22, 22)
      g.setFont(new Font("SansSerif", Font.BOLD, 17))
      g.setColor(Color.WHITE)
      g.drawString(labels(i), x + 18, 300)
      g.setFont(new Font("SansSerif", Font.PLAIN, 14))
      g.setColor(new Color(190, 205, 245))
      g.drawString(descriptions(i), x + 18, 330)
      g.drawString("LEVEL " + levels(i) + " / 3", x + 18, 360)
      val cost = 100 + levels(i) * 100
      val buyText = if (levels(i) >= 3) "MAX LEVEL" else "BUY " + cost
      drawButton(g, buyText, x + 12, 385, 166, 48, levels(i) < 3 && coins >= cost)
      i += 1
    }
    drawButton(g, "BACK (B)", 35, 610, 145, 48, true)
  }

  private def drawControls(g: Graphics2D): Unit = {
    drawTitle(g)
    centerText(g, "EXPLORER CONTROLS", 155, 25, Color.WHITE)
    val lines = Array(
      "W A S D / ARROW KEYS  -  MOVE YOUR STAR SHIP",
      "SPACE  -  LIGHT DASH (USES ENERGY)",
      "Q  -  AURA SHIELD (USES ENERGY)",
      "LEFT MOUSE CLICK  -  COSMIC PULSE AT POINTER",
      "P OR ESC  -  PAUSE / RESUME",
      "B  -  RETURN TO MENU",
      "ENTER  -  NEXT LEVEL AFTER COMPLETION",
      "COLLECT THE GOLD STAR SHARDS AND AVOID PURPLE COMETS"
    )
    var i = 0
    while (i < lines.length) {
      g.setFont(new Font("SansSerif", Font.BOLD, 17))
      g.setColor(new Color(215, 225, 255))
      g.drawString(lines(i), 180, 225 + i * 43)
      i += 1
    }
    drawButton(g, "BACK (B)", 35, 610, 145, 48, true)
  }

  private def drawShard(g: Graphics2D, shard: EclipseShard): Unit = {
    if (!shard.taken) {
      val pulse = 2 + ((Math.sin(tick / 12.0 + shard.phase) + 1.0) * 2.0).toInt
      val x = shard.x.toInt
      val y = shard.y.toInt
      g.setColor(new Color(255, 200, 81, 65))
      g.fillOval(x - 15 - pulse, y - 15 - pulse, 30 + pulse * 2, 30 + pulse * 2)
      val diamond = new Polygon()
      diamond.addPoint(x, y - 12 - pulse)
      diamond.addPoint(x + 9 + pulse / 2, y)
      diamond.addPoint(x, y + 12 + pulse)
      diamond.addPoint(x - 9 - pulse / 2, y)
      g.setColor(new Color(255, 222, 111))
      g.fillPolygon(diamond)
      g.setColor(Color.WHITE)
      g.drawLine(x, y - 7, x, y + 6)
    }
  }

  private def drawComet(g: Graphics2D, comet: EclipseComet): Unit = {
    val x = comet.x.toInt
    val y = comet.y.toInt
    g.setStroke(new BasicStroke(5.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND))
    g.setColor(new Color(145, 89, 255, 85))
    g.drawLine(x + 5, y - comet.radius, x - 3, y - comet.radius - 34)
    g.setColor(new Color(161, 107, 255, 210))
    g.fillOval(x - comet.radius, y - comet.radius, comet.radius * 2, comet.radius * 2)
    g.setColor(new Color(225, 209, 255))
    g.fillOval(x - comet.radius / 2, y - comet.radius / 2, comet.radius, comet.radius)
  }

  private def drawPlayer(g: Graphics2D): Unit = {
    val x = playerX.toInt
    val y = playerY.toInt
    if (shieldFrames > 0) {
      g.setStroke(new BasicStroke(3.0f))
      g.setColor(new Color(96, 220, 255, 170))
      g.drawOval(x - 34, y - 34, 68, 68)
      g.setColor(new Color(96, 220, 255, 35))
      g.fillOval(x - 34, y - 34, 68, 68)
    }
    if (hitCooldown > 0 && (tick / 5) % 2 == 0) g.setColor(new Color(255, 255, 255, 130))
    else g.setColor(new Color(89, 220, 255))
    val ship = new Polygon()
    ship.addPoint(x, y - 23)
    ship.addPoint(x + 20, y + 17)
    ship.addPoint(x, y + 9)
    ship.addPoint(x - 20, y + 17)
    g.fillPolygon(ship)
    g.setColor(Color.WHITE)
    g.fillOval(x - 5, y - 4, 10, 10)
    g.setColor(new Color(255, 167, 91, 180))
    g.fillOval(x - 7, y + 15, 14, 20 + (tick % 5))
    if (pulseFrames > 0) {
      g.setStroke(new BasicStroke(3.0f))
      g.setColor(new Color(114, 237, 255, 190))
      g.drawOval(x - 25 - pulseFrames, y - 25 - pulseFrames, 50 + pulseFrames * 2, 50 + pulseFrames * 2)
    }
  }

  private def drawHud(g: Graphics2D): Unit = {
    g.setColor(new Color(5, 8, 30, 205))
    g.fillRoundRect(18, 14, 965, 66, 18, 18)
    g.setFont(new Font("SansSerif", Font.BOLD, 16))
    g.setColor(Color.WHITE)
    g.drawString("LEVEL " + level + " / 12", 35, 42)
    g.drawString("SHARDS " + collected + " / " + target, 170, 42)
    g.drawString("LIVES " + lives, 350, 42)
    g.drawString("COINS " + coins, 470, 42)
    g.drawString("SCORE " + score, 620, 42)
    g.setColor(new Color(40, 48, 78))
    g.fillRoundRect(790, 29, 165, 15, 10, 10)
    g.setColor(new Color(93, 223, 255))
    g.fillRoundRect(790, 29, (165.0 * energy / 100.0).toInt, 15, 10, 10)
    g.setFont(new Font("SansSerif", Font.PLAIN, 11))
    g.setColor(Color.WHITE)
    g.drawString("ENERGY", 790, 22)
    g.setFont(new Font("SansSerif", Font.PLAIN, 12))
    g.setColor(new Color(202, 213, 255))
    g.drawString("SPACE: DASH   Q: SHIELD   CLICK: PULSE   P: PAUSE   B: MENU", 250, 690)
  }

  private def drawPlay(g: Graphics2D): Unit = {
    drawSpaceBackground(g)
    g.setColor(new Color(14, 12, 45, 70))
    g.fillRect(0, 0, screenWidth, screenHeight)
    var i = 0
    while (i < shards.length) {
      drawShard(g, shards(i))
      i += 1
    }
    i = 0
    while (i < comets.length) {
      drawComet(g, comets(i))
      i += 1
    }
    drawPlayer(g)
    drawHud(g)
    if (shieldFrames > 0) {
      g.setFont(new Font("SansSerif", Font.BOLD, 13))
      g.setColor(new Color(135, 235, 255))
      g.drawString("AURA SHIELD ACTIVE", 28, 105)
    }
  }

  private def drawOverlay(g: Graphics2D, heading: String, subheading: String): Unit = {
    g.setColor(new Color(3, 5, 24, 205))
    g.fillRect(0, 0, screenWidth, screenHeight)
    centerText(g, heading, 250, 42, new Color(255, 222, 155))
    centerText(g, subheading, 295, 18, new Color(214, 221, 255))
  }

  private def drawPause(g: Graphics2D): Unit = {
    drawOverlay(g, "COSMIC PAUSED", "Take a breath, explorer")
    drawButton(g, "RESUME", 370, 340, 260, 54, true)
    drawButton(g, "MAIN MENU", 370, 406, 260, 54, true)
  }

  private def drawComplete(g: Graphics2D): Unit = {
    drawSpaceBackground(g)
    drawOverlay(g, "LEVEL " + level + " CLEARED!", "You restored a piece of the Eclipse Core")
    centerText(g, "SCORE " + score + "       COINS " + coins, 340, 20, new Color(255, 225, 145))
    val nextLabel = if (level < 12) "NEXT LEVEL (ENTER)" else "FINISH JOURNEY"
    drawButton(g, nextLabel, 370, 390, 260, 54, true)
    drawButton(g, "MAIN MENU", 370, 456, 260, 54, true)
  }

  private def drawGameOver(g: Graphics2D): Unit = {
    drawSpaceBackground(g)
    drawOverlay(g, "SHIP NEEDS REPAIR", "The comets were too strong this time")
    centerText(g, "FINAL SCORE: " + score, 340, 21, Color.WHITE)
    drawButton(g, "TRY AGAIN (ENTER)", 370, 390, 260, 54, true)
    drawButton(g, "MAIN MENU", 370, 456, 260, 54, true)
  }

  override def paintComponent(graphics: Graphics): Unit = {
    super.paintComponent(graphics)
    val g = graphics.create().asInstanceOf[Graphics2D]
    g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)
    if (screen == "MENU") {
      drawSpaceBackground(g)
      drawMenu(g)
    } else if (screen == "LEVELS") {
      drawSpaceBackground(g)
      drawLevels(g)
    } else if (screen == "SHOP") {
      drawSpaceBackground(g)
      drawShop(g)
    } else if (screen == "CONTROLS") {
      drawSpaceBackground(g)
      drawControls(g)
    } else if (screen == "PLAY") {
      drawPlay(g)
    } else if (screen == "PAUSE") {
      drawSpaceBackground(g)
      drawPause(g)
    } else if (screen == "COMPLETE") {
      drawComplete(g)
    } else if (screen == "GAMEOVER") {
      drawGameOver(g)
    }
    g.dispose()
  }

  override def keyPressed(e: KeyEvent): Unit = {
    val code = e.getKeyCode
    pressedKeys += code
    if (code == KeyEvent.VK_B) {
      if (screen != "MENU") {
        screen = "MENU"
        saveProgress()
      }
    } else if (code == KeyEvent.VK_P || code == KeyEvent.VK_ESCAPE) {
      if (screen == "PLAY") screen = "PAUSE"
      else if (screen == "PAUSE") screen = "PLAY"
      else if (screen != "MENU") screen = "MENU"
    } else if (code == KeyEvent.VK_ENTER) {
      if (screen == "COMPLETE") {
        if (level < 12) startLevel(level + 1) else screen = "MENU"
      } else if (screen == "GAMEOVER") {
        startLevel(level)
      }
    } else if (code == KeyEvent.VK_SPACE) {
      activateDash()
    } else if (code == KeyEvent.VK_Q) {
      activateShield()
    }
    repaint()
  }

  override def keyReleased(e: KeyEvent): Unit = {
    pressedKeys -= e.getKeyCode
  }

  override def keyTyped(e: KeyEvent): Unit = ()
  override def mouseClicked(e: MouseEvent): Unit = handleMouse(e.getX, e.getY)
  override def mousePressed(e: MouseEvent): Unit = ()
  override def mouseReleased(e: MouseEvent): Unit = ()
  override def mouseEntered(e: MouseEvent): Unit = requestFocusInWindow()
  override def mouseExited(e: MouseEvent): Unit = ()
  override def mouseMoved(e: MouseEvent): Unit = {
    mouseX = e.getX
    mouseY = e.getY
  }
  override def mouseDragged(e: MouseEvent): Unit = {
    mouseX = e.getX
    mouseY = e.getY
  }
}

CosmicEclipseEvent8.main(Array[String]())