Code Sketch
Bixuu02 pokemon battel game
Category: Programming
import java.awt.BasicStroke
import java.awt.BorderLayout
import java.awt.Color
import java.awt.Dimension
import java.awt.FlowLayout
import java.awt.Font
import java.awt.GradientPaint
import java.awt.Graphics
import java.awt.Graphics2D
import java.awt.GridLayout
import java.awt.RenderingHints
import java.awt.event.ActionEvent
import java.awt.event.ActionListener
import java.awt.event.MouseAdapter
import java.awt.event.MouseEvent
import javax.swing.BorderFactory
import javax.swing.JButton
import javax.swing.JFrame
import javax.swing.JLabel
import javax.swing.JOptionPane
import javax.swing.JPanel
import javax.swing.JPasswordField
import javax.swing.JScrollPane
import javax.swing.JTextField
import javax.swing.SwingConstants
import javax.swing.SwingUtilities
import javax.swing.Timer
import javax.swing.WindowConstants
import scala.util.Random
object BixuuCardsBattle {
// ============================================================
// COLORS
// ============================================================
val BG = new Color(8, 10, 24)
val PANEL = new Color(20, 24, 45)
val PANEL2 = new Color(32, 38, 68)
val WHITE = Color.WHITE
val CYAN = new Color(0, 220, 255)
val GOLD = new Color(255, 195, 45)
val GREEN = new Color(65, 235, 125)
val RED = new Color(255, 75, 90)
val PURPLE = new Color(180, 90, 255)
val MUTED = new Color(175, 185, 205)
val random = new Random()
// ============================================================
// CARD
// ============================================================
case class Card(
name: String,
power: Int,
speed: Int,
defense: Int,
magic: Int,
rarity: String,
description: String
)
// ============================================================
// CARDS
// ============================================================
val CARDS: Vector[Card] = Vector(
Card("Flamion",94,82,70,88,"LEGENDARY","Blazing fire monster"),
Card("Aquarion",82,91,79,92,"EPIC","Master of the deep ocean"),
Card("Voltix",91,98,61,86,"LEGENDARY","Lightning fast electric beast"),
Card("Leafra",74,77,91,84,"RARE","Guardian of the forest"),
Card("Shadowix",88,95,72,97,"LEGENDARY","Mysterious shadow creature"),
Card("Pyronox",99,76,68,89,"LEGENDARY","Volcano born monster"),
Card("Frostrix",84,83,86,90,"EPIC","Frozen warrior"),
Card("Terradon",86,64,99,72,"EPIC","Earth guardian"),
Card("Zephiron",79,100,68,87,"LEGENDARY","Ruler of the sky"),
Card("Abyssor",96,72,82,98,"LEGENDARY","Creature of the abyss"),
Card("Lumina",81,89,78,99,"LEGENDARY","Light spirit"),
Card("Drakion",100,74,91,88,"LEGENDARY","Ancient dragon warrior"),
Card("Venomix",87,92,73,81,"EPIC","Poison jungle hunter"),
Card("Rockor",77,55,100,64,"RARE","Living mountain"),
Card("Storma",93,97,75,91,"LEGENDARY","Storm controller"),
Card("Solaris",98,87,83,100,"MYTHIC","Solar energy creature"),
Card("Moonara",83,90,80,96,"EPIC","Mystical lunar creature"),
Card("Inferna",97,79,70,94,"LEGENDARY","Queen of flames"),
Card("Glacius",85,80,94,93,"EPIC","Frozen titan"),
Card("Thundra",92,99,76,90,"LEGENDARY","Thunder warrior"),
Card("Blazora",95,86,69,85,"EPIC","Fast fire dragon"),
Card("Aquafang",80,93,84,89,"RARE","Water hunter"),
Card("Darkron",94,88,81,96,"LEGENDARY","Dark energy monster"),
Card("Florion",73,84,93,88,"RARE","Magical flower beast"),
Card("Magnetor",89,78,87,82,"EPIC","Magnetic energy monster"),
Card("Cosmix",97,94,89,100,"MYTHIC","Outer space creature"),
Card("Nightfang",90,96,74,90,"LEGENDARY","Night predator"),
Card("Crystalon",78,73,98,95,"EPIC","Crystal guardian"),
Card("Razorix",91,100,67,79,"EPIC","Speed warrior"),
Card("Bixuu",100,100,100,100,"MYTHIC","Secret ultimate card")
)
// ============================================================
// USER
// ============================================================
case class UserData(
username: String,
password: String,
var wins: Int,
var losses: Int,
var xp: Int
)
var users: Vector[UserData] =
Vector(
UserData(
"player1",
"1234",
0,
0,
0
)
)
var currentUser: UserData =
users.head
// ============================================================
// WINDOW
// ============================================================
var frame: JFrame = _
var root: JPanel = _
// ============================================================
// BATTLE VARIABLES
// ============================================================
var playerCard: Card = _
var robotCard: Card = _
var playerCardView: BattleCardView = _
var robotCardView: BattleCardView = _
var battleMessage: JLabel = _
var scoreLabel: JLabel = _
var statButtons: JPanel = _
var currentRound = 1
var playerScore = 0
var robotScore = 0
var revealed = false
var playerCardSelected = false
var roundDone = false
var difficulty = "EASY"
var poolSize = 30
// ============================================================
// RUN
// ============================================================
def run(): Unit = {
SwingUtilities.invokeLater(
new Runnable {
def run(): Unit = {
createWindow()
showLogin()
}
}
)
}
// ============================================================
// WINDOW
// ============================================================
def createWindow(): Unit = {
frame =
new JFrame(
"BIXUU CARDS BATTLE"
)
frame.setDefaultCloseOperation(
WindowConstants.EXIT_ON_CLOSE
)
frame.setSize(
1180,
760
)
frame.setMinimumSize(
new Dimension(
1000,
680
)
)
frame.setLocationRelativeTo(null)
root =
new JPanel(
new BorderLayout()
)
root.setBackground(BG)
frame.setContentPane(root)
frame.setVisible(true)
}
// ============================================================
// CLEAR
// ============================================================
def clearScreen(): Unit = {
root.removeAll()
root.revalidate()
root.repaint()
}
// ============================================================
// LABEL
// ============================================================
def makeLabel(
text: String,
size: Int,
color: Color
): JLabel = {
val label =
new JLabel(text)
label.setFont(
new Font(
"Arial",
Font.BOLD,
size
)
)
label.setForeground(color)
label
}
// ============================================================
// TITLE
// ============================================================
def makeTitle(
text: String,
size: Int
): JLabel = {
val label =
new JLabel(
text,
SwingConstants.CENTER
)
label.setFont(
new Font(
"Arial",
Font.BOLD,
size
)
)
label.setForeground(WHITE)
label
}
// ============================================================
// BUTTON
// ============================================================
def makeButton(
text: String
): JButton = {
val button =
new JButton(text)
button.setFont(
new Font(
"Arial",
Font.BOLD,
16
)
)
button.setForeground(WHITE)
button.setBackground(PANEL2)
button.setFocusPainted(false)
button.setBorder(
BorderFactory.createCompoundBorder(
BorderFactory.createLineBorder(
CYAN,
2
),
BorderFactory.createEmptyBorder(
10,
15,
10,
15
)
)
)
button
}
// ============================================================
// LOGIN
// ============================================================
def showLogin(): Unit = {
clearScreen()
val panel =
new JPanel(
new GridLayout(
0,
1,
12,
12
)
)
panel.setBackground(PANEL)
panel.setBorder(
BorderFactory.createEmptyBorder(
70,
330,
70,
330
)
)
panel.add(
makeTitle(
"? BIXUU CARDS BATTLE ?",
32
)
)
panel.add(
makeLabel(
"USERNAME",
14,
MUTED
)
)
val username =
new JTextField("player1")
username.setFont(
new Font(
"Arial",
Font.PLAIN,
18
)
)
panel.add(username)
panel.add(
makeLabel(
"PASSWORD",
14,
MUTED
)
)
val password =
new JPasswordField("1234")
password.setFont(
new Font(
"Arial",
Font.PLAIN,
18
)
)
panel.add(password)
val login =
makeButton("LOGIN")
val create =
makeButton("CREATE ACCOUNT")
panel.add(login)
panel.add(create)
panel.add(
makeLabel(
"Default login: player1 / 1234",
13,
MUTED
)
)
login.addActionListener(
new ActionListener {
def actionPerformed(
e: ActionEvent
): Unit = {
val name =
username.getText.trim
val pass =
new String(
password.getPassword
)
users.find(
u =>
u.username == name &&
u.password == pass
) match {
case Some(u) =>
currentUser = u
showHome()
case None =>
JOptionPane.showMessageDialog(
frame,
"Wrong username or password!",
"LOGIN ERROR",
JOptionPane.ERROR_MESSAGE
)
}
}
}
)
create.addActionListener(
new ActionListener {
def actionPerformed(
e: ActionEvent
): Unit = {
showCreateAccount()
}
}
)
root.add(
panel,
BorderLayout.CENTER
)
root.revalidate()
root.repaint()
}
// ============================================================
// CREATE ACCOUNT
// ============================================================
def showCreateAccount(): Unit = {
clearScreen()
val panel =
new JPanel(
new GridLayout(
0,
1,
12,
12
)
)
panel.setBackground(PANEL)
panel.setBorder(
BorderFactory.createEmptyBorder(
60,
330,
60,
330
)
)
panel.add(
makeTitle(
"CREATE ACCOUNT",
30
)
)
val user =
new JTextField()
val pass =
new JPasswordField()
val confirm =
new JPasswordField()
panel.add(
makeLabel(
"USERNAME",
14,
MUTED
)
)
panel.add(user)
panel.add(
makeLabel(
"PASSWORD",
14,
MUTED
)
)
panel.add(pass)
panel.add(
makeLabel(
"CONFIRM PASSWORD",
14,
MUTED
)
)
panel.add(confirm)
val create =
makeButton("CREATE")
val back =
makeButton("BACK")
panel.add(create)
panel.add(back)
create.addActionListener(
new ActionListener {
def actionPerformed(
e: ActionEvent
): Unit = {
val name =
user.getText.trim
val p =
new String(
pass.getPassword
)
val p2 =
new String(
confirm.getPassword
)
if (
name.isEmpty ||
p.isEmpty
) {
JOptionPane.showMessageDialog(
frame,
"Enter username and password!",
"ERROR",
JOptionPane.ERROR_MESSAGE
)
} else if (p != p2) {
JOptionPane.showMessageDialog(
frame,
"Passwords do not match!",
"ERROR",
JOptionPane.ERROR_MESSAGE
)
} else if (
users.exists(
_.username == name
)
) {
JOptionPane.showMessageDialog(
frame,
"Username already exists!",
"ERROR",
JOptionPane.ERROR_MESSAGE
)
} else {
val newUser =
UserData(
name,
p,
0,
0,
0
)
users =
users :+ newUser
currentUser =
newUser
showHome()
}
}
}
)
back.addActionListener(
new ActionListener {
def actionPerformed(
e: ActionEvent
): Unit = {
showLogin()
}
}
)
root.add(
panel,
BorderLayout.CENTER
)
root.revalidate()
root.repaint()
}
// ============================================================
// HOME
// ============================================================
def showHome(): Unit = {
clearScreen()
val header =
new JPanel(
new BorderLayout()
)
header.setBackground(PANEL)
header.setBorder(
BorderFactory.createEmptyBorder(
15,
20,
15,
20
)
)
header.add(
makeLabel(
"? BIXUU CARDS BATTLE",
28,
GOLD
),
BorderLayout.WEST
)
header.add(
makeLabel(
"PLAYER: " +
currentUser.username +
" | WINS: " +
currentUser.wins +
" | LOSSES: " +
currentUser.losses +
" | XP: " +
currentUser.xp,
14,
WHITE
),
BorderLayout.EAST
)
val menu =
new JPanel(
new GridLayout(
2,
3,
20,
20
)
)
menu.setBackground(BG)
menu.setBorder(
BorderFactory.createEmptyBorder(
70,
100,
70,
100
)
)
val battle =
makeButton(
"? ROBOT BATTLE"
)
val collection =
makeButton(
"? CARD COLLECTION"
)
val profile =
makeButton(
"? PROFILE"
)
val rules =
makeButton(
"? HOW TO PLAY"
)
val randomCardButton =
makeButton(
"? RANDOM CARD"
)
val logout =
makeButton(
"? LOGOUT"
)
menu.add(battle)
menu.add(collection)
menu.add(profile)
menu.add(rules)
menu.add(randomCardButton)
menu.add(logout)
battle.addActionListener(
new ActionListener {
def actionPerformed(
e: ActionEvent
): Unit = showDifficulty()
}
)
collection.addActionListener(
new ActionListener {
def actionPerformed(
e: ActionEvent
): Unit = showCollection()
}
)
profile.addActionListener(
new ActionListener {
def actionPerformed(
e: ActionEvent
): Unit = showProfile()
}
)
rules.addActionListener(
new ActionListener {
def actionPerformed(
e: ActionEvent
): Unit = showRules()
}
)
randomCardButton.addActionListener(
new ActionListener {
def actionPerformed(
e: ActionEvent
): Unit = {
val c =
randomCard()
JOptionPane.showMessageDialog(
frame,
"CARD: " + c.name +
"\n\nPower: " + c.power +
"\nSpeed: " + c.speed +
"\nDefense: " + c.defense +
"\nMagic: " + c.magic +
"\nRarity: " + c.rarity +
"\n\n" + c.description,
"RANDOM CARD",
JOptionPane.INFORMATION_MESSAGE
)
}
}
)
logout.addActionListener(
new ActionListener {
def actionPerformed(
e: ActionEvent
): Unit = showLogin()
}
)
root.add(
header,
BorderLayout.NORTH
)
root.add(
menu,
BorderLayout.CENTER
)
root.revalidate()
root.repaint()
}
// ============================================================
// DIFFICULTY
// ============================================================
def showDifficulty(): Unit = {
clearScreen()
val panel =
new JPanel(
new GridLayout(
0,
1,
15,
15
)
)
panel.setBackground(BG)
panel.setBorder(
BorderFactory.createEmptyBorder(
70,
300,
70,
300
)
)
panel.add(
makeTitle(
"CHOOSE ROBOT DIFFICULTY",
32
)
)
val easy =
makeButton(
"EASY ? 30 CARD POOL"
)
val medium =
makeButton(
"MEDIUM ? 20 CARD POOL"
)
val hard =
makeButton(
"HARD ? 10 CARD POOL"
)
val back =
makeButton(
"BACK"
)
panel.add(easy)
panel.add(medium)
panel.add(hard)
panel.add(back)
easy.addActionListener(
new ActionListener {
def actionPerformed(
e: ActionEvent
): Unit =
startBattle(
"EASY",
30
)
}
)
medium.addActionListener(
new ActionListener {
def actionPerformed(
e: ActionEvent
): Unit =
startBattle(
"MEDIUM",
20
)
}
)
hard.addActionListener(
new ActionListener {
def actionPerformed(
e: ActionEvent
): Unit =
startBattle(
"HARD",
10
)
}
)
back.addActionListener(
new ActionListener {
def actionPerformed(
e: ActionEvent
): Unit =
showHome()
}
)
root.add(
panel,
BorderLayout.CENTER
)
root.revalidate()
root.repaint()
}
// ============================================================
// CARD HELPERS
// ============================================================
def randomCard(): Card = {
CARDS(
random.nextInt(
CARDS.length
)
)
}
def statValue(
card: Card,
stat: String
): Int = {
stat match {
case "POWER" =>
card.power
case "SPEED" =>
card.speed
case "DEFENSE" =>
card.defense
case "MAGIC" =>
card.magic
case _ =>
0
}
}
def bestStat(
card: Card
): String = {
Vector(
"POWER" -> card.power,
"SPEED" -> card.speed,
"DEFENSE" -> card.defense,
"MAGIC" -> card.magic
).maxBy(
x => x._2
)._1
}
// ============================================================
// CARD VIEW
// ============================================================
class BattleCardView
extends JPanel {
var card: Option[Card] =
None
var revealed =
false
var selected =
false
var flipAngle =
0.0
setPreferredSize(
new Dimension(
330,
440
)
)
setOpaque(false)
// ==========================================================
// IMPORTANT:
// CARD PANEL ITSELF IS CLICKABLE
// ==========================================================
addMouseListener(
new MouseAdapter {
override def mousePressed(
e: MouseEvent
): Unit = {
if (
revealed &&
!roundDone &&
!isRobotCardView
) {
selectPlayerCard()
}
}
}
)
def isRobotCardView: Boolean = {
this eq robotCardView
}
def selectPlayerCard(): Unit = {
playerCardSelected = true
selected = true
repaint()
if (battleMessage != null) {
battleMessage.setText(
"? YOUR CARD SELECTED! NOW CHOOSE A STAT!"
)
}
enableStats(true)
}
override def paintComponent(
g: Graphics
): Unit = {
super.paintComponent(g)
val g2 =
g.asInstanceOf[Graphics2D]
g2.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON
)
val w =
getWidth
val h =
getHeight
val cardWidth =
w - 40
val cardHeight =
h - 30
val scale =
math.abs(
math.cos(
flipAngle
)
)
val drawWidth =
math.max(
10,
(cardWidth * scale).toInt
)
val drawX =
(w - drawWidth) / 2
// --------------------------------------------------------
// CARD BACK
// --------------------------------------------------------
if (!revealed) {
g2.setPaint(
new GradientPaint(
0,
0,
new Color(
80,
20,
140
),
w,
h,
new Color(
5,
70,
140
)
)
)
g2.fillRoundRect(
drawX,
15,
drawWidth,
cardHeight,
30,
30
)
g2.setColor(CYAN)
g2.setStroke(
new BasicStroke(4)
)
g2.drawRoundRect(
drawX,
15,
drawWidth,
cardHeight,
30,
30
)
if (
drawWidth > 60
) {
g2.setColor(GOLD)
g2.setFont(
new Font(
"Arial",
Font.BOLD,
65
)
)
g2.drawString(
"?",
w / 2 - 20,
h / 2 + 25
)
}
} else {
// ------------------------------------------------------
// REVEALED CARD
// ------------------------------------------------------
val c =
card.get
g2.setPaint(
new GradientPaint(
0,
0,
new Color(
45,
20,
80
),
w,
h,
new Color(
10,
50,
80
)
)
)
g2.fillRoundRect(
drawX,
15,
drawWidth,
cardHeight,
30,
30
)
if (selected) {
g2.setColor(GOLD)
g2.setStroke(
new BasicStroke(6)
)
} else {
g2.setColor(CYAN)
g2.setStroke(
new BasicStroke(2)
)
}
g2.drawRoundRect(
drawX,
15,
drawWidth,
cardHeight,
30,
30
)
if (
drawWidth > 120
) {
g2.setColor(GOLD)
g2.setFont(
new Font(
"Arial",
Font.BOLD,
23
)
)
g2.drawString(
c.name,
drawX + 18,
55
)
g2.setColor(
rarityColor(
c.rarity
)
)
g2.setFont(
new Font(
"Arial",
Font.BOLD,
13
)
)
g2.drawString(
c.rarity,
drawX + 20,
78
)
g2.setColor(
new Color(
110,
65,
160
)
)
g2.fillOval(
drawX +
drawWidth / 2 -
55,
95,
110,
110
)
g2.setColor(GOLD)
g2.setFont(
new Font(
"Arial",
Font.BOLD,
50
)
)
g2.drawString(
c.name.substring(0, 1),
drawX +
drawWidth / 2 -
16,
170
)
drawStat(
g2,
"POWER",
c.power,
drawX + 20,
245
)
drawStat(
g2,
"SPEED",
c.speed,
drawX + 20,
280
)
drawStat(
g2,
"DEFENSE",
c.defense,
drawX + 20,
315
)
drawStat(
g2,
"MAGIC",
c.magic,
drawX + 20,
350
)
g2.setColor(MUTED)
g2.setFont(
new Font(
"Arial",
Font.PLAIN,
12
)
)
g2.drawString(
c.description,
drawX + 20,
395
)
// ----------------------------------------------------
// TAP INDICATOR
// ----------------------------------------------------
if (
!isRobotCardView &&
!selected &&
revealed &&
!roundDone
) {
g2.setColor(
new Color(
255,
255,
255,
220
)
)
g2.setFont(
new Font(
"Arial",
Font.BOLD,
14
)
)
g2.drawString(
"TAP THIS CARD",
drawX + 90,
425
)
}
if (
!isRobotCardView &&
selected
) {
g2.setColor(GOLD)
g2.setFont(
new Font(
"Arial",
Font.BOLD,
15
)
)
g2.drawString(
"? SELECTED",
drawX + 100,
425
)
}
}
}
}
def drawStat(
g: Graphics2D,
name: String,
value: Int,
x: Int,
y: Int
): Unit = {
g.setColor(WHITE)
g.setFont(
new Font(
"Arial",
Font.BOLD,
13
)
)
g.drawString(
name,
x,
y
)
g.setColor(PANEL2)
g.fillRoundRect(
x + 80,
y - 14,
150,
17,
10,
10
)
g.setColor(
if (value >= 90)
GOLD
else if (value >= 75)
CYAN
else
GREEN
)
g.fillRoundRect(
x + 80,
y - 14,
(150.0 * value / 100.0).toInt,
17,
10,
10
)
g.setColor(WHITE)
g.drawString(
value.toString,
x + 240,
y
)
}
}
// ============================================================
// START BATTLE
// ============================================================
def startBattle(
diff: String,
size: Int
): Unit = {
difficulty = diff
poolSize = size
currentRound = 1
playerScore = 0
robotScore = 0
showBattle()
}
// ============================================================
// GET CARD
// ============================================================
def getPoolCard(): Card = {
val size =
math.min(
poolSize,
CARDS.length
)
CARDS(
random.nextInt(size)
)
}
// ============================================================
// SHOW BATTLE
// ============================================================
def showBattle(): Unit = {
clearScreen()
revealed = false
playerCardSelected = false
roundDone = false
playerCard =
getPoolCard()
robotCard =
getPoolCard()
val header =
new JPanel(
new BorderLayout()
)
header.setBackground(PANEL)
header.setBorder(
BorderFactory.createEmptyBorder(
10,
20,
10,
20
)
)
header.add(
makeTitle(
"ROUND " +
currentRound +
" / 10",
24
),
BorderLayout.WEST
)
scoreLabel =
makeLabel(
"YOU: " +
playerScore +
" ROBOT: " +
robotScore,
20,
GOLD
)
scoreLabel.setHorizontalAlignment(
SwingConstants.CENTER
)
header.add(
scoreLabel,
BorderLayout.CENTER
)
header.add(
makeLabel(
difficulty,
18,
CYAN
),
BorderLayout.EAST
)
// ----------------------------------------------------------
// CARDS
// ----------------------------------------------------------
val cards =
new JPanel(
new GridLayout(
1,
2,
50,
0
)
)
cards.setBackground(BG)
cards.setBorder(
BorderFactory.createEmptyBorder(
20,
100,
10,
100
)
)
robotCardView =
new BattleCardView
playerCardView =
new BattleCardView
robotCardView.card =
Some(robotCard)
playerCardView.card =
Some(playerCard)
val robotBox =
new JPanel(
new BorderLayout()
)
robotBox.setBackground(BG)
robotBox.add(
makeTitle(
"? ROBOT CARD",
20
),
BorderLayout.NORTH
)
robotBox.add(
robotCardView,
BorderLayout.CENTER
)
val playerBox =
new JPanel(
new BorderLayout()
)
playerBox.setBackground(BG)
playerBox.add(
makeTitle(
"? YOUR CARD",
20
),
BorderLayout.NORTH
)
playerBox.add(
playerCardView,
BorderLayout.CENTER
)
cards.add(robotBox)
cards.add(playerBox)
// ==========================================================
// EXTRA CLICK LISTENER ON PLAYER BOX
// This makes the whole YOUR CARD area clickable.
// ==========================================================
playerBox.addMouseListener(
new MouseAdapter {
override def mousePressed(
e: MouseEvent
): Unit = {
if (
revealed &&
!roundDone
) {
playerCardSelected = true
playerCardView.selected =
true
playerCardView.repaint()
battleMessage.setText(
"? CARD SELECTED! CHOOSE POWER / SPEED / DEFENSE / MAGIC."
)
enableStats(true)
}
}
}
)
// Also make the card itself clickable.
playerCardView.addMouseListener(
new MouseAdapter {
override def mousePressed(
e: MouseEvent
): Unit = {
if (
revealed &&
!roundDone
) {
playerCardSelected = true
playerCardView.selected =
true
playerCardView.repaint()
battleMessage.setText(
"? YOUR CARD SELECTED! NOW CHOOSE A STAT!"
)
enableStats(true)
}
}
}
)
// ==========================================================
// BOTTOM
// ==========================================================
val bottom =
new JPanel(
new BorderLayout()
)
bottom.setBackground(PANEL)
bottom.setBorder(
BorderFactory.createEmptyBorder(
10,
20,
15,
20
)
)
battleMessage =
makeLabel(
"PRESS FLIP CARDS TO START!",
16,
WHITE
)
battleMessage.setHorizontalAlignment(
SwingConstants.CENTER
)
bottom.add(
battleMessage,
BorderLayout.NORTH
)
val controls =
new JPanel(
new BorderLayout()
)
controls.setBackground(PANEL)
val left =
new JPanel(
new FlowLayout()
)
left.setBackground(PANEL)
val flip =
makeButton(
"? FLIP CARDS"
)
val exit =
makeButton(
"EXIT"
)
left.add(flip)
left.add(exit)
controls.add(
left,
BorderLayout.WEST
)
statButtons =
new JPanel(
new FlowLayout()
)
statButtons.setBackground(PANEL)
val power =
makeButton(
"? POWER"
)
val speed =
makeButton(
"? SPEED"
)
val defense =
makeButton(
"? DEFENSE"
)
val magic =
makeButton(
"? MAGIC"
)
statButtons.add(power)
statButtons.add(speed)
statButtons.add(defense)
statButtons.add(magic)
enableStats(false)
controls.add(
statButtons,
BorderLayout.CENTER
)
bottom.add(
controls,
BorderLayout.SOUTH
)
// ==========================================================
// FLIP
// ==========================================================
flip.addActionListener(
new ActionListener {
def actionPerformed(
e: ActionEvent
): Unit = {
if (!revealed) {
flipCards()
}
}
}
)
// ==========================================================
// STATS
// ==========================================================
power.addActionListener(
new ActionListener {
def actionPerformed(
e: ActionEvent
): Unit = {
chooseStat("POWER")
}
}
)
speed.addActionListener(
new ActionListener {
def actionPerformed(
e: ActionEvent
): Unit = {
chooseStat("SPEED")
}
}
)
defense.addActionListener(
new ActionListener {
def actionPerformed(
e: ActionEvent
): Unit = {
chooseStat("DEFENSE")
}
}
)
magic.addActionListener(
new ActionListener {
def actionPerformed(
e: ActionEvent
): Unit = {
chooseStat("MAGIC")
}
}
)
exit.addActionListener(
new ActionListener {
def actionPerformed(
e: ActionEvent
): Unit = {
showHome()
}
}
)
root.add(
header,
BorderLayout.NORTH
)
root.add(
cards,
BorderLayout.CENTER
)
root.add(
bottom,
BorderLayout.SOUTH
)
root.revalidate()
root.repaint()
}
// ============================================================
// ENABLE STATS
// ============================================================
def enableStats(
enabled: Boolean
): Unit = {
if (
statButtons != null
) {
var i = 0
while (
i <
statButtons.getComponentCount
) {
statButtons
.getComponent(i)
.setEnabled(enabled)
i += 1
}
}
}
// ============================================================
// FLIP ANIMATION
// ============================================================
def flipCards(): Unit = {
revealed = true
playerCardSelected = false
battleMessage.setText(
"? SPINNING CARD FLIP..."
)
enableStats(false)
val start =
System.currentTimeMillis()
val duration =
1100L
val timer =
new Timer(
25,
null
)
timer.addActionListener(
new ActionListener {
def actionPerformed(
e: ActionEvent
): Unit = {
val elapsed =
System.currentTimeMillis() -
start
val progress =
math.min(
1.0,
elapsed.toDouble /
duration.toDouble
)
val angle =
progress * math.Pi
playerCardView.flipAngle =
angle
robotCardView.flipAngle =
angle
if (
progress >= 0.5
) {
playerCardView.revealed =
true
robotCardView.revealed =
true
}
playerCardView.repaint()
robotCardView.repaint()
if (
progress >= 1.0
) {
timer.stop()
playerCardView.revealed =
true
robotCardView.revealed =
true
playerCardView.flipAngle =
math.Pi
robotCardView.flipAngle =
math.Pi
playerCardView.repaint()
robotCardView.repaint()
battleMessage.setText(
"? TAP YOUR CARD TO SELECT IT!"
)
}
}
}
)
timer.start()
}
// ============================================================
// CHOOSE STAT
// ============================================================
def chooseStat(
stat: String
): Unit = {
if (!revealed) {
battleMessage.setText(
"FLIP THE CARDS FIRST!"
)
return
}
if (!playerCardSelected) {
battleMessage.setText(
"? TAP YOUR CARD FIRST!"
)
return
}
if (roundDone)
return
roundDone = true
enableStats(false)
val playerValue =
statValue(
playerCard,
stat
)
val robotStat =
robotChooseStat()
val robotValue =
statValue(
robotCard,
robotStat
)
if (
playerValue >
robotValue
) {
playerScore += 1
currentUser.wins += 1
currentUser.xp += 20
battleMessage.setText(
"? YOU WIN! " +
stat +
" " +
playerValue +
" VS " +
robotStat +
" " +
robotValue
)
} else if (
playerValue <
robotValue
) {
robotScore += 1
currentUser.losses += 1
currentUser.xp += 5
battleMessage.setText(
"? ROBOT WINS! " +
stat +
" " +
playerValue +
" VS " +
robotStat +
" " +
robotValue
)
} else {
currentUser.xp += 10
battleMessage.setText(
"? DRAW! " +
playerValue +
" VS " +
robotValue
)
}
scoreLabel.setText(
"YOU: " +
playerScore +
" ROBOT: " +
robotScore
)
val next =
new Timer(
1800,
null
)
next.setRepeats(false)
next.addActionListener(
new ActionListener {
def actionPerformed(
e: ActionEvent
): Unit = {
if (
currentRound >= 10
) {
showResult()
} else {
currentRound += 1
showBattle()
}
}
}
)
next.start()
}
// ============================================================
// ROBOT AI
// ============================================================
def robotChooseStat(): String = {
difficulty match {
case "EASY" =>
val stats =
Vector(
"POWER",
"SPEED",
"DEFENSE",
"MAGIC"
)
stats(
random.nextInt(
stats.length
)
)
case "MEDIUM" =>
if (
random.nextInt(100) < 75
) {
bestStat(
robotCard
)
} else {
val stats =
Vector(
"POWER",
"SPEED",
"DEFENSE",
"MAGIC"
)
stats(
random.nextInt(
stats.length
)
)
}
case "HARD" =>
val stats =
Vector(
"POWER",
"SPEED",
"DEFENSE",
"MAGIC"
)
stats.maxBy(
s =>
statValue(
robotCard,
s
) -
statValue(
playerCard,
s
)
)
case _ =>
"POWER"
}
}
// ============================================================
// RESULT
// ============================================================
def showResult(): Unit = {
clearScreen()
val panel =
new JPanel(
new GridLayout(
0,
1,
18,
18
)
)
panel.setBackground(BG)
panel.setBorder(
BorderFactory.createEmptyBorder(
70,
300,
70,
300
)
)
val result =
if (
playerScore >
robotScore
)
"? YOU ARE THE CHAMPION!"
else if (
playerScore <
robotScore
)
"? ROBOT WON!"
else
"? PERFECT DRAW!"
panel.add(
makeTitle(
result,
34
)
)
panel.add(
makeTitle(
"YOU " +
playerScore +
" - " +
robotScore +
" ROBOT",
28
)
)
panel.add(
makeTitle(
"XP: " +
currentUser.xp,
20
)
)
val again =
makeButton(
"? PLAY AGAIN"
)
val home =
makeButton(
"? HOME"
)
panel.add(again)
panel.add(home)
again.addActionListener(
new ActionListener {
def actionPerformed(
e: ActionEvent
): Unit =
showDifficulty()
}
)
home.addActionListener(
new ActionListener {
def actionPerformed(
e: ActionEvent
): Unit =
showHome()
}
)
root.add(
panel,
BorderLayout.CENTER
)
root.revalidate()
root.repaint()
}
// ============================================================
// COLLECTION
// ============================================================
def showCollection(): Unit = {
clearScreen()
val cards =
new JPanel(
new GridLayout(
0,
4,
10,
10
)
)
cards.setBackground(BG)
cards.setBorder(
BorderFactory.createEmptyBorder(
20,
20,
20,
20
)
)
CARDS.foreach {
c =>
val button =
new JButton(
"<html><center>" +
"<b>" +
c.name +
"</b><br>" +
c.rarity +
"<br><br>" +
"P " +
c.power +
" | S " +
c.speed +
"<br>" +
"D " +
c.defense +
" | M " +
c.magic +
"</center></html>"
)
button.setForeground(
WHITE
)
button.setBackground(
PANEL2
)
button.setFocusPainted(
false
)
button.setBorder(
BorderFactory.createLineBorder(
rarityColor(
c.rarity
),
2
)
)
button.addActionListener(
new ActionListener {
def actionPerformed(
e: ActionEvent
): Unit = {
JOptionPane.showMessageDialog(
frame,
c.name +
"\n\n" +
c.description +
"\n\nPower: " +
c.power +
"\nSpeed: " +
c.speed +
"\nDefense: " +
c.defense +
"\nMagic: " +
c.magic +
"\nRarity: " +
c.rarity,
"CARD DETAILS",
JOptionPane.INFORMATION_MESSAGE
)
}
}
)
cards.add(button)
}
val scroll =
new JScrollPane(
cards
)
scroll.setBorder(null)
val back =
makeButton(
"BACK HOME"
)
back.addActionListener(
new ActionListener {
def actionPerformed(
e: ActionEvent
): Unit =
showHome()
}
)
root.add(
makeTitle(
"? CARD COLLECTION",
30
),
BorderLayout.NORTH
)
root.add(
scroll,
BorderLayout.CENTER
)
root.add(
back,
BorderLayout.SOUTH
)
root.revalidate()
root.repaint()
}
// ============================================================
// RARITY
// ============================================================
def rarityColor(
rarity: String
): Color = {
rarity match {
case "MYTHIC" =>
new Color(
255,
80,
200
)
case "LEGENDARY" =>
GOLD
case "EPIC" =>
PURPLE
case "RARE" =>
CYAN
case _ =>
WHITE
}
}
// ============================================================
// PROFILE
// ============================================================
def showProfile(): Unit = {
clearScreen()
val panel =
new JPanel(
new GridLayout(
0,
1,
15,
15
)
)
panel.setBackground(PANEL)
panel.setBorder(
BorderFactory.createEmptyBorder(
70,
300,
70,
300
)
)
panel.add(
makeTitle(
"? PLAYER PROFILE",
32
)
)
panel.add(
makeLabel(
"Username: " +
currentUser.username,
20,
WHITE
)
)
panel.add(
makeLabel(
"Wins: " +
currentUser.wins,
20,
GREEN
)
)
panel.add(
makeLabel(
"Losses: " +
currentUser.losses,
20,
RED
)
)
panel.add(
makeLabel(
"XP: " +
currentUser.xp,
20,
GOLD
)
)
val back =
makeButton(
"BACK HOME"
)
back.addActionListener(
new ActionListener {
def actionPerformed(
e: ActionEvent
): Unit =
showHome()
}
)
panel.add(back)
root.add(
panel,
BorderLayout.CENTER
)
root.revalidate()
root.repaint()
}
// ============================================================
// RULES
// ============================================================
def showRules(): Unit = {
clearScreen()
val panel =
new JPanel(
new BorderLayout()
)
panel.setBackground(PANEL)
panel.setBorder(
BorderFactory.createEmptyBorder(
40,
100,
40,
100
)
)
panel.add(
makeTitle(
"? HOW TO PLAY",
32
),
BorderLayout.NORTH
)
val text =
"<html>" +
"<body style='font-family:Arial;font-size:17px'>" +
"<h2>BIXUU CARDS BATTLE</h2>" +
"<p>1. Choose a difficulty.</p>" +
"<p>2. Press FLIP CARDS.</p>" +
"<p>3. Cards spin and reveal.</p>" +
"<p>4. ? TAP YOUR CARD.</p>" +
"<p>5. Select POWER / SPEED / DEFENSE / MAGIC.</p>" +
"<p>6. Robot automatically chooses its stat.</p>" +
"<p>7. Higher number wins.</p>" +
"<p>8. Ten rounds decide the champion.</p>" +
"<p><b>BIXUU = 100 / 100 / 100 / 100</b></p>" +
"</body>" +
"</html>"
val info =
new JLabel(text)
info.setForeground(
WHITE
)
info.setHorizontalAlignment(
SwingConstants.CENTER
)
panel.add(
info,
BorderLayout.CENTER
)
val back =
makeButton(
"BACK HOME"
)
back.addActionListener(
new ActionListener {
def actionPerformed(
e: ActionEvent
): Unit =
showHome()
}
)
panel.add(
back,
BorderLayout.SOUTH
)
root.add(
panel,
BorderLayout.CENTER
)
root.revalidate()
root.repaint()
}
}
// ============================================================
// START GAME
// ============================================================
BixuuCardsBattle.run()