Code Sketch
Bixuu INFINITY REALMS SEASON ETERNAL BLOOM AWAKENING
Category: Programming
import java.awt.{BasicStroke, Color, Dimension, Font, FontMetrics, Graphics, Graphics2D, GradientPaint, RenderingHints, Polygon}
import java.awt.event.{ActionEvent, ActionListener, KeyEvent, KeyListener, MouseEvent, MouseListener, WindowAdapter, WindowEvent}
import java.awt.geom.AffineTransform
import javax.swing.{JFrame, JPanel, SwingUtilities, Timer, WindowConstants}
import scala.collection.mutable.ArrayBuffer
import scala.collection.mutable
import scala.util.Random
object InfinityRealmsEternalBloom {
private val VIEW_W = 1100
private val VIEW_H = 720
private val WORLD_W = 1850.0
private val WORLD_H = 1320.0
def main(args: Array[String]): Unit = {
SwingUtilities.invokeLater(new Runnable {
override def run(): Unit = {
val frame = new JFrame("INFINITY REALMS SEASON - ETERNAL BLOOM AWAKENING")
val panel = new GamePanel()
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE)
frame.setContentPane(panel)
frame.pack()
frame.setResizable(false)
frame.setLocationRelativeTo(null)
frame.addWindowListener(new WindowAdapter {
override def windowClosing(e: WindowEvent): Unit = panel.stopLoop()
override def windowClosed(e: WindowEvent): Unit = panel.stopLoop()
})
frame.setVisible(true)
panel.requestFocusInWindow()
}
})
}
private case class Crystal(var x: Double, var y: Double, var collected: Boolean, var kind: Int)
private case class Wisp(var x: Double, var y: Double, var stunned: Double)
private case class Tree(x: Double, y: Double, size: Double, kind: Int)
private class GamePanel extends JPanel with ActionListener with KeyListener with MouseListener {
private val MENU = 0
private val LOGIN = 1
private val AVATAR = 2
private val PLAY = 3
private val PAUSE = 4
private val WIN = 5
private val LOST = 6
private var screen = MENU
private var playerName = "Bloom Explorer"
private var editingName = false
private var avatar = 0
private var realm = 0
private var playerX = 145.0
private var playerY = WORLD_H * 0.52
private var camX = 0.0
private var camY = 0.0
private var targetX = -1.0
private var targetY = -1.0
private var health = 3
private var coins = 0
private var crystalsCollected = 0
private var energy = 100.0
private var dashTime = 0.0
private var dashCooldown = 0.0
private var shieldTime = 0.0
private var damageCooldown = 0.0
private var elapsed = 0.0
private var message = "Collect Bloom Crystals and awaken the Ancient Tree!"
private var messageTime = 5.0
private var portalOpen = false
private var worldAwakened = false
private val keys = mutable.Set[Int]()
private val crystals = ArrayBuffer[Crystal]()
private val wisps = ArrayBuffer[Wisp]()
private val trees = ArrayBuffer[Tree]()
private val flowers = ArrayBuffer[(Double, Double, Int)]()
private val rng = new Random(8065L)
private val timer = new Timer(16, this)
setPreferredSize(new Dimension(VIEW_W, VIEW_H))
setFocusable(true)
setDoubleBuffered(true)
addKeyListener(this)
addMouseListener(this)
setToolTipText("WASD: move | SPACE: dash | Q: shield | E: interact | P: pause")
timer.start()
def stopLoop(): Unit = timer.stop()
private def setMessage(s: String, seconds: Double): Unit = {
message = s
messageTime = seconds
}
private def beginGame(): Unit = {
realm = 0
health = 3
coins = 0
crystalsCollected = 0
energy = 100.0
playerX = 145.0
playerY = WORLD_H * 0.52
targetX = -1.0
targetY = -1.0
elapsed = 0.0
worldAwakened = false
createRealm()
screen = PLAY
setMessage("Welcome, " + playerName + "! Gather 7 crystals, then reach the Ancient Tree.", 6.0)
requestFocusInWindow()
}
private def createRealm(): Unit = {
crystals.clear()
wisps.clear()
trees.clear()
flowers.clear()
portalOpen = false
val treeCount = 65
var i = 0
while (i < treeCount) {
val tx = 80.0 + rng.nextDouble() * (WORLD_W - 160.0)
val ty = 70.0 + rng.nextDouble() * (WORLD_H - 140.0)
trees += Tree(tx, ty, 0.75 + rng.nextDouble() * 0.8, rng.nextInt(3))
i += 1
}
i = 0
while (i < 185) {
val fx = 30.0 + rng.nextDouble() * (WORLD_W - 60.0)
val fy = 30.0 + rng.nextDouble() * (WORLD_H - 60.0)
flowers += ((fx, fy, rng.nextInt(5)))
i += 1
}
val crystalCount = 14 + realm * 4
i = 0
while (i < crystalCount) {
val cx = 300.0 + rng.nextDouble() * (WORLD_W - 610.0)
val cy = 105.0 + rng.nextDouble() * (WORLD_H - 210.0)
crystals += Crystal(cx, cy, false, rng.nextInt(4))
i += 1
}
i = 0
while (i < 3 + realm) {
val ex = 430.0 + rng.nextDouble() * (WORLD_W - 570.0)
val ey = 100.0 + rng.nextDouble() * (WORLD_H - 200.0)
wisps += Wisp(ex, ey, 0.0)
i += 1
}
playerX = 145.0
playerY = WORLD_H * 0.52
targetX = -1.0
targetY = -1.0
camX = 0.0
camY = 0.0
}
private def goalForRealm: Int = 7 + realm * 2
private def startDash(): Unit = {
if (screen == PLAY && dashCooldown <= 0.0) {
dashTime = 0.24
dashCooldown = 1.25
setMessage("PETAL DASH!", 0.8)
}
}
private def useShield(): Unit = {
if (screen == PLAY && energy >= 28.0 && shieldTime <= 0.0) {
energy -= 28.0
shieldTime = 3.2
setMessage("Nature Shield activated!", 1.5)
} else if (screen == PLAY) {
setMessage("Need 28 Nature Energy for a shield.", 2.0)
}
}
private def interact(): Unit = {
if (screen != PLAY) return
val portalX = WORLD_W - 190.0
val portalY = WORLD_H - 190.0
val d = distance(playerX, playerY, portalX, portalY)
if (d < 125.0) {
if (crystalsCollected >= goalForRealm) {
if (realm < 2) {
realm += 1
crystalsCollected = 0
health = math.min(3, health + 1)
energy = math.min(100.0, energy + 35.0)
createRealm()
setMessage("Realm awakened! Welcome to " + realmName + ".", 4.0)
} else {
worldAwakened = true
screen = WIN
}
} else {
setMessage("The portal needs " + goalForRealm + " Bloom Crystals. You have " + crystalsCollected + ".", 3.0)
}
} else if (distance(playerX, playerY, 150.0, WORLD_H * 0.52) < 100.0) {
energy = math.min(100.0, energy + 20.0)
health = math.min(3, health + 1)
setMessage("The Home Grove restores your nature energy.", 2.5)
} else {
setMessage("Find the glowing Ancient Tree portal at the far end of the realm.", 2.3)
}
}
private def realmName: String = realm match {
case 0 => "Verdant Grove"
case 1 => "Crystal Falls"
case _ => "Moonlit Canopy"
}
private def distance(x1: Double, y1: Double, x2: Double, y2: Double): Double = {
val dx = x1 - x2
val dy = y1 - y2
math.sqrt(dx * dx + dy * dy)
}
override def actionPerformed(e: ActionEvent): Unit = {
if (screen == PLAY) updateGame(0.016)
repaint()
}
private def updateGame(dt: Double): Unit = {
elapsed += dt
if (messageTime > 0.0) messageTime -= dt
if (dashTime > 0.0) dashTime -= dt
if (dashCooldown > 0.0) dashCooldown -= dt
if (shieldTime > 0.0) shieldTime -= dt
if (damageCooldown > 0.0) damageCooldown -= dt
energy = math.min(100.0, energy + dt * 2.4)
var mx = 0.0
var my = 0.0
if (keys.contains(KeyEvent.VK_W) || keys.contains(KeyEvent.VK_UP)) my -= 1.0
if (keys.contains(KeyEvent.VK_S) || keys.contains(KeyEvent.VK_DOWN)) my += 1.0
if (keys.contains(KeyEvent.VK_A) || keys.contains(KeyEvent.VK_LEFT)) mx -= 1.0
if (keys.contains(KeyEvent.VK_D) || keys.contains(KeyEvent.VK_RIGHT)) mx += 1.0
if (mx != 0.0 || my != 0.0) {
val len = math.sqrt(mx * mx + my * my)
mx /= len
my /= len
targetX = -1.0
targetY = -1.0
} else if (targetX >= 0.0 && targetY >= 0.0) {
val dx = targetX - playerX
val dy = targetY - playerY
val len = math.sqrt(dx * dx + dy * dy)
if (len > 13.0) {
mx = dx / len
my = dy / len
} else {
targetX = -1.0
targetY = -1.0
}
}
val speedBonus = math.min(95.0, crystalsCollected * 5.0)
var moveSpeed = 205.0 + speedBonus
if (dashTime > 0.0) moveSpeed *= 2.65
playerX = math.max(35.0, math.min(WORLD_W - 35.0, playerX + mx * moveSpeed * dt))
playerY = math.max(50.0, math.min(WORLD_H - 50.0, playerY + my * moveSpeed * dt))
var i = 0
while (i < crystals.length) {
val c = crystals(i)
if (!c.collected && distance(playerX, playerY, c.x, c.y) < 34.0) {
c.collected = true
crystalsCollected += 1
coins += 15 + realm * 5
energy = math.min(100.0, energy + 7.0)
setMessage("Bloom Crystal collected! +" + (15 + realm * 5) + " coins.", 1.3)
}
i += 1
}
i = 0
while (i < wisps.length) {
val w = wisps(i)
if (w.stunned > 0.0) {
w.stunned -= dt
} else {
val d = distance(w.x, w.y, playerX, playerY)
if (d < 345.0 && d > 1.0) {
val sp = 62.0 + realm * 10.0
w.x += ((playerX - w.x) / d) * sp * dt
w.y += ((playerY - w.y) / d) * sp * dt
}
if (d < 31.0 && damageCooldown <= 0.0 && shieldTime <= 0.0) {
health -= 1
damageCooldown = 1.15
w.stunned = 1.0
setMessage("A Thorn Wisp touched you! Find a crystal or use your Nature Shield.", 2.5)
if (health <= 0) screen = LOST
} else if (d < 31.0 && shieldTime > 0.0) {
w.stunned = 1.4
}
}
i += 1
}
val desiredCamX = math.max(0.0, math.min(WORLD_W - VIEW_W, playerX - VIEW_W / 2.0))
val desiredCamY = math.max(0.0, math.min(WORLD_H - VIEW_H, playerY - VIEW_H / 2.0))
camX += (desiredCamX - camX) * 0.12
camY += (desiredCamY - camY) * 0.12
}
override def paintComponent(gg: Graphics): Unit = {
super.paintComponent(gg)
val g = gg.asInstanceOf[Graphics2D]
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)
g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON)
screen match {
case MENU => drawMenu(g)
case LOGIN => drawLogin(g)
case AVATAR => drawAvatar(g)
case PLAY => drawGame(g)
case PAUSE => drawGame(g); drawPause(g)
case WIN => drawEnd(g, true)
case LOST => drawEnd(g, false)
case _ => drawMenu(g)
}
}
private def drawMenu(g: Graphics2D): Unit = {
drawBackdrop(g)
drawCentered(g, "INFINITY REALMS SEASON", VIEW_W / 2, 150, new Font("Serif", Font.BOLD, 34), new Color(222, 255, 220))
drawCentered(g, "ETERNAL BLOOM AWAKENING", VIEW_W / 2, 215, new Font("Serif", Font.BOLD, 43), new Color(255, 239, 177))
drawCentered(g, "A MAGICAL NATURE ADVENTURE", VIEW_W / 2, 260, new Font("SansSerif", Font.BOLD, 16), new Color(202, 245, 220))
drawLargeTree(g, VIEW_W / 2, 390, 1.25)
drawButton(g, 390, 555, 320, 66, "START YOUR ADVENTURE", true)
drawCentered(g, "Explore three realms ? Collect crystals ? Awaken the Ancient Tree", VIEW_W / 2, 663, new Font("SansSerif", Font.PLAIN, 14), Color.WHITE)
}
private def drawLogin(g: Graphics2D): Unit = {
drawBackdrop(g)
drawCentered(g, "WELCOME, EXPLORER", VIEW_W / 2, 170, new Font("Serif", Font.BOLD, 38), new Color(255, 239, 177))
drawCentered(g, "Enter your name to begin your journey", VIEW_W / 2, 220, new Font("SansSerif", Font.PLAIN, 18), Color.WHITE)
g.setColor(new Color(8, 38, 37, 215)); g.fillRoundRect(300, 280, 500, 76, 22, 22)
g.setColor(new Color(165, 239, 192)); g.setStroke(new BasicStroke(2f)); g.drawRoundRect(300, 280, 500, 76, 22, 22)
g.setFont(new Font("SansSerif", Font.BOLD, 23)); g.setColor(Color.WHITE)
val label = if (playerName.isEmpty) "Type your name..." else playerName
g.drawString(label + (if (editingName) "|" else ""), 330, 327)
drawButton(g, 390, 425, 320, 62, "CONTINUE", true)
drawCentered(g, "Click the name box, type your name, then click Continue.", VIEW_W / 2, 525, new Font("SansSerif", Font.PLAIN, 15), new Color(226, 255, 231))
}
private def drawAvatar(g: Graphics2D): Unit = {
drawBackdrop(g)
drawCentered(g, "CHOOSE YOUR BLOOM GUARDIAN", VIEW_W / 2, 145, new Font("Serif", Font.BOLD, 32), new Color(255, 239, 177))
val names = Array("MOSS RANGER", "PETAL MAGE", "CRYSTAL KNIGHT", "SUN GUARDIAN")
var i = 0
while (i < 4) {
val x = 105 + i * 225
val selected = avatar == i
g.setColor(if (selected) new Color(45, 119, 79, 235) else new Color(7, 36, 35, 220))
g.fillRoundRect(x, 245, 175, 220, 20, 20)
g.setColor(if (selected) new Color(255, 225, 130) else new Color(133, 207, 164))
g.setStroke(new BasicStroke(if (selected) 4f else 2f))
g.drawRoundRect(x, 245, 175, 220, 20, 20)
drawAvatarSprite(g, x + 87, 330, i, 1.25)
drawCentered(g, names(i), x + 87, 420, new Font("SansSerif", Font.BOLD, 13), Color.WHITE)
drawCentered(g, selectedLabel(i), x + 87, 447, new Font("SansSerif", Font.PLAIN, 11), new Color(203, 245, 214))
i += 1
}
drawButton(g, 390, 535, 320, 62, "ENTER THE REALM", true)
drawCentered(g, "Click a guardian to select your avatar.", VIEW_W / 2, 635, new Font("SansSerif", Font.PLAIN, 14), Color.WHITE)
}
private def selectedLabel(i: Int): String = i match {
case 0 => "Quick explorer"
case 1 => "Nature energy"
case 2 => "Strong shield"
case _ => "Balanced guardian"
}
private def drawBackdrop(g: Graphics2D): Unit = {
g.setPaint(new GradientPaint(0, 0, new Color(7, 37, 42), 0, VIEW_H, new Color(19, 91, 62)))
g.fillRect(0, 0, VIEW_W, VIEW_H)
var i = 0
while (i < 34) {
val x = (i * 137 + 43) % VIEW_W
val y = (i * 79 + 27) % 430
val r = 2 + (i % 4)
g.setColor(new Color(210, 255, 210, 95 + (i % 4) * 25))
g.fillOval(x, y, r, r)
i += 1
}
g.setColor(new Color(8, 56, 42))
g.fillOval(-120, 430, 430, 420)
g.fillOval(760, 420, 480, 460)
g.setColor(new Color(13, 76, 51))
g.fillOval(120, 490, 480, 310)
g.fillOval(570, 480, 470, 340)
}
private def drawGame(g: Graphics2D): Unit = {
val old = g.getTransform
g.translate(-camX.toInt, -camY.toInt)
val top = realm match {
case 0 => new Color(40, 112, 71)
case 1 => new Color(40, 105, 105)
case _ => new Color(43, 66, 103)
}
val bottom = realm match {
case 0 => new Color(13, 67, 48)
case 1 => new Color(12, 66, 80)
case _ => new Color(20, 38, 77)
}
g.setPaint(new GradientPaint(0, 0, top, 0, WORLD_H.toFloat, bottom))
g.fillRect(0, 0, WORLD_W.toInt, WORLD_H.toInt)
g.setColor(new Color(210, 246, 187, 22))
var gx = 0
while (gx < WORLD_W.toInt) { g.drawLine(gx, 0, gx, WORLD_H.toInt); gx += 100 }
var gy = 0
while (gy < WORLD_H.toInt) { g.drawLine(0, gy, WORLD_W.toInt, gy); gy += 100 }
drawWindingPath(g)
var i = 0
while (i < flowers.length) {
val f = flowers(i)
drawFlower(g, f._1, f._2, f._3)
i += 1
}
i = 0
while (i < trees.length) { val t = trees(i); drawTree(g, t.x, t.y, t.size, t.kind); i += 1 }
drawBase(g)
drawPortal(g)
i = 0
while (i < crystals.length) { val c = crystals(i); if (!c.collected) drawCrystal(g, c.x, c.y, c.kind); i += 1 }
i = 0
while (i < wisps.length) { val w = wisps(i); drawWisp(g, w.x, w.y, w.stunned > 0.0); i += 1 }
drawPlayer(g, playerX, playerY)
if (shieldTime > 0.0) {
g.setColor(new Color(160, 235, 255, 95))
g.setStroke(new BasicStroke(4f))
g.drawOval((playerX - 29).toInt, (playerY - 36).toInt, 58, 72)
}
g.setTransform(old)
drawHud(g)
}
private def drawWindingPath(g: Graphics2D): Unit = {
val p = new Polygon()
p.addPoint(0, (WORLD_H * 0.52).toInt - 70)
p.addPoint(430, (WORLD_H * 0.52).toInt - 110)
p.addPoint(690, (WORLD_H * 0.35).toInt)
p.addPoint(980, (WORLD_H * 0.42).toInt + 80)
p.addPoint(1250, (WORLD_H * 0.63).toInt)
p.addPoint(WORLD_W.toInt, WORLD_H.toInt - 120)
g.setColor(new Color(192, 178, 117, 45)); g.setStroke(new BasicStroke(105f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g.drawPolyline(Array(0, 430, 690, 980, 1250, WORLD_W.toInt), Array((WORLD_H * 0.52).toInt, (WORLD_H * 0.52).toInt - 110, (WORLD_H * 0.35).toInt, (WORLD_H * 0.42).toInt + 80, (WORLD_H * 0.63).toInt, WORLD_H.toInt - 120), 6)
g.setColor(new Color(234, 220, 167, 25)); g.setStroke(new BasicStroke(3f)); g.drawPolyline(Array(0, 430, 690, 980, 1250, WORLD_W.toInt), Array((WORLD_H * 0.52).toInt, (WORLD_H * 0.52).toInt - 110, (WORLD_H * 0.35).toInt, (WORLD_H * 0.42).toInt + 80, (WORLD_H * 0.63).toInt, WORLD_H.toInt - 120), 6)
}
private def drawTree(g: Graphics2D, x: Double, y: Double, scale: Double, kind: Int): Unit = {
val s = scale
g.setColor(new Color(56, 43, 32)); g.fillRoundRect((x - 8 * s).toInt, (y - 12 * s).toInt, (16 * s).toInt, (43 * s).toInt, 8, 8)
val c = kind match {
case 0 => new Color(35, 105, 65)
case 1 => new Color(45, 132, 92)
case _ => new Color(64, 112, 97)
}
g.setColor(c); g.fillOval((x - 37 * s).toInt, (y - 61 * s).toInt, (74 * s).toInt, (68 * s).toInt)
g.setColor(c.brighter()); g.fillOval((x - 25 * s).toInt, (y - 76 * s).toInt, (49 * s).toInt, (54 * s).toInt)
g.setColor(new Color(194, 255, 181, 105)); g.fillOval((x - 11 * s).toInt, (y - 65 * s).toInt, (17 * s).toInt, (17 * s).toInt)
}
private def drawFlower(g: Graphics2D, x: Double, y: Double, kind: Int): Unit = {
val col = kind match {
case 0 => new Color(255, 189, 222)
case 1 => new Color(248, 235, 164)
case 2 => new Color(182, 202, 255)
case 3 => new Color(255, 255, 235)
case _ => new Color(210, 165, 255)
}
g.setColor(new Color(38, 110, 61)); g.drawLine(x.toInt, y.toInt, x.toInt, (y + 9).toInt)
g.setColor(col)
g.fillOval((x - 4).toInt, (y - 7).toInt, 7, 7)
g.fillOval((x + 1).toInt, (y - 3).toInt, 7, 7)
g.fillOval((x - 7).toInt, (y - 2).toInt, 7, 7)
g.setColor(new Color(255, 224, 116)); g.fillOval((x - 2).toInt, (y - 2).toInt, 5, 5)
}
private def drawBase(g: Graphics2D): Unit = {
val x = 150.0; val y = WORLD_H * 0.52
g.setColor(new Color(255, 227, 128, 40)); g.fillOval((x - 65).toInt, (y - 57).toInt, 130, 114)
g.setColor(new Color(186, 232, 153)); g.setStroke(new BasicStroke(4f)); g.drawOval((x - 49).toInt, (y - 42).toInt, 98, 84)
drawLargeTree(g, x.toInt, y.toInt - 15, 0.45)
g.setColor(Color.WHITE); g.setFont(new Font("SansSerif", Font.BOLD, 13)); g.drawString("HOME GROVE", (x - 47).toInt, (y + 68).toInt)
}
private def drawPortal(g: Graphics2D): Unit = {
val x = WORLD_W - 190.0; val y = WORLD_H - 190.0
val required = crystalsCollected >= goalForRealm
val glow = if (required) new Color(247, 226, 129, 85) else new Color(110, 179, 190, 55)
g.setColor(glow); g.fillOval((x - 78).toInt, (y - 91).toInt, 156, 182)
g.setColor(if (required) new Color(255, 225, 136) else new Color(135, 206, 202))
g.setStroke(new BasicStroke(8f)); g.drawOval((x - 53).toInt, (y - 70).toInt, 106, 140)
g.setColor(new Color(22, 45, 62, 195)); g.fillOval((x - 43).toInt, (y - 60).toInt, 86, 120)
g.setColor(new Color(175, 245, 213, 155)); g.drawArc((x - 35).toInt, (y - 50).toInt, 70, 100, 40, 260)
g.setColor(Color.WHITE); g.setFont(new Font("SansSerif", Font.BOLD, 14)); g.drawString("ANCIENT TREE", (x - 55).toInt, (y + 103).toInt)
}
private def drawCrystal(g: Graphics2D, x: Double, y: Double, kind: Int): Unit = {
val col = kind match {
case 0 => new Color(140, 255, 186)
case 1 => new Color(126, 226, 255)
case 2 => new Color(233, 166, 255)
case _ => new Color(255, 225, 133)
}
g.setColor(new Color(col.getRed, col.getGreen, col.getBlue, 55)); g.fillOval((x - 21).toInt, (y - 21).toInt, 42, 42)
val p = new Polygon()
p.addPoint(x.toInt, (y - 17).toInt); p.addPoint((x + 12).toInt, (y - 2).toInt); p.addPoint(x.toInt, (y + 17).toInt); p.addPoint((x - 12).toInt, (y - 2).toInt)
g.setColor(col); g.fillPolygon(p)
g.setColor(Color.WHITE); g.setStroke(new BasicStroke(2f)); g.drawLine(x.toInt, (y - 12).toInt, (x + 4).toInt, (y - 1).toInt)
}
private def drawWisp(g: Graphics2D, x: Double, y: Double, stunned: Boolean): Unit = {
val col = if (stunned) new Color(170, 220, 255, 160) else new Color(177, 255, 210, 200)
g.setColor(new Color(col.getRed, col.getGreen, col.getBlue, 55)); g.fillOval((x - 24).toInt, (y - 24).toInt, 48, 48)
g.setColor(col); g.fillOval((x - 12).toInt, (y - 14).toInt, 24, 28)
g.setColor(new Color(30, 66, 56)); g.fillOval((x - 6).toInt, (y - 5).toInt, 4, 5); g.fillOval((x + 3).toInt, (y - 5).toInt, 4, 5)
}
private def drawPlayer(g: Graphics2D, x: Double, y: Double): Unit = {
g.setColor(new Color(0, 0, 0, 65)); g.fillOval((x - 18).toInt, (y + 15).toInt, 36, 13)
drawAvatarSprite(g, x.toInt, y.toInt, avatar, 0.72)
}
private def drawAvatarSprite(g: Graphics2D, x: Int, y: Int, style: Int, scale: Double): Unit = {
val coat = style match {
case 0 => new Color(80, 184, 115)
case 1 => new Color(175, 112, 218)
case 2 => new Color(85, 149, 203)
case _ => new Color(225, 166, 73)
}
val s = scale
g.setColor(new Color(0, 0, 0, 70)); g.fillOval((x - 15 * s).toInt, (y + 17 * s).toInt, (30 * s).toInt, (9 * s).toInt)
g.setColor(coat); g.fillRoundRect((x - 12 * s).toInt, (y - 1 * s).toInt, (24 * s).toInt, (27 * s).toInt, 10, 10)
g.setColor(new Color(239, 202, 151)); g.fillOval((x - 9 * s).toInt, (y - 22 * s).toInt, (18 * s).toInt, (19 * s).toInt)
g.setColor(new Color(47, 76, 54)); g.fillArc((x - 11 * s).toInt, (y - 26 * s).toInt, (22 * s).toInt, (16 * s).toInt, 0, 180)
g.setColor(new Color(255, 243, 189)); g.fillOval((x + 4 * s).toInt, (y - 16 * s).toInt, (3 * s).toInt, (3 * s).toInt)
}
private def drawLargeTree(g: Graphics2D, x: Int, y: Int, scale: Double): Unit = {
val s = scale
g.setColor(new Color(82, 57, 35)); g.fillRoundRect((x - 12 * s).toInt, (y - 5 * s).toInt, (24 * s).toInt, (85 * s).toInt, 12, 12)
g.setColor(new Color(39, 135, 82)); g.fillOval((x - 67 * s).toInt, (y - 91 * s).toInt, (134 * s).toInt, (112 * s).toInt)
g.setColor(new Color(62, 164, 98)); g.fillOval((x - 47 * s).toInt, (y - 116 * s).toInt, (94 * s).toInt, (95 * s).toInt)
g.setColor(new Color(189, 255, 174, 190)); g.fillOval((x - 10 * s).toInt, (y - 82 * s).toInt, (19 * s).toInt, (19 * s).toInt)
}
private def drawHud(g: Graphics2D): Unit = {
g.setColor(new Color(4, 25, 31, 205)); g.fillRoundRect(18, 16, 420, 105, 18, 18)
g.setColor(new Color(169, 231, 184)); g.setStroke(new BasicStroke(2f)); g.drawRoundRect(18, 16, 420, 105, 18, 18)
g.setFont(new Font("SansSerif", Font.BOLD, 17)); g.setColor(Color.WHITE); g.drawString("" + playerName + " ? " + realmName, 34, 44)
g.setFont(new Font("SansSerif", Font.PLAIN, 14)); g.drawString("Bloom Crystals: " + crystalsCollected + " / " + goalForRealm, 34, 70)
g.drawString("Coins: " + coins + " Health: " + health + " Nature Energy: " + energy.toInt, 34, 96)
g.setColor(new Color(4, 25, 31, 205)); g.fillRoundRect(VIEW_W - 193, 18, 172, 58, 15, 15)
g.setColor(new Color(240, 222, 149)); g.drawRoundRect(VIEW_W - 193, 18, 172, 58, 15, 15)
drawButton(g, VIEW_W - 178, 28, 142, 38, "PAUSE (P)", false)
if (messageTime > 0.0) {
g.setColor(new Color(7, 34, 34, 205)); g.fillRoundRect(190, VIEW_H - 66, 720, 42, 18, 18)
drawCentered(g, message, VIEW_W / 2, VIEW_H - 39, new Font("SansSerif", Font.BOLD, 14), new Color(255, 246, 205))
}
val barX = VIEW_W - 215; val barY = VIEW_H - 28
g.setColor(new Color(0, 0, 0, 130)); g.fillRoundRect(barX, barY, 180, 12, 8, 8)
g.setColor(new Color(100, 232, 155)); g.fillRoundRect(barX, barY, (180.0 * energy / 100.0).toInt, 12, 8, 8)
}
private def drawPause(g: Graphics2D): Unit = {
g.setColor(new Color(0, 0, 0, 165)); g.fillRect(0, 0, VIEW_W, VIEW_H)
drawCentered(g, "PAUSED", VIEW_W / 2, 265, new Font("Serif", Font.BOLD, 48), Color.WHITE)
drawButton(g, 390, 330, 320, 60, "RESUME", true)
drawButton(g, 390, 410, 320, 60, "RETURN TO MENU", false)
}
private def drawEnd(g: Graphics2D, success: Boolean): Unit = {
drawBackdrop(g)
if (success) {
drawLargeTree(g, VIEW_W / 2, 385, 1.55)
drawCentered(g, "ETERNAL BLOOM AWAKENED!", VIEW_W / 2, 145, new Font("Serif", Font.BOLD, 39), new Color(255, 239, 177))
drawCentered(g, "You restored the three realms, " + playerName + "!", VIEW_W / 2, 205, new Font("SansSerif", Font.PLAIN, 18), Color.WHITE)
} else {
drawCentered(g, "THE WISPS OVERTOOK YOU", VIEW_W / 2, 190, new Font("Serif", Font.BOLD, 38), new Color(255, 205, 180))
drawCentered(g, "Return to the Home Grove and try again.", VIEW_W / 2, 245, new Font("SansSerif", Font.PLAIN, 18), Color.WHITE)
}
drawButton(g, 390, 555, 320, 62, if (success) "PLAY AGAIN" else "RETRY", true)
}
private def drawButton(g: Graphics2D, x: Int, y: Int, w: Int, h: Int, label: String, bright: Boolean): Unit = {
g.setColor(if (bright) new Color(54, 139, 88) else new Color(20, 76, 69))
g.fillRoundRect(x, y, w, h, 22, 22)
g.setColor(if (bright) new Color(255, 224, 143) else new Color(163, 229, 185))
g.setStroke(new BasicStroke(2.2f)); g.drawRoundRect(x, y, w, h, 22, 22)
drawCentered(g, label, x + w / 2, y + h / 2 + 6, new Font("SansSerif", Font.BOLD, 17), Color.WHITE)
}
private def drawCentered(g: Graphics2D, text: String, centerX: Int, baselineY: Int, font: Font, color: Color): Unit = {
g.setFont(font); g.setColor(color)
val fm = g.getFontMetrics(font)
g.drawString(text, centerX - fm.stringWidth(text) / 2, baselineY)
}
private def inside(mx: Int, my: Int, x: Int, y: Int, w: Int, h: Int): Boolean = mx >= x && mx <= x + w && my >= y && my <= y + h
override def mousePressed(e: MouseEvent): Unit = {
requestFocusInWindow()
val mx = e.getX
val my = e.getY
screen match {
case MENU =>
if (inside(mx, my, 390, 555, 320, 66)) screen = LOGIN
case LOGIN =>
if (inside(mx, my, 300, 280, 500, 76)) {
if (!editingName && playerName == "Bloom Explorer") playerName = ""
editingName = true
}
else if (inside(mx, my, 390, 425, 320, 62)) {
if (playerName.trim.isEmpty) playerName = "Bloom Explorer"
editingName = false
screen = AVATAR
} else editingName = false
case AVATAR =>
var i = 0
while (i < 4) {
if (inside(mx, my, 105 + i * 225, 245, 175, 220)) avatar = i
i += 1
}
if (inside(mx, my, 390, 535, 320, 62)) beginGame()
case PLAY =>
if (inside(mx, my, VIEW_W - 193, 18, 172, 58)) screen = PAUSE
else {
targetX = mx + camX
targetY = my + camY
}
case PAUSE =>
if (inside(mx, my, 390, 330, 320, 60)) { screen = PLAY; requestFocusInWindow() }
else if (inside(mx, my, 390, 410, 320, 60)) { screen = MENU; keys.clear() }
case WIN => if (inside(mx, my, 390, 555, 320, 62)) beginGame()
case LOST => if (inside(mx, my, 390, 555, 320, 62)) beginGame()
case _ =>
}
repaint()
}
override def keyPressed(e: KeyEvent): Unit = {
val code = e.getKeyCode
if (screen == PLAY) {
keys += code
if (code == KeyEvent.VK_SPACE) startDash()
else if (code == KeyEvent.VK_Q) useShield()
else if (code == KeyEvent.VK_E) interact()
else if (code == KeyEvent.VK_P || code == KeyEvent.VK_ESCAPE) screen = PAUSE
} else if (screen == PAUSE && (code == KeyEvent.VK_P || code == KeyEvent.VK_ESCAPE)) {
screen = PLAY
requestFocusInWindow()
} else if (screen == LOGIN && code == KeyEvent.VK_ENTER) {
if (playerName.trim.isEmpty) playerName = "Bloom Explorer"
editingName = false
screen = AVATAR
} else if (screen == AVATAR && code == KeyEvent.VK_ENTER) {
beginGame()
}
}
override def keyReleased(e: KeyEvent): Unit = keys -= e.getKeyCode
override def keyTyped(e: KeyEvent): Unit = {
if (screen == LOGIN && editingName) {
val ch = e.getKeyChar
if (ch == '\b') {
if (playerName.length > 0) playerName = playerName.substring(0, playerName.length - 1)
} else if (!Character.isISOControl(ch) && playerName.length < 18) {
playerName += ch
}
repaint()
}
}
override def mouseClicked(e: MouseEvent): Unit = {}
override def mouseReleased(e: MouseEvent): Unit = {}
override def mouseEntered(e: MouseEvent): Unit = {}
override def mouseExited(e: MouseEvent): Unit = {}
}
}
InfinityRealmsEternalBloom.main(Array[String]())