User prompt
Give the player 3 lives
User prompt
Make attacks more predictable
User prompt
Give each boss lots of different attacks
User prompt
Move the menu screen hi apart more for better visibilty
Code edit (1 edits merged)
Please save this source code
User prompt
Boss Gauntlet: Arena Survival
Initial prompt
Create a game where you have to choose a boss out of many and survive for as long as you can in a set arena against that boss. Each boss has a different name and different t attack styles but they all get Jarde as they go along. Some bosses are harder than others
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Boss class var Boss = Container.expand(function () { var self = Container.call(this); // Boss type will be set after creation self.bossType = null; self.attackTimer = 0; self.attackInterval = 90; // frames self.difficulty = 1; self.phase = 1; self.timeAlive = 0; self.asset = null; self.init = function (bossType) { self.bossType = bossType; var assetId = bossType.asset; self.asset = self.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5 }); self.difficulty = bossType.difficulty; self.attackInterval = bossType.baseInterval; self.phase = 1; self.timeAlive = 0; }; self.update = function () { self.timeAlive++; // Increase difficulty over time if (self.timeAlive % 600 === 0 && self.attackInterval > 30) { self.attackInterval -= 10; self.phase++; } }; return self; }); // Player class var Player = Container.expand(function () { var self = Container.call(this); var playerGfx = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); self.radius = playerGfx.width / 2; self.update = function () {}; return self; }); // Projectile class var Projectile = Container.expand(function () { var self = Container.call(this); self.speedX = 0; self.speedY = 0; self.radius = 30; self.asset = null; self.type = null; self.init = function (type, colorAsset) { self.type = type; self.asset = self.attachAsset(colorAsset, { anchorX: 0.5, anchorY: 0.5 }); self.radius = self.asset.width / 2; }; self.update = function () { self.x += self.speedX; self.y += self.speedY; // Bounce off arena edges if .bounce is set if (self.bounce) { var minX = ARENA_X + self.radius; var maxX = ARENA_X + ARENA_W - self.radius; var minY = ARENA_Y + self.radius; var maxY = ARENA_Y + ARENA_H - self.radius; if (self.x <= minX && self.speedX < 0 || self.x >= maxX && self.speedX > 0) { self.speedX *= -1; self.x = Math.max(minX, Math.min(maxX, self.x)); } if (self.y <= minY && self.speedY < 0 || self.y >= maxY && self.speedY > 0) { self.speedY *= -1; self.y = Math.max(minY, Math.min(maxY, self.y)); } } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x181818 }); /**** * Game Code ****/ // Arena border // Projectiles // Bosses // Player: Circle, blue // Bosses: Each boss will have a unique color and shape for now. // Arena settings var ARENA_W = 1800; var ARENA_H = 2400; var ARENA_X = (2048 - ARENA_W) / 2; var ARENA_Y = (2732 - ARENA_H) / 2; // Boss definitions var bossDefs = [{ name: "Inferno", asset: "boss_red", proj: "proj_red", color: 0xe74c3c, difficulty: 2, baseInterval: 70, pattern: "spiral" }, { name: "Verdant", asset: "boss_green", proj: "proj_green", color: 0x27ae60, difficulty: 1, baseInterval: 90, pattern: "burst" }, { name: "Solaris", asset: "boss_yellow", proj: "proj_yellow", color: 0xf1c40f, difficulty: 3, baseInterval: 50, pattern: "aimed" }]; // Game state var player = null; var boss = null; var projectiles = []; var survivalTime = 0; var gameStarted = false; var bossChoice = null; var dragNode = null; var lastMoveX = 0, lastMoveY = 0; // Arena border var arenaBorder = LK.getAsset('arena_border', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2 }); game.addChild(arenaBorder); // GUI: Survival time var timeTxt = new Text2('0.0s', { size: 110, fill: 0xFFFFFF }); timeTxt.anchor.set(0.5, 0); LK.gui.top.addChild(timeTxt); // GUI: Player lives var playerLives = 3; var livesTxt = new Text2('Lives: 3', { size: 90, fill: 0xFF6666 }); livesTxt.anchor.set(0.5, 0); livesTxt.y = 120; // Place below timeTxt LK.gui.top.addChild(livesTxt); // GUI: Boss name var bossNameTxt = new Text2('', { size: 90, fill: 0xFFECB3 }); bossNameTxt.anchor.set(0.5, 0); LK.gui.top.addChild(bossNameTxt); // GUI: Boss select var bossSelectTxt = new Text2('Choose Your Boss', { size: 120, fill: 0xFFFFFF }); bossSelectTxt.anchor.set(0.5, 0); LK.gui.center.addChild(bossSelectTxt); var bossSelectButtons = []; for (var i = 0; i < bossDefs.length; i++) { var b = bossDefs[i]; var btn = LK.getAsset(b.asset, { anchorX: 0.5, anchorY: 0.5, // Increase horizontal spacing from 400 to 600, and vertical offset from 200 to 350 x: 2048 / 2 + (i - 1) * 600, y: 2732 / 2 + 350, scaleX: 1.1, scaleY: 1.1 }); btn.bossIndex = i; bossSelectButtons.push(btn); game.addChild(btn); // Add boss name label var label = new Text2(b.name, { size: 70, fill: 0xFFFFFF }); label.anchor.set(0.5, 0); label.x = btn.x; // Move label further below the button for clarity (from +140 to +200) label.y = btn.y + 200; game.addChild(label); btn._label = label; } // Hide arena and GUI until boss is chosen arenaBorder.visible = false; timeTxt.visible = false; bossNameTxt.visible = false; // Boss select handler game.down = function (x, y, obj) { if (!gameStarted) { // Check if a boss button was pressed for (var i = 0; i < bossSelectButtons.length; i++) { var btn = bossSelectButtons[i]; var dx = x - btn.x; var dy = y - btn.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < 120) { // Boss chosen bossChoice = bossDefs[btn.bossIndex]; startGame(); return; } } } else { // Start drag if inside player var dx = x - player.x; var dy = y - player.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < player.radius) { dragNode = player; lastMoveX = x; lastMoveY = y; } } }; game.up = function (x, y, obj) { dragNode = null; }; function handleMove(x, y, obj) { if (dragNode && gameStarted) { // Clamp to arena var px = x, py = y; var minX = ARENA_X + player.radius; var maxX = ARENA_X + ARENA_W - player.radius; var minY = ARENA_Y + player.radius; var maxY = ARENA_Y + ARENA_H - player.radius; px = Math.max(minX, Math.min(maxX, px)); py = Math.max(minY, Math.min(maxY, py)); dragNode.x = px; dragNode.y = py; lastMoveX = px; lastMoveY = py; } } game.move = handleMove; // Start game after boss selection function startGame() { // Hide boss select UI bossSelectTxt.visible = false; for (var i = 0; i < bossSelectButtons.length; i++) { bossSelectButtons[i].visible = false; bossSelectButtons[i]._label.visible = false; } // Show arena and GUI arenaBorder.visible = true; timeTxt.visible = true; bossNameTxt.visible = true; // Create player player = new Player(); player.x = 2048 / 2; player.y = 2732 / 2 + 600; game.addChild(player); // Create boss boss = new Boss(); boss.init(bossChoice); boss.x = 2048 / 2; boss.y = 2732 / 2 - 700; game.addChild(boss); // Set boss name bossNameTxt.setText(bossChoice.name); // Reset state projectiles = []; survivalTime = 0; playerLives = 3; livesTxt.setText('Lives: ' + playerLives); gameStarted = true; } // Boss attack patterns function bossAttack() { if (!boss || !player) return; var bossType = bossChoice; var projAsset = bossType.proj; var cx = boss.x, cy = boss.y; var px = player.x, py = player.y; var phase = boss.phase; var n, angle, i, p, speed, spread, baseAngle, offset, j, delay, targetX, targetY; // Each boss has a set of possible attacks, randomly chosen var attackList = []; if (bossType.name === "Inferno") { attackList = ["spiral", // Rotating spiral "double_spiral", // Two spirals, offset "wall", // Horizontal/vertical wall "cross", // Cross pattern "aimed_burst" // Burst of aimed shots ]; } else if (bossType.name === "Verdant") { attackList = ["burst", // All directions "flower", // Petal/flower pattern "arc", // Arc sweep "ring", // Expanding ring "random_bounce" // Random directions ]; } else if (bossType.name === "Solaris") { attackList = ["aimed", // Aimed shots "triple_aimed", // Three aimed shots "sniper", // Single fast shot "spread", // Wide spread "rain" // Rain from above ]; } else { attackList = [bossType.pattern]; } // Cycle through attacks in order for predictability if (!boss._attackIndex) boss._attackIndex = 0; var pattern = attackList[boss._attackIndex % attackList.length]; boss._attackIndex++; // --- Inferno Attacks --- if (pattern === "spiral") { // Rotating spiral n = 8 + phase; baseAngle = boss.timeAlive * 0.07 % (2 * Math.PI); for (i = 0; i < n; i++) { angle = baseAngle + 2 * Math.PI / n * i; p = new Projectile(); p.init("spiral", projAsset); p.x = cx; p.y = cy; speed = 7 + phase * 0.7; p.speedX = Math.cos(angle) * speed; p.speedY = Math.sin(angle) * speed; projectiles.push(p); game.addChild(p); } } else if (pattern === "double_spiral") { // Two spirals, offset n = 10 + phase; baseAngle = boss.timeAlive * 0.09 % (2 * Math.PI); for (j = 0; j < 2; j++) { offset = j * Math.PI / n; for (i = 0; i < n; i++) { angle = baseAngle + 2 * Math.PI / n * i + offset; p = new Projectile(); p.init("double_spiral", projAsset); p.x = cx; p.y = cy; speed = 6 + phase * 0.6; p.speedX = Math.cos(angle) * speed; p.speedY = Math.sin(angle) * speed; projectiles.push(p); game.addChild(p); } } } else if (pattern === "wall") { // Shoots a wall of projectiles horizontally or vertically var vertical = Math.random() < 0.5; n = 10 + Math.floor(phase / 2); for (i = 0; i < n; i++) { p = new Projectile(); p.init("wall", projAsset); if (vertical) { p.x = ARENA_X + ARENA_W / (n + 1) * (i + 1); p.y = cy; p.speedX = 0; p.speedY = 7 + phase * 0.7; } else { p.x = cx; p.y = ARENA_Y + ARENA_H / (n + 1) * (i + 1); p.speedX = 7 + phase * 0.7; p.speedY = 0; } projectiles.push(p); game.addChild(p); } } else if (pattern === "cross") { // Shoots in a cross pattern (up, down, left, right) var dirs = [[0, 1], [0, -1], [1, 0], [-1, 0]]; for (i = 0; i < dirs.length; i++) { p = new Projectile(); p.init("cross", projAsset); p.x = cx; p.y = cy; speed = 10 + phase; p.speedX = dirs[i][0] * speed; p.speedY = dirs[i][1] * speed; projectiles.push(p); game.addChild(p); } } else if (pattern === "aimed_burst") { // Burst of aimed shots with spread n = 5 + Math.floor(phase / 2); var toPlayer = Math.atan2(py - cy, px - cx); spread = Math.PI / 6 + Math.PI / 32 * phase; for (i = 0; i < n; i++) { angle = toPlayer + spread * (i - (n - 1) / 2) / n; p = new Projectile(); p.init("aimed_burst", projAsset); p.x = cx; p.y = cy; speed = 8 + phase * 0.7; p.speedX = Math.cos(angle) * speed; p.speedY = Math.sin(angle) * speed; projectiles.push(p); game.addChild(p); } // --- Verdant Attacks --- } else if (pattern === "burst") { // All directions n = 12 + phase * 2; for (i = 0; i < n; i++) { angle = 2 * Math.PI / n * i; p = new Projectile(); p.init("burst", projAsset); p.x = cx; p.y = cy; speed = 5 + phase * 0.5; p.speedX = Math.cos(angle) * speed; p.speedY = Math.sin(angle) * speed; projectiles.push(p); game.addChild(p); } } else if (pattern === "flower") { // Petal/flower pattern (alternating speeds) n = 10 + phase; for (i = 0; i < n; i++) { angle = 2 * Math.PI / n * i; p = new Projectile(); p.init("flower", projAsset); p.x = cx; p.y = cy; speed = (i % 2 === 0 ? 7 : 4) + phase * 0.4; p.speedX = Math.cos(angle) * speed; p.speedY = Math.sin(angle) * speed; projectiles.push(p); game.addChild(p); } } else if (pattern === "arc") { // Arc sweep (quarter circle) n = 8 + phase; var arcStart = Math.PI / 4; var arcEnd = Math.PI * 3 / 4; for (i = 0; i < n; i++) { angle = arcStart + (arcEnd - arcStart) * (i / (n - 1)); p = new Projectile(); p.init("arc", projAsset); p.x = cx; p.y = cy; speed = 6 + phase * 0.5; p.speedX = Math.cos(angle) * speed; p.speedY = Math.sin(angle) * speed; projectiles.push(p); game.addChild(p); } } else if (pattern === "ring") { // Expanding ring (slow projectiles) n = 16 + phase * 2; for (i = 0; i < n; i++) { angle = 2 * Math.PI / n * i; p = new Projectile(); p.init("ring", projAsset); p.x = cx; p.y = cy; speed = 3 + phase * 0.2; p.speedX = Math.cos(angle) * speed; p.speedY = Math.sin(angle) * speed; projectiles.push(p); game.addChild(p); } } else if (pattern === "random_bounce") { // Deterministic directions, evenly spaced, for predictability n = 6 + phase; for (i = 0; i < n; i++) { angle = 2 * Math.PI / n * i + boss.timeAlive % 60 * 0.05; // slight rotation over time p = new Projectile(); p.init("random_bounce", projAsset); p.x = cx; p.y = cy; speed = 6 + i % 3 + phase * 0.3; // deterministic speed p.speedX = Math.cos(angle) * speed; p.speedY = Math.sin(angle) * speed; // Mark as bouncing (handled in update) p.bounce = true; projectiles.push(p); game.addChild(p); } // --- Solaris Attacks --- } else if (pattern === "aimed") { // Aimed shots at player, with some spread n = 2 + Math.floor(phase / 2); var toPlayer = Math.atan2(py - cy, px - cx); spread = Math.PI / 8 + Math.PI / 32 * phase; for (i = 0; i < n; i++) { angle = toPlayer + spread * (i - (n - 1) / 2); p = new Projectile(); p.init("aimed", projAsset); p.x = cx; p.y = cy; speed = 10 + phase; p.speedX = Math.cos(angle) * speed; p.speedY = Math.sin(angle) * speed; projectiles.push(p); game.addChild(p); } } else if (pattern === "triple_aimed") { // Three aimed shots, tight spread n = 3; var toPlayer = Math.atan2(py - cy, px - cx); spread = Math.PI / 16; for (i = 0; i < n; i++) { angle = toPlayer + spread * (i - 1); p = new Projectile(); p.init("triple_aimed", projAsset); p.x = cx; p.y = cy; speed = 12 + phase * 0.7; p.speedX = Math.cos(angle) * speed; p.speedY = Math.sin(angle) * speed; projectiles.push(p); game.addChild(p); } } else if (pattern === "sniper") { // Single fast shot at player var toPlayer = Math.atan2(py - cy, px - cx); p = new Projectile(); p.init("sniper", projAsset); p.x = cx; p.y = cy; speed = 18 + phase; p.speedX = Math.cos(toPlayer) * speed; p.speedY = Math.sin(toPlayer) * speed; projectiles.push(p); game.addChild(p); } else if (pattern === "spread") { // Wide spread n = 7 + Math.floor(phase / 2); var toPlayer = Math.atan2(py - cy, px - cx); spread = Math.PI / 3; for (i = 0; i < n; i++) { angle = toPlayer - spread / 2 + spread * (i / (n - 1)); p = new Projectile(); p.init("spread", projAsset); p.x = cx; p.y = cy; speed = 8 + phase * 0.5; p.speedX = Math.cos(angle) * speed; p.speedY = Math.sin(angle) * speed; projectiles.push(p); game.addChild(p); } } else if (pattern === "rain") { // Rain from above (projectiles fall from random x at top) n = 8 + phase; for (i = 0; i < n; i++) { p = new Projectile(); p.init("rain", projAsset); p.x = ARENA_X + Math.random() * ARENA_W; p.y = ARENA_Y + 40; p.speedX = 0; p.speedY = 12 + phase * 0.7; projectiles.push(p); game.addChild(p); } } else { // Fallback: default to spiral n = 8 + phase; baseAngle = boss.timeAlive * 0.07 % (2 * Math.PI); for (i = 0; i < n; i++) { angle = baseAngle + 2 * Math.PI / n * i; p = new Projectile(); p.init("spiral", projAsset); p.x = cx; p.y = cy; speed = 7 + phase * 0.7; p.speedX = Math.cos(angle) * speed; p.speedY = Math.sin(angle) * speed; projectiles.push(p); game.addChild(p); } } } // Main game update game.update = function () { if (!gameStarted) return; // Update survival time survivalTime += 1 / 60; timeTxt.setText(survivalTime.toFixed(1) + "s"); // Update boss if (boss) { boss.update(); boss.attackTimer++; if (boss.attackTimer >= boss.attackInterval) { boss.attackTimer = 0; bossAttack(); } } // Update projectiles for (var i = projectiles.length - 1; i >= 0; i--) { var p = projectiles[i]; p.update(); // Remove if out of arena if (p.x < ARENA_X - 100 || p.x > ARENA_X + ARENA_W + 100 || p.y < ARENA_Y - 100 || p.y > ARENA_Y + ARENA_H + 100) { p.destroy(); projectiles.splice(i, 1); continue; } // Collision with player if (player._invuln && player._invuln > 0) { player._invuln--; continue; } var dx = p.x - player.x; var dy = p.y - player.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < player.radius + p.radius - 10) { // Player hit LK.effects.flashScreen(0xff0000, 800); playerLives--; livesTxt.setText('Lives: ' + playerLives); if (playerLives <= 0) { LK.showGameOver(); return; } else { // Remove all projectiles and respawn player at start position for (var j = 0; j < projectiles.length; j++) { projectiles[j].destroy(); } projectiles = []; player.x = 2048 / 2; player.y = 2732 / 2 + 600; clampPlayerStart(); // Brief invulnerability (skip collision for 60 frames) player._invuln = 60; break; } } } }; // Prevent player from being placed in top left 100x100 function clampPlayerStart() { var minX = ARENA_X + player.radius; var minY = ARENA_Y + player.radius; if (player.x < minX) player.x = minX; if (player.y < minY) player.y = minY; } // On game reset, restore boss select UI LK.on('reset', function () { bossSelectTxt.visible = true; for (var i = 0; i < bossSelectButtons.length; i++) { bossSelectButtons[i].visible = true; bossSelectButtons[i]._label.visible = true; } arenaBorder.visible = false; timeTxt.visible = false; bossNameTxt.visible = false; gameStarted = false; bossChoice = null; playerLives = 3; livesTxt.setText('Lives: ' + playerLives); // Remove player, boss, projectiles if (player) { player.destroy(); player = null; } if (boss) { boss.destroy(); boss = null; } for (var i = 0; i < projectiles.length; i++) { projectiles[i].destroy(); } projectiles = []; });
===================================================================
--- original.js
+++ change.js
@@ -158,8 +158,17 @@
fill: 0xFFFFFF
});
timeTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(timeTxt);
+// GUI: Player lives
+var playerLives = 3;
+var livesTxt = new Text2('Lives: 3', {
+ size: 90,
+ fill: 0xFF6666
+});
+livesTxt.anchor.set(0.5, 0);
+livesTxt.y = 120; // Place below timeTxt
+LK.gui.top.addChild(livesTxt);
// GUI: Boss name
var bossNameTxt = new Text2('', {
size: 90,
fill: 0xFFECB3
@@ -280,8 +289,10 @@
bossNameTxt.setText(bossChoice.name);
// Reset state
projectiles = [];
survivalTime = 0;
+ playerLives = 3;
+ livesTxt.setText('Lives: ' + playerLives);
gameStarted = true;
}
// Boss attack patterns
function bossAttack() {
@@ -624,16 +635,36 @@
projectiles.splice(i, 1);
continue;
}
// Collision with player
+ if (player._invuln && player._invuln > 0) {
+ player._invuln--;
+ continue;
+ }
var dx = p.x - player.x;
var dy = p.y - player.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < player.radius + p.radius - 10) {
// Player hit
LK.effects.flashScreen(0xff0000, 800);
- LK.showGameOver();
- return;
+ playerLives--;
+ livesTxt.setText('Lives: ' + playerLives);
+ if (playerLives <= 0) {
+ LK.showGameOver();
+ return;
+ } else {
+ // Remove all projectiles and respawn player at start position
+ for (var j = 0; j < projectiles.length; j++) {
+ projectiles[j].destroy();
+ }
+ projectiles = [];
+ player.x = 2048 / 2;
+ player.y = 2732 / 2 + 600;
+ clampPlayerStart();
+ // Brief invulnerability (skip collision for 60 frames)
+ player._invuln = 60;
+ break;
+ }
}
}
};
// Prevent player from being placed in top left 100x100
@@ -654,8 +685,10 @@
timeTxt.visible = false;
bossNameTxt.visible = false;
gameStarted = false;
bossChoice = null;
+ playerLives = 3;
+ livesTxt.setText('Lives: ' + playerLives);
// Remove player, boss, projectiles
if (player) {
player.destroy();
player = null;
make a red firey circle with black eyes that are mad and no mouth. In-Game asset. 2d. High contrast. No shadows
a happy blue circle simple. In-Game asset. 2d. High contrast. No shadows
a green circle that is very smart and has a monocle and has orange eyes. In-Game asset. 2d. High contrast. No shadows
only the ball
make a yellow circle that is like the sun that has sunglasses on. In-Game asset. 2d. High contrast. No shadows
only the sorce of the light
a grey circle with orange wyes and he is a space king. In-Game asset. 2d. High contrast. No shadows
make the beard a bit shorter
a purple circle with purple crystal armour and a sturn look on his face. only the head In-Game asset. 2d. High contrast. No shadows
a purple crystal. In-Game asset. 2d. High contrast. No shadows
a black circle that is dark and evil and has red eyes and an evil smirk. In-Game asset. 2d. High contrast. No shadows
remove the red aura and just have a red outline
a white circle with blue eyes and an icy face. In-Game asset. 2d. High contrast. No shadows
a snowflake. In-Game asset. 2d. High contrast. No shadows
remove the guns
a blue energy ball. In-Game asset. 2d. High contrast. No shadows
music_inferno
Music
music_verdant
Music
music_solaris
Music
music_abyss
Music
music_tempest
Music
music_prism
Music
music_obsidian
Music
music_blizzard
Music
music_ember
Music
music_menu
Music
sig_inferno
Sound effect
sig_verdant
Sound effect
sig_solaris
Sound effect
sig_abyss
Sound effect
sig_tempest
Sound effect
sig_prism
Sound effect
sig_obsidian
Sound effect
sig_blizzard
Sound effect
sig_ember
Sound effect