Code Sketch
Bixuu spring season event 6
Category: Programming
import java.awt.{BasicStroke, Color, Dimension, Font, GradientPaint, Graphics, Graphics2D, Polygon, RenderingHints, Rectangle}
import java.awt.event.{ActionEvent, ActionListener, KeyAdapter, KeyEvent, MouseAdapter, MouseEvent}
import java.awt.geom.{Ellipse2D, RoundRectangle2D}
import java.util.Locale
import java.util.prefs.Preferences
import javax.swing.{JFrame, JOptionPane, JPanel, SwingUtilities, Timer, WindowConstants}
import scala.collection.mutable.ArrayBuffer
import scala.util.Random
import scala.util.Try
object ButterflyBloom {
private val AppTitle = "BUTTERFLY BLOOM - SPRING SEASON ADVENTURE"
private val WindowWidth = 1000
private val WindowHeight = 720
private val SkyTop = new Color(105, 190, 224)
private val SkyBottom = new Color(211, 244, 225)
private val DeepGreen = new Color(36, 105, 76)
private val LeafGreen = new Color(73, 157, 103)
private val Mint = new Color(154, 255, 209)
private val Cream = new Color(255, 249, 224)
private val Gold = new Color(255, 213, 105)
private val Ink = new Color(30, 61, 58)
private val PanelFill = new Color(13, 52, 51, 220)
private case class UiButton(rect: Rectangle, label: String, action: () => Unit, enabled: Boolean)
private class Butterfly(var x: Double, var y: Double, var angle: Double,
var phase: Double, val colorIndex: Int) {
var alive = true
}
private class Thorn(var x: Double, var y: Double, var vx: Double, var vy: Double,
val radius: Double) {
}
private class BloomPanel(val playerName: String) extends JPanel {
private val safeName = playerName.toLowerCase(Locale.ROOT).replaceAll("[^a-z0-9_-]", "_")
private val prefs = Preferences.userRoot().node("BixuuGames/ButterflyBloom/players/" + safeName)
private val random = new Random()
private val buttons = ArrayBuffer[UiButton]()
private val butterflies = ArrayBuffer[Butterfly]()
private val thorns = ArrayBuffer[Thorn]()
private var screen = "menu"
private var level = 1
private var selectedLevel = 1
private var highestLevel = math.max(1, prefs.getInt("highestLevel", 1))
private var pollenCoins = math.max(0, prefs.getInt("pollenCoins", 0))
private var collected = 0
private var goal = 7
private var lives = 3
private var shieldTicks = 0
private var dashTicks = 0
private var dashCooldown = 0
private var playerX = 500.0
private var playerY = 490.0
private var targetX = 500.0
private var targetY = 490.0
private var hasTarget = false
private var up = false
private var down = false
private var left = false
private var right = false
private var paused = false
private var tick = 0
private var selectedStyle = math.max(0, math.min(3, prefs.getInt("selectedStyle", 0)))
private var message = "Collect the glowing butterflies!"
private var messageTicks = 180
setPreferredSize(new Dimension(WindowWidth, WindowHeight))
setFocusable(true)
setBackground(SkyBottom)
private val gameTimer = new Timer(16, new ActionListener {
override def actionPerformed(event: ActionEvent): Unit = {
updateGame()
repaint()
}
})
def startLoop(): Unit = gameTimer.start()
private def saveProgress(): Unit = {
Try {
prefs.putInt("highestLevel", highestLevel)
prefs.putInt("pollenCoins", pollenCoins)
prefs.putInt("selectedStyle", selectedStyle)
prefs.flush()
}
}
private def setMessage(text: String): Unit = {
message = text
messageTicks = 180
}
private def wingColor(index: Int): Color = {
index match {
case 0 => new Color(255, 123, 174)
case 1 => new Color(118, 208, 255)
case 2 => new Color(255, 197, 91)
case _ => new Color(190, 145, 255)
}
}
private def styleName(index: Int): String = {
index match {
case 0 => "Rose Flutter"
case 1 => "Sky Monarch"
case 2 => "Sun Petal"
case _ => "Lavender Dream"
}
}
private def styleCost(index: Int): Int = {
index match {
case 0 => 0
case 1 => 60
case 2 => 100
case _ => 150
}
}
private def styleOwned(index: Int): Boolean = {
if (index == 0) true else prefs.getBoolean("styleOwned" + index, false)
}
private def addButton(g: Graphics2D, x: Int, y: Int, w: Int, h: Int,
label: String, enabled: Boolean = true)(action: => Unit): Unit = {
val rect = new Rectangle(x, y, w, h)
buttons += UiButton(rect, label, () => action, enabled)
val fill = if (enabled) new Color(19, 91, 73, 235) else new Color(80, 100, 91, 190)
g.setColor(fill)
g.fill(new RoundRectangle2D.Double(x, y, w, h, 22, 22))
g.setColor(if (enabled) new Color(190, 255, 220) else new Color(175, 190, 181))
g.setStroke(new BasicStroke(2.0f))
g.draw(new RoundRectangle2D.Double(x, y, w, h, 22, 22))
g.setFont(new Font("SansSerif", Font.BOLD, 16))
val fm = g.getFontMetrics
g.setColor(if (enabled) Cream else new Color(205, 211, 205))
g.drawString(label, x + (w - fm.stringWidth(label)) / 2, y + (h + fm.getAscent - fm.getDescent) / 2)
}
private def drawText(g: Graphics2D, value: String, x: Int, y: Int, size: Int,
color: Color, bold: Boolean = false): Unit = {
g.setFont(new Font("SansSerif", if (bold) Font.BOLD else Font.PLAIN, size))
g.setColor(color)
g.drawString(value, x, y)
}
private def drawPanel(g: Graphics2D, x: Int, y: Int, w: Int, h: Int): Unit = {
g.setColor(PanelFill)
g.fill(new RoundRectangle2D.Double(x, y, w, h, 28, 28))
g.setColor(new Color(200, 255, 224, 185))
g.setStroke(new BasicStroke(2.0f))
g.draw(new RoundRectangle2D.Double(x, y, w, h, 28, 28))
}
private def drawFlower(g: Graphics2D, x: Double, y: Double, size: Double, color: Color): Unit = {
g.setColor(color)
var i = 0
while (i < 6) {
val angle = i * math.Pi / 3.0
val px = x + math.cos(angle) * size * 0.42
val py = y + math.sin(angle) * size * 0.42
g.fill(new Ellipse2D.Double(px - size * 0.28, py - size * 0.28, size * 0.56, size * 0.56))
i += 1
}
g.setColor(new Color(255, 220, 92))
g.fill(new Ellipse2D.Double(x - size * 0.20, y - size * 0.20, size * 0.40, size * 0.40))
}
private def drawButterfly(g: Graphics2D, x: Double, y: Double, size: Double,
color: Color, flap: Double): Unit = {
val wing = math.max(0.58, math.abs(math.sin(flap)))
g.setColor(new Color(color.getRed, color.getGreen, color.getBlue, 190))
g.fill(new Ellipse2D.Double(x - size * 0.72 * wing, y - size * 0.62, size * 0.78 * wing, size * 0.88))
g.fill(new Ellipse2D.Double(x + size * 0.02, y - size * 0.62, size * 0.78 * wing, size * 0.88))
g.fill(new Ellipse2D.Double(x - size * 0.57 * wing, y + size * 0.03, size * 0.63 * wing, size * 0.62))
g.fill(new Ellipse2D.Double(x - size * 0.06, y + size * 0.03, size * 0.63 * wing, size * 0.62))
g.setColor(new Color(50, 62, 58))
g.fill(new RoundRectangle2D.Double(x - size * 0.07, y - size * 0.38, size * 0.14, size * 0.98, size * 0.12, size * 0.12))
g.setStroke(new BasicStroke(1.5f))
g.drawArc((x - size * 0.28).toInt, (y - size * 0.68).toInt, (size * 0.28).toInt, (size * 0.45).toInt, 0, 100)
g.drawArc(x.toInt, (y - size * 0.68).toInt, (size * 0.28).toInt, (size * 0.45).toInt, 80, 100)
}
private def drawWorld(g: Graphics2D): Unit = {
val w = getWidth
val h = getHeight
g.setPaint(new GradientPaint(0, 0, SkyTop, 0, h, SkyBottom))
g.fillRect(0, 0, w, h)
g.setColor(new Color(255, 246, 190, 220))
g.fill(new Ellipse2D.Double(w - 170, 50, 90, 90))
g.setColor(new Color(255, 255, 255, 95))
g.fill(new Ellipse2D.Double(105, 95, 130, 35))
g.fill(new Ellipse2D.Double(155, 80, 95, 45))
g.fill(new Ellipse2D.Double(680, 125, 150, 32))
g.fill(new Ellipse2D.Double(730, 108, 90, 48))
val hillBack = new Polygon()
hillBack.addPoint(0, 390)
hillBack.addPoint(145, 270)
hillBack.addPoint(290, 390)
hillBack.addPoint(460, 255)
hillBack.addPoint(650, 390)
hillBack.addPoint(815, 275)
hillBack.addPoint(1000, 390)
hillBack.addPoint(1000, h)
hillBack.addPoint(0, h)
g.setColor(new Color(109, 178, 128))
g.fillPolygon(hillBack)
val hillFront = new Polygon()
hillFront.addPoint(0, 465)
hillFront.addPoint(190, 365)
hillFront.addPoint(375, 470)
hillFront.addPoint(570, 350)
hillFront.addPoint(760, 470)
hillFront.addPoint(900, 375)
hillFront.addPoint(1000, 430)
hillFront.addPoint(1000, h)
hillFront.addPoint(0, h)
g.setColor(new Color(66, 145, 99))
g.fillPolygon(hillFront)
g.setColor(new Color(39, 120, 83))
g.fillRect(0, 505, w, h - 505)
g.setColor(new Color(110, 190, 113, 95))
var i = 0
while (i < 34) {
val x = (i * 137 + 31) % math.max(1, w)
val y = 515 + ((i * 71) % 190)
g.drawLine(x, y, x - 4, y - 14)
g.drawLine(x, y, x + 5, y - 12)
i += 1
}
drawFlower(g, 90, 570, 24, new Color(255, 154, 190))
drawFlower(g, 870, 610, 28, new Color(255, 239, 154))
drawFlower(g, 760, 535, 18, new Color(193, 160, 255))
drawFlower(g, 230, 645, 19, new Color(255, 177, 205))
}
private def drawHeader(g: Graphics2D, title: String, subtitle: String): Unit = {
drawText(g, title, 34, 52, 29, new Color(24, 83, 64), true)
drawText(g, subtitle, 36, 79, 14, new Color(47, 99, 75), false)
drawText(g, "PLAYER: " + playerName + " POLLEN: " + pollenCoins, 700, 48, 14, Ink, true)
}
private def startLevel(value: Int): Unit = {
level = math.max(1, math.min(12, value))
selectedLevel = level
collected = 0
goal = 6 + level * 2
lives = 3
shieldTicks = 0
dashTicks = 0
dashCooldown = 0
paused = false
playerX = 500.0
playerY = 500.0
targetX = playerX
targetY = playerY
hasTarget = false
butterflies.clear()
thorns.clear()
var i = 0
while (i < goal + 4) {
butterflies += new Butterfly(90 + random.nextInt(820).toDouble, 175 + random.nextInt(430).toDouble,
random.nextDouble() * 6.0, random.nextDouble() * 6.0, random.nextInt(4))
i += 1
}
val thornCount = math.min(10, 2 + level)
i = 0
while (i < thornCount) {
thorns += new Thorn(100 + random.nextInt(800).toDouble, 190 + random.nextInt(390).toDouble,
(random.nextDouble() - 0.5) * (1.0 + level * 0.08),
(random.nextDouble() - 0.5) * (1.0 + level * 0.08), 14.0 + random.nextInt(5))
i += 1
}
screen = "game"
setMessage("Level " + level + " - gather " + goal + " butterflies")
requestFocusInWindow()
}
private def completeLevel(): Unit = {
screen = "complete"
val reward = 25 + level * 8
pollenCoins += reward
if (level < 12) highestLevel = math.max(highestLevel, level + 1)
else highestLevel = 12
saveProgress()
setMessage("Beautiful work! You earned " + reward + " pollen coins.")
}
private def updateGame(): Unit = {
tick += 1
if (messageTicks > 0) messageTicks -= 1
if (screen == "game" && !paused) {
var dx = 0.0
var dy = 0.0
if (left) dx -= 1.0
if (right) dx += 1.0
if (up) dy -= 1.0
if (down) dy += 1.0
if (dx != 0.0 || dy != 0.0) hasTarget = false
val speed = if (dashTicks > 0) 8.6 else 4.1
if (dx != 0.0 || dy != 0.0) {
val length = math.sqrt(dx * dx + dy * dy)
playerX += dx / length * speed
playerY += dy / length * speed
} else if (hasTarget) {
val tx = targetX - playerX
val ty = targetY - playerY
val distance = math.sqrt(tx * tx + ty * ty)
if (distance < 7.0) hasTarget = false
else {
playerX += tx / distance * speed
playerY += ty / distance * speed
}
}
playerX = math.max(48.0, math.min(getWidth - 48.0, playerX))
playerY = math.max(145.0, math.min(getHeight - 45.0, playerY))
if (dashTicks > 0) dashTicks -= 1
if (dashCooldown > 0) dashCooldown -= 1
if (shieldTicks > 0) shieldTicks -= 1
var i = butterflies.length - 1
while (i >= 0) {
val b = butterflies(i)
b.phase += 0.09
b.angle += math.sin(b.phase) * 0.004
b.x += math.cos(b.angle) * 0.65
b.y += math.sin(b.angle) * 0.55
if (b.x < 55.0 || b.x > getWidth - 55.0) b.angle = math.Pi - b.angle
if (b.y < 155.0 || b.y > getHeight - 55.0) b.angle = -b.angle
val px = b.x - playerX
val py = b.y - playerY
if (px * px + py * py < 34.0 * 34.0) {
butterflies.remove(i)
collected += 1
pollenCoins += 2
if (collected % 4 == 0) setMessage("Combo! +2 pollen coins")
}
i -= 1
}
i = 0
while (i < thorns.length) {
val t = thorns(i)
t.x += t.vx
t.y += t.vy
if (t.x < 55.0 || t.x > getWidth - 55.0) t.vx = -t.vx
if (t.y < 165.0 || t.y > getHeight - 55.0) t.vy = -t.vy
val px = t.x - playerX
val py = t.y - playerY
if (px * px + py * py < (t.radius + 15.0) * (t.radius + 15.0)) {
if (shieldTicks <= 0 && dashTicks <= 0) {
lives -= 1
playerX = 500.0
playerY = 500.0
setMessage("Watch out for thorn vines!")
if (lives <= 0) screen = "gameover"
}
}
i += 1
}
if (collected >= goal) completeLevel()
if (tick % 25 == 0) saveProgress()
}
}
private def drawMenu(g: Graphics2D): Unit = {
drawHeader(g, "BUTTERFLY BLOOM", "A magical spring adventure - collect, explore and let the garden bloom")
drawPanel(g, 250, 145, 500, 475)
drawButterfly(g, 500, 235, 58, wingColor(selectedStyle), tick * 0.12)
drawText(g, "WELCOME, " + playerName.toUpperCase(Locale.ROOT), 355, 322, 18, Cream, true)
drawText(g, "Your garden is waiting for you!", 372, 350, 15, new Color(215, 250, 224), false)
addButton(g, 365, 380, 270, 48, "PLAY ADVENTURE") { screen = "levels" }
addButton(g, 365, 438, 270, 42, "BUTTERFLY WARDROBE") { screen = "wardrobe" }
addButton(g, 365, 490, 270, 42, "POLLEN SHOP") { screen = "shop" }
addButton(g, 365, 542, 270, 42, "HOW TO PLAY") { screen = "help" }
drawText(g, "12 LEVELS | 4 WING STYLES | LOCAL SAVE", 355, 600, 13, Cream, true)
}
private def drawLevels(g: Graphics2D): Unit = {
drawHeader(g, "CHOOSE YOUR GARDEN", "Complete a level to unlock the next one")
drawPanel(g, 165, 125, 670, 500)
var i = 1
while (i <= 12) {
val col = (i - 1) % 4
val row = (i - 1) / 4
val x = 220 + col * 145
val y = 175 + row * 115
val unlocked = i <= highestLevel
addButton(g, x, y, 112, 76, if (unlocked) "LEVEL " + i else "LOCKED", unlocked) {
if (unlocked) startLevel(i)
}
i += 1
}
addButton(g, 365, 545, 270, 48, "BACK TO HOME") { screen = "menu" }
}
private def drawWardrobe(g: Graphics2D): Unit = {
drawHeader(g, "BUTTERFLY WARDROBE", "Choose the wings that will follow you through the garden")
drawPanel(g, 135, 130, 730, 495)
var i = 0
while (i < 4) {
val x = 205 + i * 150
val owned = styleOwned(i)
drawButterfly(g, x + 45, 260, 40, wingColor(i), tick * 0.10 + i)
drawText(g, styleName(i), x - 8, 330, 13, Cream, true)
val label = if (selectedStyle == i) "EQUIPPED" else if (owned) "EQUIP" else "BUY " + styleCost(i)
addButton(g, x - 12, 355, 116, 42, label, true) {
if (owned) {
selectedStyle = i
prefs.putInt("selectedStyle", selectedStyle)
saveProgress()
setMessage(styleName(i) + " equipped!")
} else if (pollenCoins >= styleCost(i)) {
pollenCoins -= styleCost(i)
prefs.putBoolean("styleOwned" + i, true)
selectedStyle = i
saveProgress()
setMessage("New wings unlocked!")
} else setMessage("You need more pollen coins.")
}
i += 1
}
addButton(g, 365, 535, 270, 48, "BACK TO HOME") { screen = "menu" }
}
private def drawShop(g: Graphics2D): Unit = {
drawHeader(g, "POLLEN SHOP", "Spend pollen coins on beautiful wing styles")
drawPanel(g, 200, 145, 600, 440)
drawText(g, "YOUR POLLEN COINS: " + pollenCoins, 385, 205, 19, Gold, true)
drawText(g, "1. Sky Monarch - 60 coins", 300, 275, 18, Cream, true)
drawText(g, "2. Sun Petal - 100 coins", 300, 335, 18, Cream, true)
drawText(g, "3. Lavender Dream - 150 coins", 300, 395, 18, Cream, true)
addButton(g, 350, 450, 300, 46, "OPEN WARDROBE") { screen = "wardrobe" }
addButton(g, 350, 510, 300, 46, "BACK TO HOME") { screen = "menu" }
}
private def drawHelp(g: Graphics2D): Unit = {
drawHeader(g, "HOW TO PLAY", "Simple controls - explore at your own pace")
drawPanel(g, 190, 135, 620, 470)
drawText(g, "W A S D / ARROW KEYS - Move your butterfly", 250, 220, 17, Cream, true)
drawText(g, "MOUSE CLICK - Move to the chosen place", 250, 270, 17, Cream, true)
drawText(g, "SPACE - Petal dash (short speed boost)", 250, 320, 17, Cream, true)
drawText(g, "Q - Petal shield (protects from thorn vines)", 250, 370, 17, Cream, true)
drawText(g, "E - Restore one life using 20 pollen coins", 250, 420, 17, Cream, true)
drawText(g, "B - Back to level selection / home", 250, 470, 17, Cream, true)
addButton(g, 365, 530, 270, 46, "BACK TO HOME") { screen = "menu" }
}
private def drawGame(g: Graphics2D): Unit = {
drawHeader(g, "LEVEL " + level + " - BUTTERFLY MEADOW", "Collect the glowing butterflies and avoid the thorn vines")
drawPanel(g, 20, 95, 960, 54)
drawText(g, "BUTTERFLIES: " + collected + " / " + goal, 45, 129, 17, Cream, true)
drawText(g, "LIVES: " + lives, 330, 129, 17, Cream, true)
drawText(g, "POLLEN: " + pollenCoins, 470, 129, 17, Gold, true)
drawText(g, if (shieldTicks > 0) "SHIELD ON" else "Q: SHIELD", 680, 129, 15, Mint, true)
drawText(g, if (dashCooldown <= 0) "SPACE: DASH READY" else "DASH RECHARGING", 805, 129, 13, Cream, true)
var i = 0
while (i < butterflies.length) {
val b = butterflies(i)
drawButterfly(g, b.x, b.y, 18, wingColor(b.colorIndex), b.phase)
i += 1
}
i = 0
while (i < thorns.length) {
val t = thorns(i)
g.setColor(new Color(113, 69, 91, 220))
g.setStroke(new BasicStroke(5.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND))
g.drawLine((t.x - t.radius).toInt, (t.y + t.radius).toInt, (t.x + t.radius).toInt, (t.y - t.radius).toInt)
g.drawLine((t.x - t.radius).toInt, (t.y - t.radius).toInt, (t.x + t.radius).toInt, (t.y + t.radius).toInt)
g.setColor(new Color(255, 186, 210, 210))
g.fill(new Ellipse2D.Double(t.x - 5, t.y - 5, 10, 10))
i += 1
}
if (shieldTicks > 0) {
g.setColor(new Color(127, 230, 255, 95))
g.fill(new Ellipse2D.Double(playerX - 32, playerY - 32, 64, 64))
g.setColor(new Color(185, 250, 255, 220))
g.setStroke(new BasicStroke(3.0f))
g.draw(new Ellipse2D.Double(playerX - 32, playerY - 32, 64, 64))
}
drawButterfly(g, playerX, playerY, 31, wingColor(selectedStyle), tick * 0.16)
drawText(g, playerName, (playerX - 25).toInt, (playerY + 43).toInt, 12, Cream, true)
drawPanel(g, 270, 650, 460, 42)
drawText(g, "WASD / ARROWS: MOVE CLICK: MOVE B: BACK", 295, 677, 13, Cream, true)
if (paused) {
drawPanel(g, 350, 270, 300, 150)
drawText(g, "PAUSED", 450, 320, 28, Cream, true)
drawText(g, "Press P to continue", 415, 360, 16, Mint, false)
}
}
private def drawComplete(g: Graphics2D): Unit = {
drawHeader(g, "LEVEL COMPLETE!", "The meadow is blooming because of you")
drawPanel(g, 250, 155, 500, 430)
drawButterfly(g, 500, 260, 55, wingColor(selectedStyle), tick * 0.12)
drawText(g, "LEVEL " + level + " CLEARED", 390, 350, 24, Cream, true)
drawText(g, "You collected " + collected + " butterflies!", 385, 388, 17, Mint, true)
drawText(g, "Pollen coins saved: " + pollenCoins, 390, 420, 16, Gold, true)
if (level < 12) addButton(g, 365, 455, 270, 48, "NEXT LEVEL (ENTER)") { startLevel(level + 1) }
else addButton(g, 365, 455, 270, 48, "PLAY AGAIN") { startLevel(1) }
addButton(g, 365, 515, 270, 42, "LEVEL SELECT (B)") { screen = "levels" }
}
private def drawGameOver(g: Graphics2D): Unit = {
drawHeader(g, "GARDEN REST BREAK", "The thorn vines slowed you down - try again")
drawPanel(g, 280, 190, 440, 350)
drawText(g, "DON'T GIVE UP!", 405, 275, 27, Cream, true)
drawText(g, "Butterflies collected: " + collected + " / " + goal, 365, 325, 17, Mint, true)
addButton(g, 365, 375, 270, 48, "RETRY LEVEL") { startLevel(level) }
addButton(g, 365, 435, 270, 42, "LEVEL SELECT (B)") { screen = "levels" }
}
override def paintComponent(graphics: Graphics): Unit = {
super.paintComponent(graphics)
val g = graphics.create().asInstanceOf[Graphics2D]
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)
g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY)
buttons.clear()
drawWorld(g)
screen match {
case "menu" => drawMenu(g)
case "levels" => drawLevels(g)
case "wardrobe" => drawWardrobe(g)
case "shop" => drawShop(g)
case "help" => drawHelp(g)
case "game" => drawGame(g)
case "complete" => drawComplete(g)
case "gameover" => drawGameOver(g)
case _ => drawMenu(g)
}
if (messageTicks > 0 && screen != "game") {
g.setColor(new Color(20, 65, 55, 205))
g.fill(new RoundRectangle2D.Double(255, getHeight - 42, 490, 30, 16, 16))
drawText(g, message, 275, getHeight - 22, 13, Cream, true)
}
g.dispose()
}
addMouseListener(new MouseAdapter {
override def mouseClicked(event: MouseEvent): Unit = {
var handled = false
val found = buttons.find(_.rect.contains(event.getPoint))
if (found.isDefined) {
val item = found.get
if (item.enabled) item.action()
handled = true
}
if (!handled && screen == "game" && !paused) {
targetX = event.getX.toDouble
targetY = event.getY.toDouble
hasTarget = true
}
repaint()
requestFocusInWindow()
}
})
addKeyListener(new KeyAdapter {
override def keyPressed(event: KeyEvent): Unit = {
val code = event.getKeyCode
if (code == KeyEvent.VK_W || code == KeyEvent.VK_UP) up = true
if (code == KeyEvent.VK_S || code == KeyEvent.VK_DOWN) down = true
if (code == KeyEvent.VK_A || code == KeyEvent.VK_LEFT) left = true
if (code == KeyEvent.VK_D || code == KeyEvent.VK_RIGHT) right = true
if (code == KeyEvent.VK_P && screen == "game") paused = !paused
if (code == KeyEvent.VK_B) {
if (screen == "game" || screen == "complete" || screen == "gameover") screen = "levels"
else if (screen != "menu") screen = "menu"
}
if (code == KeyEvent.VK_ENTER) {
if (screen == "complete" && level < 12) startLevel(level + 1)
else if (screen == "complete" && level == 12) startLevel(1)
else if (screen == "levels") startLevel(selectedLevel)
}
if (code == KeyEvent.VK_SPACE && screen == "game" && !paused && dashCooldown <= 0) {
dashTicks = 14
dashCooldown = 100
setMessage("Petal Dash!")
}
if (code == KeyEvent.VK_Q && screen == "game" && !paused) {
if (pollenCoins >= 10 && shieldTicks <= 0) {
pollenCoins -= 10
shieldTicks = 180
saveProgress()
setMessage("Petal Shield activated!")
} else if (shieldTicks > 0) setMessage("Your shield is already active.")
else setMessage("You need 10 pollen coins for a shield.")
}
if (code == KeyEvent.VK_E && screen == "game" && !paused) {
if (pollenCoins >= 20 && lives < 3) {
pollenCoins -= 20
lives += 1
saveProgress()
setMessage("A flower healed one life!")
} else if (lives >= 3) setMessage("Your lives are already full.")
else setMessage("You need 20 pollen coins to heal.")
}
repaint()
}
override def keyReleased(event: KeyEvent): Unit = {
val code = event.getKeyCode
if (code == KeyEvent.VK_W || code == KeyEvent.VK_UP) up = false
if (code == KeyEvent.VK_S || code == KeyEvent.VK_DOWN) down = false
if (code == KeyEvent.VK_A || code == KeyEvent.VK_LEFT) left = false
if (code == KeyEvent.VK_D || code == KeyEvent.VK_RIGHT) right = false
}
})
addFocusListener(new java.awt.event.FocusAdapter {
override def focusLost(event: java.awt.event.FocusEvent): Unit = {
up = false
down = false
left = false
right = false
}
})
}
def main(args: Array[String]): Unit = {
SwingUtilities.invokeLater(new Runnable {
override def run(): Unit = {
val entered = JOptionPane.showInputDialog(null, "Enter your Butterfly Bloom player name:",
"Butterfly Bloom Login", JOptionPane.QUESTION_MESSAGE)
val name = if (entered == null || entered.trim.isEmpty) "Player" else entered.trim.take(18)
val panel = new BloomPanel(name)
val frame = new JFrame(AppTitle)
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE)
frame.setContentPane(panel)
frame.pack()
frame.setMinimumSize(new Dimension(850, 640))
frame.setLocationRelativeTo(null)
frame.setVisible(true)
panel.startLoop()
panel.requestFocusInWindow()
}
})
}
}
ButterflyBloom.main(Array[String]())