Code Sketch
yoiii111
Category: Programming
import java.awt.BasicStroke
import java.awt.BorderLayout
import java.awt.Color
import java.awt.GradientPaint
import java.awt.Graphics
import java.awt.Graphics2D
import java.awt.RenderingHints
import java.awt.Polygon
import java.awt.Point
import java.awt.event.ActionEvent
import java.awt.event.ActionListener
import java.awt.event.KeyAdapter
import java.awt.event.KeyEvent
import java.awt.event.MouseAdapter
import java.awt.event.MouseEvent
import javax.swing.JButton
import javax.swing.JFrame
import javax.swing.JLabel
import javax.swing.JPanel
import javax.swing.SwingConstants
import javax.swing.Timer
import javax.swing.WindowConstants
import scala.collection.mutable.ArrayBuffer
// ============================================================
// GOKUL ASHTAMI ULTRA FESTIVAL
// CLEAN SCALA / SWING VERSION
// ============================================================
//
// LEFT / A = MOVE LEFT
// RIGHT / D = MOVE RIGHT
// UP / W / SPACE= JUMP
// P = PAUSE
// R = RESET
// MOUSE CLICK = JUMP
//
// FEATURES
// - Janmashtami opening screen
// - Palna Utsav
// - Gokul adventure
// - Coins
// - Makhan
// - Enemies
// - Moving platforms
// - Dahi Handi
// - Levels
// - Score
// - Combo
// - Lives
// - Countdown
// - Checkpoint
// - Particles
// - Final celebration
// ============================================================
// ============================================================
// CONSTANTS
// ============================================================
val GAME_WIDTH: Int = 1200
val GAME_HEIGHT: Int = 760
val GROUND_HEIGHT: Int = 100
val PLAYER_WIDTH: Int = 46
val PLAYER_HEIGHT: Int = 64
val GRAVITY_VALUE: Double = 0.58
val JUMP_VALUE: Double = -12.5
val TOTAL_LEVELS: Int = 5
val LEVEL_TIME: Int = 70
// ============================================================
// DATA TYPES
// ============================================================
case class CoinData(
var x: Double,
var y: Double,
var collected: Boolean
)
case class MakhanData(
var x: Double,
var y: Double,
var collected: Boolean
)
case class EnemyData(
var x: Double,
var y: Double,
var vx: Double,
var minX: Double,
var maxX: Double,
var active: Boolean
)
case class PlatformData(
var x: Double,
var y: Double,
val width: Int,
val height: Int,
var vx: Double,
val minX: Double,
val maxX: Double
)
case class ParticleData(
var x: Double,
var y: Double,
var vx: Double,
var vy: Double,
var life: Int,
val kind: Int
)
case class StarData(
x: Double,
y: Double
)
case class FlowerData(
x: Int,
y: Int,
size: Int,
kind: Int
)
// ============================================================
// GAME STATE
// ============================================================
var stage: Int = 0
var level: Int = 1
var score: Int = 0
var lives: Int = 3
var timeLeft: Int = LEVEL_TIME
var combo: Int = 0
var bestCombo: Int = 0
var coinCount: Int = 0
var makhanCount: Int = 0
var running: Boolean = true
var paused: Boolean = false
var victory: Boolean = false
var playerX: Double = 120.0
var playerY: Double = 500.0
var velocityY: Double = 0.0
var jumping: Boolean = false
var leftPressed: Boolean = false
var rightPressed: Boolean = false
var invincibleTicks: Int = 0
var messageText: String = ""
var messageTicks: Int = 0
var festivalTicks: Int = 0
var glowTicks: Int = 0
var checkpointX: Double = 120.0
var checkpointActive: Boolean = false
var handiBroken: Boolean = false
var handiHits: Int = 0
var handiRequired: Int = 1
// ============================================================
// COLLECTIONS
// ============================================================
val coins =
ArrayBuffer[CoinData]()
val makhan =
ArrayBuffer[MakhanData]()
val enemies =
ArrayBuffer[EnemyData]()
val platforms =
ArrayBuffer[PlatformData]()
val particles =
ArrayBuffer[ParticleData]()
val stars =
ArrayBuffer[StarData]()
val flowers =
ArrayBuffer[FlowerData]()
// ============================================================
// FRAME / PANEL
// ============================================================
var gameFrame: JFrame = null
var festivalPanel: JPanel = null
var mainTimer: Timer = null
var clockTimer: Timer = null
// ============================================================
// HANDI
// ============================================================
val handiX: Double = 540.0
val handiY: Double = 95.0
// ============================================================
// BASIC HELPERS
// ============================================================
def clampValue(
value: Double,
minValue: Double,
maxValue: Double
): Double = {
math.max(
minValue,
math.min(
maxValue,
value
)
)
}
def rectanglesOverlap(
x1: Double,
y1: Double,
w1: Double,
h1: Double,
x2: Double,
y2: Double,
w2: Double,
h2: Double
): Boolean = {
x1 < x2 + w2 &&
x1 + w1 > x2 &&
y1 < y2 + h2 &&
y1 + h1 > y2
}
def playerTouches(
x: Double,
y: Double,
w: Double,
h: Double
): Boolean = {
rectanglesOverlap(
playerX,
playerY,
PLAYER_WIDTH,
PLAYER_HEIGHT,
x,
y,
w,
h
)
}
def addScore(
amount: Int
): Unit = {
score += amount
if (score < 0) {
score = 0
}
}
def addCombo(): Unit = {
combo += 1
if (combo > bestCombo) {
bestCombo = combo
}
}
def showMessage(
text: String,
ticks: Int
): Unit = {
messageText = text
messageTicks = ticks
}
// ============================================================
// PARTICLES
// ============================================================
def createBurst(
px: Double,
py: Double,
amount: Int
): Unit = {
var i: Int = 0
while (i < amount) {
val angle: Double =
math.random * math.Pi * 2.0
val speed: Double =
1.0 + math.random * 6.0
particles +=
ParticleData(
px,
py,
math.cos(angle) * speed,
math.sin(angle) * speed - 2.0,
30 + (math.random * 45).toInt,
i % 4
)
i += 1
}
}
def createStars(): Unit = {
stars.clear()
var i: Int = 0
while (i < 100) {
stars +=
StarData(
math.random * GAME_WIDTH,
math.random * 420
)
i += 1
}
}
// ============================================================
// CLEAR WORLD
// ============================================================
def clearWorld(): Unit = {
coins.clear()
makhan.clear()
enemies.clear()
platforms.clear()
particles.clear()
flowers.clear()
}
// ============================================================
// SETUP LEVEL
// ============================================================
def setupLevel(
requestedLevel: Int
): Unit = {
clearWorld()
level = requestedLevel
stage = 2
running = true
paused = false
victory = false
playerX = 120.0
playerY =
GAME_HEIGHT -
GROUND_HEIGHT -
PLAYER_HEIGHT
velocityY = 0.0
jumping = false
checkpointX = 120.0
checkpointActive = false
invincibleTicks = 0
handiBroken = false
handiHits = 0
if (level <= 2) {
handiRequired = 1
} else if (level <= 4) {
handiRequired = 2
} else {
handiRequired = 3
}
// ----------------------------------------------------------
// COINS
// ----------------------------------------------------------
val coinTotal: Int =
7 + level * 2
var i: Int = 0
while (i < coinTotal) {
val cx: Int =
150 + (i * 125) % 980
val cy: Int =
360 - (i % 3) * 65
coins +=
CoinData(
cx.toDouble,
cy.toDouble,
false
)
i += 1
}
// ----------------------------------------------------------
// MAKHAN
// ----------------------------------------------------------
val makhanTotal: Int =
2 + level
i = 0
while (i < makhanTotal) {
val mx: Int =
220 + (i * 170) % 850
val my: Int =
440 - (i % 2) * 100
makhan +=
MakhanData(
mx.toDouble,
my.toDouble,
false
)
i += 1
}
// ----------------------------------------------------------
// ENEMIES
// ----------------------------------------------------------
val enemyTotal: Int =
math.min(
2 + level,
6
)
i = 0
while (i < enemyTotal) {
val ex: Int =
300 + (i * 155) % 760
val ey: Double =
GAME_HEIGHT -
GROUND_HEIGHT -
46
val speed: Double =
if ((i % 2) == 0)
1.2 + level * 0.22
else
-1.1 - level * 0.18
enemies +=
EnemyData(
ex.toDouble,
ey,
speed,
math.max(80, ex - 100).toDouble,
math.min(1090, ex + 190).toDouble,
true
)
i += 1
}
// ----------------------------------------------------------
// MOVING PLATFORMS
// ----------------------------------------------------------
val platformTotal: Int =
2 + level
i = 0
while (i < platformTotal) {
val px: Int =
180 + i * 175
val py: Int =
450 - (i % 3) * 90
val direction: Double =
if ((i % 2) == 0)
1.0
else
-1.0
platforms +=
PlatformData(
px.toDouble,
py.toDouble,
125,
18,
direction * 1.1,
math.max(60, px - 90).toDouble,
math.min(1020, px + 160).toDouble
)
i += 1
}
// ----------------------------------------------------------
// FLOWERS
// ----------------------------------------------------------
i = 0
while (i < 40) {
flowers +=
FlowerData(
10 + (i * 37) % 1170,
600 + (i % 3) * 25,
8 + (i % 3) * 3,
i % 4
)
i += 1
}
timeLeft = LEVEL_TIME
if (level == 1) {
showMessage(
"LEVEL 1 - MAKHAN CHOR ADVENTURE",
160
)
} else if (level == 2) {
showMessage(
"LEVEL 2 - GOKUL FUN RUN",
160
)
} else if (level == 3) {
showMessage(
"LEVEL 3 - GOVINDA CHALLENGE",
160
)
} else if (level == 4) {
showMessage(
"LEVEL 4 - DAHI HANDI MASTER",
160
)
} else {
showMessage(
"LEVEL 5 - FINAL JANMASHTAMI",
180
)
}
}
// ============================================================
// START FESTIVAL
// ============================================================
def startFestival(): Unit = {
clearWorld()
stage = 0
level = 1
score = 0
lives = 3
timeLeft = LEVEL_TIME
combo = 0
bestCombo = 0
coinCount = 0
makhanCount = 0
running = true
paused = false
victory = false
playerX = 120.0
playerY = 500.0
velocityY = 0.0
jumping = false
checkpointX = 120.0
checkpointActive = false
handiBroken = false
handiHits = 0
handiRequired = 1
festivalTicks = 320
glowTicks = 0
createStars()
showMessage(
"SHREE KRISHNA JANMA MAHOTSAV",
240
)
}
// ============================================================
// NEXT STAGE
// ============================================================
def nextStage(): Unit = {
if (stage == 0) {
stage = 1
showMessage(
"BAL GOPAL PALNA UTSAV",
200
)
} else if (stage == 1) {
setupLevel(1)
} else if (stage == 2) {
if (handiBroken) {
if (level < TOTAL_LEVELS) {
setupLevel(
level + 1
)
} else {
stage = 3
running = true
victory = false
festivalTicks = 320
addScore(1000)
createBurst(
handiX + 55,
handiY + 40,
140
)
showMessage(
"GRAND DAHI HANDI MAHOTSAV!",
220
)
}
} else {
showMessage(
"FIRST BREAK THE DAHI HANDI!",
100
)
}
} else if (stage == 3) {
stage = 5
victory = true
running = false
}
}
// ============================================================
// RESET PLAYER
// ============================================================
def resetPlayer(): Unit = {
playerX = checkpointX
playerY =
GAME_HEIGHT -
GROUND_HEIGHT -
PLAYER_HEIGHT
velocityY = 0.0
jumping = false
invincibleTicks = 120
}
// ============================================================
// LOSE LIFE
// ============================================================
def loseLife(): Unit = {
lives -= 1
combo = 0
createBurst(
playerX + 22,
playerY + 30,
25
)
if (lives <= 0) {
running = false
victory = false
showMessage(
"FESTIVAL CHALLENGE OVER",
180
)
} else {
resetPlayer()
timeLeft = LEVEL_TIME
showMessage(
"TRY AGAIN GOVINDA!",
100
)
}
}
// ============================================================
// CHECKPOINT
// ============================================================
def updateCheckpoint(): Unit = {
if (
!checkpointActive &&
playerX > 500
) {
checkpointActive = true
checkpointX = 500
addScore(50)
createBurst(
500,
520,
20
)
showMessage(
"CHECKPOINT ACTIVATED!",
90
)
}
}
// ============================================================
// COINS
// ============================================================
def updateCoins(): Unit = {
var i: Int = 0
while (i < coins.length) {
val coin =
coins(i)
if (
!coin.collected &&
playerTouches(
coin.x,
coin.y,
26,
26
)
) {
coin.collected = true
coinCount += 1
addCombo()
addScore(
10 + combo * 2
)
createBurst(
coin.x + 13,
coin.y + 13,
8
)
}
i += 1
}
}
// ============================================================
// MAKHAN
// ============================================================
def updateMakhan(): Unit = {
var i: Int = 0
while (i < makhan.length) {
val item =
makhan(i)
if (
!item.collected &&
playerTouches(
item.x,
item.y,
38,
35
)
) {
item.collected = true
makhanCount += 1
addCombo()
addScore(
45 + level * 10
)
glowTicks = 70
createBurst(
item.x + 19,
item.y + 18,
12
)
showMessage(
"MAKHAN MILA!",
55
)
}
i += 1
}
}
// ============================================================
// ENEMIES
// ============================================================
def updateEnemies(): Unit = {
var i: Int = 0
while (i < enemies.length) {
val enemy =
enemies(i)
if (enemy.active) {
enemy.x += enemy.vx
if (
enemy.x < enemy.minX ||
enemy.x > enemy.maxX
) {
enemy.vx =
-enemy.vx
}
if (
invincibleTicks <= 0 &&
playerTouches(
enemy.x,
enemy.y,
46,
46
)
) {
enemy.active = false
loseLife()
}
}
i += 1
}
}
// ============================================================
// PLATFORMS
// ============================================================
def updatePlatforms(): Unit = {
var i: Int = 0
while (i < platforms.length) {
val platform =
platforms(i)
platform.x += platform.vx
if (
platform.x < platform.minX ||
platform.x > platform.maxX
) {
platform.vx =
-platform.vx
}
i += 1
}
}
// ============================================================
// PLATFORM LANDING
// ============================================================
def checkPlatformLanding(): Unit = {
if (velocityY >= 0.0) {
var i: Int = 0
while (i < platforms.length) {
val platform =
platforms(i)
val oldBottom =
playerY +
PLAYER_HEIGHT -
velocityY
val newBottom =
playerY +
PLAYER_HEIGHT
val horizontal =
playerX + PLAYER_WIDTH >
platform.x &&
playerX <
platform.x + platform.width
val vertical =
oldBottom <=
platform.y + 8 &&
newBottom >=
platform.y
if (
horizontal &&
vertical
) {
playerY =
platform.y -
PLAYER_HEIGHT
velocityY = 0.0
jumping = false
}
i += 1
}
}
}
// ============================================================
// DAHI HANDI HIT
// ============================================================
def hitHandi(): Unit = {
if (
stage == 2 &&
!handiBroken &&
playerTouches(
handiX,
handiY,
110,
82
) &&
playerY < 300
) {
handiHits += 1
addCombo()
addScore(
180 + level * 100
)
createBurst(
handiX + 55,
handiY + 40,
30
)
if (
handiHits >= handiRequired
) {
handiBroken = true
addScore(
600 + level * 250
)
festivalTicks = 220
createBurst(
handiX + 55,
handiY + 40,
100
)
showMessage(
"JAY SHREE KRISHNA! DAHI HANDI PHODLI!",
190
)
} else {
showMessage(
"HANDI HIT " +
handiHits +
" / " +
handiRequired,
75
)
}
}
}
// ============================================================
// PLAYER UPDATE
// ============================================================
def updatePlayer(): Unit = {
if (
!running ||
paused ||
stage < 2
) {
return
}
if (leftPressed) {
playerX -= 6.5
}
if (rightPressed) {
playerX += 6.5
}
playerX =
clampValue(
playerX,
0,
GAME_WIDTH - PLAYER_WIDTH
)
velocityY += GRAVITY_VALUE
playerY += velocityY
val groundY =
GAME_HEIGHT -
GROUND_HEIGHT -
PLAYER_HEIGHT
if (playerY >= groundY) {
playerY = groundY
velocityY = 0.0
jumping = false
}
checkPlatformLanding()
if (
playerY >
GAME_HEIGHT + 60
) {
loseLife()
}
updateCheckpoint()
updateCoins()
updateMakhan()
updateEnemies()
updatePlatforms()
hitHandi()
}
// ============================================================
// PARTICLE UPDATE
// ============================================================
def updateParticles(): Unit = {
var i: Int =
particles.length - 1
while (i >= 0) {
val p =
particles(i)
p.x += p.vx
p.y += p.vy
p.vy += 0.22
p.life -= 1
if (p.life <= 0) {
particles.remove(i)
}
i -= 1
}
}
// ============================================================
// EFFECT UPDATE
// ============================================================
def updateEffects(): Unit = {
if (messageTicks > 0) {
messageTicks -= 1
}
if (festivalTicks > 0) {
festivalTicks -= 1
}
if (glowTicks > 0) {
glowTicks -= 1
}
if (invincibleTicks > 0) {
invincibleTicks -= 1
}
}
// ============================================================
// CLOCK
// ============================================================
def clockTick(): Unit = {
if (
running &&
!paused &&
stage >= 2
) {
timeLeft -= 1
if (timeLeft <= 0) {
timeLeft = LEVEL_TIME
loseLife()
}
}
}
// ============================================================
// DRAW STAR
// ============================================================
def drawStar(
g: Graphics2D,
cx: Int,
cy: Int,
outerRadius: Int,
innerRadius: Int
): Unit = {
val polygon =
new Polygon()
var i: Int = 0
while (i < 10) {
val angle =
-math.Pi / 2.0 +
i * math.Pi / 5.0
val radius =
if ((i % 2) == 0)
outerRadius
else
innerRadius
val px =
cx +
(
math.cos(angle) *
radius
).toInt
val py =
cy +
(
math.sin(angle) *
radius
).toInt
polygon.addPoint(
px,
py
)
i += 1
}
g.fillPolygon(
polygon
)
}
// ============================================================
// GAME PANEL
// ============================================================
festivalPanel =
new JPanel {
override def paintComponent(
graphics: Graphics
): Unit = {
super.paintComponent(graphics)
val g =
graphics.asInstanceOf[Graphics2D]
g.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON
)
// ======================================================
// BIRTH SCREEN
// ======================================================
if (stage == 0) {
g.setPaint(
new GradientPaint(
0,
0,
new Color(
20,
25,
95
),
0,
getHeight,
new Color(
105,
35,
120
)
)
)
g.fillRect(
0,
0,
getWidth,
getHeight
)
var i: Int = 0
while (i < stars.length) {
val star =
stars(i)
g.setColor(
new Color(
255,
242,
150
)
)
g.fillOval(
star.x.toInt,
star.y.toInt,
3,
3
)
i += 1
}
g.setColor(
new Color(
255,
238,
170
)
)
g.fillOval(
430,
75,
340,
340
)
g.setColor(
new Color(
35,
25,
75
)
)
g.fillRect(
310,
405,
580,
245
)
val roof =
new Polygon()
roof.addPoint(
280,
405
)
roof.addPoint(
600,
210
)
roof.addPoint(
920,
405
)
g.fillPolygon(roof)
g.setColor(
new Color(
200,
145,
55
)
)
g.fillRoundRect(
455,
465,
290,
78,
25,
25
)
g.setColor(
new Color(
80,
100,
220
)
)
g.fillOval(
545,
415,
110,
110
)
g.setColor(
Color.WHITE
)
g.setFont(
new java.awt.Font(
"Serif",
java.awt.Font.BOLD,
44
)
)
g.drawString(
"SHREE KRISHNA JANMA",
355,
595
)
g.setFont(
new java.awt.Font(
"Arial",
java.awt.Font.BOLD,
21
)
)
g.drawString(
"GOKUL ASHTAMI ULTIMATE FESTIVAL",
390,
635
)
g.setColor(
new Color(
255,
220,
80
)
)
g.drawString(
"CLICK / SPACE TO START",
455,
690
)
drawMessage(
g
)
return
}
// ======================================================
// PALNA SCREEN
// ======================================================
if (stage == 1) {
g.setPaint(
new GradientPaint(
0,
0,
new Color(
85,
155,
235
),
0,
getHeight,
new Color(
255,
220,
165
)
)
)
g.fillRect(
0,
0,
getWidth,
getHeight
)
g.setColor(
new Color(
216,
172,
95
)
)
g.fillRect(
300,
275,
600,
355
)
val roof =
new Polygon()
roof.addPoint(
245,
275
)
roof.addPoint(
600,
80
)
roof.addPoint(
955,
275
)
g.setColor(
new Color(
175,
92,
45
)
)
g.fillPolygon(roof)
g.setColor(
new Color(
105,
65,
35
)
)
g.setStroke(
new BasicStroke(5)
)
g.drawLine(
420,
250,
420,
505
)
g.drawLine(
780,
250,
780,
505
)
g.setColor(
new Color(
175,
110,
48
)
)
g.fillRoundRect(
415,
465,
370,
85,
25,
25
)
g.setColor(
new Color(
90,
100,
220
)
)
g.fillOval(
540,
410,
100,
100
)
g.setColor(
new Color(
255,
220,
180
)
)
g.fillOval(
558,
390,
64,
64
)
g.setColor(
Color.WHITE
)
g.setFont(
new java.awt.Font(
"Serif",
java.awt.Font.BOLD,
38
)
)
g.drawString(
"BAL GOPAL PALNA UTSAV",
385,
125
)
g.setFont(
new java.awt.Font(
"Arial",
java.awt.Font.BOLD,
20
)
)
g.drawString(
"CLICK / SPACE TO JHULA",
455,
680
)
drawMessage(g)
return
}
// ======================================================
// MAIN WORLD BACKGROUND
// ======================================================
g.setPaint(
new GradientPaint(
0,
0,
if (level >= 4)
new Color(
60,
80,
165
)
else
new Color(
80,
170,
240
),
0,
getHeight,
if (level >= 4)
new Color(
185,
100,
145
)
else
new Color(
255,
220,
140
)
)
)
g.fillRect(
0,
0,
getWidth,
getHeight
)
// ======================================================
// SUN / MOON
// ======================================================
g.setColor(
new Color(
255,
240,
135
)
)
g.fillOval(
950,
55,
100,
100
)
// ======================================================
// CLOUDS
// ======================================================
g.setColor(
new Color(
255,
255,
255,
215
)
)
g.fillOval(
40,
85,
120,
52
)
g.fillOval(
110,
55,
130,
68
)
g.fillOval(
205,
88,
110,
50
)
g.fillOval(
700,
100,
120,
50
)
g.fillOval(
760,
70,
135,
68
)
g.fillOval(
865,
100,
115,
50
)
// ======================================================
// HILLS
// ======================================================
g.setColor(
new Color(
70,
160,
80
)
)
g.fillOval(
-220,
430,
680,
300
)
g.fillOval(
230,
430,
660,
300
)
g.fillOval(
730,
430,
700,
300
)
// ======================================================
// GROUND
// ======================================================
g.setColor(
new Color(
65,
145,
65
)
)
g.fillRect(
0,
GAME_HEIGHT - GROUND_HEIGHT,
getWidth,
GROUND_HEIGHT
)
// ======================================================
// TEMPLE
// ======================================================
g.setColor(
new Color(
235,
185,
105
)
)
g.fillRect(
970,
330,
200,
250
)
val templeRoof =
new Polygon()
templeRoof.addPoint(
940,
330
)
templeRoof.addPoint(
1070,
205
)
templeRoof.addPoint(
1200,
330
)
g.setColor(
new Color(
185,
100,
50
)
)
g.fillPolygon(
templeRoof
)
// ======================================================
// FLOWERS
// ======================================================
var fi: Int = 0
while (fi < flowers.length) {
val flower =
flowers(fi)
g.setColor(
new Color(
50,
120,
45
)
)
g.setStroke(
new BasicStroke(2)
)
g.drawLine(
flower.x,
flower.y,
flower.x,
flower.y - flower.size * 2
)
val flowerColor =
if (flower.kind == 0)
new Color(245, 75, 100)
else if (flower.kind == 1)
new Color(255, 220, 60)
else if (flower.kind == 2)
new Color(255, 145, 70)
else
Color.WHITE
g.setColor(
flowerColor
)
g.fillOval(
flower.x - flower.size / 2,
flower.y -
flower.size * 2 -
flower.size / 2,
flower.size,
flower.size
)
fi += 1
}
// ======================================================
// PLATFORMS
// ======================================================
var pi: Int = 0
while (pi < platforms.length) {
val platform =
platforms(pi)
g.setColor(
new Color(
160,
102,
55
)
)
g.fillRoundRect(
platform.x.toInt,
platform.y.toInt,
platform.width,
platform.height,
10,
10
)
g.setColor(
new Color(
95,
55,
30
)
)
g.drawRoundRect(
platform.x.toInt,
platform.y.toInt,
platform.width,
platform.height,
10,
10
)
pi += 1
}
// ======================================================
// GOVINDA PYRAMID
// ======================================================
var row: Int = 0
while (row < 3) {
val count =
5 - row
var col: Int = 0
while (col < count) {
val px: Int =
295 +
row * 60 +
col * 125
val py: Int =
515 -
row * 70
g.setColor(
if ((col + row) % 2 == 0)
new Color(45, 100, 210)
else
new Color(225, 65, 75)
)
g.fillRoundRect(
px,
py,
72,
60,
14,
14
)
g.setColor(
new Color(
255,
220,
180
)
)
g.fillOval(
px + 15,
py - 24,
42,
42
)
col += 1
}
row += 1
}
// ======================================================
// TOP GOVINDA
// ======================================================
g.setColor(
new Color(
45,
90,
210
)
)
g.fillRoundRect(
520,
350,
72,
62,
14,
14
)
g.setColor(
new Color(
255,
220,
180
)
)
g.fillOval(
535,
328,
42,
42
)
// ======================================================
// PEACOCK FEATHER
// ======================================================
g.setColor(
new Color(
35,
155,
70
)
)
g.setStroke(
new BasicStroke(3)
)
g.drawLine(
555,
330,
570,
298
)
g.setColor(
new Color(
35,
110,
215
)
)
g.fillOval(
567,
291,
12,
15
)
// ======================================================
// HANDI ROPE
// ======================================================
g.setColor(
new Color(
95,
60,
35
)
)
g.setStroke(
new BasicStroke(5)
)
g.drawLine(
(handiX + 55).toInt,
0,
(handiX + 55).toInt,
handiY.toInt
)
// ======================================================
// HANDI
// ======================================================
if (!handiBroken) {
g.setColor(
new Color(
190,
122,
62
)
)
g.fillOval(
handiX.toInt,
handiY.toInt,
110,
82
)
g.setColor(
new Color(
105,
65,
35
)
)
g.drawOval(
handiX.toInt,
handiY.toInt,
110,
82
)
g.setColor(Color.WHITE)
g.fillOval(
handiX.toInt + 10,
handiY.toInt + 5,
90,
20
)
g.setColor(
new Color(
145,
85,
40
)
)
g.fillRect(
handiX.toInt + 30,
handiY.toInt - 10,
50,
13
)
} else {
g.setColor(
new Color(
185,
120,
60
)
)
g.fillArc(
handiX.toInt,
handiY.toInt,
52,
48,
0,
180
)
g.fillArc(
handiX.toInt + 58,
handiY.toInt + 4,
52,
48,
0,
180
)
}
// ======================================================
// COINS
// ======================================================
var ci: Int = 0
while (ci < coins.length) {
val coin =
coins(ci)
if (!coin.collected) {
g.setColor(
new Color(
255,
210,
40
)
)
g.fillOval(
coin.x.toInt,
coin.y.toInt,
26,
26
)
g.setColor(
new Color(
255,
245,
160
)
)
g.drawOval(
coin.x.toInt + 4,
coin.y.toInt + 4,
18,
18
)
}
ci += 1
}
// ======================================================
// MAKHAN
// ======================================================
var mi: Int = 0
while (mi < makhan.length) {
val item =
makhan(mi)
if (!item.collected) {
g.setColor(
new Color(
175,
112,
58
)
)
g.fillOval(
item.x.toInt,
item.y.toInt,
38,
35
)
g.setColor(Color.WHITE)
g.fillOval(
item.x.toInt + 5,
item.y.toInt + 3,
28,
12
)
}
mi += 1
}
// ======================================================
// ENEMIES
// ======================================================
var ei: Int = 0
while (ei < enemies.length) {
val enemy =
enemies(ei)
if (enemy.active) {
g.setColor(
new Color(
95,
65,
150
)
)
g.fillRoundRect(
enemy.x.toInt,
enemy.y.toInt,
46,
46,
12,
12
)
g.setColor(
new Color(
255,
220,
180
)
)
g.fillOval(
enemy.x.toInt + 6,
enemy.y.toInt - 14,
34,
34
)
}
ei += 1
}
// ======================================================
// PLAYER
// ======================================================
if (
invincibleTicks <= 0 ||
invincibleTicks % 8 < 4
) {
g.setColor(
new Color(
35,
85,
210
)
)
g.fillRoundRect(
playerX.toInt,
playerY.toInt,
PLAYER_WIDTH,
PLAYER_HEIGHT,
12,
12
)
g.setColor(
new Color(
255,
220,
180
)
)
g.fillOval(
playerX.toInt + 6,
playerY.toInt - 16,
34,
34
)
g.setColor(
new Color(
220,
45,
55
)
)
g.fillRect(
playerX.toInt + 4,
playerY.toInt - 6,
38,
7
)
// PEACOCK FEATHER
g.setColor(
new Color(
35,
155,
70
)
)
g.setStroke(
new BasicStroke(3)
)
g.drawLine(
playerX.toInt + 28,
playerY.toInt - 2,
playerX.toInt + 38,
playerY.toInt - 25
)
g.setColor(
new Color(
35,
110,
215
)
)
g.fillOval(
playerX.toInt + 34,
playerY.toInt - 32,
11,
15
)
}
// ======================================================
// GLOW
// ======================================================
if (glowTicks > 0) {
g.setColor(
new Color(
255,
230,
90,
100
)
)
g.fillOval(
playerX.toInt - 15,
playerY.toInt - 35,
75,
75
)
}
// ======================================================
// PARTICLES
// ======================================================
var pindex: Int = 0
while (pindex < particles.length) {
val p =
particles(pindex)
val particleColor =
if (p.kind == 0)
new Color(255, 215, 50)
else if (p.kind == 1)
new Color(255, 100, 100)
else if (p.kind == 2)
new Color(100, 220, 255)
else
Color.WHITE
g.setColor(
particleColor
)
val particleSize =
if (p.life % 2 == 0)
7
else
4
g.fillOval(
p.x.toInt,
p.y.toInt,
particleSize,
particleSize
)
pindex += 1
}
// ======================================================
// HUD
// ======================================================
drawHUD(g)
drawMessage(g)
// ======================================================
// PAUSE
// ======================================================
if (
paused &&
running
) {
g.setColor(
new Color(
0,
0,
0,
180
)
)
g.fillRect(
0,
0,
getWidth,
getHeight
)
g.setColor(Color.WHITE)
g.setFont(
new java.awt.Font(
"Arial",
java.awt.Font.BOLD,
58
)
)
g.drawString(
"PAUSED",
470,
340
)
g.setFont(
new java.awt.Font(
"Arial",
java.awt.Font.BOLD,
20
)
)
g.drawString(
"PRESS P TO CONTINUE",
470,
380
)
}
// ======================================================
// CELEBRATION
// ======================================================
if (stage == 3) {
g.setColor(
new Color(
0,
0,
0,
135
)
)
g.fillRect(
0,
0,
getWidth,
getHeight
)
g.setColor(
new Color(
255,
220,
60
)
)
g.setFont(
new java.awt.Font(
"Serif",
java.awt.Font.BOLD,
52
)
)
g.drawString(
"JAY SHREE KRISHNA!",
355,
250
)
g.setFont(
new java.awt.Font(
"Arial",
java.awt.Font.BOLD,
32
)
)
g.drawString(
"GRAND DAHI HANDI MAHOTSAV",
335,
315
)
g.setColor(Color.WHITE)
g.setFont(
new java.awt.Font(
"Arial",
java.awt.Font.BOLD,
23
)
)
g.drawString(
"GOVINDA AALA RE!",
475,
370
)
}
// ======================================================
// FINAL SCREEN
// ======================================================
if (!running) {
g.setColor(
new Color(
0,
0,
0,
205
)
)
g.fillRect(
0,
0,
getWidth,
getHeight
)
if (victory) {
g.setColor(
new Color(
255,
220,
60
)
)
g.setFont(
new java.awt.Font(
"Arial",
java.awt.Font.BOLD,
46
)
)
g.drawString(
"JANMASHTAMI CHAMPION!",
300,
245
)
} else {
g.setColor(Color.WHITE)
g.setFont(
new java.awt.Font(
"Arial",
java.awt.Font.BOLD,
50
)
)
g.drawString(
"GAME OVER",
440,
245
)
}
g.setColor(Color.WHITE)
g.setFont(
new java.awt.Font(
"Arial",
java.awt.Font.BOLD,
22
)
)
g.drawString(
"FINAL SCORE: " + score,
465,
315
)
g.drawString(
"COINS: " + coinCount,
500,
350
)
g.drawString(
"MAKHAN: " + makhanCount,
490,
385
)
g.drawString(
"BEST COMBO: " + bestCombo,
470,
420
)
g.setFont(
new java.awt.Font(
"Arial",
java.awt.Font.BOLD,
18
)
)
g.drawString(
"PRESS R OR CLICK RESET",
450,
475
)
}
}
// ========================================================
// HUD
// ========================================================
def drawHUD(
g: Graphics2D
): Unit = {
if (stage < 1) {
return
}
g.setColor(
new Color(
0,
0,
0,
145
)
)
g.fillRoundRect(
14,
14,
790,
80,
16,
16
)
g.setColor(Color.WHITE)
g.setFont(
new java.awt.Font(
"Arial",
java.awt.Font.BOLD,
18
)
)
g.drawString(
"GOKUL ASHTAMI",
28,
40
)
g.drawString(
"LEVEL " + level,
185,
40
)
g.drawString(
"SCORE " + score,
280,
40
)
g.drawString(
"LIVES " + lives,
410,
40
)
if (stage >= 2) {
g.drawString(
"TIME " + timeLeft,
515,
40
)
g.drawString(
"COMBO x" + combo,
625,
40
)
}
g.setFont(
new java.awt.Font(
"Arial",
java.awt.Font.PLAIN,
13
)
)
g.drawString(
"COINS " +
coinCount +
" MAKHAN " +
makhanCount +
" BEST " +
bestCombo,
28,
68
)
if (
stage == 2 &&
!handiBroken
) {
g.setColor(
new Color(
0,
0,
0,
130
)
)
g.fillRoundRect(
385,
108,
430,
42,
14,
14
)
g.setColor(Color.WHITE)
g.drawString(
"BREAK HANDI: " +
handiHits +
" / " +
handiRequired,
500,
136
)
}
g.setColor(
new Color(
0,
0,
0,
120
)
)
g.fillRoundRect(
845,
14,
335,
80,
14,
14
)
g.setColor(Color.WHITE)
g.setFont(
new java.awt.Font(
"Arial",
java.awt.Font.BOLD,
13
)
)
g.drawString(
"A/D OR LEFT/RIGHT = MOVE",
865,
38
)
g.drawString(
"W/UP/SPACE/MOUSE = JUMP",
865,
60
)
g.drawString(
"P = PAUSE R = RESET",
865,
81
)
}
// ========================================================
// MESSAGE
// ========================================================
def drawMessage(
g: Graphics2D
): Unit = {
if (
messageTicks > 0 &&
messageText != ""
) {
g.setColor(
new Color(
0,
0,
0,
160
)
)
g.fillRoundRect(
230,
165,
740,
62,
18,
18
)
g.setColor(
new Color(
255,
230,
80
)
)
g.setFont(
new java.awt.Font(
"Arial",
java.awt.Font.BOLD,
21
)
)
g.drawString(
messageText,
270,
205
)
}
}
}
// ============================================================
// KEYBOARD INPUT
// ============================================================
festivalPanel.setFocusable(true)
festivalPanel.addKeyListener(
new KeyAdapter {
override def keyPressed(
event: KeyEvent
): Unit = {
val keyCode: Int =
event.getKeyCode
if (
keyCode == KeyEvent.VK_LEFT ||
keyCode == KeyEvent.VK_A
) {
leftPressed = true
}
if (
keyCode == KeyEvent.VK_RIGHT ||
keyCode == KeyEvent.VK_D
) {
rightPressed = true
}
if (
keyCode == KeyEvent.VK_UP ||
keyCode == KeyEvent.VK_W ||
keyCode == KeyEvent.VK_SPACE
) {
if (stage == 0) {
nextStage()
} else if (stage == 1) {
nextStage()
} else if (
running &&
!paused &&
stage >= 2 &&
!jumping
) {
velocityY = JUMP_VALUE
jumping = true
}
}
if (
keyCode == KeyEvent.VK_P &&
running
) {
paused = !paused
}
if (
keyCode == KeyEvent.VK_R
) {
startFestival()
festivalPanel.repaint()
}
}
override def keyReleased(
event: KeyEvent
): Unit = {
val keyCode: Int =
event.getKeyCode
if (
keyCode == KeyEvent.VK_LEFT ||
keyCode == KeyEvent.VK_A
) {
leftPressed = false
}
if (
keyCode == KeyEvent.VK_RIGHT ||
keyCode == KeyEvent.VK_D
) {
rightPressed = false
}
}
}
)
// ============================================================
// MOUSE INPUT
// ============================================================
festivalPanel.addMouseListener(
new MouseAdapter {
override def mousePressed(
event: MouseEvent
): Unit = {
if (stage == 0) {
nextStage()
} else if (stage == 1) {
nextStage()
} else if (
running &&
!paused &&
stage >= 2 &&
!jumping
) {
velocityY = JUMP_VALUE
jumping = true
}
festivalPanel.requestFocusInWindow()
}
}
)
// ============================================================
// MAIN GAME LOOP
// ============================================================
mainTimer =
new Timer(
25,
new ActionListener {
override def actionPerformed(
event: ActionEvent
): Unit = {
if (
running &&
!paused
) {
updatePlayer()
updateParticles()
updateEffects()
festivalPanel.repaint()
}
}
}
)
// ============================================================
// CLOCK LOOP
// ============================================================
clockTimer =
new Timer(
1000,
new ActionListener {
override def actionPerformed(
event: ActionEvent
): Unit = {
clockTick()
festivalPanel.repaint()
}
}
)
// ============================================================
// RESET BUTTON
// ============================================================
val resetButton =
new JButton(
"RESET JANMASHTAMI"
)
resetButton.setFont(
new java.awt.Font(
"Arial",
java.awt.Font.BOLD,
14
)
)
resetButton.addActionListener(
new ActionListener {
override def actionPerformed(
event: ActionEvent
): Unit = {
startFestival()
festivalPanel.requestFocusInWindow()
festivalPanel.repaint()
}
}
)
// ============================================================
// NEXT BUTTON
// ============================================================
val nextButton =
new JButton(
"NEXT FESTIVAL"
)
nextButton.setFont(
new java.awt.Font(
"Arial",
java.awt.Font.BOLD,
14
)
)
nextButton.addActionListener(
new ActionListener {
override def actionPerformed(
event: ActionEvent
): Unit = {
if (
stage == 0 ||
stage == 1 ||
(stage == 3 && running)
) {
nextStage()
}
festivalPanel.requestFocusInWindow()
festivalPanel.repaint()
}
}
)
// ============================================================
// FRAME
// ============================================================
gameFrame =
new JFrame(
"GOKUL ASHTAMI - ULTRA JANMASHTAMI FESTIVAL"
)
gameFrame.setDefaultCloseOperation(
WindowConstants.DISPOSE_ON_CLOSE
)
gameFrame.setSize(
GAME_WIDTH,
GAME_HEIGHT
)
gameFrame.setLocationRelativeTo(
null
)
gameFrame.setLayout(
new BorderLayout()
)
// ============================================================
// PANEL
// ============================================================
gameFrame.add(
festivalPanel,
BorderLayout.CENTER
)
// ============================================================
// BOTTOM PANEL
// ============================================================
val bottomPanel =
new JPanel(
new BorderLayout()
)
bottomPanel.add(
resetButton,
BorderLayout.WEST
)
bottomPanel.add(
new JLabel(
"SHREE KRISHNA JANMA MAHOTSAV | GOVINDA AALA RE!",
SwingConstants.CENTER
),
BorderLayout.CENTER
)
bottomPanel.add(
nextButton,
BorderLayout.EAST
)
gameFrame.add(
bottomPanel,
BorderLayout.SOUTH
)
// ============================================================
// CLOSE CLEANUP
// ============================================================
gameFrame.addWindowListener(
new java.awt.event.WindowAdapter {
override def windowClosed(
event: java.awt.event.WindowEvent
): Unit = {
if (mainTimer != null) {
mainTimer.stop()
}
if (clockTimer != null) {
clockTimer.stop()
}
}
}
)
// ============================================================
// START
// ============================================================
startFestival()
mainTimer.start()
clockTimer.start()
gameFrame.setVisible(true)
festivalPanel.requestFocusInWindow()
festivalPanel.repaint()