Code Sketch
yoiiiii
Category: Programming
//scala
import java.awt.BasicStroke
import java.awt.BorderLayout
import java.awt.Color
import java.awt.Cursor
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.Point
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 java.awt.event.MouseMotionAdapter
import javax.swing.DefaultListModel
import javax.swing.JButton
import javax.swing.JColorChooser
import javax.swing.JFileChooser
import javax.swing.JFrame
import javax.swing.JLabel
import javax.swing.JList
import javax.swing.JOptionPane
import javax.swing.JPanel
import javax.swing.JScrollPane
import javax.swing.JSplitPane
import javax.swing.JTabbedPane
import javax.swing.JTextArea
import javax.swing.JTextField
import javax.swing.ListSelectionModel
import javax.swing.SwingUtilities
import javax.swing.Timer
import javax.swing.WindowConstants
import scala.collection.mutable.ArrayBuffer
// ============================================================
// ULTRA LEGEND DRAW + GAME STUDIO X8
// CLEAN / CORRECT SCALA VERSION
// ============================================================
val CANVAS_WIDTH: Int = 1000
val CANVAS_HEIGHT: Int = 650
val CENTER_X: Int = 500
val CENTER_Y: Int = 325
// ============================================================
// DRAW MODEL
// ============================================================
case class DrawItem(
points: Vector[Point],
strokeColor: Color,
fillColor: Color,
filled: Boolean,
itemName: String,
visible: Boolean,
locked: Boolean
)
// ============================================================
// GLOBAL DRAW STATE
// ============================================================
var drawItems =
ArrayBuffer[DrawItem]()
var undoStack =
ArrayBuffer[ArrayBuffer[DrawItem]]()
var redoStack =
ArrayBuffer[ArrayBuffer[DrawItem]]()
var currentTool: String =
"PENCIL"
var currentStrokeColor: Color =
new Color(20, 90, 220)
var currentFillColor: Color =
new Color(255, 180, 40)
var brushWidth: Float =
5.0f
var gridEnabled: Boolean =
true
var snapEnabled: Boolean =
false
var drawingActive: Boolean =
false
var selectedItemIndex: Int =
-1
var movingSelected: Boolean =
false
var resizingSelected: Boolean =
false
var resizeMode: String =
""
var previousMousePoint: Point =
new Point(0, 0)
var originalSelectedPoints: Vector[Point] =
Vector.empty
var temporaryPoints =
ArrayBuffer[Point]()
var generatedDrawingCode: String =
""
var generatedGameCode: String =
""
// ============================================================
// UI REFERENCES
// ============================================================
var mainFrame: JFrame =
null
var drawingCanvas: JPanel =
null
var drawingCodeArea: JTextArea =
null
var mainStatus: JLabel =
null
var objectModel =
new DefaultListModel[String]()
var shapeModel =
new DefaultListModel[String]()
var objectList: JList[String] =
null
var shapeList: JList[String] =
null
var objectSearchField: JTextField =
null
// ============================================================
// BUTTON HELPER
// ============================================================
def createButton(
label: String
): JButton = {
val button =
new JButton(label)
button.setFocusable(false)
button.setFont(
new Font(
"Arial",
Font.BOLD,
11
)
)
button
}
// ============================================================
// STATUS
// ============================================================
def setMainStatus(
message: String
): Unit = {
if (
mainStatus != null
) {
mainStatus.setText(
message
)
}
}
def repaintDrawingCanvas(): Unit = {
if (
drawingCanvas != null
) {
drawingCanvas.repaint()
}
}
// ============================================================
// HISTORY COPY
// ============================================================
def copyDrawItems(
source: ArrayBuffer[DrawItem]
): ArrayBuffer[DrawItem] = {
val result =
ArrayBuffer[DrawItem]()
var i: Int =
0
while (
i < source.length
) {
val item =
source(i)
val copiedPoints =
item.points.map(
p =>
new Point(
p.x,
p.y
)
)
result +=
item.copy(
points = copiedPoints
)
i += 1
}
result
}
// ============================================================
// UNDO
// ============================================================
def saveHistory(): Unit = {
undoStack +=
copyDrawItems(
drawItems
)
redoStack.clear()
while (
undoStack.length > 50
) {
undoStack.remove(0)
}
}
def performUndo(): Unit = {
if (
undoStack.nonEmpty
) {
redoStack +=
copyDrawItems(
drawItems
)
val oldState =
undoStack.last
undoStack.remove(
undoStack.length - 1
)
drawItems.clear()
drawItems ++=
copyDrawItems(
oldState
)
selectedItemIndex =
-1
repaintDrawingCanvas()
setMainStatus(
"UNDO COMPLETE"
)
} else {
setMainStatus(
"NOTHING TO UNDO"
)
}
}
// ============================================================
// REDO
// ============================================================
def performRedo(): Unit = {
if (
redoStack.nonEmpty
) {
undoStack +=
copyDrawItems(
drawItems
)
val nextState =
redoStack.last
redoStack.remove(
redoStack.length - 1
)
drawItems.clear()
drawItems ++=
copyDrawItems(
nextState
)
selectedItemIndex =
-1
repaintDrawingCanvas()
setMainStatus(
"REDO COMPLETE"
)
} else {
setMainStatus(
"NOTHING TO REDO"
)
}
}
// ============================================================
// MOUSE / GEOMETRY
// ============================================================
def snapCoordinate(
value: Int
): Int = {
if (
snapEnabled
) {
(value / 10) * 10
} else {
value
}
}
def canvasPoint(
e: MouseEvent
): Point = {
val px =
math.max(
0,
math.min(
CANVAS_WIDTH - 1,
snapCoordinate(
e.getX
)
)
)
val py =
math.max(
0,
math.min(
CANVAS_HEIGHT - 1,
snapCoordinate(
e.getY
)
)
)
new Point(
px,
py
)
}
def pointDistance(
a: Point,
b: Point
): Double = {
math.hypot(
b.x - a.x,
b.y - a.y
)
}
def isClosedShape(
points: Iterable[Point]
): Boolean = {
val seq =
points.toSeq
seq.length >= 3 &&
pointDistance(
seq.head,
seq.last
) <= 50
}
// ============================================================
// ITEM BOUNDS
// ============================================================
def itemBounds(
item: DrawItem
): java.awt.Rectangle = {
if (
item.points.isEmpty
) {
new java.awt.Rectangle(
0,
0,
1,
1
)
} else {
var minX =
item.points.head.x
var maxX =
item.points.head.x
var minY =
item.points.head.y
var maxY =
item.points.head.y
var i: Int =
1
while (
i < item.points.length
) {
val p =
item.points(i)
if (
p.x < minX
) {
minX = p.x
}
if (
p.x > maxX
) {
maxX = p.x
}
if (
p.y < minY
) {
minY = p.y
}
if (
p.y > maxY
) {
maxY = p.y
}
i += 1
}
new java.awt.Rectangle(
minX,
minY,
math.max(
1,
maxX - minX
),
math.max(
1,
maxY - minY
)
)
}
}
// ============================================================
// SEGMENT DISTANCE
// ============================================================
def pointToSegmentDistance(
p: Point,
a: Point,
b: Point
): Double = {
val dx: Double =
b.x - a.x
val dy: Double =
b.y - a.y
if (
dx == 0.0 &&
dy == 0.0
) {
pointDistance(
p,
a
)
} else {
val numerator: Double =
(p.x - a.x) * dx +
(p.y - a.y) * dy
val denominator: Double =
dx * dx +
dy * dy
val t: Double =
math.max(
0.0,
math.min(
1.0,
numerator /
denominator
)
)
val cx: Double =
a.x + t * dx
val cy: Double =
a.y + t * dy
math.hypot(
p.x - cx,
p.y - cy
)
}
}
// ============================================================
// POLYGON
// ============================================================
def pointInsidePolygon(
p: Point,
points: Seq[Point]
): Boolean = {
if (
points.length < 3
) {
false
} else {
var inside: Boolean =
false
var j: Int =
points.length - 1
var i: Int =
0
while (
i < points.length
) {
val xi =
points(i).x
val yi =
points(i).y
val xj =
points(j).x
val yj =
points(j).y
val hit =
((yi > p.y) != (yj > p.y)) &&
(
p.x <
(
xj - xi
).toDouble *
(
p.y - yi
).toDouble /
(
yj - yi + 0.000001
) +
xi
)
if (
hit
) {
inside =
!inside
}
j =
i
i += 1
}
inside
}
}
// ============================================================
// HIT TEST
// ============================================================
def findItemAt(
p: Point
): Int = {
var found: Int =
-1
var i: Int =
drawItems.length - 1
while (
i >= 0 &&
found < 0
) {
val item =
drawItems(i)
if (
item.visible
) {
val b =
itemBounds(item)
val expanded =
new java.awt.Rectangle(
b.x - 15,
b.y - 15,
b.width + 30,
b.height + 30
)
if (
expanded.contains(p)
) {
if (
item.filled &&
isClosedShape(item.points) &&
pointInsidePolygon(
p,
item.points
)
) {
found =
i
} else {
var j: Int =
1
while (
j < item.points.length &&
found < 0
) {
if (
pointToSegmentDistance(
p,
item.points(j - 1),
item.points(j)
) < 18
) {
found =
i
}
j += 1
}
}
}
}
i -= 1
}
found
}
// ============================================================
// HANDLE HELPERS
// ============================================================
def selectionHandles(
r: java.awt.Rectangle
): Array[(String, Point)] = {
val mx =
r.x + r.width / 2
val my =
r.y + r.height / 2
Array(
("TL", new Point(r.x, r.y)),
("TM", new Point(mx, r.y)),
("TR", new Point(r.x + r.width, r.y)),
("ML", new Point(r.x, my)),
("MR", new Point(r.x + r.width, my)),
("BL", new Point(r.x, r.y + r.height)),
("BM", new Point(mx, r.y + r.height)),
("BR", new Point(r.x + r.width, r.y + r.height))
)
}
def findResizeHandle(
item: DrawItem,
p: Point
): String = {
val b =
itemBounds(item)
val r =
new java.awt.Rectangle(
b.x - 8,
b.y - 8,
b.width + 16,
b.height + 16
)
val handles =
selectionHandles(r)
var answer: String =
""
var i: Int =
0
while (
i < handles.length &&
answer == ""
) {
if (
pointDistance(
p,
handles(i)._2
) <= 14
) {
answer =
handles(i)._1
}
i += 1
}
answer
}
// ============================================================
// MOVE
// ============================================================
def moveSelectedItem(
dx: Int,
dy: Int
): Unit = {
if (
selectedItemIndex >= 0 &&
selectedItemIndex < drawItems.length
) {
val item =
drawItems(
selectedItemIndex
)
if (
!item.locked
) {
val movedPoints =
item.points.map(
p =>
new Point(
p.x + dx,
p.y + dy
)
)
drawItems(
selectedItemIndex
) =
item.copy(
points = movedPoints
)
}
}
}
// ============================================================
// RESIZE
// ============================================================
def resizeSelectedItem(
p: Point
): Unit = {
if (
selectedItemIndex >= 0 &&
selectedItemIndex < drawItems.length &&
originalSelectedPoints.nonEmpty
) {
val item =
drawItems(
selectedItemIndex
)
var minX =
originalSelectedPoints.head.x
var maxX =
originalSelectedPoints.head.x
var minY =
originalSelectedPoints.head.y
var maxY =
originalSelectedPoints.head.y
var i: Int =
1
while (
i < originalSelectedPoints.length
) {
val q =
originalSelectedPoints(i)
if (
q.x < minX
) {
minX = q.x
}
if (
q.x > maxX
) {
maxX = q.x
}
if (
q.y < minY
) {
minY = q.y
}
if (
q.y > maxY
) {
maxY = q.y
}
i += 1
}
val oldWidth: Int =
math.max(
1,
maxX - minX
)
val oldHeight: Int =
math.max(
1,
maxY - minY
)
var newMinX =
minX
var newMaxX =
maxX
var newMinY =
minY
var newMaxY =
maxY
if (resizeMode == "TL") {
newMinX = p.x
newMinY = p.y
} else if (resizeMode == "TR") {
newMaxX = p.x
newMinY = p.y
} else if (resizeMode == "BL") {
newMinX = p.x
newMaxY = p.y
} else if (resizeMode == "BR") {
newMaxX = p.x
newMaxY = p.y
} else if (resizeMode == "TM") {
newMinY = p.y
} else if (resizeMode == "BM") {
newMaxY = p.y
} else if (resizeMode == "ML") {
newMinX = p.x
} else if (resizeMode == "MR") {
newMaxX = p.x
}
val newWidth: Int =
math.max(
5,
newMaxX - newMinX
)
val newHeight: Int =
math.max(
5,
newMaxY - newMinY
)
val scaled =
originalSelectedPoints.map(
q => {
val nx =
newMinX +
(
(
q.x - minX
).toDouble *
newWidth /
oldWidth
).toInt
val ny =
newMinY +
(
(
q.y - minY
).toDouble *
newHeight /
oldHeight
).toInt
new Point(
nx,
ny
)
}
)
drawItems(
selectedItemIndex
) =
item.copy(
points = scaled
)
}
}
// ============================================================
// SHAPE HELPERS
// ============================================================
def polygonPoints(
sideCount: Int,
radius: Int,
startAngle: Double
): Vector[Point] = {
val result =
ArrayBuffer[Point]()
var i: Int =
0
while (
i <= sideCount
) {
val angle =
startAngle +
i *
2.0 *
math.Pi /
sideCount.toDouble
result +=
new Point(
CENTER_X +
(
math.cos(angle) *
radius
).toInt,
CENTER_Y +
(
math.sin(angle) *
radius
).toInt
)
i += 1
}
result.toVector
}
def ellipsePoints(
radiusX: Int,
radiusY: Int
): Vector[Point] = {
val result =
ArrayBuffer[Point]()
var degree: Int =
0
while (
degree <= 360
) {
val angle =
degree *
math.Pi /
180.0
result +=
new Point(
CENTER_X +
(
math.cos(angle) *
radiusX
).toInt,
CENTER_Y +
(
math.sin(angle) *
radiusY
).toInt
)
degree += 3
}
result.toVector
}
def starPoints(
pointCount: Int,
outerRadius: Int
): Vector[Point] = {
val result =
ArrayBuffer[Point]()
var i: Int =
0
while (
i <= pointCount * 2
) {
val angle =
-math.Pi / 2.0 +
i *
math.Pi /
pointCount
val radius =
if (
i % 2 == 0
) {
outerRadius
} else {
(
outerRadius *
0.45
).toInt
}
result +=
new Point(
CENTER_X +
(
math.cos(angle) *
radius
).toInt,
CENTER_Y +
(
math.sin(angle) *
radius
).toInt
)
i += 1
}
result.toVector
}
def heartPoints():
Vector[Point] = {
val result =
ArrayBuffer[Point]()
var i: Int =
0
while (
i <= 180
) {
val t =
i *
math.Pi /
180.0
val x =
16 *
math.pow(
math.sin(t),
3
)
val y =
13 *
math.cos(t) -
5 *
math.cos(2 * t) -
2 *
math.cos(3 * t) -
math.cos(4 * t)
result +=
new Point(
CENTER_X +
(x * 13).toInt,
CENTER_Y -
(y * 13).toInt
)
i += 1
}
result.toVector
}
// ============================================================
// SHAPE LIBRARY
// ============================================================
val allShapeNames =
Array(
"LINE",
"SQUARE",
"RECTANGLE",
"CIRCLE",
"ELLIPSE",
"TRIANGLE",
"DIAMOND",
"PENTAGON",
"HEXAGON",
"HEPTAGON",
"OCTAGON",
"STAR 5",
"STAR 6",
"STAR 8",
"HEART",
"ARROW RIGHT",
"ARROW LEFT",
"ARROW UP",
"ARROW DOWN",
"PLUS",
"CLOUD",
"SUN",
"MOON",
"RING",
"ARC",
"WAVE",
"SPIRAL",
"BURST",
"SNOWFLAKE"
)
var shapeIndex: Int =
0
while (
shapeIndex < allShapeNames.length
) {
shapeModel.addElement(
allShapeNames(shapeIndex)
)
shapeIndex += 1
}
// ============================================================
// GET SHAPE GEOMETRY
// ============================================================
def getShapeGeometry(
name: String
): Vector[Point] = {
val upper =
name.toUpperCase
if (upper == "LINE") {
Vector(
new Point(100,150),
new Point(900,500)
)
} else if (upper == "SQUARE") {
Vector(
new Point(300,125),
new Point(700,125),
new Point(700,525),
new Point(300,525),
new Point(300,125)
)
} else if (upper == "RECTANGLE") {
Vector(
new Point(150,200),
new Point(850,200),
new Point(850,450),
new Point(150,450),
new Point(150,200)
)
} else if (upper == "CIRCLE") {
ellipsePoints(
220,
220
)
} else if (upper == "ELLIPSE") {
ellipsePoints(
300,
160
)
} else if (upper == "TRIANGLE") {
polygonPoints(
3,
250,
-math.Pi / 2
)
} else if (upper == "DIAMOND") {
Vector(
new Point(500,75),
new Point(840,325),
new Point(500,575),
new Point(160,325),
new Point(500,75)
)
} else if (upper == "PENTAGON") {
polygonPoints(
5,
250,
-math.Pi / 2
)
} else if (upper == "HEXAGON") {
polygonPoints(
6,
240,
0
)
} else if (upper == "HEPTAGON") {
polygonPoints(
7,
235,
-math.Pi / 2
)
} else if (upper == "OCTAGON") {
polygonPoints(
8,
235,
math.Pi / 8
)
} else if (upper == "STAR 5") {
starPoints(
5,
255
)
} else if (upper == "STAR 6") {
starPoints(
6,
250
)
} else if (upper == "STAR 8") {
starPoints(
8,
245
)
} else if (upper == "HEART") {
heartPoints()
} else if (upper == "ARROW RIGHT") {
Vector(
new Point(130,240),
new Point(620,240),
new Point(620,140),
new Point(860,325),
new Point(620,510),
new Point(620,410),
new Point(130,410),
new Point(130,240)
)
} else if (upper == "ARROW LEFT") {
Vector(
new Point(870,240),
new Point(380,240),
new Point(380,140),
new Point(140,325),
new Point(380,510),
new Point(380,410),
new Point(870,410),
new Point(870,240)
)
} else if (upper == "ARROW UP") {
Vector(
new Point(430,535),
new Point(430,300),
new Point(275,300),
new Point(500,70),
new Point(725,300),
new Point(570,300),
new Point(570,535),
new Point(430,535)
)
} else if (upper == "ARROW DOWN") {
Vector(
new Point(430,115),
new Point(430,350),
new Point(275,350),
new Point(500,580),
new Point(725,350),
new Point(570,350),
new Point(570,115),
new Point(430,115)
)
} else if (upper == "PLUS") {
Vector(
new Point(430,100),
new Point(570,100),
new Point(570,245),
new Point(715,245),
new Point(715,405),
new Point(570,405),
new Point(570,550),
new Point(430,550),
new Point(430,405),
new Point(285,405),
new Point(285,245),
new Point(430,245),
new Point(430,100)
)
} else if (upper == "CLOUD") {
Vector(
new Point(170,470),
new Point(215,350),
new Point(330,270),
new Point(440,300),
new Point(530,195),
new Point(660,220),
new Point(770,320),
new Point(835,375),
new Point(800,470),
new Point(170,470)
)
} else if (upper == "SUN") {
starPoints(
16,
250
)
} else if (upper == "MOON") {
ellipsePoints(
230,
230
)
} else if (upper == "RING") {
ellipsePoints(
230,
230
)
} else if (upper == "BURST") {
starPoints(
20,
255
)
} else if (upper == "SNOWFLAKE") {
Vector(
new Point(500,75),
new Point(500,575),
new Point(245,160),
new Point(755,490),
new Point(245,490),
new Point(755,160)
)
} else {
ellipsePoints(
230,
160
)
}
}
// ============================================================
// OBJECT LIBRARY
// ============================================================
val allObjectNames =
Array(
"CAR",
"SPORTS CAR",
"RACING CAR",
"TRUCK",
"BUS",
"TRAIN",
"AIRPLANE",
"JET",
"HELICOPTER",
"ROCKET",
"BICYCLE",
"MOTORBIKE",
"SCOOTER",
"BOAT",
"SHIP",
"SUBMARINE",
"DRONE",
"UFO",
"HOUSE",
"VILLA",
"PALACE",
"CASTLE",
"TOWER",
"SCHOOL",
"HOSPITAL",
"BRIDGE",
"LIGHTHOUSE",
"CITY",
"SKYSCRAPER",
"STADIUM",
"TREE",
"PALM TREE",
"FLOWER",
"CACTUS",
"MOUNTAIN",
"VOLCANO",
"ISLAND",
"CLOUD",
"RAINBOW",
"SUN",
"MOON",
"PLANET",
"EARTH",
"SATURN",
"ROBOT",
"AI ROBOT",
"ASTRONAUT",
"KING",
"QUEEN",
"CAT",
"DOG",
"BIRD",
"FISH",
"SHARK",
"WHALE",
"DOLPHIN",
"LION",
"TIGER",
"ELEPHANT",
"HORSE",
"RABBIT",
"BEAR",
"PANDA",
"MONKEY",
"FOX",
"DEER",
"COW",
"GOAT",
"CHICKEN",
"DUCK",
"BUTTERFLY",
"BEE",
"SNAKE",
"TURTLE",
"APPLE",
"BANANA",
"ORANGE",
"MANGO",
"WATERMELON",
"PIZZA",
"BURGER",
"CAKE",
"ICE CREAM",
"GUITAR",
"PIANO",
"DRUM",
"CAMERA",
"COMPUTER",
"PHONE",
"BOOK",
"PENCIL",
"CLOCK",
"KEY",
"LAMP",
"CHAIR",
"TABLE",
"BACKPACK",
"STAR",
"HEART",
"DIAMOND",
"CROWN",
"TROPHY",
"GIFT",
"BALLOON",
"UMBRELLA",
"FOOTBALL",
"BASKETBALL",
"TENNIS BALL",
"CRICKET BAT",
"CRICKET BALL",
"FUTURE CAR",
"CYBER CITY",
"NEON TOWER",
"HOLOGRAM",
"TIME MACHINE"
)
var objectIndex: Int =
0
while (
objectIndex < allObjectNames.length
) {
objectModel.addElement(
allObjectNames(objectIndex)
)
objectIndex += 1
}
// ============================================================
// OBJECT GEOMETRY
// ============================================================
def getObjectGeometry(
name: String
): Vector[Point] = {
val upper =
name.toUpperCase
if (
upper.indexOf("CAR") >= 0
) {
Vector(
new Point(100,470),
new Point(205,365),
new Point(390,355),
new Point(470,235),
new Point(665,235),
new Point(775,355),
new Point(900,370),
new Point(955,470),
new Point(100,470)
)
} else if (
upper.indexOf("HOUSE") >= 0 ||
upper == "VILLA" ||
upper == "PALACE" ||
upper == "CASTLE"
) {
Vector(
new Point(220,555),
new Point(220,300),
new Point(500,65),
new Point(780,300),
new Point(780,555),
new Point(220,555)
)
} else if (
upper.indexOf("TREE") >= 0
) {
Vector(
new Point(455,580),
new Point(545,580),
new Point(545,350),
new Point(680,270),
new Point(600,150),
new Point(500,215),
new Point(400,150),
new Point(320,270),
new Point(455,350),
new Point(455,580)
)
} else if (
upper == "BIRD"
) {
Vector(
new Point(190,350),
new Point(385,215),
new Point(500,300),
new Point(650,175),
new Point(815,320),
new Point(635,420),
new Point(450,400),
new Point(315,475),
new Point(190,350)
)
} else if (
upper == "FISH" ||
upper == "SHARK" ||
upper == "WHALE" ||
upper == "DOLPHIN"
) {
Vector(
new Point(140,325),
new Point(325,210),
new Point(650,210),
new Point(850,325),
new Point(650,440),
new Point(325,440),
new Point(140,325)
)
} else if (
upper.indexOf("ROCKET") >= 0 ||
upper == "UFO"
) {
Vector(
new Point(425,520),
new Point(450,220),
new Point(500,55),
new Point(550,220),
new Point(575,520),
new Point(500,595),
new Point(425,520)
)
} else if (
upper.indexOf("ROBOT") >= 0
) {
Vector(
new Point(355,555),
new Point(355,295),
new Point(335,295),
new Point(335,135),
new Point(665,135),
new Point(665,295),
new Point(645,295),
new Point(645,555),
new Point(355,555)
)
} else if (
upper.indexOf("MOUNTAIN") >= 0
) {
Vector(
new Point(40,560),
new Point(290,205),
new Point(430,400),
new Point(625,70),
new Point(960,560),
new Point(40,560)
)
} else if (
upper == "FLOWER"
) {
Vector(
new Point(500,585),
new Point(500,315),
new Point(390,225),
new Point(500,115),
new Point(610,225),
new Point(500,315),
new Point(500,585)
)
} else if (
upper == "STAR" ||
upper == "HEART"
) {
if (
upper == "STAR"
) {
starPoints(
5,
255
)
} else {
heartPoints()
}
} else if (
upper == "CROWN"
) {
Vector(
new Point(235,490),
new Point(195,150),
new Point(390,295),
new Point(500,85),
new Point(610,295),
new Point(805,150),
new Point(765,490),
new Point(235,490)
)
} else {
polygonPoints(
6,
235,
0
)
}
}
// ============================================================
// ADD OBJECT
// ============================================================
def addObjectToCanvas(
name: String
): Unit = {
saveHistory()
val geometry =
getObjectGeometry(name)
drawItems +=
DrawItem(
geometry,
currentStrokeColor,
currentFillColor,
isClosedShape(geometry),
name,
true,
false
)
selectedItemIndex =
drawItems.length - 1
currentTool =
"SELECT"
repaintDrawingCanvas()
setMainStatus(
"OBJECT ADDED: " + name
)
}
// ============================================================
// ADD SHAPE
// ============================================================
def addShapeToCanvas(
name: String
): Unit = {
saveHistory()
val geometry =
getShapeGeometry(name)
drawItems +=
DrawItem(
geometry,
currentStrokeColor,
currentFillColor,
isClosedShape(geometry),
name,
true,
false
)
selectedItemIndex =
drawItems.length - 1
currentTool =
"SELECT"
repaintDrawingCanvas()
setMainStatus(
"SHAPE ADDED: " + name
)
}
// ============================================================
// CLEAR
// ============================================================
def clearDrawing(): Unit = {
if (
drawItems.nonEmpty
) {
saveHistory()
}
drawItems.clear()
temporaryPoints.clear()
selectedItemIndex =
-1
if (
drawingCodeArea != null
) {
drawingCodeArea.setText(
"// CANVAS CLEARED"
)
}
repaintDrawingCanvas()
setMainStatus(
"CANVAS CLEARED"
)
}
// ============================================================
// BUCKET
// ============================================================
def bucketFillSelected(): Unit = {
if (
selectedItemIndex >= 0 &&
selectedItemIndex < drawItems.length
) {
val item =
drawItems(
selectedItemIndex
)
if (
isClosedShape(
item.points
)
) {
saveHistory()
drawItems(
selectedItemIndex
) =
item.copy(
fillColor =
currentFillColor,
filled =
true
)
repaintDrawingCanvas()
setMainStatus(
"BUCKET FILL COMPLETE"
)
} else {
setMainStatus(
"CLOSED OBJECT REQUIRED"
)
}
} else {
setMainStatus(
"SELECT OBJECT FIRST"
)
}
}
// ============================================================
// COLOR NAME
// ============================================================
def kojoColorName(
c: Color
): String = {
val r =
c.getRed
val g =
c.getGreen
val b =
c.getBlue
if (
r > 220 &&
g < 100 &&
b < 100
) {
"red"
} else if (
r < 100 &&
g > 170 &&
b < 120
) {
"green"
} else if (
r < 100 &&
g < 150 &&
b > 170
) {
"blue"
} else if (
r > 220 &&
g > 170 &&
b < 130
) {
"yellow"
} else if (
r > 220 &&
g > 100 &&
b < 110
) {
"orange"
} else if (
r > 150 &&
b > 150
) {
"magenta"
} else {
"black"
}
}
// ============================================================
// DRAW CODE
// ============================================================
def generateDrawingCode(): Unit = {
val builder =
new StringBuilder()
builder.append(
"// ULTRA LEGEND GENERATED CODE\n"
)
builder.append(
"cleari()\n"
)
builder.append(
"setAnimationDelay(5)\n\n"
)
if (
drawItems.isEmpty
) {
builder.append(
"// NOTHING DRAWN\n"
)
} else {
var i: Int =
0
while (
i < drawItems.length
) {
val item =
drawItems(i)
if (
item.visible &&
item.points.nonEmpty
) {
builder.append(
"// " +
item.itemName +
"\n"
)
builder.append(
"setPenColor(" +
kojoColorName(
item.strokeColor
) +
")\n"
)
builder.append(
"penUp()\n"
)
builder.append(
"setPosition(" +
(
item.points.head.x -
CENTER_X
) +
", " +
(
CENTER_Y -
item.points.head.y
) +
")\n"
)
builder.append(
"penDown()\n"
)
var j: Int =
1
while (
j < item.points.length
) {
builder.append(
"lineTo(" +
(
item.points(j).x -
CENTER_X
) +
", " +
(
CENTER_Y -
item.points(j).y
) +
")\n"
)
j += 1
}
builder.append(
"\n"
)
}
i += 1
}
}
generatedDrawingCode =
builder.toString
if (
drawingCodeArea != null
) {
drawingCodeArea.setText(
generatedDrawingCode
)
}
setMainStatus(
"DRAW CODE GENERATED"
)
}
// ============================================================
// COPY
// ============================================================
def copyGeneratedText(
text: String
): Unit = {
try {
val clipboard =
java.awt.Toolkit
.getDefaultToolkit
.getSystemClipboard
clipboard.setContents(
new java.awt.datatransfer.StringSelection(
text
),
null
)
setMainStatus(
"CODE COPIED"
)
} catch {
case _: Exception =>
setMainStatus(
"COPY FAILED"
)
}
}
// ============================================================
// SAVE
// ============================================================
def saveGeneratedText(
text: String
): Unit = {
val chooser =
new JFileChooser()
chooser.setDialogTitle(
"SAVE SCALA CODE"
)
if (
chooser.showSaveDialog(mainFrame) ==
JFileChooser.APPROVE_OPTION
) {
try {
var file =
chooser.getSelectedFile
if (
!file.getName
.toLowerCase
.endsWith(".scala")
) {
file =
new java.io.File(
file.getAbsolutePath +
".scala"
)
}
val writer =
new java.io.PrintWriter(
file
)
writer.write(text)
writer.close()
setMainStatus(
"CODE SAVED"
)
} catch {
case _: Exception =>
setMainStatus(
"SAVE ERROR"
)
}
}
}
// ============================================================
// GAME LIST
// ============================================================
val gameNames =
Array(
"SLING BALL",
"TIC TAC TOE",
"PONG",
"KEYBOARD SNAKE",
"KEYBOARD RUNNER",
"KEYBOARD SPACE",
"KEYBOARD CAR",
"KEYBOARD PLATFORM",
"KEYBOARD MAZE",
"KEYBOARD DODGE"
)
val gameDescriptions =
Array(
"Mouse drag and launch ball.",
"Mouse Tic Tac Toe.",
"Mouse paddle Pong.",
"Arrow / WASD Snake.",
"Arrow / WASD runner with coins and enemies.",
"Arrow movement and SPACE shooting.",
"Arrow controlled car.",
"Platform game with jump and coins.",
"Keyboard maze.",
"Keyboard enemy dodge game."
)
// ============================================================
// GAME FRAME
// ============================================================
def createGameFrame(
title: String
): JFrame = {
val frame =
new JFrame(title)
frame.setDefaultCloseOperation(
WindowConstants.DISPOSE_ON_CLOSE
)
frame.setSize(
900,
650
)
frame.setLocationRelativeTo(
mainFrame
)
frame
}
// ============================================================
// TIMER CLEANUP
// ============================================================
def stopTimerWhenClosed(
frame: JFrame,
timerObject: Timer
): Unit = {
frame.addWindowListener(
new java.awt.event.WindowAdapter {
override def windowClosed(
e: java.awt.event.WindowEvent
): Unit = {
timerObject.stop()
}
}
)
}
// ============================================================
// MOUSE SLING BALL
// ============================================================
def launchSlingBall(): Unit = {
val frame =
createGameFrame(
"SLING BALL - MOUSE"
)
var ballX: Double =
120
var ballY: Double =
500
var velocityX: Double =
0
var velocityY: Double =
0
var launched: Boolean =
false
var won: Boolean =
false
var aimX: Double =
120
var aimY: Double =
500
val target =
new java.awt.Rectangle(
760,
100,
70,
70
)
val panel =
new JPanel {
override def paintComponent(
graphics: Graphics
): Unit = {
super.paintComponent(
graphics
)
val g =
graphics.asInstanceOf[Graphics2D]
g.setPaint(
new GradientPaint(
0,
0,
new Color(
30,
100,
160
),
0,
getHeight,
new Color(
5,
15,
35
)
)
)
g.fillRect(
0,
0,
getWidth,
getHeight
)
g.setColor(
Color.RED
)
g.fillOval(
target.x,
target.y,
target.width,
target.height
)
g.setColor(
Color.YELLOW
)
g.fillOval(
ballX.toInt - 10,
ballY.toInt - 10,
20,
20
)
if (
!launched
) {
g.setColor(
Color.GREEN
)
g.drawLine(
ballX.toInt,
ballY.toInt,
aimX.toInt,
aimY.toInt
)
}
g.setColor(
Color.WHITE
)
g.setFont(
new Font(
"Arial",
Font.BOLD,
18
)
)
g.drawString(
if (won)
"YOU WIN!"
else
"MOVE MOUSE / RELEASE TO LAUNCH",
20,
30
)
}
}
panel.addMouseMotionListener(
new MouseMotionAdapter {
override def mouseMoved(
e: MouseEvent
): Unit = {
if (!launched) {
aimX =
e.getX
aimY =
e.getY
panel.repaint()
}
}
}
)
panel.addMouseListener(
new MouseAdapter {
override def mouseReleased(
e: MouseEvent
): Unit = {
if (!launched) {
velocityX =
(ballX - e.getX) * 0.08
velocityY =
(ballY - e.getY) * 0.08
launched =
true
}
}
}
)
val slingTimer: Timer =
new Timer(
25,
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
if (
launched &&
!won
) {
velocityY += 0.25
ballX += velocityX
ballY += velocityY
if (
ballX < 10 ||
ballX > panel.getWidth - 10
) {
velocityX =
-velocityX
}
if (
ballY < 10
) {
velocityY =
-velocityY
}
if (
ballY >
panel.getHeight + 20
) {
ballX = 120
ballY = 500
velocityX = 0
velocityY = 0
launched = false
}
if (
target.contains(
ballX.toInt,
ballY.toInt
)
) {
won = true
}
panel.repaint()
}
}
}
)
slingTimer.start()
stopTimerWhenClosed(
frame,
slingTimer
)
frame.add(panel)
frame.setVisible(true)
}
// ============================================================
// TIC TAC TOE
// ============================================================
def launchTicTacToe(): Unit = {
val frame =
createGameFrame(
"TIC TAC TOE"
)
val board =
Array.fill[Int](9)(0)
var humanTurn =
true
var finished =
false
def winner(
player: Int
): Boolean = {
val lines =
Array(
Array(0,1,2),
Array(3,4,5),
Array(6,7,8),
Array(0,3,6),
Array(1,4,7),
Array(2,5,8),
Array(0,4,8),
Array(2,4,6)
)
var found =
false
var i =
0
while (
i < lines.length
) {
if (
board(lines(i)(0)) == player &&
board(lines(i)(1)) == player &&
board(lines(i)(2)) == player
) {
found =
true
}
i += 1
}
found
}
def fullBoard(): Boolean = {
var full =
true
var i =
0
while (
i < 9
) {
if (
board(i) == 0
) {
full =
false
}
i += 1
}
full
}
def computerMove(): Unit = {
var chosen =
-1
var i =
0
while (
i < 9 &&
chosen < 0
) {
if (
board(i) == 0
) {
chosen =
i
}
i += 1
}
if (
chosen >= 0
) {
board(chosen) =
2
}
}
val panel =
new JPanel {
override def paintComponent(
graphics: Graphics
): Unit = {
super.paintComponent(
graphics
)
val g =
graphics.asInstanceOf[Graphics2D]
g.setColor(
new Color(
245,
248,
255
)
)
g.fillRect(
0,
0,
getWidth,
getHeight
)
g.setColor(
Color.BLACK
)
g.setStroke(
new BasicStroke(
5
)
)
var i =
1
while (
i < 3
) {
g.drawLine(
i * getWidth / 3,
0,
i * getWidth / 3,
getHeight
)
g.drawLine(
0,
i * getHeight / 3,
getWidth,
i * getHeight / 3
)
i += 1
}
g.setFont(
new Font(
"Arial",
Font.BOLD,
80
)
)
i = 0
while (
i < 9
) {
if (
board(i) != 0
) {
val col =
i % 3
val row =
i / 3
g.setColor(
if (
board(i) == 1
)
Color.BLUE
else
Color.RED
)
g.drawString(
if (
board(i) == 1
)
"X"
else
"O",
col * getWidth / 3 + 65,
row * getHeight / 3 + 100
)
}
i += 1
}
g.setColor(
Color.DARK_GRAY
)
g.setFont(
new Font(
"Arial",
Font.BOLD,
20
)
)
g.drawString(
if (finished)
"GAME OVER"
else if (humanTurn)
"YOUR TURN"
else
"COMPUTER TURN",
20,
28
)
}
}
panel.addMouseListener(
new MouseAdapter {
override def mousePressed(
e: MouseEvent
): Unit = {
if (
humanTurn &&
!finished
) {
val col =
math.max(
0,
math.min(
2,
e.getX /
math.max(
1,
panel.getWidth / 3
)
)
)
val row =
math.max(
0,
math.min(
2,
e.getY /
math.max(
1,
panel.getHeight / 3
)
)
)
val index =
row * 3 + col
if (
board(index) == 0
) {
board(index) =
1
if (
winner(1) ||
fullBoard()
) {
finished =
true
} else {
humanTurn =
false
computerMove()
if (
winner(2) ||
fullBoard()
) {
finished =
true
} else {
humanTurn =
true
}
}
panel.repaint()
}
}
}
}
)
frame.add(panel)
frame.setVisible(true)
}
// ============================================================
// MOUSE PONG
// ============================================================
def launchPong(): Unit = {
val frame =
createGameFrame(
"PONG - MOUSE"
)
var paddleX: Double =
350
var ballX: Double =
450
var ballY: Double =
250
var vx: Double =
5
var vy: Double =
4
var score: Int =
0
val panel =
new JPanel {
override def paintComponent(
graphics: Graphics
): Unit = {
super.paintComponent(
graphics
)
val g =
graphics.asInstanceOf[Graphics2D]
g.setColor(
Color.BLACK
)
g.fillRect(
0,
0,
getWidth,
getHeight
)
g.setColor(
Color.WHITE
)
g.fillOval(
ballX.toInt - 10,
ballY.toInt - 10,
20,
20
)
g.fillRoundRect(
paddleX.toInt,
getHeight - 60,
150,
20,
10,
10
)
g.setFont(
new Font(
"Arial",
Font.BOLD,
20
)
)
g.drawString(
"SCORE: " + score,
20,
30
)
}
}
panel.addMouseMotionListener(
new MouseMotionAdapter {
override def mouseMoved(
e: MouseEvent
): Unit = {
paddleX =
math.max(
0,
math.min(
panel.getWidth - 150,
e.getX - 75
)
)
}
}
)
val pongTimer: Timer =
new Timer(
25,
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
ballX += vx
ballY += vy
if (
ballX < 10 ||
ballX > panel.getWidth - 10
) {
vx =
-vx
}
if (
ballY < 10
) {
vy =
-vy
}
if (
ballY >
panel.getHeight - 85 &&
ballX >= paddleX &&
ballX <= paddleX + 150
) {
vy =
-math.abs(vy)
score += 1
}
if (
ballY >
panel.getHeight + 10
) {
ballX =
panel.getWidth / 2.0
ballY =
panel.getHeight / 2.0
vx = 5
vy = -4
score = 0
}
panel.repaint()
}
}
)
pongTimer.start()
stopTimerWhenClosed(
frame,
pongTimer
)
frame.add(panel)
frame.setVisible(true)
}
// ============================================================
// KEYBOARD SNAKE
// CELL SIZE FIX
// ============================================================
def launchKeyboardSnake(): Unit = {
val frame =
createGameFrame(
"SNAKE - KEYBOARD"
)
val cellSize: Int =
25
val snakeBody =
ArrayBuffer[Point](
new Point(10,10),
new Point(9,10),
new Point(8,10)
)
var food =
new Point(
16,
10
)
var directionX: Int =
1
var directionY: Int =
0
var score: Int =
0
var running: Boolean =
true
val panel =
new JPanel {
override def paintComponent(
graphics: Graphics
): Unit = {
super.paintComponent(
graphics
)
val g =
graphics.asInstanceOf[Graphics2D]
g.setColor(
new Color(
15,
45,
22
)
)
g.fillRect(
0,
0,
getWidth,
getHeight
)
// GRID
g.setColor(
new Color(
255,
255,
255,
18
)
)
var gx: Int =
0
while (
gx <= getWidth
) {
g.drawLine(
gx,
0,
gx,
getHeight
)
gx += cellSize
}
var gy: Int =
0
while (
gy <= getHeight
) {
g.drawLine(
0,
gy,
getWidth,
gy
)
gy += cellSize
}
// FOOD
g.setColor(
Color.RED
)
g.fillOval(
food.x * cellSize + 3,
food.y * cellSize + 3,
cellSize - 6,
cellSize - 6
)
// BODY
var i: Int =
0
while (
i < snakeBody.length
) {
if (
i == 0
) {
g.setColor(
new Color(
80,
245,
100
)
)
} else {
g.setColor(
new Color(
35,
175,
65
)
)
}
g.fillRoundRect(
snakeBody(i).x * cellSize + 2,
snakeBody(i).y * cellSize + 2,
cellSize - 4,
cellSize - 4,
8,
8
)
i += 1
}
// SCORE
g.setColor(
Color.WHITE
)
g.setFont(
new Font(
"Arial",
Font.BOLD,
19
)
)
g.drawString(
"ARROWS / WASD SCORE: " + score,
15,
25
)
if (
!running
) {
g.setColor(
new Color(
0,
0,
0,
180
)
)
g.fillRect(
0,
0,
getWidth,
getHeight
)
g.setColor(
Color.WHITE
)
g.setFont(
new Font(
"Arial",
Font.BOLD,
42
)
)
g.drawString(
"GAME OVER",
300,
285
)
g.setFont(
new Font(
"Arial",
Font.BOLD,
20
)
)
g.drawString(
"FINAL SCORE: " + score,
345,
325
)
}
}
}
panel.setFocusable(true)
panel.addKeyListener(
new java.awt.event.KeyAdapter {
override def keyPressed(
e: java.awt.event.KeyEvent
): Unit = {
val key =
e.getKeyCode
if (
key ==
java.awt.event.KeyEvent.VK_LEFT ||
key ==
java.awt.event.KeyEvent.VK_A
) {
if (
directionX != 1
) {
directionX =
-1
directionY =
0
}
} else if (
key ==
java.awt.event.KeyEvent.VK_RIGHT ||
key ==
java.awt.event.KeyEvent.VK_D
) {
if (
directionX != -1
) {
directionX =
1
directionY =
0
}
} else if (
key ==
java.awt.event.KeyEvent.VK_UP ||
key ==
java.awt.event.KeyEvent.VK_W
) {
if (
directionY != 1
) {
directionX =
0
directionY =
-1
}
} else if (
key ==
java.awt.event.KeyEvent.VK_DOWN ||
key ==
java.awt.event.KeyEvent.VK_S
) {
if (
directionY != -1
) {
directionX =
0
directionY =
1
}
}
}
}
)
val snakeTimer: Timer =
new Timer(
110,
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
if (
running &&
snakeBody.nonEmpty
) {
val head =
snakeBody.head
val nextX =
head.x +
directionX
val nextY =
head.y +
directionY
val columnCount: Int =
math.max(
1,
panel.getWidth /
cellSize
)
val rowCount: Int =
math.max(
1,
panel.getHeight /
cellSize
)
// WALL
if (
nextX < 0 ||
nextY < 0 ||
nextX >= columnCount ||
nextY >= rowCount
) {
running =
false
} else {
val newHead =
new Point(
nextX,
nextY
)
// SELF COLLISION
var collision =
false
var i: Int =
0
while (
i < snakeBody.length
) {
if (
snakeBody(i).x ==
newHead.x &&
snakeBody(i).y ==
newHead.y
) {
collision =
true
}
i += 1
}
if (
collision
) {
running =
false
} else {
snakeBody.prepend(
newHead
)
// FOOD
if (
newHead.x ==
food.x &&
newHead.y ==
food.y
) {
score +=
1
var foodFound =
false
var foodX: Int =
0
var foodY: Int =
0
while (
!foodFound
) {
foodX =
(
math.random *
columnCount
).toInt
foodY =
(
math.random *
rowCount
).toInt
foodFound =
true
var check: Int =
0
while (
check < snakeBody.length
) {
if (
snakeBody(check).x ==
foodX &&
snakeBody(check).y ==
foodY
) {
foodFound =
false
}
check += 1
}
}
food =
new Point(
foodX,
foodY
)
} else {
snakeBody.remove(
snakeBody.length - 1
)
}
}
}
panel.repaint()
}
}
}
)
snakeTimer.start()
stopTimerWhenClosed(
frame,
snakeTimer
)
frame.add(
panel,
BorderLayout.CENTER
)
frame.setVisible(true)
panel.requestFocusInWindow()
}
// ============================================================
// KEYBOARD RUNNER
// ============================================================
def launchKeyboardRunner(): Unit = {
val frame =
createGameFrame(
"KEYBOARD RUNNER"
)
var playerX: Double =
100
var playerY: Double =
450
var velocityY: Double =
0
var score: Int =
0
var jumping: Boolean =
false
var running: Boolean =
true
val coins =
ArrayBuffer[Point](
new Point(300,390),
new Point(500,330),
new Point(700,390)
)
val enemies =
ArrayBuffer[Point](
new Point(550,450),
new Point(800,450)
)
val panel =
new JPanel {
override def paintComponent(
graphics: Graphics
): Unit = {
super.paintComponent(graphics)
val g =
graphics.asInstanceOf[Graphics2D]
g.setPaint(
new GradientPaint(
0,
0,
new Color(
75,
180,
250
),
0,
getHeight,
new Color(
210,
240,
255
)
)
)
g.fillRect(
0,
0,
getWidth,
getHeight
)
g.setColor(
new Color(
70,
180,
75
)
)
g.fillRect(
0,
getHeight - 100,
getWidth,
100
)
g.setColor(
Color.BLUE
)
g.fillRoundRect(
playerX.toInt,
playerY.toInt,
45,
65,
10,
10
)
g.setColor(
Color.YELLOW
)
var i =
0
while (
i < coins.length
) {
g.fillOval(
coins(i).x,
coins(i).y,
25,
25
)
i += 1
}
g.setColor(
Color.RED
)
i = 0
while (
i < enemies.length
) {
g.fillRect(
enemies(i).x,
enemies(i).y,
45,
45
)
i += 1
}
g.setColor(
Color.WHITE
)
g.setFont(
new Font(
"Arial",
Font.BOLD,
17
)
)
g.drawString(
"A/D or ARROWS = MOVE SPACE = JUMP SCORE: " +
score,
15,
28
)
if (
!running
) {
g.setColor(
Color.BLACK
)
g.fillRect(
0,
0,
getWidth,
getHeight
)
g.setColor(
Color.WHITE
)
g.setFont(
new Font(
"Arial",
Font.BOLD,
40
)
)
g.drawString(
"GAME OVER",
305,
300
)
}
}
}
panel.setFocusable(true)
panel.addKeyListener(
new java.awt.event.KeyAdapter {
override def keyPressed(
e: java.awt.event.KeyEvent
): Unit = {
if (
!running
) {
return
}
val key =
e.getKeyCode
if (
key ==
java.awt.event.KeyEvent.VK_LEFT ||
key ==
java.awt.event.KeyEvent.VK_A
) {
playerX -=
12
} else if (
key ==
java.awt.event.KeyEvent.VK_RIGHT ||
key ==
java.awt.event.KeyEvent.VK_D
) {
playerX +=
12
} else if (
key ==
java.awt.event.KeyEvent.VK_SPACE ||
key ==
java.awt.event.KeyEvent.VK_UP
) {
if (
!jumping
) {
velocityY =
-11
jumping =
true
}
}
playerX =
math.max(
0,
math.min(
panel.getWidth - 45,
playerX
)
)
}
}
)
val runnerTimer: Timer =
new Timer(
30,
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
if (
running
) {
velocityY +=
0.55
playerY +=
velocityY
val groundY =
panel.getHeight -
165
if (
playerY >= groundY
) {
playerY =
groundY
velocityY =
0
jumping =
false
}
var i =
coins.length - 1
while (
i >= 0
) {
val coin =
coins(i)
val hit =
playerX + 45 > coin.x &&
playerX < coin.x + 25 &&
playerY + 65 > coin.y &&
playerY < coin.y + 25
if (
hit
) {
coins.remove(i)
score +=
10
}
i -= 1
}
i = 0
while (
i < enemies.length
) {
enemies(i).x -=
3
if (
enemies(i).x < -50
) {
enemies(i).x =
panel.getWidth +
100 +
i * 200
}
val hit =
playerX + 45 > enemies(i).x &&
playerX < enemies(i).x + 45 &&
playerY + 65 > enemies(i).y &&
playerY < enemies(i).y + 45
if (
hit
) {
running =
false
}
i += 1
}
panel.repaint()
}
}
}
)
runnerTimer.start()
stopTimerWhenClosed(
frame,
runnerTimer
)
frame.add(panel)
frame.setVisible(true)
panel.requestFocusInWindow()
}
// ============================================================
// KEYBOARD SPACE
// ============================================================
def launchKeyboardSpace(): Unit = {
val frame =
createGameFrame(
"KEYBOARD SPACE"
)
var shipX: Double =
400
var laserX: Double =
-100
var laserY: Double =
-100
var enemyX: Double =
400
var enemyY: Double =
80
var score: Int =
0
val panel =
new JPanel {
override def paintComponent(
graphics: Graphics
): Unit = {
super.paintComponent(graphics)
val g =
graphics.asInstanceOf[Graphics2D]
g.setColor(
new Color(
5,
10,
30
)
)
g.fillRect(
0,
0,
getWidth,
getHeight
)
g.setColor(
Color.WHITE
)
var star: Int =
0
while (
star < 70
) {
g.fillOval(
(star * 83) %
math.max(
1,
getWidth
),
(star * 47) %
math.max(
1,
getHeight
),
2,
2
)
star += 1
}
g.setColor(
Color.CYAN
)
val ship =
new java.awt.Polygon()
ship.addPoint(
shipX.toInt,
getHeight - 70
)
ship.addPoint(
shipX.toInt + 25,
getHeight - 130
)
ship.addPoint(
shipX.toInt + 50,
getHeight - 70
)
g.fillPolygon(ship)
g.setColor(
Color.RED
)
g.fillOval(
enemyX.toInt,
enemyY.toInt,
45,
35
)
g.setColor(
Color.YELLOW
)
if (
laserY > -40
) {
g.fillRect(
laserX.toInt,
laserY.toInt,
6,
20
)
}
g.setColor(
Color.WHITE
)
g.drawString(
"LEFT / RIGHT = MOVE SPACE = FIRE SCORE: " +
score,
15,
28
)
}
}
panel.setFocusable(true)
panel.addKeyListener(
new java.awt.event.KeyAdapter {
override def keyPressed(
e: java.awt.event.KeyEvent
): Unit = {
val key =
e.getKeyCode
if (
key ==
java.awt.event.KeyEvent.VK_LEFT
) {
shipX -=
12
} else if (
key ==
java.awt.event.KeyEvent.VK_RIGHT
) {
shipX +=
12
} else if (
key ==
java.awt.event.KeyEvent.VK_SPACE
) {
laserX =
shipX + 22
laserY =
panel.getHeight - 150
}
shipX =
math.max(
0,
math.min(
panel.getWidth - 50,
shipX
)
)
}
}
)
val spaceTimer: Timer =
new Timer(
25,
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
enemyY +=
2
laserY -=
12
if (
laserX >= enemyX &&
laserX <= enemyX + 45 &&
laserY <= enemyY + 35 &&
laserY >= enemyY - 20
) {
score +=
1
enemyX =
math.random *
math.max(
1,
panel.getWidth - 45
)
enemyY =
50
}
if (
enemyY >
panel.getHeight
) {
enemyY =
50
}
panel.repaint()
}
}
)
spaceTimer.start()
stopTimerWhenClosed(
frame,
spaceTimer
)
frame.add(panel)
frame.setVisible(true)
panel.requestFocusInWindow()
}
// ============================================================
// KEYBOARD CAR
// ============================================================
def launchKeyboardCar(): Unit = {
val frame =
createGameFrame(
"KEYBOARD CAR"
)
var playerX: Double =
420
var enemyX: Double =
250
var enemyY: Double =
-100
var score: Int =
0
var running: Boolean =
true
val panel =
new JPanel {
override def paintComponent(
graphics: Graphics
): Unit = {
super.paintComponent(graphics)
val g =
graphics.asInstanceOf[Graphics2D]
g.setColor(
new Color(
45,
45,
50
)
)
g.fillRect(
0,
0,
getWidth,
getHeight
)
g.setColor(
Color.WHITE
)
var roadY: Int =
0
while (
roadY < getHeight
) {
g.fillRect(
getWidth / 2 - 5,
roadY,
10,
60
)
roadY +=
100
}
g.setColor(
Color.BLUE
)
g.fillRoundRect(
playerX.toInt,
getHeight - 125,
60,
100,
18,
18
)
g.setColor(
Color.RED
)
g.fillRoundRect(
enemyX.toInt,
enemyY.toInt,
60,
100,
18,
18
)
g.setColor(
Color.WHITE
)
g.setFont(
new Font(
"Arial",
Font.BOLD,
18
)
)
g.drawString(
"LEFT / RIGHT SCORE: " +
score,
15,
28
)
if (
!running
) {
g.setColor(
new Color(
0,
0,
0,
180
)
)
g.fillRect(
0,
0,
getWidth,
getHeight
)
g.setColor(
Color.WHITE
)
g.setFont(
new Font(
"Arial",
Font.BOLD,
42
)
)
g.drawString(
"CRASH!",
355,
300
)
}
}
}
panel.setFocusable(true)
panel.addKeyListener(
new java.awt.event.KeyAdapter {
override def keyPressed(
e: java.awt.event.KeyEvent
): Unit = {
val key =
e.getKeyCode
if (
key ==
java.awt.event.KeyEvent.VK_LEFT
) {
playerX -=
15
} else if (
key ==
java.awt.event.KeyEvent.VK_RIGHT
) {
playerX +=
15
}
playerX =
math.max(
0,
math.min(
panel.getWidth - 60,
playerX
)
)
}
}
)
val carTimer: Timer =
new Timer(
25,
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
if (
running
) {
enemyY +=
7
if (
enemyY >
panel.getHeight
) {
enemyY =
-100
enemyX =
math.random *
math.max(
1,
panel.getWidth - 60
)
score +=
1
}
val hit =
enemyX + 60 > playerX &&
enemyX < playerX + 60 &&
enemyY + 100 >
panel.getHeight - 125 &&
enemyY <
panel.getHeight
if (
hit
) {
running =
false
}
panel.repaint()
}
}
}
)
carTimer.start()
stopTimerWhenClosed(
frame,
carTimer
)
frame.add(panel)
frame.setVisible(true)
panel.requestFocusInWindow()
}
// ============================================================
// KEYBOARD PLATFORM
// ============================================================
def launchKeyboardPlatform(): Unit = {
val frame =
createGameFrame(
"KEYBOARD PLATFORM"
)
var playerX: Double =
100
var playerY: Double =
450
var velocityY: Double =
0
var score: Int =
0
var jumping: Boolean =
false
var won: Boolean =
false
val platforms =
Array(
new java.awt.Rectangle(
0,
550,
900,
70
),
new java.awt.Rectangle(
180,
430,
160,
20
),
new java.awt.Rectangle(
420,
350,
160,
20
),
new java.awt.Rectangle(
650,
260,
160,
20
)
)
val coins =
ArrayBuffer[Point](
new Point(230,395),
new Point(470,315),
new Point(705,225)
)
val goal =
new java.awt.Rectangle(
820,
170,
50,
50
)
val panel =
new JPanel {
override def paintComponent(
graphics: Graphics
): Unit = {
super.paintComponent(graphics)
val g =
graphics.asInstanceOf[Graphics2D]
g.setPaint(
new GradientPaint(
0,
0,
new Color(
60,
160,
245
),
0,
getHeight,
new Color(
210,
240,
255
)
)
)
g.fillRect(
0,
0,
getWidth,
getHeight
)
g.setColor(
new Color(
90,
180,
80
)
)
var p: Int =
0
while (
p < platforms.length
) {
g.fillRoundRect(
platforms(p).x,
platforms(p).y,
platforms(p).width,
platforms(p).height,
10,
10
)
p += 1
}
g.setColor(
Color.YELLOW
)
var c: Int =
0
while (
c < coins.length
) {
g.fillOval(
coins(c).x,
coins(c).y,
24,
24
)
c += 1
}
g.setColor(
Color.GREEN
)
g.fillOval(
goal.x,
goal.y,
goal.width,
goal.height
)
g.setColor(
Color.BLUE
)
g.fillRoundRect(
playerX.toInt,
playerY.toInt,
42,
58,
10,
10
)
g.setColor(
Color.WHITE
)
g.setFont(
new Font(
"Arial",
Font.BOLD,
17
)
)
g.drawString(
"A/D or ARROWS = MOVE SPACE = JUMP SCORE: " +
score,
15,
28
)
if (
won
) {
g.setColor(
new Color(
0,
0,
0,
170
)
)
g.fillRect(
0,
0,
getWidth,
getHeight
)
g.setColor(
Color.WHITE
)
g.setFont(
new Font(
"Arial",
Font.BOLD,
42
)
)
g.drawString(
"LEVEL COMPLETE!",
270,
300
)
}
}
}
panel.setFocusable(true)
panel.addKeyListener(
new java.awt.event.KeyAdapter {
override def keyPressed(
e: java.awt.event.KeyEvent
): Unit = {
val key =
e.getKeyCode
if (
key ==
java.awt.event.KeyEvent.VK_LEFT ||
key ==
java.awt.event.KeyEvent.VK_A
) {
playerX -=
12
} else if (
key ==
java.awt.event.KeyEvent.VK_RIGHT ||
key ==
java.awt.event.KeyEvent.VK_D
) {
playerX +=
12
} else if (
key ==
java.awt.event.KeyEvent.VK_SPACE ||
key ==
java.awt.event.KeyEvent.VK_UP
) {
if (
!jumping
) {
velocityY =
-12
jumping =
true
}
}
playerX =
math.max(
0,
math.min(
panel.getWidth - 42,
playerX
)
)
}
}
)
val platformTimer: Timer =
new Timer(
30,
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
if (
!won
) {
velocityY +=
0.55
playerY +=
velocityY
val playerRect =
new java.awt.Rectangle(
playerX.toInt,
playerY.toInt,
42,
58
)
var onPlatform =
false
var i: Int =
0
while (
i < platforms.length
) {
val platform =
platforms(i)
if (
playerRect.x + playerRect.width >
platform.x &&
playerRect.x <
platform.x + platform.width &&
playerRect.y + playerRect.height >
platform.y &&
playerRect.y + playerRect.height <
platform.y + platform.height + 20 &&
velocityY >= 0
) {
playerY =
platform.y - 58
velocityY =
0
jumping =
false
onPlatform =
true
}
i += 1
}
if (
playerY >
panel.getHeight + 50
) {
playerX =
100
playerY =
450
velocityY =
0
jumping =
false
}
i =
coins.length - 1
while (
i >= 0
) {
val coin =
new java.awt.Rectangle(
coins(i).x,
coins(i).y,
24,
24
)
if (
coin.intersects(
playerRect
)
) {
coins.remove(i)
score +=
10
}
i -= 1
}
if (
goal.intersects(
playerRect
)
) {
won =
true
}
panel.repaint()
}
}
}
)
platformTimer.start()
stopTimerWhenClosed(
frame,
platformTimer
)
frame.add(panel)
frame.setVisible(true)
panel.requestFocusInWindow()
}
// ============================================================
// KEYBOARD MAZE
// ============================================================
def launchKeyboardMaze(): Unit = {
val frame =
createGameFrame(
"KEYBOARD MAZE"
)
var playerX: Int =
50
var playerY: Int =
70
var score: Int =
0
val playerSize: Int =
30
val target =
new java.awt.Rectangle(
800,
520,
45,
45
)
val walls =
Array(
new java.awt.Rectangle(150,50,25,400),
new java.awt.Rectangle(300,200,25,350),
new java.awt.Rectangle(450,50,25,400),
new java.awt.Rectangle(600,200,25,350),
new java.awt.Rectangle(750,50,25,400)
)
val panel =
new JPanel {
override def paintComponent(
graphics: Graphics
): Unit = {
super.paintComponent(graphics)
val g =
graphics.asInstanceOf[Graphics2D]
g.setColor(
new Color(
25,
30,
60
)
)
g.fillRect(
0,
0,
getWidth,
getHeight
)
g.setColor(
new Color(
80,
80,
90
)
)
var i =
0
while (
i < walls.length
) {
g.fillRect(
walls(i).x,
walls(i).y,
walls(i).width,
walls(i).height
)
i += 1
}
g.setColor(
Color.GREEN
)
g.fillOval(
target.x,
target.y,
target.width,
target.height
)
g.setColor(
Color.CYAN
)
g.fillRoundRect(
playerX,
playerY,
playerSize,
playerSize,
8,
8
)
g.setColor(
Color.WHITE
)
g.setFont(
new Font(
"Arial",
Font.BOLD,
18
)
)
g.drawString(
"ARROWS / WASD = MOVE SCORE: " +
score,
15,
28
)
}
}
panel.setFocusable(true)
panel.addKeyListener(
new java.awt.event.KeyAdapter {
override def keyPressed(
e: java.awt.event.KeyEvent
): Unit = {
val key =
e.getKeyCode
var dx =
0
var dy =
0
if (
key ==
java.awt.event.KeyEvent.VK_LEFT ||
key ==
java.awt.event.KeyEvent.VK_A
) {
dx =
-10
} else if (
key ==
java.awt.event.KeyEvent.VK_RIGHT ||
key ==
java.awt.event.KeyEvent.VK_D
) {
dx =
10
} else if (
key ==
java.awt.event.KeyEvent.VK_UP ||
key ==
java.awt.event.KeyEvent.VK_W
) {
dy =
-10
} else if (
key ==
java.awt.event.KeyEvent.VK_DOWN ||
key ==
java.awt.event.KeyEvent.VK_S
) {
dy =
10
}
val candidate =
new java.awt.Rectangle(
playerX + dx,
playerY + dy,
playerSize,
playerSize
)
var blocked =
false
var i =
0
while (
i < walls.length
) {
if (
walls(i).intersects(
candidate
)
) {
blocked =
true
}
i += 1
}
if (
!blocked
) {
playerX =
math.max(
0,
math.min(
panel.getWidth - playerSize,
playerX + dx
)
)
playerY =
math.max(
45,
math.min(
panel.getHeight - playerSize,
playerY + dy
)
)
}
val playerRect =
new java.awt.Rectangle(
playerX,
playerY,
playerSize,
playerSize
)
if (
target.intersects(
playerRect
)
) {
score +=
1
playerX =
50
playerY =
70
}
panel.repaint()
}
}
)
frame.add(panel)
frame.setVisible(true)
panel.requestFocusInWindow()
}
// ============================================================
// KEYBOARD DODGE
// ============================================================
def launchKeyboardDodge(): Unit = {
val frame =
createGameFrame(
"KEYBOARD DODGE"
)
var playerX: Double =
400
var playerY: Double =
500
var score: Int =
0
var running: Boolean =
true
val enemies =
ArrayBuffer[Point](
new Point(100,-50),
new Point(300,-180),
new Point(550,-100),
new Point(750,-230)
)
val panel =
new JPanel {
override def paintComponent(
graphics: Graphics
): Unit = {
super.paintComponent(graphics)
val g =
graphics.asInstanceOf[Graphics2D]
g.setColor(
new Color(
20,
25,
40
)
)
g.fillRect(
0,
0,
getWidth,
getHeight
)
g.setColor(
Color.CYAN
)
g.fillOval(
playerX.toInt,
playerY.toInt,
45,
45
)
g.setColor(
Color.RED
)
var i =
0
while (
i < enemies.length
) {
g.fillRoundRect(
enemies(i).x,
enemies(i).y,
40,
40,
8,
8
)
i += 1
}
g.setColor(
Color.WHITE
)
g.setFont(
new Font(
"Arial",
Font.BOLD,
18
)
)
g.drawString(
"ARROWS / WASD SCORE: " +
score,
15,
28
)
if (
!running
) {
g.setColor(
new Color(
0,
0,
0,
180
)
)
g.fillRect(
0,
0,
getWidth,
getHeight
)
g.setColor(
Color.WHITE
)
g.setFont(
new Font(
"Arial",
Font.BOLD,
42
)
)
g.drawString(
"DODGED: " + score,
305,
300
)
}
}
}
panel.setFocusable(true)
panel.addKeyListener(
new java.awt.event.KeyAdapter {
override def keyPressed(
e: java.awt.event.KeyEvent
): Unit = {
val key =
e.getKeyCode
if (
key ==
java.awt.event.KeyEvent.VK_LEFT ||
key ==
java.awt.event.KeyEvent.VK_A
) {
playerX -=
14
} else if (
key ==
java.awt.event.KeyEvent.VK_RIGHT ||
key ==
java.awt.event.KeyEvent.VK_D
) {
playerX +=
14
} else if (
key ==
java.awt.event.KeyEvent.VK_UP ||
key ==
java.awt.event.KeyEvent.VK_W
) {
playerY -=
14
} else if (
key ==
java.awt.event.KeyEvent.VK_DOWN ||
key ==
java.awt.event.KeyEvent.VK_S
) {
playerY +=
14
}
playerX =
math.max(
0,
math.min(
panel.getWidth - 45,
playerX
)
)
playerY =
math.max(
45,
math.min(
panel.getHeight - 45,
playerY
)
)
}
}
)
val dodgeTimer: Timer =
new Timer(
30,
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
if (
running
) {
var i =
0
while (
i < enemies.length
) {
enemies(i).y +=
5 + i
if (
enemies(i).y >
panel.getHeight
) {
enemies(i).y =
-60
enemies(i).x =
(
math.random *
math.max(
1,
panel.getWidth - 40
)
).toInt
score +=
1
}
val hit =
enemies(i).x + 40 >
playerX &&
enemies(i).x <
playerX + 45 &&
enemies(i).y + 40 >
playerY &&
enemies(i).y <
playerY + 45
if (
hit
) {
running =
false
}
i += 1
}
panel.repaint()
}
}
}
)
dodgeTimer.start()
stopTimerWhenClosed(
frame,
dodgeTimer
)
frame.add(panel)
frame.setVisible(true)
panel.requestFocusInWindow()
}
// ============================================================
// GAME ROUTER
// ============================================================
def startSelectedGame(
name: String
): Unit = {
if (
name == "SLING BALL"
) {
launchSlingBall()
} else if (
name == "TIC TAC TOE"
) {
launchTicTacToe()
} else if (
name == "PONG"
) {
launchPong()
} else if (
name == "KEYBOARD SNAKE"
) {
launchKeyboardSnake()
} else if (
name == "KEYBOARD RUNNER"
) {
launchKeyboardRunner()
} else if (
name == "KEYBOARD SPACE"
) {
launchKeyboardSpace()
} else if (
name == "KEYBOARD CAR"
) {
launchKeyboardCar()
} else if (
name == "KEYBOARD PLATFORM"
) {
launchKeyboardPlatform()
} else if (
name == "KEYBOARD MAZE"
) {
launchKeyboardMaze()
} else {
launchKeyboardDodge()
}
}
// ============================================================
// GAME STUDIO WINDOW
// ============================================================
def openGameStudio(): Unit = {
val frame =
new JFrame(
"ULTRA LEGEND GAME STUDIO X8"
)
frame.setDefaultCloseOperation(
WindowConstants.DISPOSE_ON_CLOSE
)
frame.setSize(
1200,
750
)
frame.setLocationRelativeTo(
mainFrame
)
val gameModel =
new DefaultListModel[String]()
var i =
0
while (
i < gameNames.length
) {
gameModel.addElement(
gameNames(i)
)
i += 1
}
val gameList =
new JList[String](
gameModel
)
gameList.setSelectionMode(
ListSelectionModel.SINGLE_SELECTION
)
gameList.setFont(
new Font(
"Arial",
Font.BOLD,
14
)
)
val searchField =
new JTextField(
14
)
val searchButton =
createButton(
"SEARCH"
)
val playButton =
createButton(
"PLAY"
)
val codeButton =
createButton(
"GAME CODE"
)
val closeButton =
createButton(
"CLOSE"
)
val infoArea =
new JTextArea()
infoArea.setEditable(false)
infoArea.setFont(
new Font(
"Monospaced",
Font.PLAIN,
13
)
)
infoArea.setText(
"ULTRA LEGEND GAME STUDIO X8\n\n" +
"MOUSE + KEYBOARD GAMES\n\n" +
"DOUBLE CLICK A GAME = PLAY\n\n" +
"KEYBOARD GAMES:\n" +
"SNAKE\n" +
"RUNNER\n" +
"SPACE\n" +
"CAR\n" +
"PLATFORM\n" +
"MAZE\n" +
"DODGE"
)
val searchPanel =
new JPanel(
new FlowLayout(
FlowLayout.LEFT
)
)
searchPanel.add(
new JLabel(
"SEARCH:"
)
)
searchPanel.add(
searchField
)
searchPanel.add(
searchButton
)
val leftPanel =
new JPanel(
new BorderLayout()
)
leftPanel.add(
new JLabel(
"GAME LIBRARY"
),
BorderLayout.NORTH
)
leftPanel.add(
searchPanel,
BorderLayout.CENTER
)
leftPanel.add(
new JScrollPane(
gameList
),
BorderLayout.SOUTH
)
val rightPanel =
new JPanel(
new BorderLayout()
)
rightPanel.add(
new JLabel(
"GAME INFORMATION"
),
BorderLayout.NORTH
)
rightPanel.add(
new JScrollPane(
infoArea
),
BorderLayout.CENTER
)
val split =
new JSplitPane(
JSplitPane.HORIZONTAL_SPLIT,
leftPanel,
rightPanel
)
split.setDividerLocation(
380
)
gameList.addListSelectionListener(
new javax.swing.event.ListSelectionListener {
override def valueChanged(
e: javax.swing.event.ListSelectionEvent
): Unit = {
if (
!e.getValueIsAdjusting
) {
val selected =
gameList.getSelectedValue
if (
selected != null
) {
var description =
""
var j =
0
while (
j < gameNames.length
) {
if (
gameNames(j) ==
selected
) {
description =
gameDescriptions(j)
}
j += 1
}
infoArea.setText(
"GAME:\n\n" +
selected +
"\n\n" +
description
)
}
}
}
}
)
searchButton.addActionListener(
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
val query =
searchField
.getText
.trim
.toLowerCase
gameModel.clear()
var j =
0
while (
j < gameNames.length
) {
if (
query.isEmpty ||
gameNames(j)
.toLowerCase
.indexOf(query) >= 0
) {
gameModel.addElement(
gameNames(j)
)
}
j += 1
}
}
}
)
playButton.addActionListener(
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
val selected =
gameList.getSelectedValue
if (
selected != null
) {
startSelectedGame(
selected
)
} else {
JOptionPane.showMessageDialog(
frame,
"SELECT A GAME FIRST."
)
}
}
}
)
gameList.addMouseListener(
new MouseAdapter {
override def mouseClicked(
e: MouseEvent
): Unit = {
if (
e.getClickCount == 2
) {
val selected =
gameList.getSelectedValue
if (
selected != null
) {
startSelectedGame(
selected
)
}
}
}
}
)
codeButton.addActionListener(
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
val selected =
gameList.getSelectedValue
if (
selected != null
) {
val codeFrame =
new JFrame(
"GAME CODE - " +
selected
)
codeFrame.setDefaultCloseOperation(
WindowConstants.DISPOSE_ON_CLOSE
)
codeFrame.setSize(
800,
600
)
codeFrame.setLocationRelativeTo(
frame
)
val area =
new JTextArea()
area.setFont(
new Font(
"Monospaced",
Font.PLAIN,
13
)
)
area.setText(
"// ULTRA LEGEND GAME STUDIO X8\n" +
"// GAME: " +
selected +
"\n\n" +
"// Select PLAY in the Game Studio to launch this game."
)
codeFrame.add(
new JScrollPane(
area
),
BorderLayout.CENTER
)
codeFrame.setVisible(true)
} else {
JOptionPane.showMessageDialog(
frame,
"SELECT A GAME FIRST."
)
}
}
}
)
closeButton.addActionListener(
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
frame.dispose()
}
}
)
val bottomPanel =
new JPanel(
new FlowLayout(
FlowLayout.CENTER
)
)
bottomPanel.add(
playButton
)
bottomPanel.add(
codeButton
)
bottomPanel.add(
closeButton
)
frame.setLayout(
new BorderLayout()
)
frame.add(
split,
BorderLayout.CENTER
)
frame.add(
bottomPanel,
BorderLayout.SOUTH
)
frame.setVisible(true)
}
// ============================================================
// MAIN DRAWING CANVAS
// ============================================================
drawingCanvas =
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
)
// WHITE BACKGROUND
g.setColor(
Color.WHITE
)
g.fillRect(
0,
0,
getWidth,
getHeight
)
// GRID
if (
gridEnabled
) {
g.setColor(
new Color(
0,
0,
0,
20
)
)
var x: Int =
0
while (
x <= CANVAS_WIDTH
) {
g.drawLine(
x,
0,
x,
CANVAS_HEIGHT
)
x +=
50
}
var y: Int =
0
while (
y <= CANVAS_HEIGHT
) {
g.drawLine(
0,
y,
CANVAS_WIDTH,
y
)
y +=
50
}
}
// OBJECTS
var i: Int =
0
while (
i < drawItems.length
) {
val item =
drawItems(i)
if (
item.visible &&
item.points.length >= 2
) {
if (
item.filled &&
item.points.length >= 3
) {
val path =
new java.awt.geom.Path2D.Double()
path.moveTo(
item.points.head.x,
item.points.head.y
)
var j: Int =
1
while (
j < item.points.length
) {
path.lineTo(
item.points(j).x,
item.points(j).y
)
j += 1
}
path.closePath()
g.setColor(
item.fillColor
)
g.fill(path)
}
g.setColor(
item.strokeColor
)
g.setStroke(
new BasicStroke(
brushWidth,
BasicStroke.CAP_ROUND,
BasicStroke.JOIN_ROUND
)
)
var j: Int =
1
while (
j < item.points.length
) {
g.drawLine(
item.points(j - 1).x,
item.points(j - 1).y,
item.points(j).x,
item.points(j).y
)
j += 1
}
}
i += 1
}
// TEMPORARY DRAW
if (
temporaryPoints.length >= 2
) {
g.setColor(
currentStrokeColor
)
g.setStroke(
new BasicStroke(
brushWidth,
BasicStroke.CAP_ROUND,
BasicStroke.JOIN_ROUND
)
)
var j: Int =
1
while (
j < temporaryPoints.length
) {
g.drawLine(
temporaryPoints(j - 1).x,
temporaryPoints(j - 1).y,
temporaryPoints(j).x,
temporaryPoints(j).y
)
j += 1
}
}
// SELECTION
if (
selectedItemIndex >= 0 &&
selectedItemIndex < drawItems.length &&
currentTool == "SELECT"
) {
val bounds =
itemBounds(
drawItems(
selectedItemIndex
)
)
val rect =
new java.awt.Rectangle(
bounds.x - 8,
bounds.y - 8,
bounds.width + 16,
bounds.height + 16
)
g.setColor(
new Color(
0,
105,
240
)
)
g.setStroke(
new BasicStroke(2)
)
g.drawRect(
rect.x,
rect.y,
rect.width,
rect.height
)
val handles =
selectionHandles(rect)
var h: Int =
0
while (
h < handles.length
) {
val hp =
handles(h)._2
g.setColor(
Color.WHITE
)
g.fillRect(
hp.x - 5,
hp.y - 5,
10,
10
)
g.setColor(
new Color(
0,
105,
240
)
)
g.drawRect(
hp.x - 5,
hp.y - 5,
10,
10
)
h += 1
}
}
}
}
// ============================================================
// CANVAS INPUT
// ============================================================
drawingCanvas.setFocusable(true)
drawingCanvas.addMouseListener(
new MouseAdapter {
override def mousePressed(
e: MouseEvent
): Unit = {
val p =
canvasPoint(e)
if (
currentTool == "SELECT"
) {
val hit =
findItemAt(p)
if (
selectedItemIndex >= 0 &&
selectedItemIndex < drawItems.length
) {
val handle =
findResizeHandle(
drawItems(
selectedItemIndex
),
p
)
if (
handle != ""
) {
if (
!drawItems(
selectedItemIndex
).locked
) {
saveHistory()
resizingSelected =
true
movingSelected =
false
resizeMode =
handle
originalSelectedPoints =
drawItems(
selectedItemIndex
).points
previousMousePoint =
p
}
} else if (
hit ==
selectedItemIndex
) {
if (
!drawItems(
selectedItemIndex
).locked
) {
saveHistory()
movingSelected =
true
resizingSelected =
false
previousMousePoint =
p
}
} else {
selectedItemIndex =
hit
}
} else {
selectedItemIndex =
hit
}
repaintDrawingCanvas()
} else if (
currentTool == "BUCKET"
) {
val hit =
findItemAt(p)
if (
hit >= 0
) {
selectedItemIndex =
hit
bucketFillSelected()
} else {
setMainStatus(
"SELECT A CLOSED OBJECT"
)
}
} else if (
currentTool == "ERASER"
) {
val hit =
findItemAt(p)
if (
hit >= 0 &&
!drawItems(hit).locked
) {
saveHistory()
drawItems.remove(hit)
selectedItemIndex =
-1
repaintDrawingCanvas()
setMainStatus(
"OBJECT ERASED"
)
}
} else {
saveHistory()
temporaryPoints.clear()
temporaryPoints +=
p
drawingActive =
true
selectedItemIndex =
-1
setMainStatus(
"DRAWING..."
)
}
}
override def mouseReleased(
e: MouseEvent
): Unit = {
if (
currentTool == "SELECT"
) {
movingSelected =
false
resizingSelected =
false
} else if (
drawingActive
) {
temporaryPoints +=
canvasPoint(e)
if (
temporaryPoints.length >= 2
) {
drawItems +=
DrawItem(
temporaryPoints.toVector,
currentStrokeColor,
currentFillColor,
isClosedShape(
temporaryPoints
),
"FREEHAND",
true,
false
)
selectedItemIndex =
drawItems.length - 1
}
temporaryPoints.clear()
drawingActive =
false
repaintDrawingCanvas()
setMainStatus(
"DRAWING RECORDED"
)
}
}
}
)
// ============================================================
// CANVAS DRAG
// ============================================================
drawingCanvas.addMouseMotionListener(
new MouseMotionAdapter {
override def mouseDragged(
e: MouseEvent
): Unit = {
val p =
canvasPoint(e)
if (
currentTool == "SELECT"
) {
if (
movingSelected &&
selectedItemIndex >= 0
) {
moveSelectedItem(
p.x - previousMousePoint.x,
p.y - previousMousePoint.y
)
previousMousePoint =
p
repaintDrawingCanvas()
} else if (
resizingSelected &&
selectedItemIndex >= 0
) {
resizeSelectedItem(p)
repaintDrawingCanvas()
}
} else if (
drawingActive
) {
if (
temporaryPoints.isEmpty ||
pointDistance(
temporaryPoints.last,
p
) >= 2
) {
temporaryPoints +=
p
repaintDrawingCanvas()
}
}
}
}
)
// ============================================================
// MAIN BUTTONS
// ============================================================
val pencilButton =
createButton(
"PENCIL"
)
val selectButton =
createButton(
"SELECT"
)
val eraserButton =
createButton(
"ERASER"
)
val bucketButton =
createButton(
"BUCKET"
)
val undoButton =
createButton(
"UNDO"
)
val redoButton =
createButton(
"REDO"
)
val clearButton =
createButton(
"CLEAR"
)
val drawCodeButton =
createButton(
"DRAW CODE"
)
val copyButton =
createButton(
"COPY"
)
val saveButton =
createButton(
"SAVE"
)
val gamesButton =
createButton(
"GAMES"
)
val gridButton =
createButton(
"GRID"
)
val snapButton =
createButton(
"SNAP"
)
val strokeButton =
createButton(
"STROKE"
)
val fillButton =
createButton(
"FILL"
)
// ============================================================
// TOOLBAR
// ============================================================
val toolbar =
new JPanel(
new FlowLayout(
FlowLayout.LEFT,
3,
3
)
)
toolbar.add(
pencilButton
)
toolbar.add(
selectButton
)
toolbar.add(
eraserButton
)
toolbar.add(
bucketButton
)
toolbar.add(
undoButton
)
toolbar.add(
redoButton
)
toolbar.add(
clearButton
)
toolbar.add(
drawCodeButton
)
toolbar.add(
copyButton
)
toolbar.add(
saveButton
)
toolbar.add(
gamesButton
)
toolbar.add(
gridButton
)
toolbar.add(
snapButton
)
toolbar.add(
strokeButton
)
toolbar.add(
fillButton
)
// ============================================================
// LIBRARY UI
// ============================================================
objectList =
new JList[String](
objectModel
)
objectList.setFont(
new Font(
"Arial",
Font.BOLD,
13
)
)
shapeList =
new JList[String](
shapeModel
)
shapeList.setFont(
new Font(
"Arial",
Font.BOLD,
13
)
)
objectSearchField =
new JTextField(
12
)
val objectSearchButton =
createButton(
"SEARCH"
)
val objectSearchPanel =
new JPanel(
new FlowLayout(
FlowLayout.LEFT
)
)
objectSearchPanel.add(
objectSearchField
)
objectSearchPanel.add(
objectSearchButton
)
val objectPanel =
new JPanel(
new BorderLayout()
)
objectPanel.add(
new JLabel(
"OBJECT LIBRARY"
),
BorderLayout.NORTH
)
objectPanel.add(
objectSearchPanel,
BorderLayout.CENTER
)
objectPanel.add(
new JScrollPane(
objectList
),
BorderLayout.SOUTH
)
val shapePanel =
new JPanel(
new BorderLayout()
)
shapePanel.add(
new JLabel(
"SHAPE LIBRARY"
),
BorderLayout.NORTH
)
shapePanel.add(
new JScrollPane(
shapeList
),
BorderLayout.CENTER
)
val libraryTabs =
new JTabbedPane()
libraryTabs.addTab(
"OBJECTS",
objectPanel
)
libraryTabs.addTab(
"SHAPES",
shapePanel
)
// ============================================================
// SEARCH
// ============================================================
objectSearchButton.addActionListener(
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
val query =
objectSearchField
.getText
.trim
.toLowerCase
objectModel.clear()
var i: Int =
0
while (
i < allObjectNames.length
) {
if (
query.isEmpty ||
allObjectNames(i)
.toLowerCase
.indexOf(query) >= 0
) {
objectModel.addElement(
allObjectNames(i)
)
}
i += 1
}
}
}
)
// ============================================================
// OBJECT DOUBLE CLICK
// ============================================================
objectList.addMouseListener(
new MouseAdapter {
override def mouseClicked(
e: MouseEvent
): Unit = {
if (
e.getClickCount == 2
) {
val selected =
objectList.getSelectedValue
if (
selected != null
) {
addObjectToCanvas(
selected
)
}
}
}
}
)
// ============================================================
// SHAPE DOUBLE CLICK
// ============================================================
shapeList.addMouseListener(
new MouseAdapter {
override def mouseClicked(
e: MouseEvent
): Unit = {
if (
e.getClickCount == 2
) {
val selected =
shapeList.getSelectedValue
if (
selected != null
) {
addShapeToCanvas(
selected
)
}
}
}
}
)
// ============================================================
// CODE AREA
// ============================================================
drawingCodeArea =
new JTextArea()
drawingCodeArea.setEditable(
false
)
drawingCodeArea.setFont(
new Font(
"Monospaced",
Font.PLAIN,
13
)
)
drawingCodeArea.setText(
"// DRAW SOMETHING\n" +
"// THEN PRESS DRAW CODE"
)
// ============================================================
// PANELS
// ============================================================
val canvasPanel =
new JPanel(
new BorderLayout()
)
canvasPanel.add(
new JLabel(
"DRAWING CANVAS"
),
BorderLayout.NORTH
)
canvasPanel.add(
drawingCanvas,
BorderLayout.CENTER
)
val codePanel =
new JPanel(
new BorderLayout()
)
codePanel.add(
new JLabel(
"GENERATED KOJO / SCALA CODE"
),
BorderLayout.NORTH
)
codePanel.add(
new JScrollPane(
drawingCodeArea
),
BorderLayout.CENTER
)
val canvasCodeSplit =
new JSplitPane(
JSplitPane.HORIZONTAL_SPLIT,
canvasPanel,
codePanel
)
canvasCodeSplit.setDividerLocation(
650
)
val mainSplit =
new JSplitPane(
JSplitPane.HORIZONTAL_SPLIT,
libraryTabs,
canvasCodeSplit
)
mainSplit.setDividerLocation(
280
)
// ============================================================
// STATUS
// ============================================================
mainStatus =
new JLabel(
"ULTRA LEGEND X8 READY"
)
mainStatus.setFont(
new Font(
"Arial",
Font.BOLD,
13
)
)
// ============================================================
// MAIN FRAME
// ============================================================
mainFrame =
new JFrame(
"ULTRA LEGEND DRAW + GAME STUDIO X8"
)
mainFrame.setDefaultCloseOperation(
WindowConstants.EXIT_ON_CLOSE
)
mainFrame.setSize(
1650,
900
)
mainFrame.setMinimumSize(
new Dimension(
1100,
650
)
)
mainFrame.setLocationRelativeTo(
null
)
mainFrame.setLayout(
new BorderLayout(
4,
4
)
)
mainFrame.add(
toolbar,
BorderLayout.NORTH
)
mainFrame.add(
mainSplit,
BorderLayout.CENTER
)
mainFrame.add(
mainStatus,
BorderLayout.SOUTH
)
// ============================================================
// TOOL EVENTS
// ============================================================
pencilButton.addActionListener(
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
currentTool =
"PENCIL"
selectedItemIndex =
-1
setMainStatus(
"PENCIL MODE"
)
drawingCanvas.requestFocusInWindow()
}
}
)
selectButton.addActionListener(
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
currentTool =
"SELECT"
setMainStatus(
"SELECT / MOVE / RESIZE"
)
repaintDrawingCanvas()
drawingCanvas.requestFocusInWindow()
}
}
)
eraserButton.addActionListener(
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
currentTool =
"ERASER"
selectedItemIndex =
-1
setMainStatus(
"ERASER MODE"
)
drawingCanvas.requestFocusInWindow()
}
}
)
bucketButton.addActionListener(
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
currentTool =
"BUCKET"
setMainStatus(
"BUCKET MODE"
)
drawingCanvas.requestFocusInWindow()
}
}
)
undoButton.addActionListener(
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
performUndo()
}
}
)
redoButton.addActionListener(
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
performRedo()
}
}
)
clearButton.addActionListener(
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
clearDrawing()
}
}
)
drawCodeButton.addActionListener(
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
generateDrawingCode()
}
}
)
copyButton.addActionListener(
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
copyGeneratedText(
drawingCodeArea.getText
)
}
}
)
saveButton.addActionListener(
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
saveGeneratedText(
drawingCodeArea.getText
)
}
}
)
gamesButton.addActionListener(
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
openGameStudio()
}
}
)
gridButton.addActionListener(
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
gridEnabled =
!gridEnabled
repaintDrawingCanvas()
setMainStatus(
if (
gridEnabled
)
"GRID ON"
else
"GRID OFF"
)
}
}
)
snapButton.addActionListener(
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
snapEnabled =
!snapEnabled
setMainStatus(
if (
snapEnabled
)
"SNAP ON"
else
"SNAP OFF"
)
}
}
)
strokeButton.addActionListener(
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
val chosen =
JColorChooser.showDialog(
mainFrame,
"CHOOSE STROKE COLOR",
currentStrokeColor
)
if (
chosen != null
) {
currentStrokeColor =
chosen
setMainStatus(
"STROKE COLOR CHANGED"
)
}
}
}
)
fillButton.addActionListener(
new ActionListener {
override def actionPerformed(
e: ActionEvent
): Unit = {
val chosen =
JColorChooser.showDialog(
mainFrame,
"CHOOSE FILL COLOR",
currentFillColor
)
if (
chosen != null
) {
currentFillColor =
chosen
if (
selectedItemIndex >= 0
) {
bucketFillSelected()
} else {
setMainStatus(
"FILL COLOR CHANGED"
)
}
}
}
}
)
// ============================================================
// SHORTCUTS
// ============================================================
drawingCanvas.addKeyListener(
new java.awt.event.KeyAdapter {
override def keyPressed(
e: java.awt.event.KeyEvent
): Unit = {
val key =
e.getKeyCode
if (
e.isControlDown &&
key ==
java.awt.event.KeyEvent.VK_Z
) {
performUndo()
} else if (
e.isControlDown &&
key ==
java.awt.event.KeyEvent.VK_Y
) {
performRedo()
} else if (
e.isControlDown &&
key ==
java.awt.event.KeyEvent.VK_G
) {
generateDrawingCode()
} else if (
e.isControlDown &&
key ==
java.awt.event.KeyEvent.VK_C
) {
copyGeneratedText(
drawingCodeArea.getText
)
} else if (
e.isControlDown &&
key ==
java.awt.event.KeyEvent.VK_S
) {
saveGeneratedText(
drawingCodeArea.getText
)
} else if (
e.isControlDown &&
key ==
java.awt.event.KeyEvent.VK_D
) {
openGameStudio()
} else if (
key ==
java.awt.event.KeyEvent.VK_DELETE
) {
if (
selectedItemIndex >= 0 &&
selectedItemIndex < drawItems.length
) {
saveHistory()
drawItems.remove(
selectedItemIndex
)
selectedItemIndex =
-1
repaintDrawingCanvas()
setMainStatus(
"OBJECT DELETED"
)
}
} else if (
key ==
java.awt.event.KeyEvent.VK_P
) {
currentTool =
"PENCIL"
} else if (
key ==
java.awt.event.KeyEvent.VK_V
) {
currentTool =
"SELECT"
} else if (
key ==
java.awt.event.KeyEvent.VK_B
) {
currentTool =
"BUCKET"
} else if (
key ==
java.awt.event.KeyEvent.VK_E
) {
currentTool =
"ERASER"
} else if (
key ==
java.awt.event.KeyEvent.VK_F1
) {
JOptionPane.showMessageDialog(
mainFrame,
"P = PENCIL\n" +
"V = SELECT\n" +
"B = BUCKET\n" +
"E = ERASER\n" +
"DELETE = DELETE\n\n" +
"CTRL+Z = UNDO\n" +
"CTRL+Y = REDO\n" +
"CTRL+G = DRAW CODE\n" +
"CTRL+C = COPY\n" +
"CTRL+S = SAVE\n" +
"CTRL+D = GAME STUDIO",
"ULTRA SHORTCUTS",
JOptionPane.INFORMATION_MESSAGE
)
}
}
}
)
// ============================================================
// START
// ============================================================
SwingUtilities.invokeLater(
new Runnable {
override def run(): Unit = {
mainFrame.setVisible(
true
)
drawingCanvas.requestFocusInWindow()
setMainStatus(
"ULTRA LEGEND X8 READY"
)
}
}
)
//