Code edit (1 edits merged)
Please save this source code
User prompt
Arena Brawlers: Ultimate Showdown
Initial prompt
Subreddit for Brawl Stars, the free multiplayer mobile arena fighter/party brawler/shoot 'em up game from Supercell. Fast-paced 3v3 and Battle Royale matches 🔥 Collect unique Brawlers. Play with your friends. Be the last one standing!
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { highScore: 0 }); /**** * Classes ****/ var ArenaWall = Container.expand(function () { var self = Container.call(this); self.wallGraphics = []; self.createWalls = function (centerX, centerY, size) { // Clear existing walls for (var i = 0; i < self.wallGraphics.length; i++) { self.removeChild(self.wallGraphics[i]); } self.wallGraphics = []; // Calculate positions var halfSize = size / 2; var wallSize = 30; var numWalls = Math.floor(size / wallSize); // Top and bottom walls for (var x = 0; x < numWalls; x++) { var topWall = self.attachAsset('arenaWall', { anchorX: 0.5, anchorY: 0.5, x: centerX - halfSize + (x + 0.5) * wallSize, y: centerY - halfSize }); self.wallGraphics.push(topWall); var bottomWall = self.attachAsset('arenaWall', { anchorX: 0.5, anchorY: 0.5, x: centerX - halfSize + (x + 0.5) * wallSize, y: centerY + halfSize }); self.wallGraphics.push(bottomWall); } // Left and right walls (skip corners) for (var y = 1; y < numWalls - 1; y++) { var leftWall = self.attachAsset('arenaWall', { anchorX: 0.5, anchorY: 0.5, x: centerX - halfSize, y: centerY - halfSize + (y + 0.5) * wallSize }); self.wallGraphics.push(leftWall); var rightWall = self.attachAsset('arenaWall', { anchorX: 0.5, anchorY: 0.5, x: centerX + halfSize, y: centerY - halfSize + (y + 0.5) * wallSize }); self.wallGraphics.push(rightWall); } }; return self; }); var Brawler = Container.expand(function () { var self = Container.call(this); // Character graphic var graphic = self.attachAsset('brawler', { anchorX: 0.5, anchorY: 0.5 }); // Health bar background var healthBarBg = self.attachAsset('healthBarBg', { anchorX: 0.5, anchorY: 0.5, y: -60 }); // Health bar var healthBar = self.attachAsset('healthBar', { anchorX: 0, anchorY: 0.5, y: -60, x: -40 }); // Properties self.maxHealth = 100; self.health = self.maxHealth; self.attackCooldown = 0; self.attackCooldownMax = 20; self.speed = 5; self.isDragging = false; self.direction = { x: 0, y: 0 }; self.isPlayer = false; self.isEnemy = false; self.attackDamage = 20; self.lastPosition = { x: 0, y: 0 }; self.isDead = false; // Movement AI for enemies self.moveTowards = function (target, speed) { if (!target || self.isDead) { return; } var dx = target.x - self.x; var dy = target.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { self.direction.x = dx / distance; self.direction.y = dy / distance; self.x += self.direction.x * speed; self.y += self.direction.y * speed; } }; // Attack method self.attack = function () { if (self.attackCooldown > 0 || self.isDead) { return; } var projectile = new Projectile(); projectile.x = self.x; projectile.y = self.y; projectile.direction = { x: self.direction.x || 1, y: self.direction.y || 0 }; projectile.owner = self; game.addChild(projectile); gameState.projectiles.push(projectile); self.attackCooldown = self.attackCooldownMax; LK.getSound('shoot').play(); }; // Take damage method self.takeDamage = function (amount) { if (self.isDead) { return; } self.health -= amount; // Update health bar healthBar.width = self.health / self.maxHealth * 80; // Flash the character red LK.effects.flashObject(graphic, 0xff0000, 200); LK.getSound('hit').play(); if (self.health <= 0) { self.die(); } }; // Die method self.die = function () { if (self.isDead) { return; } self.isDead = true; tween(self, { alpha: 0 }, { duration: 500, onFinish: function onFinish() { self.markForRemoval = true; } }); if (self.isPlayer) { LK.showGameOver(); } else if (self.isEnemy) { gameState.score += 100; gameState.defeatedEnemies++; scoreTxt.setText("Score: " + gameState.score); if (gameState.defeatedEnemies >= gameState.totalEnemies) { LK.showYouWin(); } } }; // Event handlers self.down = function (x, y, obj) { if (self.isPlayer && !self.isDead) { self.isDragging = true; } }; self.up = function (x, y, obj) { if (self.isPlayer) { self.isDragging = false; } }; self.update = function () { // Store last position self.lastPosition.x = self.x; self.lastPosition.y = self.y; // Update cooldowns if (self.attackCooldown > 0) { self.attackCooldown--; } // Keep within arena bounds var arenaSize = gameState.arenaSize; var halfSize = arenaSize / 2; if (self.x < gameState.arenaCenter.x - halfSize + 50) { self.x = gameState.arenaCenter.x - halfSize + 50; } if (self.x > gameState.arenaCenter.x + halfSize - 50) { self.x = gameState.arenaCenter.x + halfSize - 50; } if (self.y < gameState.arenaCenter.y - halfSize + 50) { self.y = gameState.arenaCenter.y - halfSize + 50; } if (self.y > gameState.arenaCenter.y + halfSize - 50) { self.y = gameState.arenaCenter.y + halfSize - 50; } }; return self; }); var Enemy = Brawler.expand(function () { var self = Brawler.call(this); // Override the default brawler graphic with enemy graphic var graphic = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); self.isEnemy = true; self.targetUpdateCooldown = 0; self.currentTarget = null; // Override the update method var parentUpdate = self.update; self.update = function () { if (self.isDead) { return; } // Base update from parent parentUpdate(); // Update target every so often if (self.targetUpdateCooldown <= 0) { self.findNewTarget(); self.targetUpdateCooldown = 60; // Update target every 60 frames } else { self.targetUpdateCooldown--; } // Move towards target if (self.currentTarget && !self.currentTarget.isDead) { self.moveTowards(self.currentTarget, self.speed); // Attack if close enough var dx = self.currentTarget.x - self.x; var dy = self.currentTarget.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 300) { // Set direction for projectile self.direction.x = dx / distance; self.direction.y = dy / distance; // Attack with some randomness if (Math.random() < 0.03) { self.attack(); } } } else { // If no target or target is dead, wander randomly if (Math.random() < 0.02) { self.direction.x = Math.random() * 2 - 1; self.direction.y = Math.random() * 2 - 1; var mag = Math.sqrt(self.direction.x * self.direction.x + self.direction.y * self.direction.y); self.direction.x /= mag; self.direction.y /= mag; } self.x += self.direction.x * self.speed / 2; self.y += self.direction.y * self.speed / 2; } }; self.findNewTarget = function () { // Target the player if (gameState.player && !gameState.player.isDead) { self.currentTarget = gameState.player; return; } // No valid targets self.currentTarget = null; }; return self; }); var PowerUp = Container.expand(function () { var self = Container.call(this); var graphic = self.attachAsset('powerUp', { anchorX: 0.5, anchorY: 0.5 }); self.type = 'health'; // health, damage, speed self.value = 20; // Visual effect - floating animation self.floatAnim = function () { tween(graphic, { y: -5 }, { duration: 1000, easing: tween.sinceOut, onFinish: function onFinish() { tween(graphic, { y: 5 }, { duration: 1000, easing: tween.sinceOut, onFinish: self.floatAnim }); } }); }; self.floatAnim(); return self; }); var Projectile = Container.expand(function () { var self = Container.call(this); var graphic = self.attachAsset('projectile', { anchorX: 0.5, anchorY: 0.5 }); self.direction = { x: 0, y: 0 }; self.speed = 12; self.damage = 10; self.lifetime = 60; // frames the projectile lives for self.owner = null; self.update = function () { self.x += self.direction.x * self.speed; self.y += self.direction.y * self.speed; self.lifetime--; if (self.lifetime <= 0) { self.markForRemoval = true; } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x222222 }); /**** * Game Code ****/ // Game state tracking var gameState = { arenaCenter: { x: 2048 / 2, y: 2732 / 2 }, arenaSize: 1800, minArenaSize: 1000, arenaShrinkRate: 0.2, arenaShrinkStart: 1000, // ticks before arena starts shrinking arenaShrinkTimer: 0, projectiles: [], powerUps: [], enemies: [], player: null, score: 0, level: 1, defeatedEnemies: 0, totalEnemies: 5, gameStarted: false }; // Create arena background var arenaBackground = LK.getAsset('arena', { anchorX: 0.5, anchorY: 0.5, x: gameState.arenaCenter.x, y: gameState.arenaCenter.y, width: gameState.arenaSize, height: gameState.arenaSize, alpha: 0.3 }); game.addChild(arenaBackground); // Create arena walls var arenaWalls = new ArenaWall(); game.addChild(arenaWalls); arenaWalls.createWalls(gameState.arenaCenter.x, gameState.arenaCenter.y, gameState.arenaSize); // Create player var player = new Brawler(); player.x = gameState.arenaCenter.x; player.y = gameState.arenaCenter.y + 300; player.isPlayer = true; game.addChild(player); gameState.player = player; // Setup GUI elements var scoreTxt = new Text2("Score: 0", { size: 50, fill: 0xFFFFFF }); scoreTxt.anchor.set(0, 0); LK.gui.topRight.addChild(scoreTxt); scoreTxt.x = -250; scoreTxt.y = 50; var levelTxt = new Text2("Level: 1", { size: 50, fill: 0xFFFFFF }); levelTxt.anchor.set(0, 0); LK.gui.topRight.addChild(levelTxt); levelTxt.x = -250; levelTxt.y = 120; var arenaSizeTxt = new Text2("Arena Shrinking", { size: 40, fill: 0xFF9900 }); arenaSizeTxt.anchor.set(0.5, 0); arenaSizeTxt.alpha = 0; LK.gui.top.addChild(arenaSizeTxt); arenaSizeTxt.y = 50; // Initialize enemies function spawnEnemies() { // Clear existing enemies for (var i = gameState.enemies.length - 1; i >= 0; i--) { game.removeChild(gameState.enemies[i]); gameState.enemies.splice(i, 1); } // Set number of enemies based on level gameState.totalEnemies = 3 + gameState.level * 2; gameState.defeatedEnemies = 0; // Spawn new enemies for (var i = 0; i < gameState.totalEnemies; i++) { var enemy = new Enemy(); // Position around the arena var angle = i / gameState.totalEnemies * Math.PI * 2; var radius = gameState.arenaSize / 2 - 200; enemy.x = gameState.arenaCenter.x + Math.cos(angle) * radius; enemy.y = gameState.arenaCenter.y + Math.sin(angle) * radius; // Scale difficulty with level enemy.maxHealth = 80 + gameState.level * 20; enemy.health = enemy.maxHealth; enemy.speed = 3 + gameState.level * 0.5; game.addChild(enemy); gameState.enemies.push(enemy); } } // Spawn power-ups periodically function spawnPowerUp() { if (gameState.powerUps.length >= 5) { return; } // Limit number of power-ups var powerUp = new PowerUp(); // Random position within arena var halfSize = gameState.arenaSize / 2 - 100; powerUp.x = gameState.arenaCenter.x + Math.random() * halfSize * 2 - halfSize; powerUp.y = gameState.arenaCenter.y + Math.random() * halfSize * 2 - halfSize; // Random type var typeRoll = Math.random(); if (typeRoll < 0.4) { powerUp.type = 'health'; powerUp.tint = 0x00ff00; } else if (typeRoll < 0.7) { powerUp.type = 'damage'; powerUp.tint = 0xff0000; powerUp.value = 10; } else { powerUp.type = 'speed'; powerUp.tint = 0x0088ff; powerUp.value = 1; } game.addChild(powerUp); gameState.powerUps.push(powerUp); } // Game start function startGame() { // Reset game state gameState.score = 0; gameState.level = 1; gameState.arenaSize = 1800; gameState.arenaShrinkTimer = gameState.arenaShrinkStart; // Reset arena arenaBackground.width = gameState.arenaSize; arenaBackground.height = gameState.arenaSize; arenaWalls.createWalls(gameState.arenaCenter.x, gameState.arenaCenter.y, gameState.arenaSize); // Reset player player.health = player.maxHealth; player.isDead = false; player.alpha = 1; player.speed = 5; player.attackDamage = 20; // Spawn enemies spawnEnemies(); // Update UI scoreTxt.setText("Score: " + gameState.score); levelTxt.setText("Level: " + gameState.level); // Play music LK.playMusic('battleMusic'); gameState.gameStarted = true; } // Handle touch/mouse events var dragTarget = null; function handleMove(x, y, obj) { if (dragTarget && dragTarget.isDragging) { // Update player position dragTarget.x = x; dragTarget.y = y; // Calculate direction based on movement var dx = x - dragTarget.lastPosition.x; var dy = y - dragTarget.lastPosition.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0.1) { dragTarget.direction.x = dx / dist; dragTarget.direction.y = dy / dist; } } } game.down = function (x, y, obj) { if (!gameState.gameStarted) { startGame(); return; } dragTarget = player; if (!player.isDead) { player.isDragging = true; handleMove(x, y, obj); } }; game.up = function (x, y, obj) { if (dragTarget) { dragTarget.isDragging = false; dragTarget = null; } }; game.move = handleMove; // Main game update loop game.update = function () { if (!gameState.gameStarted) { return; } // Shrink arena over time if (gameState.arenaShrinkTimer > 0) { gameState.arenaShrinkTimer--; if (gameState.arenaShrinkTimer === 300) { // Show warning message tween(arenaSizeTxt, { alpha: 1 }, { duration: 300, onFinish: function onFinish() { tween(arenaSizeTxt, { alpha: 0 }, { duration: 300 }); } }); } } else { if (gameState.arenaSize > gameState.minArenaSize) { gameState.arenaSize -= gameState.arenaShrinkRate; // Update arena visuals arenaBackground.width = gameState.arenaSize; arenaBackground.height = gameState.arenaSize; arenaWalls.createWalls(gameState.arenaCenter.x, gameState.arenaCenter.y, gameState.arenaSize); } } // Spawn power-ups randomly if (Math.random() < 0.005) { spawnPowerUp(); } // Player attack on tap/click/drag release if (player.isDragging === false && dragTarget === null && !player.isDead) { player.attack(); } // Update projectiles and check collisions for (var i = gameState.projectiles.length - 1; i >= 0; i--) { var projectile = gameState.projectiles[i]; // Check if projectile is marked for removal if (projectile.markForRemoval) { game.removeChild(projectile); gameState.projectiles.splice(i, 1); continue; } // Check projectile collisions with enemies if (projectile.owner === player) { for (var j = 0; j < gameState.enemies.length; j++) { var enemy = gameState.enemies[j]; if (!enemy.isDead && projectile.intersects(enemy)) { enemy.takeDamage(player.attackDamage); projectile.markForRemoval = true; break; } } } // Check projectile collisions with player else if (projectile.owner.isEnemy && !player.isDead && projectile.intersects(player)) { player.takeDamage(projectile.owner.attackDamage); projectile.markForRemoval = true; } // Check if projectile is out of arena bounds var halfSize = gameState.arenaSize / 2; if (projectile.x < gameState.arenaCenter.x - halfSize || projectile.x > gameState.arenaCenter.x + halfSize || projectile.y < gameState.arenaCenter.y - halfSize || projectile.y > gameState.arenaCenter.y + halfSize) { projectile.markForRemoval = true; } } // Check power-up collisions with player for (var i = gameState.powerUps.length - 1; i >= 0; i--) { var powerUp = gameState.powerUps[i]; if (!player.isDead && powerUp.intersects(player)) { // Apply power-up effect if (powerUp.type === 'health') { player.health = Math.min(player.maxHealth, player.health + powerUp.value); // Update health bar var healthBar = player.getChildAt(2); // Health bar is at index 2 healthBar.width = player.health / player.maxHealth * 80; } else if (powerUp.type === 'damage') { player.attackDamage += powerUp.value; } else if (powerUp.type === 'speed') { player.speed += powerUp.value; } // Remove power-up game.removeChild(powerUp); gameState.powerUps.splice(i, 1); // Play sound and add score LK.getSound('powerup').play(); gameState.score += 50; scoreTxt.setText("Score: " + gameState.score); } // Remove power-ups outside arena bounds var halfSize = gameState.arenaSize / 2; if (powerUp.x < gameState.arenaCenter.x - halfSize || powerUp.x > gameState.arenaCenter.x + halfSize || powerUp.y < gameState.arenaCenter.y - halfSize || powerUp.y > gameState.arenaCenter.y + halfSize) { game.removeChild(powerUp); gameState.powerUps.splice(i, 1); } } // Check for level completion if (gameState.defeatedEnemies >= gameState.totalEnemies) { // Level up gameState.level++; levelTxt.setText("Level: " + gameState.level); // Reset arena gameState.arenaSize = 1800; gameState.arenaShrinkTimer = gameState.arenaShrinkStart; arenaBackground.width = gameState.arenaSize; arenaBackground.height = gameState.arenaSize; arenaWalls.createWalls(gameState.arenaCenter.x, gameState.arenaCenter.y, gameState.arenaSize); // Spawn new enemies spawnEnemies(); // Bonus score for completing level gameState.score += 500; scoreTxt.setText("Score: " + gameState.score); // Clear old power-ups for (var i = gameState.powerUps.length - 1; i >= 0; i--) { game.removeChild(gameState.powerUps[i]); gameState.powerUps.splice(i, 1); } } // Check for game over (player dead) if (player.isDead) { // Update high score if (gameState.score > storage.highScore) { storage.highScore = gameState.score; } } // Clean up dead enemies for (var i = gameState.enemies.length - 1; i >= 0; i--) { if (gameState.enemies[i].markForRemoval) { game.removeChild(gameState.enemies[i]); gameState.enemies.splice(i, 1); } } }; // Start music LK.playMusic('battleMusic', { fade: { start: 0, end: 0.3, duration: 1000 } }); // Initial instruction text var instructionText = new Text2("Tap to start!\nDrag to move, release to shoot", { size: 60, fill: 0xFFFFFF }); instructionText.anchor.set(0.5, 0.5); instructionText.x = gameState.arenaCenter.x; instructionText.y = gameState.arenaCenter.y - 200; game.addChild(instructionText); // Hide instructions when game starts var originalUpdate = game.update; game.update = function () { if (!gameState.gameStarted) { // Make text pulse before game starts instructionText.alpha = 0.5 + Math.sin(LK.ticks / 20) * 0.5; return; } // Remove instruction text once when game starts if (instructionText.parent) { game.removeChild(instructionText); } // Call the original update originalUpdate.call(game); };
===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,692 @@
-/****
+/****
+* Plugins
+****/
+var tween = LK.import("@upit/tween.v1");
+var storage = LK.import("@upit/storage.v1", {
+ highScore: 0
+});
+
+/****
+* Classes
+****/
+var ArenaWall = Container.expand(function () {
+ var self = Container.call(this);
+ self.wallGraphics = [];
+ self.createWalls = function (centerX, centerY, size) {
+ // Clear existing walls
+ for (var i = 0; i < self.wallGraphics.length; i++) {
+ self.removeChild(self.wallGraphics[i]);
+ }
+ self.wallGraphics = [];
+ // Calculate positions
+ var halfSize = size / 2;
+ var wallSize = 30;
+ var numWalls = Math.floor(size / wallSize);
+ // Top and bottom walls
+ for (var x = 0; x < numWalls; x++) {
+ var topWall = self.attachAsset('arenaWall', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: centerX - halfSize + (x + 0.5) * wallSize,
+ y: centerY - halfSize
+ });
+ self.wallGraphics.push(topWall);
+ var bottomWall = self.attachAsset('arenaWall', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: centerX - halfSize + (x + 0.5) * wallSize,
+ y: centerY + halfSize
+ });
+ self.wallGraphics.push(bottomWall);
+ }
+ // Left and right walls (skip corners)
+ for (var y = 1; y < numWalls - 1; y++) {
+ var leftWall = self.attachAsset('arenaWall', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: centerX - halfSize,
+ y: centerY - halfSize + (y + 0.5) * wallSize
+ });
+ self.wallGraphics.push(leftWall);
+ var rightWall = self.attachAsset('arenaWall', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: centerX + halfSize,
+ y: centerY - halfSize + (y + 0.5) * wallSize
+ });
+ self.wallGraphics.push(rightWall);
+ }
+ };
+ return self;
+});
+var Brawler = Container.expand(function () {
+ var self = Container.call(this);
+ // Character graphic
+ var graphic = self.attachAsset('brawler', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ // Health bar background
+ var healthBarBg = self.attachAsset('healthBarBg', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ y: -60
+ });
+ // Health bar
+ var healthBar = self.attachAsset('healthBar', {
+ anchorX: 0,
+ anchorY: 0.5,
+ y: -60,
+ x: -40
+ });
+ // Properties
+ self.maxHealth = 100;
+ self.health = self.maxHealth;
+ self.attackCooldown = 0;
+ self.attackCooldownMax = 20;
+ self.speed = 5;
+ self.isDragging = false;
+ self.direction = {
+ x: 0,
+ y: 0
+ };
+ self.isPlayer = false;
+ self.isEnemy = false;
+ self.attackDamage = 20;
+ self.lastPosition = {
+ x: 0,
+ y: 0
+ };
+ self.isDead = false;
+ // Movement AI for enemies
+ self.moveTowards = function (target, speed) {
+ if (!target || self.isDead) {
+ return;
+ }
+ var dx = target.x - self.x;
+ var dy = target.y - self.y;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ if (distance > 0) {
+ self.direction.x = dx / distance;
+ self.direction.y = dy / distance;
+ self.x += self.direction.x * speed;
+ self.y += self.direction.y * speed;
+ }
+ };
+ // Attack method
+ self.attack = function () {
+ if (self.attackCooldown > 0 || self.isDead) {
+ return;
+ }
+ var projectile = new Projectile();
+ projectile.x = self.x;
+ projectile.y = self.y;
+ projectile.direction = {
+ x: self.direction.x || 1,
+ y: self.direction.y || 0
+ };
+ projectile.owner = self;
+ game.addChild(projectile);
+ gameState.projectiles.push(projectile);
+ self.attackCooldown = self.attackCooldownMax;
+ LK.getSound('shoot').play();
+ };
+ // Take damage method
+ self.takeDamage = function (amount) {
+ if (self.isDead) {
+ return;
+ }
+ self.health -= amount;
+ // Update health bar
+ healthBar.width = self.health / self.maxHealth * 80;
+ // Flash the character red
+ LK.effects.flashObject(graphic, 0xff0000, 200);
+ LK.getSound('hit').play();
+ if (self.health <= 0) {
+ self.die();
+ }
+ };
+ // Die method
+ self.die = function () {
+ if (self.isDead) {
+ return;
+ }
+ self.isDead = true;
+ tween(self, {
+ alpha: 0
+ }, {
+ duration: 500,
+ onFinish: function onFinish() {
+ self.markForRemoval = true;
+ }
+ });
+ if (self.isPlayer) {
+ LK.showGameOver();
+ } else if (self.isEnemy) {
+ gameState.score += 100;
+ gameState.defeatedEnemies++;
+ scoreTxt.setText("Score: " + gameState.score);
+ if (gameState.defeatedEnemies >= gameState.totalEnemies) {
+ LK.showYouWin();
+ }
+ }
+ };
+ // Event handlers
+ self.down = function (x, y, obj) {
+ if (self.isPlayer && !self.isDead) {
+ self.isDragging = true;
+ }
+ };
+ self.up = function (x, y, obj) {
+ if (self.isPlayer) {
+ self.isDragging = false;
+ }
+ };
+ self.update = function () {
+ // Store last position
+ self.lastPosition.x = self.x;
+ self.lastPosition.y = self.y;
+ // Update cooldowns
+ if (self.attackCooldown > 0) {
+ self.attackCooldown--;
+ }
+ // Keep within arena bounds
+ var arenaSize = gameState.arenaSize;
+ var halfSize = arenaSize / 2;
+ if (self.x < gameState.arenaCenter.x - halfSize + 50) {
+ self.x = gameState.arenaCenter.x - halfSize + 50;
+ }
+ if (self.x > gameState.arenaCenter.x + halfSize - 50) {
+ self.x = gameState.arenaCenter.x + halfSize - 50;
+ }
+ if (self.y < gameState.arenaCenter.y - halfSize + 50) {
+ self.y = gameState.arenaCenter.y - halfSize + 50;
+ }
+ if (self.y > gameState.arenaCenter.y + halfSize - 50) {
+ self.y = gameState.arenaCenter.y + halfSize - 50;
+ }
+ };
+ return self;
+});
+var Enemy = Brawler.expand(function () {
+ var self = Brawler.call(this);
+ // Override the default brawler graphic with enemy graphic
+ var graphic = self.attachAsset('enemy', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.isEnemy = true;
+ self.targetUpdateCooldown = 0;
+ self.currentTarget = null;
+ // Override the update method
+ var parentUpdate = self.update;
+ self.update = function () {
+ if (self.isDead) {
+ return;
+ }
+ // Base update from parent
+ parentUpdate();
+ // Update target every so often
+ if (self.targetUpdateCooldown <= 0) {
+ self.findNewTarget();
+ self.targetUpdateCooldown = 60; // Update target every 60 frames
+ } else {
+ self.targetUpdateCooldown--;
+ }
+ // Move towards target
+ if (self.currentTarget && !self.currentTarget.isDead) {
+ self.moveTowards(self.currentTarget, self.speed);
+ // Attack if close enough
+ var dx = self.currentTarget.x - self.x;
+ var dy = self.currentTarget.y - self.y;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ if (distance < 300) {
+ // Set direction for projectile
+ self.direction.x = dx / distance;
+ self.direction.y = dy / distance;
+ // Attack with some randomness
+ if (Math.random() < 0.03) {
+ self.attack();
+ }
+ }
+ } else {
+ // If no target or target is dead, wander randomly
+ if (Math.random() < 0.02) {
+ self.direction.x = Math.random() * 2 - 1;
+ self.direction.y = Math.random() * 2 - 1;
+ var mag = Math.sqrt(self.direction.x * self.direction.x + self.direction.y * self.direction.y);
+ self.direction.x /= mag;
+ self.direction.y /= mag;
+ }
+ self.x += self.direction.x * self.speed / 2;
+ self.y += self.direction.y * self.speed / 2;
+ }
+ };
+ self.findNewTarget = function () {
+ // Target the player
+ if (gameState.player && !gameState.player.isDead) {
+ self.currentTarget = gameState.player;
+ return;
+ }
+ // No valid targets
+ self.currentTarget = null;
+ };
+ return self;
+});
+var PowerUp = Container.expand(function () {
+ var self = Container.call(this);
+ var graphic = self.attachAsset('powerUp', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.type = 'health'; // health, damage, speed
+ self.value = 20;
+ // Visual effect - floating animation
+ self.floatAnim = function () {
+ tween(graphic, {
+ y: -5
+ }, {
+ duration: 1000,
+ easing: tween.sinceOut,
+ onFinish: function onFinish() {
+ tween(graphic, {
+ y: 5
+ }, {
+ duration: 1000,
+ easing: tween.sinceOut,
+ onFinish: self.floatAnim
+ });
+ }
+ });
+ };
+ self.floatAnim();
+ return self;
+});
+var Projectile = Container.expand(function () {
+ var self = Container.call(this);
+ var graphic = self.attachAsset('projectile', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.direction = {
+ x: 0,
+ y: 0
+ };
+ self.speed = 12;
+ self.damage = 10;
+ self.lifetime = 60; // frames the projectile lives for
+ self.owner = null;
+ self.update = function () {
+ self.x += self.direction.x * self.speed;
+ self.y += self.direction.y * self.speed;
+ self.lifetime--;
+ if (self.lifetime <= 0) {
+ self.markForRemoval = true;
+ }
+ };
+ return self;
+});
+
+/****
* Initialize Game
-****/
+****/
var game = new LK.Game({
- backgroundColor: 0x000000
-});
\ No newline at end of file
+ backgroundColor: 0x222222
+});
+
+/****
+* Game Code
+****/
+// Game state tracking
+var gameState = {
+ arenaCenter: {
+ x: 2048 / 2,
+ y: 2732 / 2
+ },
+ arenaSize: 1800,
+ minArenaSize: 1000,
+ arenaShrinkRate: 0.2,
+ arenaShrinkStart: 1000,
+ // ticks before arena starts shrinking
+ arenaShrinkTimer: 0,
+ projectiles: [],
+ powerUps: [],
+ enemies: [],
+ player: null,
+ score: 0,
+ level: 1,
+ defeatedEnemies: 0,
+ totalEnemies: 5,
+ gameStarted: false
+};
+// Create arena background
+var arenaBackground = LK.getAsset('arena', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: gameState.arenaCenter.x,
+ y: gameState.arenaCenter.y,
+ width: gameState.arenaSize,
+ height: gameState.arenaSize,
+ alpha: 0.3
+});
+game.addChild(arenaBackground);
+// Create arena walls
+var arenaWalls = new ArenaWall();
+game.addChild(arenaWalls);
+arenaWalls.createWalls(gameState.arenaCenter.x, gameState.arenaCenter.y, gameState.arenaSize);
+// Create player
+var player = new Brawler();
+player.x = gameState.arenaCenter.x;
+player.y = gameState.arenaCenter.y + 300;
+player.isPlayer = true;
+game.addChild(player);
+gameState.player = player;
+// Setup GUI elements
+var scoreTxt = new Text2("Score: 0", {
+ size: 50,
+ fill: 0xFFFFFF
+});
+scoreTxt.anchor.set(0, 0);
+LK.gui.topRight.addChild(scoreTxt);
+scoreTxt.x = -250;
+scoreTxt.y = 50;
+var levelTxt = new Text2("Level: 1", {
+ size: 50,
+ fill: 0xFFFFFF
+});
+levelTxt.anchor.set(0, 0);
+LK.gui.topRight.addChild(levelTxt);
+levelTxt.x = -250;
+levelTxt.y = 120;
+var arenaSizeTxt = new Text2("Arena Shrinking", {
+ size: 40,
+ fill: 0xFF9900
+});
+arenaSizeTxt.anchor.set(0.5, 0);
+arenaSizeTxt.alpha = 0;
+LK.gui.top.addChild(arenaSizeTxt);
+arenaSizeTxt.y = 50;
+// Initialize enemies
+function spawnEnemies() {
+ // Clear existing enemies
+ for (var i = gameState.enemies.length - 1; i >= 0; i--) {
+ game.removeChild(gameState.enemies[i]);
+ gameState.enemies.splice(i, 1);
+ }
+ // Set number of enemies based on level
+ gameState.totalEnemies = 3 + gameState.level * 2;
+ gameState.defeatedEnemies = 0;
+ // Spawn new enemies
+ for (var i = 0; i < gameState.totalEnemies; i++) {
+ var enemy = new Enemy();
+ // Position around the arena
+ var angle = i / gameState.totalEnemies * Math.PI * 2;
+ var radius = gameState.arenaSize / 2 - 200;
+ enemy.x = gameState.arenaCenter.x + Math.cos(angle) * radius;
+ enemy.y = gameState.arenaCenter.y + Math.sin(angle) * radius;
+ // Scale difficulty with level
+ enemy.maxHealth = 80 + gameState.level * 20;
+ enemy.health = enemy.maxHealth;
+ enemy.speed = 3 + gameState.level * 0.5;
+ game.addChild(enemy);
+ gameState.enemies.push(enemy);
+ }
+}
+// Spawn power-ups periodically
+function spawnPowerUp() {
+ if (gameState.powerUps.length >= 5) {
+ return;
+ } // Limit number of power-ups
+ var powerUp = new PowerUp();
+ // Random position within arena
+ var halfSize = gameState.arenaSize / 2 - 100;
+ powerUp.x = gameState.arenaCenter.x + Math.random() * halfSize * 2 - halfSize;
+ powerUp.y = gameState.arenaCenter.y + Math.random() * halfSize * 2 - halfSize;
+ // Random type
+ var typeRoll = Math.random();
+ if (typeRoll < 0.4) {
+ powerUp.type = 'health';
+ powerUp.tint = 0x00ff00;
+ } else if (typeRoll < 0.7) {
+ powerUp.type = 'damage';
+ powerUp.tint = 0xff0000;
+ powerUp.value = 10;
+ } else {
+ powerUp.type = 'speed';
+ powerUp.tint = 0x0088ff;
+ powerUp.value = 1;
+ }
+ game.addChild(powerUp);
+ gameState.powerUps.push(powerUp);
+}
+// Game start
+function startGame() {
+ // Reset game state
+ gameState.score = 0;
+ gameState.level = 1;
+ gameState.arenaSize = 1800;
+ gameState.arenaShrinkTimer = gameState.arenaShrinkStart;
+ // Reset arena
+ arenaBackground.width = gameState.arenaSize;
+ arenaBackground.height = gameState.arenaSize;
+ arenaWalls.createWalls(gameState.arenaCenter.x, gameState.arenaCenter.y, gameState.arenaSize);
+ // Reset player
+ player.health = player.maxHealth;
+ player.isDead = false;
+ player.alpha = 1;
+ player.speed = 5;
+ player.attackDamage = 20;
+ // Spawn enemies
+ spawnEnemies();
+ // Update UI
+ scoreTxt.setText("Score: " + gameState.score);
+ levelTxt.setText("Level: " + gameState.level);
+ // Play music
+ LK.playMusic('battleMusic');
+ gameState.gameStarted = true;
+}
+// Handle touch/mouse events
+var dragTarget = null;
+function handleMove(x, y, obj) {
+ if (dragTarget && dragTarget.isDragging) {
+ // Update player position
+ dragTarget.x = x;
+ dragTarget.y = y;
+ // Calculate direction based on movement
+ var dx = x - dragTarget.lastPosition.x;
+ var dy = y - dragTarget.lastPosition.y;
+ var dist = Math.sqrt(dx * dx + dy * dy);
+ if (dist > 0.1) {
+ dragTarget.direction.x = dx / dist;
+ dragTarget.direction.y = dy / dist;
+ }
+ }
+}
+game.down = function (x, y, obj) {
+ if (!gameState.gameStarted) {
+ startGame();
+ return;
+ }
+ dragTarget = player;
+ if (!player.isDead) {
+ player.isDragging = true;
+ handleMove(x, y, obj);
+ }
+};
+game.up = function (x, y, obj) {
+ if (dragTarget) {
+ dragTarget.isDragging = false;
+ dragTarget = null;
+ }
+};
+game.move = handleMove;
+// Main game update loop
+game.update = function () {
+ if (!gameState.gameStarted) {
+ return;
+ }
+ // Shrink arena over time
+ if (gameState.arenaShrinkTimer > 0) {
+ gameState.arenaShrinkTimer--;
+ if (gameState.arenaShrinkTimer === 300) {
+ // Show warning message
+ tween(arenaSizeTxt, {
+ alpha: 1
+ }, {
+ duration: 300,
+ onFinish: function onFinish() {
+ tween(arenaSizeTxt, {
+ alpha: 0
+ }, {
+ duration: 300
+ });
+ }
+ });
+ }
+ } else {
+ if (gameState.arenaSize > gameState.minArenaSize) {
+ gameState.arenaSize -= gameState.arenaShrinkRate;
+ // Update arena visuals
+ arenaBackground.width = gameState.arenaSize;
+ arenaBackground.height = gameState.arenaSize;
+ arenaWalls.createWalls(gameState.arenaCenter.x, gameState.arenaCenter.y, gameState.arenaSize);
+ }
+ }
+ // Spawn power-ups randomly
+ if (Math.random() < 0.005) {
+ spawnPowerUp();
+ }
+ // Player attack on tap/click/drag release
+ if (player.isDragging === false && dragTarget === null && !player.isDead) {
+ player.attack();
+ }
+ // Update projectiles and check collisions
+ for (var i = gameState.projectiles.length - 1; i >= 0; i--) {
+ var projectile = gameState.projectiles[i];
+ // Check if projectile is marked for removal
+ if (projectile.markForRemoval) {
+ game.removeChild(projectile);
+ gameState.projectiles.splice(i, 1);
+ continue;
+ }
+ // Check projectile collisions with enemies
+ if (projectile.owner === player) {
+ for (var j = 0; j < gameState.enemies.length; j++) {
+ var enemy = gameState.enemies[j];
+ if (!enemy.isDead && projectile.intersects(enemy)) {
+ enemy.takeDamage(player.attackDamage);
+ projectile.markForRemoval = true;
+ break;
+ }
+ }
+ }
+ // Check projectile collisions with player
+ else if (projectile.owner.isEnemy && !player.isDead && projectile.intersects(player)) {
+ player.takeDamage(projectile.owner.attackDamage);
+ projectile.markForRemoval = true;
+ }
+ // Check if projectile is out of arena bounds
+ var halfSize = gameState.arenaSize / 2;
+ if (projectile.x < gameState.arenaCenter.x - halfSize || projectile.x > gameState.arenaCenter.x + halfSize || projectile.y < gameState.arenaCenter.y - halfSize || projectile.y > gameState.arenaCenter.y + halfSize) {
+ projectile.markForRemoval = true;
+ }
+ }
+ // Check power-up collisions with player
+ for (var i = gameState.powerUps.length - 1; i >= 0; i--) {
+ var powerUp = gameState.powerUps[i];
+ if (!player.isDead && powerUp.intersects(player)) {
+ // Apply power-up effect
+ if (powerUp.type === 'health') {
+ player.health = Math.min(player.maxHealth, player.health + powerUp.value);
+ // Update health bar
+ var healthBar = player.getChildAt(2); // Health bar is at index 2
+ healthBar.width = player.health / player.maxHealth * 80;
+ } else if (powerUp.type === 'damage') {
+ player.attackDamage += powerUp.value;
+ } else if (powerUp.type === 'speed') {
+ player.speed += powerUp.value;
+ }
+ // Remove power-up
+ game.removeChild(powerUp);
+ gameState.powerUps.splice(i, 1);
+ // Play sound and add score
+ LK.getSound('powerup').play();
+ gameState.score += 50;
+ scoreTxt.setText("Score: " + gameState.score);
+ }
+ // Remove power-ups outside arena bounds
+ var halfSize = gameState.arenaSize / 2;
+ if (powerUp.x < gameState.arenaCenter.x - halfSize || powerUp.x > gameState.arenaCenter.x + halfSize || powerUp.y < gameState.arenaCenter.y - halfSize || powerUp.y > gameState.arenaCenter.y + halfSize) {
+ game.removeChild(powerUp);
+ gameState.powerUps.splice(i, 1);
+ }
+ }
+ // Check for level completion
+ if (gameState.defeatedEnemies >= gameState.totalEnemies) {
+ // Level up
+ gameState.level++;
+ levelTxt.setText("Level: " + gameState.level);
+ // Reset arena
+ gameState.arenaSize = 1800;
+ gameState.arenaShrinkTimer = gameState.arenaShrinkStart;
+ arenaBackground.width = gameState.arenaSize;
+ arenaBackground.height = gameState.arenaSize;
+ arenaWalls.createWalls(gameState.arenaCenter.x, gameState.arenaCenter.y, gameState.arenaSize);
+ // Spawn new enemies
+ spawnEnemies();
+ // Bonus score for completing level
+ gameState.score += 500;
+ scoreTxt.setText("Score: " + gameState.score);
+ // Clear old power-ups
+ for (var i = gameState.powerUps.length - 1; i >= 0; i--) {
+ game.removeChild(gameState.powerUps[i]);
+ gameState.powerUps.splice(i, 1);
+ }
+ }
+ // Check for game over (player dead)
+ if (player.isDead) {
+ // Update high score
+ if (gameState.score > storage.highScore) {
+ storage.highScore = gameState.score;
+ }
+ }
+ // Clean up dead enemies
+ for (var i = gameState.enemies.length - 1; i >= 0; i--) {
+ if (gameState.enemies[i].markForRemoval) {
+ game.removeChild(gameState.enemies[i]);
+ gameState.enemies.splice(i, 1);
+ }
+ }
+};
+// Start music
+LK.playMusic('battleMusic', {
+ fade: {
+ start: 0,
+ end: 0.3,
+ duration: 1000
+ }
+});
+// Initial instruction text
+var instructionText = new Text2("Tap to start!\nDrag to move, release to shoot", {
+ size: 60,
+ fill: 0xFFFFFF
+});
+instructionText.anchor.set(0.5, 0.5);
+instructionText.x = gameState.arenaCenter.x;
+instructionText.y = gameState.arenaCenter.y - 200;
+game.addChild(instructionText);
+// Hide instructions when game starts
+var originalUpdate = game.update;
+game.update = function () {
+ if (!gameState.gameStarted) {
+ // Make text pulse before game starts
+ instructionText.alpha = 0.5 + Math.sin(LK.ticks / 20) * 0.5;
+ return;
+ }
+ // Remove instruction text once when game starts
+ if (instructionText.parent) {
+ game.removeChild(instructionText);
+ }
+ // Call the original update
+ originalUpdate.call(game);
+};
\ No newline at end of file