/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var AcidBomb = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('acidBomb', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 2; self.directionX = 0; self.directionY = 0; self.damage = 5; self.poisonDamage = 2; self.poisonDuration = 180; self.update = function () { if (gamePaused) return; self.x += self.directionX * self.speed; self.y += self.directionY * self.speed; }; return self; }); var BlackBullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('blackBullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 4; self.directionX = 0; self.directionY = 0; self.damage = 10; self.update = function () { if (gamePaused) return; self.x += self.directionX * self.speed; self.y += self.directionY * self.speed; }; return self; }); var BlackHole = Container.expand(function () { var self = Container.call(this); var holeGraphics = self.attachAsset('blackHole', { anchorX: 0.5, anchorY: 0.5, alpha: 0.8 }); self.radius = 64; // 1 block radius self.duration = 300; // 5 seconds at 60fps self.timer = 0; self.damageTimer = 0; self.pullStrength = 1.5; self.update = function () { if (gamePaused) return; self.timer++; self.damageTimer++; // Pull and damage effects var dx = playerTank.x - self.x; var dy = playerTank.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.radius * 2) { // Pull player toward center var pullX = dx > 0 ? -self.pullStrength : self.pullStrength; var pullY = dy > 0 ? -self.pullStrength : self.pullStrength; if (!checkWallCollision(playerTank.x + pullX, playerTank.y)) { playerTank.x += pullX; } if (!checkWallCollision(playerTank.x, playerTank.y + pullY)) { playerTank.y += pullY; } // Damage at center every second if (distance <= 32 && self.damageTimer >= 60) { playerTank.health -= 8; hasBeenHurt = true; LK.getSound('hit').play(); if (playerTank.health <= 0) { LK.showGameOver(); } } } // Pull and damage enemies for (var i = skinTanks.length - 1; i >= 0; i--) { var dx = skinTanks[i].x - self.x; var dy = skinTanks[i].y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.radius * 2) { var pullX = dx > 0 ? -self.pullStrength : self.pullStrength; var pullY = dy > 0 ? -self.pullStrength : self.pullStrength; if (!checkWallCollision(skinTanks[i].x + pullX, skinTanks[i].y)) { skinTanks[i].x += pullX; } if (!checkWallCollision(skinTanks[i].x, skinTanks[i].y + pullY)) { skinTanks[i].y += pullY; } } } // Damage enemies every second if (self.damageTimer >= 60) { self.damageTimer = 0; for (var i = skinTanks.length - 1; i >= 0; i--) { var dx = skinTanks[i].x - self.x; var dy = skinTanks[i].y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.radius) { skinTanks[i].health -= 2; } } for (var i = redTanks.length - 1; i >= 0; i--) { var dx = redTanks[i].x - self.x; var dy = redTanks[i].y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.radius) { redTanks[i].health -= 4; } } for (var i = greenTanks.length - 1; i >= 0; i--) { var dx = greenTanks[i].x - self.x; var dy = greenTanks[i].y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.radius) { greenTanks[i].health -= 15; } } // White tanks die instantly for (var i = whiteTanks.length - 1; i >= 0; i--) { var dx = whiteTanks[i].x - self.x; var dy = whiteTanks[i].y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.radius) { whiteTanks[i].destroy(); whiteTanks.splice(i, 1); LK.setScore(LK.getScore() + 40); totalEnemiesKilled++; storage.totalEnemiesKilled = totalEnemiesKilled; } } } if (self.timer >= self.duration) { self.destroy(); var index = blackHoles.indexOf(self); if (index > -1) { blackHoles.splice(index, 1); } } }; return self; }); var BlackTank = Container.expand(function () { var self = Container.call(this); var tankGraphics = self.attachAsset('blackTank', { anchorX: 0.5, anchorY: 0.5 }); self.health = 225; self.speed = 1; self.shootCooldown = 0; self.update = function () { if (gamePaused) return; if (self.shootCooldown > 0) { self.shootCooldown--; } var target = playerTank; // Check if should target white tank instead for (var i = 0; i < whiteTanks.length; i++) { var dx = whiteTanks[i].x - self.x; var dy = whiteTanks[i].y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 400) { target = whiteTanks[i]; break; } } var dx = target.x - self.x; var dy = target.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); // Move toward target when in range if (distance < 350) { var moveX = dx > 0 ? self.speed : -self.speed; var moveY = dy > 0 ? self.speed : -self.speed; var newX = self.x + moveX; var newY = self.y + moveY; var targetAngle = Math.atan2(dy, dx); tween.stop(self, { rotation: true }); tween(self, { rotation: targetAngle }, { duration: 300, easing: tween.easeOut }); if (!checkWallCollision(newX, self.y)) { self.x = newX; } if (!checkWallCollision(self.x, newY)) { self.y = newY; } } if (distance < 300 && self.shootCooldown <= 0) { var length = Math.sqrt(dx * dx + dy * dy); var dirX = dx / length; var dirY = dy / length; var blackBullet = new BlackBullet(); blackBullet.x = self.x; blackBullet.y = self.y; blackBullet.directionX = dirX; blackBullet.directionY = dirY; blackBullets.push(blackBullet); game.addChild(blackBullet); self.shootCooldown = 120; LK.getSound('shoot').play(); } }; return self; }); var Dynamite = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('dynamite', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 3; self.directionX = 0; self.directionY = 0; self.damage = 25; self.explosionRadius = 80; self.update = function () { if (gamePaused) return; self.x += self.directionX * self.speed; self.y += self.directionY * self.speed; }; return self; }); var ElectricField = Container.expand(function () { var self = Container.call(this); var fieldGraphics = self.attachAsset('electricField', { anchorX: 0.5, anchorY: 0.5, alpha: 0.5 }); self.radius = 160; // 2 blocks radius self.duration = 300; // 5 seconds at 60fps self.timer = 0; self.damageTimer = 0; self.update = function () { if (gamePaused) return; self.timer++; self.damageTimer++; // Damage every 60 frames (1 second) if (self.damageTimer >= 60) { self.damageTimer = 0; // Check player damage var dx = playerTank.x - self.x; var dy = playerTank.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.radius) { playerTank.health -= 2; hasBeenHurt = true; LK.getSound('hit').play(); if (playerTank.health <= 0) { LK.showGameOver(); } } // Check enemy damage and change targets for (var i = skinTanks.length - 1; i >= 0; i--) { var dx = skinTanks[i].x - self.x; var dy = skinTanks[i].y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.radius) { skinTanks[i].health -= 0.5; skinTanks[i].targetWhiteTank = true; } } for (var i = redTanks.length - 1; i >= 0; i--) { var dx = redTanks[i].x - self.x; var dy = redTanks[i].y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.radius) { redTanks[i].health -= 2; redTanks[i].targetWhiteTank = true; } } for (var i = greenTanks.length - 1; i >= 0; i--) { var dx = greenTanks[i].x - self.x; var dy = greenTanks[i].y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.radius) { greenTanks[i].health -= 10; greenTanks[i].targetWhiteTank = true; } } } if (self.timer >= self.duration) { self.destroy(); var index = electricFields.indexOf(self); if (index > -1) { electricFields.splice(index, 1); } } }; return self; }); var EnemyBullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('enemyBullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 4; self.directionX = 0; self.directionY = 0; self.damage = 10; self.update = function () { if (gamePaused) return; self.x += self.directionX * self.speed; self.y += self.directionY * self.speed; }; return self; }); var GreenTank = Container.expand(function () { var self = Container.call(this); var tankGraphics = self.attachAsset('greenTank', { anchorX: 0.5, anchorY: 0.5 }); self.health = 40; self.speed = 0.8; self.shootCooldown = 0; self.update = function () { if (gamePaused) return; if (self.shootCooldown > 0) { self.shootCooldown--; } var target = playerTank; // Check if should target white tank instead due to electric field if (self.targetWhiteTank) { for (var i = 0; i < whiteTanks.length; i++) { var dx = whiteTanks[i].x - self.x; var dy = whiteTanks[i].y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 400) { target = whiteTanks[i]; break; } } } var dx = target.x - self.x; var dy = target.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); // Move toward player when they can see them (within range) if (distance < 300) { var moveX = dx > 0 ? self.speed : -self.speed; var moveY = dy > 0 ? self.speed : -self.speed; var newX = self.x + moveX; var newY = self.y + moveY; // Calculate target angle for rotation var targetAngle = Math.atan2(dy, dx); // Stop any existing rotation tween tween.stop(self, { rotation: true }); // Smoothly rotate the tank to face the movement direction tween(self, { rotation: targetAngle }, { duration: 300, easing: tween.easeOut }); if (!checkWallCollision(newX, self.y)) { self.x = newX; } if (!checkWallCollision(self.x, newY)) { self.y = newY; } } if (distance < 200 && self.shootCooldown <= 0) { var length = Math.sqrt(dx * dx + dy * dy); var dirX = dx / length; var dirY = dy / length; var acidBomb = new AcidBomb(); acidBomb.x = self.x; acidBomb.y = self.y; acidBomb.directionX = dirX; acidBomb.directionY = dirY; acidBombs.push(acidBomb); game.addChild(acidBomb); self.shootCooldown = 150; LK.getSound('shoot').play(); } }; return self; }); var Medkit = Container.expand(function () { var self = Container.call(this); var medkitGraphics = self.attachAsset('medkit', { anchorX: 0.5, anchorY: 0.5 }); return self; }); var PlayerBullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('playerBullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 8; self.directionX = 0; self.directionY = 0; self.damage = 10; self.update = function () { if (gamePaused) return; self.x += self.directionX * self.speed; self.y += self.directionY * self.speed; }; return self; }); var PlayerTank = Container.expand(function () { var self = Container.call(this); var tankGraphics = self.attachAsset('playerTank', { anchorX: 0.5, anchorY: 0.5 }); self.maxHealth = 100; self.health = 100; self.speed = 3; self.shootCooldown = 0; self.poisonTimer = 0; self.poisonDamage = 0; self.update = function () { if (gamePaused) return; if (self.shootCooldown > 0) { self.shootCooldown--; } if (self.poisonTimer > 0) { self.poisonTimer--; if (LK.ticks % 30 === 0) { self.health -= self.poisonDamage; if (self.health <= 0) { LK.showGameOver(); } } } }; return self; }); var Portal = Container.expand(function () { var self = Container.call(this); var portalGraphics = self.attachAsset('portal', { anchorX: 0.5, anchorY: 0.5 }); self.update = function () { // Portal no longer rotates }; return self; }); var RedTank = Container.expand(function () { var self = Container.call(this); var tankGraphics = self.attachAsset('redTank', { anchorX: 0.5, anchorY: 0.5 }); self.health = 80; self.speed = 1; self.shootCooldown = 0; self.update = function () { if (gamePaused) return; if (self.shootCooldown > 0) { self.shootCooldown--; } var target = playerTank; // Check if should target white tank instead due to electric field if (self.targetWhiteTank) { for (var i = 0; i < whiteTanks.length; i++) { var dx = whiteTanks[i].x - self.x; var dy = whiteTanks[i].y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 400) { target = whiteTanks[i]; break; } } } var dx = target.x - self.x; var dy = target.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); // Move toward player when they can see them (within range) if (distance < 350) { var moveX = dx > 0 ? self.speed : -self.speed; var moveY = dy > 0 ? self.speed : -self.speed; var newX = self.x + moveX; var newY = self.y + moveY; // Calculate target angle for rotation var targetAngle = Math.atan2(dy, dx); // Stop any existing rotation tween tween.stop(self, { rotation: true }); // Smoothly rotate the tank to face the movement direction tween(self, { rotation: targetAngle }, { duration: 300, easing: tween.easeOut }); if (!checkWallCollision(newX, self.y)) { self.x = newX; } if (!checkWallCollision(self.x, newY)) { self.y = newY; } } if (distance < 250 && self.shootCooldown <= 0) { var length = Math.sqrt(dx * dx + dy * dy); var dirX = dx / length; var dirY = dy / length; var dynamite = new Dynamite(); dynamite.x = self.x; dynamite.y = self.y; dynamite.directionX = dirX; dynamite.directionY = dirY; dynamites.push(dynamite); game.addChild(dynamite); self.shootCooldown = 120; LK.getSound('shoot').play(); } }; return self; }); var SkinTank = Container.expand(function () { var self = Container.call(this); var tankGraphics = self.attachAsset('skinTank', { anchorX: 0.5, anchorY: 0.5 }); self.health = 50; self.speed = 1.5; self.shootCooldown = 0; self.explosionRadius = 100; self.lastPlayerX = 0; self.lastPlayerY = 0; self.update = function () { if (gamePaused) return; if (self.shootCooldown > 0) { self.shootCooldown--; } var target = playerTank; var targetWhiteTank = false; // Check if should target white tank instead due to electric field if (self.targetWhiteTank) { for (var i = 0; i < whiteTanks.length; i++) { var dx = whiteTanks[i].x - self.x; var dy = whiteTanks[i].y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 400) { target = whiteTanks[i]; targetWhiteTank = true; break; } } } var dx = target.x - self.x; var dy = target.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 150) { var moveX = dx > 0 ? self.speed : -self.speed; var moveY = dy > 0 ? self.speed : -self.speed; var newX = self.x + moveX; var newY = self.y + moveY; // Calculate target angle for rotation var targetAngle = Math.atan2(dy, dx); // Stop any existing rotation tween tween.stop(self, { rotation: true }); // Smoothly rotate the tank to face the movement direction tween(self, { rotation: targetAngle }, { duration: 300, easing: tween.easeOut }); if (!checkWallCollision(newX, self.y)) { self.x = newX; } if (!checkWallCollision(self.x, newY)) { self.y = newY; } } if (distance < 300 && self.shootCooldown <= 0) { var length = Math.sqrt(dx * dx + dy * dy); var dirX = dx / length; var dirY = dy / length; var bullet = new EnemyBullet(); bullet.x = self.x; bullet.y = self.y; bullet.directionX = dirX; bullet.directionY = dirY; bullet.damage = 3; enemyBullets.push(bullet); game.addChild(bullet); self.shootCooldown = 90; LK.getSound('shoot').play(); } }; return self; }); var Wall = Container.expand(function () { var self = Container.call(this); var wallGraphics = self.attachAsset('wall', { anchorX: 0.5, anchorY: 0.5 }); return self; }); var WhiteBullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('whiteBullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 4; self.directionX = 0; self.directionY = 0; self.damage = 10; self.update = function () { if (gamePaused) return; self.x += self.directionX * self.speed; self.y += self.directionY * self.speed; }; return self; }); var WhiteTank = Container.expand(function () { var self = Container.call(this); var tankGraphics = self.attachAsset('whiteTank', { anchorX: 0.5, anchorY: 0.5 }); self.health = 275; self.speed = 1; self.shootCooldown = 0; self.targetWhiteTank = false; self.update = function () { if (gamePaused) return; if (self.shootCooldown > 0) { self.shootCooldown--; } var target = playerTank; var targetBlackTank = false; // Check if should target black tank instead for (var i = 0; i < blackTanks.length; i++) { var dx = blackTanks[i].x - self.x; var dy = blackTanks[i].y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 400) { target = blackTanks[i]; targetBlackTank = true; break; } } var dx = target.x - self.x; var dy = target.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); // Move toward target when in range if (distance < 350) { var moveX = dx > 0 ? self.speed : -self.speed; var moveY = dy > 0 ? self.speed : -self.speed; var newX = self.x + moveX; var newY = self.y + moveY; var targetAngle = Math.atan2(dy, dx); tween.stop(self, { rotation: true }); tween(self, { rotation: targetAngle }, { duration: 300, easing: tween.easeOut }); if (!checkWallCollision(newX, self.y)) { self.x = newX; } if (!checkWallCollision(self.x, newY)) { self.y = newY; } } if (distance < 300 && self.shootCooldown <= 0) { var length = Math.sqrt(dx * dx + dy * dy); var dirX = dx / length; var dirY = dy / length; var whiteBullet = new WhiteBullet(); whiteBullet.x = self.x; whiteBullet.y = self.y; whiteBullet.directionX = dirX; whiteBullet.directionY = dirY; whiteBullets.push(whiteBullet); game.addChild(whiteBullet); self.shootCooldown = 120; LK.getSound('shoot').play(); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x2F4F2F }); /**** * Game Code ****/ var gridWidth = 32; var gridHeight = 42; var cellSize = 64; var walls = []; var skinTanks = []; var redTanks = []; var greenTanks = []; var playerBullets = []; var enemyBullets = []; var dynamites = []; var acidBombs = []; var explosions = []; var medkits = []; var whiteTanks = []; var blackTanks = []; var whiteBullets = []; var blackBullets = []; var electricFields = []; var blackHoles = []; var playerTank; var portal; var currentLevel = 1; var gameStarted = false; var isDragging = false; var gamePaused = false; var showingMainMenu = true; // Main menu container var mainMenu = new Container(); mainMenu.visible = true; LK.gui.center.addChild(mainMenu); // Main menu background image var menuBackground = LK.getAsset('darkGreen', { anchorX: 0.5, anchorY: 0.5, scaleX: 32, scaleY: 43, alpha: 0.8 }); mainMenu.addChild(menuBackground); // Play button var playButton = new Text2('PLAY', { size: 120, fill: 0xFFFFFF, font: "monospace" }); playButton.anchor.set(0.5, 0.5); playButton.x = 0; playButton.y = 0; mainMenu.addChild(playButton); // Version text var versionText = new Text2('v.0.1.4', { size: 80, fill: 0xFFFF00, font: "monospace" }); versionText.anchor.set(1, 1); versionText.x = 950; // Adjusted position to ensure visibility versionText.y = 1300; // Adjusted position to ensure visibility mainMenu.addChild(versionText); // Experiments screen container var experimentsScreen = new Container(); experimentsScreen.visible = false; LK.gui.center.addChild(experimentsScreen); // Experiments screen background var experimentsBackground = LK.getAsset('darkGreen', { anchorX: 0.5, anchorY: 0.5, scaleX: 32, scaleY: 43, alpha: 0.8 }); experimentsScreen.addChild(experimentsBackground); // Experiments title var experimentsTitle = new Text2('Do You Wanna Activate Experiments', { size: 80, fill: 0xFFFFFF, font: "monospace" }); experimentsTitle.anchor.set(0.5, 0.5); experimentsTitle.x = 0; experimentsTitle.y = -200; experimentsScreen.addChild(experimentsTitle); // Initialize new enemies setting from storage var newEnemiesEnabled = storage.newEnemiesEnabled || false; // New enemies toggle button var newEnemiesButton = new Text2(newEnemiesEnabled ? 'New Enemies - On' : 'New Enemies - Off', { size: 60, fill: newEnemiesEnabled ? 0x00FF00 : 0xFF0000, font: "monospace" }); newEnemiesButton.anchor.set(0.5, 0.5); newEnemiesButton.x = 0; newEnemiesButton.y = 0; experimentsScreen.addChild(newEnemiesButton); // New enemies button click handler newEnemiesButton.down = function (x, y, obj) { newEnemiesEnabled = !newEnemiesEnabled; storage.newEnemiesEnabled = newEnemiesEnabled; newEnemiesButton.setText(newEnemiesEnabled ? 'New Enemies - On' : 'New Enemies - Off'); newEnemiesButton.fill = newEnemiesEnabled ? 0x00FF00 : 0xFF0000; newEnemiesButton.tint = newEnemiesEnabled ? 0x00FF00 : 0xFF0000; }; // Continue button to start game after experiments screen var continueButton = new Text2('CONTINUE', { size: 80, fill: 0xFFFFFF, font: "monospace" }); continueButton.anchor.set(0.5, 0.5); continueButton.x = 0; continueButton.y = 200; experimentsScreen.addChild(continueButton); // Continue button click handler continueButton.down = function (x, y, obj) { experimentsScreen.visible = false; showingMainMenu = false; gameStarted = true; startLevel(); }; // Play button click handler playButton.down = function (x, y, obj) { mainMenu.visible = false; experimentsScreen.visible = true; }; var nextLevelScreen = new Container(); nextLevelScreen.visible = false; LK.gui.center.addChild(nextLevelScreen); // Next level screen background var nextLevelBackground = LK.getAsset('wall', { anchorX: 0.5, anchorY: 0.5, scaleX: 12, scaleY: 8, tint: 0x000000, alpha: 0.9 }); nextLevelScreen.addChild(nextLevelBackground); // Next level button var nextLevelButton = new Text2('NEXT LEVEL', { size: 80, fill: 0xFFFFFF, font: "monospace" }); nextLevelButton.anchor.set(0.5, 0.5); nextLevelButton.x = 0; nextLevelButton.y = 0; nextLevelScreen.addChild(nextLevelButton); // Next level button click handler nextLevelButton.down = function (x, y, obj) { nextLevelScreen.visible = false; gamePaused = false; // Generate new level startLevel(); }; // Return to main menu button var returnToMenuButton = new Text2('RETURN TO MAIN MENU', { size: 60, fill: 0xFFFFFF, font: "monospace" }); returnToMenuButton.anchor.set(0.5, 0.5); returnToMenuButton.x = 0; returnToMenuButton.y = 100; nextLevelScreen.addChild(returnToMenuButton); // Return to main menu button click handler returnToMenuButton.down = function (x, y, obj) { // Clear all game objects for (var i = walls.length - 1; i >= 0; i--) { walls[i].destroy(); } walls = []; for (var i = skinTanks.length - 1; i >= 0; i--) { skinTanks[i].destroy(); } skinTanks = []; for (var i = redTanks.length - 1; i >= 0; i--) { redTanks[i].destroy(); } redTanks = []; for (var i = greenTanks.length - 1; i >= 0; i--) { greenTanks[i].destroy(); } greenTanks = []; for (var i = medkits.length - 1; i >= 0; i--) { medkits[i].destroy(); } medkits = []; for (var i = playerBullets.length - 1; i >= 0; i--) { playerBullets[i].destroy(); } playerBullets = []; for (var i = enemyBullets.length - 1; i >= 0; i--) { enemyBullets[i].destroy(); } enemyBullets = []; for (var i = dynamites.length - 1; i >= 0; i--) { dynamites[i].destroy(); } dynamites = []; for (var i = acidBombs.length - 1; i >= 0; i--) { acidBombs[i].destroy(); } acidBombs = []; for (var i = explosions.length - 1; i >= 0; i--) { explosions[i].destroy(); } explosions = []; for (var i = whiteTanks.length - 1; i >= 0; i--) { whiteTanks[i].destroy(); } whiteTanks = []; for (var i = blackTanks.length - 1; i >= 0; i--) { blackTanks[i].destroy(); } blackTanks = []; for (var i = whiteBullets.length - 1; i >= 0; i--) { whiteBullets[i].destroy(); } whiteBullets = []; for (var i = blackBullets.length - 1; i >= 0; i--) { blackBullets[i].destroy(); } blackBullets = []; for (var i = electricFields.length - 1; i >= 0; i--) { electricFields[i].destroy(); } electricFields = []; for (var i = blackHoles.length - 1; i >= 0; i--) { blackHoles[i].destroy(); } blackHoles = []; // Destroy player tank and portal if they exist if (playerTank) { playerTank.destroy(); playerTank = null; } if (portal) { portal.destroy(); portal = null; } // Reset game state currentLevel = 1; gameStarted = false; isDragging = false; gamePaused = false; showingMainMenu = true; levelsWithoutDying = 0; storage.levelsWithoutDying = levelsWithoutDying; LK.setScore(0); // Hide next level screen and show main menu nextLevelScreen.visible = false; mainMenu.visible = true; }; var healthBarBackground = LK.getAsset('wall', { anchorX: 0, anchorY: 1, scaleX: 4, scaleY: 0.8, tint: 0x333333 }); LK.gui.bottomLeft.addChild(healthBarBackground); var healthBarFill = LK.getAsset('wall', { anchorX: 0, anchorY: 1, scaleX: 4, scaleY: 0.8, tint: 0x00ff00 }); LK.gui.bottomLeft.addChild(healthBarFill); var levelText = new Text2('Level: 1', { size: 50, fill: 0xFFFFFF, font: "monospace" }); levelText.anchor.set(0.5, 0); LK.gui.top.addChild(levelText); var scoreText = new Text2('Score: 0', { size: 40, fill: 0xFFFFFF, font: "monospace" }); scoreText.anchor.set(0.5, 0); scoreText.x = 0; scoreText.y = 80; LK.gui.top.addChild(scoreText); var bestScoreText = new Text2('Best: ' + (storage.bestScore || 0), { size: 35, fill: 0xFFFF00, font: "monospace" }); bestScoreText.anchor.set(0.5, 0); bestScoreText.x = 0; bestScoreText.y = 130; LK.gui.top.addChild(bestScoreText); // Achievement button var achievementButton = new Text2('ACHIEVEMENTS', { size: 30, fill: 0xFFFFFF, font: "monospace" }); achievementButton.anchor.set(1, 0); LK.gui.topRight.addChild(achievementButton); // Achievement menu (initially hidden) var achievementMenu = new Container(); achievementMenu.visible = false; LK.gui.center.addChild(achievementMenu); // Achievement menu background var menuBackground = LK.getAsset('wall', { anchorX: 0.5, anchorY: 0.5, scaleX: 15, scaleY: 20, tint: 0x000000, alpha: 0.8 }); achievementMenu.addChild(menuBackground); // Achievement title background var titleBackground = LK.getAsset('wall', { anchorX: 0.5, anchorY: 0.5, scaleX: 8, scaleY: 1.5, tint: 0x000000, alpha: 0.9 }); titleBackground.x = 0; titleBackground.y = -400; achievementMenu.addChild(titleBackground); // Achievement title var achievementTitle = new Text2('ACHIEVEMENTS', { size: 60, fill: 0xFFFF00, font: "monospace" }); achievementTitle.anchor.set(0.5, 0.5); achievementTitle.x = 0; achievementTitle.y = -400; achievementMenu.addChild(achievementTitle); // Initialize achievements in storage if they don't exist var achievements = storage.achievements || { killAllEnemies: false, useFirstMedkit: false, killFirstEnemy: false, finishWithoutDying: false, get150Score: false, beatPreviousBest: false, arriveAtLevel3: false, kill50EnemiesTotal: false, killWhiteTank: false, killBlackTank: false, have1000Score: false, pass5LevelsWithoutDying: false }; storage.achievements = achievements; // Achievement tracking variables var totalEnemiesAtStart = 0; var hasUsedMedkit = false; var hasKilledEnemy = false; var hasBeenHurt = false; var totalEnemiesKilled = storage.totalEnemiesKilled || 0; var hasKilledWhiteTank = storage.hasKilledWhiteTank || false; var hasKilledBlackTank = storage.hasKilledBlackTank || false; var levelsWithoutDying = storage.levelsWithoutDying || 0; var hasReachedScore1000 = storage.hasReachedScore1000 || false; // Achievement text elements var achievement1Text = new Text2('', { size: 40, fill: 0xFFFFFF, font: "monospace" }); achievement1Text.anchor.set(0, 0.5); achievement1Text.x = -300; achievement1Text.y = -200; achievementMenu.addChild(achievement1Text); var achievement2Text = new Text2('', { size: 40, fill: 0xFFFFFF, font: "monospace" }); achievement2Text.anchor.set(0, 0.5); achievement2Text.x = -300; achievement2Text.y = -100; achievementMenu.addChild(achievement2Text); var achievement3Text = new Text2('', { size: 40, fill: 0xFFFFFF, font: "monospace" }); achievement3Text.anchor.set(0, 0.5); achievement3Text.x = -300; achievement3Text.y = 0; achievementMenu.addChild(achievement3Text); var achievement4Text = new Text2('', { size: 40, fill: 0xFFFFFF, font: "monospace" }); achievement4Text.anchor.set(0, 0.5); achievement4Text.x = -300; achievement4Text.y = 100; achievementMenu.addChild(achievement4Text); var achievement5Text = new Text2('', { size: 40, fill: 0xFFFFFF, font: "monospace" }); achievement5Text.anchor.set(0, 0.5); achievement5Text.x = -300; achievement5Text.y = 200; achievementMenu.addChild(achievement5Text); var achievement6Text = new Text2('', { size: 40, fill: 0xFFFFFF, font: "monospace" }); achievement6Text.anchor.set(0, 0.5); achievement6Text.x = -300; achievement6Text.y = 300; achievementMenu.addChild(achievement6Text); var achievement7Text = new Text2('', { size: 40, fill: 0xFFFFFF, font: "monospace" }); achievement7Text.anchor.set(0, 0.5); achievement7Text.x = -300; achievement7Text.y = 400; achievementMenu.addChild(achievement7Text); var achievement8Text = new Text2('', { size: 40, fill: 0xFFFFFF, font: "monospace" }); achievement8Text.anchor.set(0, 0.5); achievement8Text.x = -300; achievement8Text.y = 500; achievementMenu.addChild(achievement8Text); function updateAchievementTexts() { achievement1Text.setText('Kill A White Tank - ' + (achievements.killWhiteTank ? 'DONE' : 'NOT DONE')); achievement2Text.setText('Kill A Black Tank - ' + (achievements.killBlackTank ? 'DONE' : 'NOT DONE')); achievement3Text.setText('Have 1000 Score - ' + (achievements.have1000Score ? 'DONE' : 'NOT DONE')); achievement4Text.setText('Pass 5 Levels Without Dying - ' + (achievements.pass5LevelsWithoutDying ? 'DONE' : 'NOT DONE')); achievement5Text.setText('Kill all enemies in map - ' + (achievements.killAllEnemies ? 'DONE' : 'NOT DONE')); achievement6Text.setText('Use your first MedKit - ' + (achievements.useFirstMedkit ? 'DONE' : 'NOT DONE')); achievement7Text.setText('Kill your first enemy - ' + (achievements.killFirstEnemy ? 'DONE' : 'NOT DONE')); achievement8Text.setText('Finish a level without dying - ' + (achievements.finishWithoutDying ? 'DONE' : 'NOT DONE')); // Set colors for achievement text - green for DONE, red for NOT DONE if (achievements.killWhiteTank) { achievement1Text.fill = 0x00FF00; achievement1Text.tint = 0x00FF00; } else { achievement1Text.fill = 0xFF0000; achievement1Text.tint = 0xFF0000; } if (achievements.killBlackTank) { achievement2Text.fill = 0x00FF00; achievement2Text.tint = 0x00FF00; } else { achievement2Text.fill = 0xFF0000; achievement2Text.tint = 0xFF0000; } if (achievements.have1000Score) { achievement3Text.fill = 0x00FF00; achievement3Text.tint = 0x00FF00; } else { achievement3Text.fill = 0xFF0000; achievement3Text.tint = 0xFF0000; } if (achievements.pass5LevelsWithoutDying) { achievement4Text.fill = 0x00FF00; achievement4Text.tint = 0x00FF00; } else { achievement4Text.fill = 0xFF0000; achievement4Text.tint = 0xFF0000; } if (achievements.killAllEnemies) { achievement5Text.fill = 0x00FF00; achievement5Text.tint = 0x00FF00; } else { achievement5Text.fill = 0xFF0000; achievement5Text.tint = 0xFF0000; } if (achievements.useFirstMedkit) { achievement6Text.fill = 0x00FF00; achievement6Text.tint = 0x00FF00; } else { achievement6Text.fill = 0xFF0000; achievement6Text.tint = 0xFF0000; } if (achievements.killFirstEnemy) { achievement7Text.fill = 0x00FF00; achievement7Text.tint = 0x00FF00; } else { achievement7Text.fill = 0xFF0000; achievement7Text.tint = 0xFF0000; } if (achievements.finishWithoutDying) { achievement8Text.fill = 0x00FF00; achievement8Text.tint = 0x00FF00; } else { achievement8Text.fill = 0xFF0000; achievement8Text.tint = 0xFF0000; } } // Initial text update updateAchievementTexts(); // Achievement button click handler achievementButton.down = function (x, y, obj) { achievementMenu.visible = !achievementMenu.visible; gamePaused = achievementMenu.visible; updateAchievementTexts(); }; // Close menu when clicking background menuBackground.down = function (x, y, obj) { achievementMenu.visible = false; gamePaused = false; }; function generateMaze() { walls = []; var playerTankX = 1024; var playerTankY = 1366; for (var x = 0; x < gridWidth; x++) { for (var y = 0; y < gridHeight; y++) { var wallX = x * cellSize + cellSize / 2; var wallY = y * cellSize + cellSize / 2; // Check if this wall position would be too close to player tank position var dx = Math.abs(wallX - playerTankX); var dy = Math.abs(wallY - playerTankY); var isNearPlayerTank = dx < 64 && dy < 64; // Within one cell distance if (x === 0 || x === gridWidth - 1 || y === 0 || y === gridHeight - 1) { if (!isNearPlayerTank) { var wall = new Wall(); wall.x = wallX; wall.y = wallY; walls.push(wall); game.addChild(wall); } } else if (Math.random() < 0.3 && !isNearPlayerTank) { var wall = new Wall(); wall.x = wallX; wall.y = wallY; walls.push(wall); game.addChild(wall); } } } } function spawnEnemies() { var skinCount = Math.floor(Math.random() * 6) + 10; // 10-15 skin tanks var redCount = Math.floor(Math.random() * 6) + 5; // 5-10 red tanks var greenCount = Math.floor(Math.random() * 6) + 7; // 7-12 green tanks for (var i = 0; i < skinCount; i++) { var tank = new SkinTank(); do { tank.x = Math.random() * (2048 - 200) + 100; tank.y = Math.random() * (2732 - 200) + 100; } while (checkWallCollision(tank.x, tank.y) || getDistanceToPlayer(tank.x, tank.y) < 640); skinTanks.push(tank); game.addChild(tank); } for (var i = 0; i < redCount; i++) { var tank = new RedTank(); do { tank.x = Math.random() * (2048 - 200) + 100; tank.y = Math.random() * (2732 - 200) + 100; } while (checkWallCollision(tank.x, tank.y) || getDistanceToPlayer(tank.x, tank.y) < 640); redTanks.push(tank); game.addChild(tank); } for (var i = 0; i < greenCount; i++) { var tank = new GreenTank(); do { tank.x = Math.random() * (2048 - 200) + 100; tank.y = Math.random() * (2732 - 200) + 100; } while (checkWallCollision(tank.x, tank.y) || getDistanceToPlayer(tank.x, tank.y) < 640); greenTanks.push(tank); game.addChild(tank); } // Spawn white and black tanks if new enemies are enabled if (newEnemiesEnabled) { var whiteCount = Math.floor(Math.random() * 3) + 2; // 2-4 white tanks var blackCount = Math.floor(Math.random() * 3) + 1; // 1-3 black tanks for (var i = 0; i < whiteCount; i++) { var tank = new WhiteTank(); do { tank.x = Math.random() * (2048 - 200) + 100; tank.y = Math.random() * (2732 - 200) + 100; } while (checkWallCollision(tank.x, tank.y) || getDistanceToPlayer(tank.x, tank.y) < 640); whiteTanks.push(tank); game.addChild(tank); } for (var i = 0; i < blackCount; i++) { var tank = new BlackTank(); do { tank.x = Math.random() * (2048 - 200) + 100; tank.y = Math.random() * (2732 - 200) + 100; } while (checkWallCollision(tank.x, tank.y) || getDistanceToPlayer(tank.x, tank.y) < 640); blackTanks.push(tank); game.addChild(tank); } } } function checkWallCollision(x, y) { for (var i = 0; i < walls.length; i++) { var wall = walls[i]; var dx = Math.abs(x - wall.x); var dy = Math.abs(y - wall.y); if (dx < 32 && dy < 32) { return true; } } return false; } function getDistanceToPlayer(x, y) { if (!playerTank) { return 1000; } var dx = x - playerTank.x; var dy = y - playerTank.y; return Math.sqrt(dx * dx + dy * dy); } function spawnMedkits() { var medkitCount = Math.floor(Math.random() * 4) + 3; // 3-6 medkits per level for (var i = 0; i < medkitCount; i++) { var medkit = new Medkit(); do { medkit.x = Math.random() * (2048 - 200) + 100; medkit.y = Math.random() * (2732 - 200) + 100; } while (checkWallCollision(medkit.x, medkit.y) || getDistanceToPlayer(medkit.x, medkit.y) < 150); medkits.push(medkit); game.addChild(medkit); } } function createExplosion(x, y, radius, damage) { var explosion = LK.getAsset('explosion', { anchorX: 0.5, anchorY: 0.5, x: x, y: y, scaleX: radius / 60, scaleY: radius / 60, alpha: 0.8 }); game.addChild(explosion); explosions.push(explosion); tween(explosion, { alpha: 0, scaleX: explosion.scaleX * 1.5, scaleY: explosion.scaleY * 1.5 }, { duration: 500, onFinish: function onFinish() { explosion.destroy(); var index = explosions.indexOf(explosion); if (index > -1) { explosions.splice(index, 1); } } }); var dx = playerTank.x - x; var dy = playerTank.y - y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < radius) { playerTank.health -= damage; LK.getSound('hit').play(); // Track that player has been hurt hasBeenHurt = true; if (playerTank.health <= 0) { LK.showGameOver(); } } LK.getSound('explosion').play(); } function startLevel() { for (var i = walls.length - 1; i >= 0; i--) { walls[i].destroy(); } walls = []; for (var i = skinTanks.length - 1; i >= 0; i--) { skinTanks[i].destroy(); } skinTanks = []; for (var i = redTanks.length - 1; i >= 0; i--) { redTanks[i].destroy(); } redTanks = []; for (var i = greenTanks.length - 1; i >= 0; i--) { greenTanks[i].destroy(); } greenTanks = []; for (var i = medkits.length - 1; i >= 0; i--) { medkits[i].destroy(); } medkits = []; for (var i = whiteTanks.length - 1; i >= 0; i--) { whiteTanks[i].destroy(); } whiteTanks = []; for (var i = blackTanks.length - 1; i >= 0; i--) { blackTanks[i].destroy(); } blackTanks = []; for (var i = whiteBullets.length - 1; i >= 0; i--) { whiteBullets[i].destroy(); } whiteBullets = []; for (var i = blackBullets.length - 1; i >= 0; i--) { blackBullets[i].destroy(); } blackBullets = []; for (var i = electricFields.length - 1; i >= 0; i--) { electricFields[i].destroy(); } electricFields = []; for (var i = blackHoles.length - 1; i >= 0; i--) { blackHoles[i].destroy(); } blackHoles = []; generateMaze(); spawnEnemies(); spawnMedkits(); // Track total enemies for achievement totalEnemiesAtStart = skinTanks.length + redTanks.length + greenTanks.length + whiteTanks.length + blackTanks.length; // Reset achievement tracking variables hasUsedMedkit = false; hasKilledEnemy = false; hasBeenHurt = false; // Only create player tank if it doesn't exist (first level) if (!playerTank) { playerTank = new PlayerTank(); playerTank.x = 1024; playerTank.y = 1366; playerTank.health = 100; game.addChild(playerTank); } else { // Just reset position and health for existing player tank playerTank.x = 1024; playerTank.y = 1366; playerTank.health = 100; } portal = new Portal(); do { portal.x = Math.random() * (2048 - 200) + 100; portal.y = Math.random() * (2732 - 200) + 100; } while (checkWallCollision(portal.x, portal.y) || getDistanceToPlayer(portal.x, portal.y) < 300); game.addChild(portal); levelText.setText('Level: ' + currentLevel); gameStarted = true; // Achievement: Arrive at level 3 if (currentLevel >= 3 && !achievements.arriveAtLevel3) { achievements.arriveAtLevel3 = true; storage.achievements = achievements; } } // Mouse functionality - player tank follows mouse position game.down = function (x, y, obj) { // Only start dragging if mouse is pressed on the player tank and achievements menu is not visible and next level screen is not visible if (playerTank && playerTank.x && playerTank.y && !achievementMenu.visible && !nextLevelScreen.visible) { var dx = x - playerTank.x; var dy = y - playerTank.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= 60) { // Within tank radius (tank is 120px wide, so radius ~60) isDragging = true; } } }; game.move = function (x, y, obj) { if (!gameStarted || !playerTank || !isDragging || achievementMenu.visible || nextLevelScreen.visible) { return; } // Only allow dragging if mouse is not on a wall if (checkWallCollision(x, y)) { isDragging = false; // Stop dragging when mouse is on wall return; } // Calculate direction from tank to mouse for rotation var dx = x - playerTank.x; var dy = y - playerTank.y; var targetAngle = Math.atan2(dy, dx); // Stop any existing rotation tween tween.stop(playerTank, { rotation: true }); // Smoothly rotate the tank to face the mouse direction tween(playerTank, { rotation: targetAngle }, { duration: 200, easing: tween.easeOut }); // Move player tank directly to mouse position if no wall collision playerTank.x = x; playerTank.y = y; }; game.up = function (x, y, obj) { isDragging = false; if (!gameStarted || !playerTank || achievementMenu.visible || nextLevelScreen.visible) { return; } if (playerTank.shootCooldown <= 0) { var dx = x - playerTank.x; var dy = y - playerTank.y; var length = Math.sqrt(dx * dx + dy * dy); if (length > 0) { // Calculate the angle to face the shooting direction var targetAngle = Math.atan2(dy, dx); // Stop any existing rotation tween tween.stop(playerTank, { rotation: true }); // Rotate the tank to face the shooting direction tween(playerTank, { rotation: targetAngle }, { duration: 200, easing: tween.easeOut }); var dirX = dx / length; var dirY = dy / length; var bullet = new PlayerBullet(); bullet.x = playerTank.x; bullet.y = playerTank.y; bullet.directionX = dirX; bullet.directionY = dirY; playerBullets.push(bullet); game.addChild(bullet); playerTank.shootCooldown = 15; LK.getSound('shoot').play(); } } }; // Game Over screen setup var gameOverHandled = false; // Override LK.showGameOver to add custom functionality var originalShowGameOver = LK.showGameOver; LK.showGameOver = function () { if (!gameOverHandled) { gameOverHandled = true; // Create game over screen with return to main menu button var gameOverScreen = new Container(); gameOverScreen.visible = true; LK.gui.center.addChild(gameOverScreen); // Game over background var gameOverBackground = LK.getAsset('wall', { anchorX: 0.5, anchorY: 0.5, scaleX: 12, scaleY: 8, tint: 0x000000, alpha: 0.9 }); gameOverScreen.addChild(gameOverBackground); // Game Over text var gameOverText = new Text2('GAME OVER', { size: 80, fill: 0xFF0000, font: "monospace" }); gameOverText.anchor.set(0.5, 0.5); gameOverText.x = 0; gameOverText.y = -50; gameOverScreen.addChild(gameOverText); // Return to main menu button for game over var gameOverReturnButton = new Text2('RETURN TO MAIN MENU', { size: 60, fill: 0xFFFFFF, font: "monospace" }); gameOverReturnButton.anchor.set(0.5, 0.5); gameOverReturnButton.x = 0; gameOverReturnButton.y = 50; gameOverScreen.addChild(gameOverReturnButton); // Return to main menu button click handler for game over gameOverReturnButton.down = function (x, y, obj) { // Clear all game objects for (var i = walls.length - 1; i >= 0; i--) { walls[i].destroy(); } walls = []; for (var i = skinTanks.length - 1; i >= 0; i--) { skinTanks[i].destroy(); } skinTanks = []; for (var i = redTanks.length - 1; i >= 0; i--) { redTanks[i].destroy(); } redTanks = []; for (var i = greenTanks.length - 1; i >= 0; i--) { greenTanks[i].destroy(); } greenTanks = []; for (var i = medkits.length - 1; i >= 0; i--) { medkits[i].destroy(); } medkits = []; for (var i = playerBullets.length - 1; i >= 0; i--) { playerBullets[i].destroy(); } playerBullets = []; for (var i = enemyBullets.length - 1; i >= 0; i--) { enemyBullets[i].destroy(); } enemyBullets = []; for (var i = dynamites.length - 1; i >= 0; i--) { dynamites[i].destroy(); } dynamites = []; for (var i = acidBombs.length - 1; i >= 0; i--) { acidBombs[i].destroy(); } acidBombs = []; for (var i = explosions.length - 1; i >= 0; i--) { explosions[i].destroy(); } explosions = []; for (var i = whiteTanks.length - 1; i >= 0; i--) { whiteTanks[i].destroy(); } whiteTanks = []; for (var i = blackTanks.length - 1; i >= 0; i--) { blackTanks[i].destroy(); } blackTanks = []; for (var i = whiteBullets.length - 1; i >= 0; i--) { whiteBullets[i].destroy(); } whiteBullets = []; for (var i = blackBullets.length - 1; i >= 0; i--) { blackBullets[i].destroy(); } blackBullets = []; for (var i = electricFields.length - 1; i >= 0; i--) { electricFields[i].destroy(); } electricFields = []; for (var i = blackHoles.length - 1; i >= 0; i--) { blackHoles[i].destroy(); } blackHoles = []; // Destroy player tank and portal if they exist if (playerTank) { playerTank.destroy(); playerTank = null; } if (portal) { portal.destroy(); portal = null; } // Reset game state currentLevel = 1; gameStarted = false; isDragging = false; gamePaused = false; showingMainMenu = true; gameOverHandled = false; levelsWithoutDying = 0; storage.levelsWithoutDying = levelsWithoutDying; LK.setScore(0); // Hide game over screen and show main menu gameOverScreen.destroy(); mainMenu.visible = true; }; // Auto-hide after 3 seconds and call original game over LK.setTimeout(function () { gameOverScreen.destroy(); originalShowGameOver(); }, 3000); } else { originalShowGameOver(); } }; game.update = function () { if (showingMainMenu) { return; } if (!gameStarted) { return; } if (gamePaused) return; // Movement is handled via touch/drag in game.move method for (var i = playerBullets.length - 1; i >= 0; i--) { var bullet = playerBullets[i]; if (bullet.x < 0 || bullet.x > 2048 || bullet.y < 0 || bullet.y > 2732) { bullet.destroy(); playerBullets.splice(i, 1); continue; } if (checkWallCollision(bullet.x, bullet.y)) { bullet.destroy(); playerBullets.splice(i, 1); continue; } for (var j = skinTanks.length - 1; j >= 0; j--) { if (bullet.intersects(skinTanks[j])) { skinTanks[j].health -= 3; bullet.destroy(); playerBullets.splice(i, 1); if (skinTanks[j].health <= 0) { createExplosion(skinTanks[j].x, skinTanks[j].y, 100, 15); skinTanks[j].destroy(); skinTanks.splice(j, 1); LK.setScore(LK.getScore() + 10); // Track total enemies killed totalEnemiesKilled++; storage.totalEnemiesKilled = totalEnemiesKilled; // Achievement: Kill first enemy if (!hasKilledEnemy) { hasKilledEnemy = true; achievements.killFirstEnemy = true; storage.achievements = achievements; } // Achievement: Kill 50 enemies total if (totalEnemiesKilled >= 50 && !achievements.kill50EnemiesTotal) { achievements.kill50EnemiesTotal = true; storage.achievements = achievements; } } break; } } for (var j = redTanks.length - 1; j >= 0; j--) { if (bullet.intersects(redTanks[j])) { redTanks[j].health -= 10; bullet.destroy(); playerBullets.splice(i, 1); if (redTanks[j].health <= 0) { redTanks[j].destroy(); redTanks.splice(j, 1); LK.setScore(LK.getScore() + 20); // Track total enemies killed totalEnemiesKilled++; storage.totalEnemiesKilled = totalEnemiesKilled; // Achievement: Kill first enemy if (!hasKilledEnemy) { hasKilledEnemy = true; achievements.killFirstEnemy = true; storage.achievements = achievements; } // Achievement: Kill 50 enemies total if (totalEnemiesKilled >= 50 && !achievements.kill50EnemiesTotal) { achievements.kill50EnemiesTotal = true; storage.achievements = achievements; } } break; } } for (var j = greenTanks.length - 1; j >= 0; j--) { if (bullet.intersects(greenTanks[j])) { greenTanks[j].health -= 25; bullet.destroy(); playerBullets.splice(i, 1); if (greenTanks[j].health <= 0) { greenTanks[j].destroy(); greenTanks.splice(j, 1); LK.setScore(LK.getScore() + 30); // Track total enemies killed totalEnemiesKilled++; storage.totalEnemiesKilled = totalEnemiesKilled; // Achievement: Kill first enemy if (!hasKilledEnemy) { hasKilledEnemy = true; achievements.killFirstEnemy = true; storage.achievements = achievements; } // Achievement: Kill 50 enemies total if (totalEnemiesKilled >= 50 && !achievements.kill50EnemiesTotal) { achievements.kill50EnemiesTotal = true; storage.achievements = achievements; } } break; } } for (var j = whiteTanks.length - 1; j >= 0; j--) { if (bullet.intersects(whiteTanks[j])) { whiteTanks[j].health -= 25; bullet.destroy(); playerBullets.splice(i, 1); if (whiteTanks[j].health <= 0) { whiteTanks[j].destroy(); whiteTanks.splice(j, 1); LK.setScore(LK.getScore() + 40); totalEnemiesKilled++; storage.totalEnemiesKilled = totalEnemiesKilled; if (!hasKilledEnemy) { hasKilledEnemy = true; achievements.killFirstEnemy = true; storage.achievements = achievements; } if (totalEnemiesKilled >= 50 && !achievements.kill50EnemiesTotal) { achievements.kill50EnemiesTotal = true; storage.achievements = achievements; } // Achievement: Kill a white tank if (!hasKilledWhiteTank) { hasKilledWhiteTank = true; storage.hasKilledWhiteTank = hasKilledWhiteTank; achievements.killWhiteTank = true; storage.achievements = achievements; } } break; } } for (var j = blackTanks.length - 1; j >= 0; j--) { if (bullet.intersects(blackTanks[j])) { blackTanks[j].health -= 25; bullet.destroy(); playerBullets.splice(i, 1); if (blackTanks[j].health <= 0) { blackTanks[j].destroy(); blackTanks.splice(j, 1); LK.setScore(LK.getScore() + 50); totalEnemiesKilled++; storage.totalEnemiesKilled = totalEnemiesKilled; if (!hasKilledEnemy) { hasKilledEnemy = true; achievements.killFirstEnemy = true; storage.achievements = achievements; } if (totalEnemiesKilled >= 50 && !achievements.kill50EnemiesTotal) { achievements.kill50EnemiesTotal = true; storage.achievements = achievements; } // Achievement: Kill a black tank if (!hasKilledBlackTank) { hasKilledBlackTank = true; storage.hasKilledBlackTank = hasKilledBlackTank; achievements.killBlackTank = true; storage.achievements = achievements; } } break; } } } for (var i = enemyBullets.length - 1; i >= 0; i--) { var bullet = enemyBullets[i]; if (bullet.x < 0 || bullet.x > 2048 || bullet.y < 0 || bullet.y > 2732) { bullet.destroy(); enemyBullets.splice(i, 1); continue; } if (checkWallCollision(bullet.x, bullet.y)) { bullet.destroy(); enemyBullets.splice(i, 1); continue; } if (bullet.intersects(playerTank)) { playerTank.health -= bullet.damage; bullet.destroy(); enemyBullets.splice(i, 1); LK.getSound('hit').play(); // Track that player has been hurt hasBeenHurt = true; if (playerTank.health <= 0) { LK.showGameOver(); } continue; } } for (var i = dynamites.length - 1; i >= 0; i--) { var dynamite = dynamites[i]; if (dynamite.x < 0 || dynamite.x > 2048 || dynamite.y < 0 || dynamite.y > 2732) { createExplosion(dynamite.x, dynamite.y, dynamite.explosionRadius, dynamite.damage); dynamite.destroy(); dynamites.splice(i, 1); continue; } if (checkWallCollision(dynamite.x, dynamite.y)) { createExplosion(dynamite.x, dynamite.y, dynamite.explosionRadius, dynamite.damage); dynamite.destroy(); dynamites.splice(i, 1); continue; } if (dynamite.intersects(playerTank)) { createExplosion(dynamite.x, dynamite.y, dynamite.explosionRadius, dynamite.damage); dynamite.destroy(); dynamites.splice(i, 1); continue; } } for (var i = acidBombs.length - 1; i >= 0; i--) { var acidBomb = acidBombs[i]; if (acidBomb.x < 0 || acidBomb.x > 2048 || acidBomb.y < 0 || acidBomb.y > 2732) { acidBomb.destroy(); acidBombs.splice(i, 1); continue; } if (checkWallCollision(acidBomb.x, acidBomb.y)) { acidBomb.destroy(); acidBombs.splice(i, 1); continue; } if (acidBomb.intersects(playerTank)) { playerTank.health -= acidBomb.damage; playerTank.poisonTimer = acidBomb.poisonDuration; playerTank.poisonDamage = acidBomb.poisonDamage; acidBomb.destroy(); acidBombs.splice(i, 1); LK.getSound('hit').play(); // Track that player has been hurt hasBeenHurt = true; if (playerTank.health <= 0) { LK.showGameOver(); } continue; } } // Handle white bullets for (var i = whiteBullets.length - 1; i >= 0; i--) { var bullet = whiteBullets[i]; if (bullet.x < 0 || bullet.x > 2048 || bullet.y < 0 || bullet.y > 2732) { bullet.destroy(); whiteBullets.splice(i, 1); continue; } if (checkWallCollision(bullet.x, bullet.y)) { bullet.destroy(); whiteBullets.splice(i, 1); continue; } if (bullet.intersects(playerTank)) { // Create electric field var electricField = new ElectricField(); electricField.x = bullet.x; electricField.y = bullet.y; electricFields.push(electricField); game.addChild(electricField); bullet.destroy(); whiteBullets.splice(i, 1); LK.getSound('explosion').play(); continue; } } // Handle black bullets for (var i = blackBullets.length - 1; i >= 0; i--) { var bullet = blackBullets[i]; if (bullet.x < 0 || bullet.x > 2048 || bullet.y < 0 || bullet.y > 2732) { bullet.destroy(); blackBullets.splice(i, 1); continue; } if (checkWallCollision(bullet.x, bullet.y)) { bullet.destroy(); blackBullets.splice(i, 1); continue; } if (bullet.intersects(playerTank)) { // Create black hole var blackHole = new BlackHole(); blackHole.x = bullet.x; blackHole.y = bullet.y; blackHoles.push(blackHole); game.addChild(blackHole); bullet.destroy(); blackBullets.splice(i, 1); LK.getSound('explosion').play(); continue; } // Check collision with white bullets for (var j = whiteBullets.length - 1; j >= 0; j--) { if (bullet.intersects(whiteBullets[j])) { // Create black hole from black bullet var blackHole = new BlackHole(); blackHole.x = bullet.x; blackHole.y = bullet.y; blackHoles.push(blackHole); game.addChild(blackHole); // Create electric field from white bullet var electricField = new ElectricField(); electricField.x = whiteBullets[j].x; electricField.y = whiteBullets[j].y; electricFields.push(electricField); game.addChild(electricField); // Destroy both bullets bullet.destroy(); blackBullets.splice(i, 1); whiteBullets[j].destroy(); whiteBullets.splice(j, 1); LK.getSound('explosion').play(); break; } } } for (var i = skinTanks.length - 1; i >= 0; i--) { if (skinTanks[i].intersects(playerTank)) { createExplosion(skinTanks[i].x, skinTanks[i].y, skinTanks[i].explosionRadius, 20); skinTanks[i].destroy(); skinTanks.splice(i, 1); } } for (var i = redTanks.length - 1; i >= 0; i--) { if (redTanks[i].intersects(playerTank)) { // Check if any part of player is within circular explosion area (radius 100) // Player tank is 120px wide, so radius is 60px var dx = playerTank.x - redTanks[i].x; var dy = playerTank.y - redTanks[i].y; var distance = Math.sqrt(dx * dx + dy * dy); var playerRadius = 60; // Half of player tank width (120px) var explosionRadius = 100; // Check if there's a clear path from explosion center to player (no walls blocking) var canDamagePlayer = true; var stepSize = 32; // Check every 32 pixels along the path var steps = Math.ceil(distance / stepSize); for (var step = 1; step <= steps; step++) { var checkX = redTanks[i].x + dx * step / steps; var checkY = redTanks[i].y + dy * step / steps; if (checkWallCollision(checkX, checkY)) { canDamagePlayer = false; break; } } if (distance <= explosionRadius + playerRadius && canDamagePlayer) { // Any part of player is within explosion radius and no walls block - deal 70 damage playerTank.health -= 70; LK.getSound('hit').play(); hasBeenHurt = true; if (playerTank.health <= 0) { LK.showGameOver(); } } createExplosion(redTanks[i].x, redTanks[i].y, 100, 0); // No additional damage from explosion redTanks[i].destroy(); redTanks.splice(i, 1); } } // Check medkit collision for healing for (var i = medkits.length - 1; i >= 0; i--) { var medkit = medkits[i]; var dx = playerTank.x - medkit.x; var dy = playerTank.y - medkit.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 50 && playerTank.health < playerTank.maxHealth) { // Close enough to collect medkit and player needs healing playerTank.health = playerTank.maxHealth; // Restore to full health medkit.destroy(); medkits.splice(i, 1); LK.getSound('hit').play(); // Use existing sound for medkit pickup // Achievement: Use first medkit if (!hasUsedMedkit) { hasUsedMedkit = true; achievements.useFirstMedkit = true; storage.achievements = achievements; } } } // Check if player is close to portal (within 100 pixels) var dx = playerTank.x - portal.x; var dy = playerTank.y - portal.y; var distanceToPortal = Math.sqrt(dx * dx + dy * dy); if (distanceToPortal < 100) { // Achievement: Kill all enemies in map var totalEnemiesRemaining = skinTanks.length + redTanks.length + greenTanks.length + whiteTanks.length + blackTanks.length; if (totalEnemiesRemaining === 0) { achievements.killAllEnemies = true; storage.achievements = achievements; } // Achievement: Finish without dying if (!hasBeenHurt) { achievements.finishWithoutDying = true; storage.achievements = achievements; // Track consecutive levels without dying levelsWithoutDying++; storage.levelsWithoutDying = levelsWithoutDying; // Achievement: Pass 5 levels without dying if (levelsWithoutDying >= 5 && !achievements.pass5LevelsWithoutDying) { achievements.pass5LevelsWithoutDying = true; storage.achievements = achievements; } } else { // Reset consecutive levels counter if player was hurt levelsWithoutDying = 0; storage.levelsWithoutDying = levelsWithoutDying; } LK.getSound('win').play(); // Clear current level enemies and bullets for (var i = playerBullets.length - 1; i >= 0; i--) { playerBullets[i].destroy(); } playerBullets = []; for (var i = enemyBullets.length - 1; i >= 0; i--) { enemyBullets[i].destroy(); } enemyBullets = []; for (var i = dynamites.length - 1; i >= 0; i--) { dynamites[i].destroy(); } dynamites = []; for (var i = acidBombs.length - 1; i >= 0; i--) { acidBombs[i].destroy(); } acidBombs = []; for (var i = explosions.length - 1; i >= 0; i--) { explosions[i].destroy(); } explosions = []; for (var i = whiteBullets.length - 1; i >= 0; i--) { whiteBullets[i].destroy(); } whiteBullets = []; for (var i = blackBullets.length - 1; i >= 0; i--) { blackBullets[i].destroy(); } blackBullets = []; for (var i = electricFields.length - 1; i >= 0; i--) { electricFields[i].destroy(); } electricFields = []; for (var i = blackHoles.length - 1; i >= 0; i--) { blackHoles[i].destroy(); } blackHoles = []; // Remove current portal portal.destroy(); // Advance to next level currentLevel++; // Show next level screen nextLevelScreen.visible = true; gamePaused = true; } // Update score display scoreText.setText('Score: ' + LK.getScore()); // Update best score if current score is higher var currentScore = LK.getScore(); var bestScore = storage.bestScore || 0; if (currentScore > bestScore) { storage.bestScore = currentScore; bestScoreText.setText('Best: ' + currentScore); // Achievement: Beat previous best score if (bestScore > 0) { achievements.beatPreviousBest = true; storage.achievements = achievements; } } // Achievement: Get 150 Score if (currentScore >= 150 && !achievements.get150Score) { achievements.get150Score = true; storage.achievements = achievements; } // Achievement: Have 1000 Score if (currentScore >= 1000 && !hasReachedScore1000) { hasReachedScore1000 = true; storage.hasReachedScore1000 = hasReachedScore1000; achievements.have1000Score = true; storage.achievements = achievements; } var healthPercentage = Math.max(0, playerTank.health) / 100; healthBarFill.scaleX = 4 * healthPercentage; if (healthPercentage > 0.6) { healthBarFill.tint = 0x00ff00; // Green } else if (healthPercentage > 0.3) { healthBarFill.tint = 0xffff00; // Yellow } else { healthBarFill.tint = 0xff0000; // Red } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var AcidBomb = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('acidBomb', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 2;
self.directionX = 0;
self.directionY = 0;
self.damage = 5;
self.poisonDamage = 2;
self.poisonDuration = 180;
self.update = function () {
if (gamePaused) return;
self.x += self.directionX * self.speed;
self.y += self.directionY * self.speed;
};
return self;
});
var BlackBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('blackBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 4;
self.directionX = 0;
self.directionY = 0;
self.damage = 10;
self.update = function () {
if (gamePaused) return;
self.x += self.directionX * self.speed;
self.y += self.directionY * self.speed;
};
return self;
});
var BlackHole = Container.expand(function () {
var self = Container.call(this);
var holeGraphics = self.attachAsset('blackHole', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.8
});
self.radius = 64; // 1 block radius
self.duration = 300; // 5 seconds at 60fps
self.timer = 0;
self.damageTimer = 0;
self.pullStrength = 1.5;
self.update = function () {
if (gamePaused) return;
self.timer++;
self.damageTimer++;
// Pull and damage effects
var dx = playerTank.x - self.x;
var dy = playerTank.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= self.radius * 2) {
// Pull player toward center
var pullX = dx > 0 ? -self.pullStrength : self.pullStrength;
var pullY = dy > 0 ? -self.pullStrength : self.pullStrength;
if (!checkWallCollision(playerTank.x + pullX, playerTank.y)) {
playerTank.x += pullX;
}
if (!checkWallCollision(playerTank.x, playerTank.y + pullY)) {
playerTank.y += pullY;
}
// Damage at center every second
if (distance <= 32 && self.damageTimer >= 60) {
playerTank.health -= 8;
hasBeenHurt = true;
LK.getSound('hit').play();
if (playerTank.health <= 0) {
LK.showGameOver();
}
}
}
// Pull and damage enemies
for (var i = skinTanks.length - 1; i >= 0; i--) {
var dx = skinTanks[i].x - self.x;
var dy = skinTanks[i].y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= self.radius * 2) {
var pullX = dx > 0 ? -self.pullStrength : self.pullStrength;
var pullY = dy > 0 ? -self.pullStrength : self.pullStrength;
if (!checkWallCollision(skinTanks[i].x + pullX, skinTanks[i].y)) {
skinTanks[i].x += pullX;
}
if (!checkWallCollision(skinTanks[i].x, skinTanks[i].y + pullY)) {
skinTanks[i].y += pullY;
}
}
}
// Damage enemies every second
if (self.damageTimer >= 60) {
self.damageTimer = 0;
for (var i = skinTanks.length - 1; i >= 0; i--) {
var dx = skinTanks[i].x - self.x;
var dy = skinTanks[i].y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= self.radius) {
skinTanks[i].health -= 2;
}
}
for (var i = redTanks.length - 1; i >= 0; i--) {
var dx = redTanks[i].x - self.x;
var dy = redTanks[i].y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= self.radius) {
redTanks[i].health -= 4;
}
}
for (var i = greenTanks.length - 1; i >= 0; i--) {
var dx = greenTanks[i].x - self.x;
var dy = greenTanks[i].y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= self.radius) {
greenTanks[i].health -= 15;
}
}
// White tanks die instantly
for (var i = whiteTanks.length - 1; i >= 0; i--) {
var dx = whiteTanks[i].x - self.x;
var dy = whiteTanks[i].y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= self.radius) {
whiteTanks[i].destroy();
whiteTanks.splice(i, 1);
LK.setScore(LK.getScore() + 40);
totalEnemiesKilled++;
storage.totalEnemiesKilled = totalEnemiesKilled;
}
}
}
if (self.timer >= self.duration) {
self.destroy();
var index = blackHoles.indexOf(self);
if (index > -1) {
blackHoles.splice(index, 1);
}
}
};
return self;
});
var BlackTank = Container.expand(function () {
var self = Container.call(this);
var tankGraphics = self.attachAsset('blackTank', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 225;
self.speed = 1;
self.shootCooldown = 0;
self.update = function () {
if (gamePaused) return;
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
var target = playerTank;
// Check if should target white tank instead
for (var i = 0; i < whiteTanks.length; i++) {
var dx = whiteTanks[i].x - self.x;
var dy = whiteTanks[i].y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 400) {
target = whiteTanks[i];
break;
}
}
var dx = target.x - self.x;
var dy = target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Move toward target when in range
if (distance < 350) {
var moveX = dx > 0 ? self.speed : -self.speed;
var moveY = dy > 0 ? self.speed : -self.speed;
var newX = self.x + moveX;
var newY = self.y + moveY;
var targetAngle = Math.atan2(dy, dx);
tween.stop(self, {
rotation: true
});
tween(self, {
rotation: targetAngle
}, {
duration: 300,
easing: tween.easeOut
});
if (!checkWallCollision(newX, self.y)) {
self.x = newX;
}
if (!checkWallCollision(self.x, newY)) {
self.y = newY;
}
}
if (distance < 300 && self.shootCooldown <= 0) {
var length = Math.sqrt(dx * dx + dy * dy);
var dirX = dx / length;
var dirY = dy / length;
var blackBullet = new BlackBullet();
blackBullet.x = self.x;
blackBullet.y = self.y;
blackBullet.directionX = dirX;
blackBullet.directionY = dirY;
blackBullets.push(blackBullet);
game.addChild(blackBullet);
self.shootCooldown = 120;
LK.getSound('shoot').play();
}
};
return self;
});
var Dynamite = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('dynamite', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 3;
self.directionX = 0;
self.directionY = 0;
self.damage = 25;
self.explosionRadius = 80;
self.update = function () {
if (gamePaused) return;
self.x += self.directionX * self.speed;
self.y += self.directionY * self.speed;
};
return self;
});
var ElectricField = Container.expand(function () {
var self = Container.call(this);
var fieldGraphics = self.attachAsset('electricField', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.5
});
self.radius = 160; // 2 blocks radius
self.duration = 300; // 5 seconds at 60fps
self.timer = 0;
self.damageTimer = 0;
self.update = function () {
if (gamePaused) return;
self.timer++;
self.damageTimer++;
// Damage every 60 frames (1 second)
if (self.damageTimer >= 60) {
self.damageTimer = 0;
// Check player damage
var dx = playerTank.x - self.x;
var dy = playerTank.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= self.radius) {
playerTank.health -= 2;
hasBeenHurt = true;
LK.getSound('hit').play();
if (playerTank.health <= 0) {
LK.showGameOver();
}
}
// Check enemy damage and change targets
for (var i = skinTanks.length - 1; i >= 0; i--) {
var dx = skinTanks[i].x - self.x;
var dy = skinTanks[i].y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= self.radius) {
skinTanks[i].health -= 0.5;
skinTanks[i].targetWhiteTank = true;
}
}
for (var i = redTanks.length - 1; i >= 0; i--) {
var dx = redTanks[i].x - self.x;
var dy = redTanks[i].y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= self.radius) {
redTanks[i].health -= 2;
redTanks[i].targetWhiteTank = true;
}
}
for (var i = greenTanks.length - 1; i >= 0; i--) {
var dx = greenTanks[i].x - self.x;
var dy = greenTanks[i].y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= self.radius) {
greenTanks[i].health -= 10;
greenTanks[i].targetWhiteTank = true;
}
}
}
if (self.timer >= self.duration) {
self.destroy();
var index = electricFields.indexOf(self);
if (index > -1) {
electricFields.splice(index, 1);
}
}
};
return self;
});
var EnemyBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('enemyBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 4;
self.directionX = 0;
self.directionY = 0;
self.damage = 10;
self.update = function () {
if (gamePaused) return;
self.x += self.directionX * self.speed;
self.y += self.directionY * self.speed;
};
return self;
});
var GreenTank = Container.expand(function () {
var self = Container.call(this);
var tankGraphics = self.attachAsset('greenTank', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 40;
self.speed = 0.8;
self.shootCooldown = 0;
self.update = function () {
if (gamePaused) return;
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
var target = playerTank;
// Check if should target white tank instead due to electric field
if (self.targetWhiteTank) {
for (var i = 0; i < whiteTanks.length; i++) {
var dx = whiteTanks[i].x - self.x;
var dy = whiteTanks[i].y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 400) {
target = whiteTanks[i];
break;
}
}
}
var dx = target.x - self.x;
var dy = target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Move toward player when they can see them (within range)
if (distance < 300) {
var moveX = dx > 0 ? self.speed : -self.speed;
var moveY = dy > 0 ? self.speed : -self.speed;
var newX = self.x + moveX;
var newY = self.y + moveY;
// Calculate target angle for rotation
var targetAngle = Math.atan2(dy, dx);
// Stop any existing rotation tween
tween.stop(self, {
rotation: true
});
// Smoothly rotate the tank to face the movement direction
tween(self, {
rotation: targetAngle
}, {
duration: 300,
easing: tween.easeOut
});
if (!checkWallCollision(newX, self.y)) {
self.x = newX;
}
if (!checkWallCollision(self.x, newY)) {
self.y = newY;
}
}
if (distance < 200 && self.shootCooldown <= 0) {
var length = Math.sqrt(dx * dx + dy * dy);
var dirX = dx / length;
var dirY = dy / length;
var acidBomb = new AcidBomb();
acidBomb.x = self.x;
acidBomb.y = self.y;
acidBomb.directionX = dirX;
acidBomb.directionY = dirY;
acidBombs.push(acidBomb);
game.addChild(acidBomb);
self.shootCooldown = 150;
LK.getSound('shoot').play();
}
};
return self;
});
var Medkit = Container.expand(function () {
var self = Container.call(this);
var medkitGraphics = self.attachAsset('medkit', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var PlayerBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('playerBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.directionX = 0;
self.directionY = 0;
self.damage = 10;
self.update = function () {
if (gamePaused) return;
self.x += self.directionX * self.speed;
self.y += self.directionY * self.speed;
};
return self;
});
var PlayerTank = Container.expand(function () {
var self = Container.call(this);
var tankGraphics = self.attachAsset('playerTank', {
anchorX: 0.5,
anchorY: 0.5
});
self.maxHealth = 100;
self.health = 100;
self.speed = 3;
self.shootCooldown = 0;
self.poisonTimer = 0;
self.poisonDamage = 0;
self.update = function () {
if (gamePaused) return;
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
if (self.poisonTimer > 0) {
self.poisonTimer--;
if (LK.ticks % 30 === 0) {
self.health -= self.poisonDamage;
if (self.health <= 0) {
LK.showGameOver();
}
}
}
};
return self;
});
var Portal = Container.expand(function () {
var self = Container.call(this);
var portalGraphics = self.attachAsset('portal', {
anchorX: 0.5,
anchorY: 0.5
});
self.update = function () {
// Portal no longer rotates
};
return self;
});
var RedTank = Container.expand(function () {
var self = Container.call(this);
var tankGraphics = self.attachAsset('redTank', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 80;
self.speed = 1;
self.shootCooldown = 0;
self.update = function () {
if (gamePaused) return;
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
var target = playerTank;
// Check if should target white tank instead due to electric field
if (self.targetWhiteTank) {
for (var i = 0; i < whiteTanks.length; i++) {
var dx = whiteTanks[i].x - self.x;
var dy = whiteTanks[i].y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 400) {
target = whiteTanks[i];
break;
}
}
}
var dx = target.x - self.x;
var dy = target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Move toward player when they can see them (within range)
if (distance < 350) {
var moveX = dx > 0 ? self.speed : -self.speed;
var moveY = dy > 0 ? self.speed : -self.speed;
var newX = self.x + moveX;
var newY = self.y + moveY;
// Calculate target angle for rotation
var targetAngle = Math.atan2(dy, dx);
// Stop any existing rotation tween
tween.stop(self, {
rotation: true
});
// Smoothly rotate the tank to face the movement direction
tween(self, {
rotation: targetAngle
}, {
duration: 300,
easing: tween.easeOut
});
if (!checkWallCollision(newX, self.y)) {
self.x = newX;
}
if (!checkWallCollision(self.x, newY)) {
self.y = newY;
}
}
if (distance < 250 && self.shootCooldown <= 0) {
var length = Math.sqrt(dx * dx + dy * dy);
var dirX = dx / length;
var dirY = dy / length;
var dynamite = new Dynamite();
dynamite.x = self.x;
dynamite.y = self.y;
dynamite.directionX = dirX;
dynamite.directionY = dirY;
dynamites.push(dynamite);
game.addChild(dynamite);
self.shootCooldown = 120;
LK.getSound('shoot').play();
}
};
return self;
});
var SkinTank = Container.expand(function () {
var self = Container.call(this);
var tankGraphics = self.attachAsset('skinTank', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 50;
self.speed = 1.5;
self.shootCooldown = 0;
self.explosionRadius = 100;
self.lastPlayerX = 0;
self.lastPlayerY = 0;
self.update = function () {
if (gamePaused) return;
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
var target = playerTank;
var targetWhiteTank = false;
// Check if should target white tank instead due to electric field
if (self.targetWhiteTank) {
for (var i = 0; i < whiteTanks.length; i++) {
var dx = whiteTanks[i].x - self.x;
var dy = whiteTanks[i].y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 400) {
target = whiteTanks[i];
targetWhiteTank = true;
break;
}
}
}
var dx = target.x - self.x;
var dy = target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 150) {
var moveX = dx > 0 ? self.speed : -self.speed;
var moveY = dy > 0 ? self.speed : -self.speed;
var newX = self.x + moveX;
var newY = self.y + moveY;
// Calculate target angle for rotation
var targetAngle = Math.atan2(dy, dx);
// Stop any existing rotation tween
tween.stop(self, {
rotation: true
});
// Smoothly rotate the tank to face the movement direction
tween(self, {
rotation: targetAngle
}, {
duration: 300,
easing: tween.easeOut
});
if (!checkWallCollision(newX, self.y)) {
self.x = newX;
}
if (!checkWallCollision(self.x, newY)) {
self.y = newY;
}
}
if (distance < 300 && self.shootCooldown <= 0) {
var length = Math.sqrt(dx * dx + dy * dy);
var dirX = dx / length;
var dirY = dy / length;
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.directionX = dirX;
bullet.directionY = dirY;
bullet.damage = 3;
enemyBullets.push(bullet);
game.addChild(bullet);
self.shootCooldown = 90;
LK.getSound('shoot').play();
}
};
return self;
});
var Wall = Container.expand(function () {
var self = Container.call(this);
var wallGraphics = self.attachAsset('wall', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var WhiteBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('whiteBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 4;
self.directionX = 0;
self.directionY = 0;
self.damage = 10;
self.update = function () {
if (gamePaused) return;
self.x += self.directionX * self.speed;
self.y += self.directionY * self.speed;
};
return self;
});
var WhiteTank = Container.expand(function () {
var self = Container.call(this);
var tankGraphics = self.attachAsset('whiteTank', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 275;
self.speed = 1;
self.shootCooldown = 0;
self.targetWhiteTank = false;
self.update = function () {
if (gamePaused) return;
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
var target = playerTank;
var targetBlackTank = false;
// Check if should target black tank instead
for (var i = 0; i < blackTanks.length; i++) {
var dx = blackTanks[i].x - self.x;
var dy = blackTanks[i].y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 400) {
target = blackTanks[i];
targetBlackTank = true;
break;
}
}
var dx = target.x - self.x;
var dy = target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Move toward target when in range
if (distance < 350) {
var moveX = dx > 0 ? self.speed : -self.speed;
var moveY = dy > 0 ? self.speed : -self.speed;
var newX = self.x + moveX;
var newY = self.y + moveY;
var targetAngle = Math.atan2(dy, dx);
tween.stop(self, {
rotation: true
});
tween(self, {
rotation: targetAngle
}, {
duration: 300,
easing: tween.easeOut
});
if (!checkWallCollision(newX, self.y)) {
self.x = newX;
}
if (!checkWallCollision(self.x, newY)) {
self.y = newY;
}
}
if (distance < 300 && self.shootCooldown <= 0) {
var length = Math.sqrt(dx * dx + dy * dy);
var dirX = dx / length;
var dirY = dy / length;
var whiteBullet = new WhiteBullet();
whiteBullet.x = self.x;
whiteBullet.y = self.y;
whiteBullet.directionX = dirX;
whiteBullet.directionY = dirY;
whiteBullets.push(whiteBullet);
game.addChild(whiteBullet);
self.shootCooldown = 120;
LK.getSound('shoot').play();
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2F4F2F
});
/****
* Game Code
****/
var gridWidth = 32;
var gridHeight = 42;
var cellSize = 64;
var walls = [];
var skinTanks = [];
var redTanks = [];
var greenTanks = [];
var playerBullets = [];
var enemyBullets = [];
var dynamites = [];
var acidBombs = [];
var explosions = [];
var medkits = [];
var whiteTanks = [];
var blackTanks = [];
var whiteBullets = [];
var blackBullets = [];
var electricFields = [];
var blackHoles = [];
var playerTank;
var portal;
var currentLevel = 1;
var gameStarted = false;
var isDragging = false;
var gamePaused = false;
var showingMainMenu = true;
// Main menu container
var mainMenu = new Container();
mainMenu.visible = true;
LK.gui.center.addChild(mainMenu);
// Main menu background image
var menuBackground = LK.getAsset('darkGreen', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 32,
scaleY: 43,
alpha: 0.8
});
mainMenu.addChild(menuBackground);
// Play button
var playButton = new Text2('PLAY', {
size: 120,
fill: 0xFFFFFF,
font: "monospace"
});
playButton.anchor.set(0.5, 0.5);
playButton.x = 0;
playButton.y = 0;
mainMenu.addChild(playButton);
// Version text
var versionText = new Text2('v.0.1.4', {
size: 80,
fill: 0xFFFF00,
font: "monospace"
});
versionText.anchor.set(1, 1);
versionText.x = 950; // Adjusted position to ensure visibility
versionText.y = 1300; // Adjusted position to ensure visibility
mainMenu.addChild(versionText);
// Experiments screen container
var experimentsScreen = new Container();
experimentsScreen.visible = false;
LK.gui.center.addChild(experimentsScreen);
// Experiments screen background
var experimentsBackground = LK.getAsset('darkGreen', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 32,
scaleY: 43,
alpha: 0.8
});
experimentsScreen.addChild(experimentsBackground);
// Experiments title
var experimentsTitle = new Text2('Do You Wanna Activate Experiments', {
size: 80,
fill: 0xFFFFFF,
font: "monospace"
});
experimentsTitle.anchor.set(0.5, 0.5);
experimentsTitle.x = 0;
experimentsTitle.y = -200;
experimentsScreen.addChild(experimentsTitle);
// Initialize new enemies setting from storage
var newEnemiesEnabled = storage.newEnemiesEnabled || false;
// New enemies toggle button
var newEnemiesButton = new Text2(newEnemiesEnabled ? 'New Enemies - On' : 'New Enemies - Off', {
size: 60,
fill: newEnemiesEnabled ? 0x00FF00 : 0xFF0000,
font: "monospace"
});
newEnemiesButton.anchor.set(0.5, 0.5);
newEnemiesButton.x = 0;
newEnemiesButton.y = 0;
experimentsScreen.addChild(newEnemiesButton);
// New enemies button click handler
newEnemiesButton.down = function (x, y, obj) {
newEnemiesEnabled = !newEnemiesEnabled;
storage.newEnemiesEnabled = newEnemiesEnabled;
newEnemiesButton.setText(newEnemiesEnabled ? 'New Enemies - On' : 'New Enemies - Off');
newEnemiesButton.fill = newEnemiesEnabled ? 0x00FF00 : 0xFF0000;
newEnemiesButton.tint = newEnemiesEnabled ? 0x00FF00 : 0xFF0000;
};
// Continue button to start game after experiments screen
var continueButton = new Text2('CONTINUE', {
size: 80,
fill: 0xFFFFFF,
font: "monospace"
});
continueButton.anchor.set(0.5, 0.5);
continueButton.x = 0;
continueButton.y = 200;
experimentsScreen.addChild(continueButton);
// Continue button click handler
continueButton.down = function (x, y, obj) {
experimentsScreen.visible = false;
showingMainMenu = false;
gameStarted = true;
startLevel();
};
// Play button click handler
playButton.down = function (x, y, obj) {
mainMenu.visible = false;
experimentsScreen.visible = true;
};
var nextLevelScreen = new Container();
nextLevelScreen.visible = false;
LK.gui.center.addChild(nextLevelScreen);
// Next level screen background
var nextLevelBackground = LK.getAsset('wall', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 12,
scaleY: 8,
tint: 0x000000,
alpha: 0.9
});
nextLevelScreen.addChild(nextLevelBackground);
// Next level button
var nextLevelButton = new Text2('NEXT LEVEL', {
size: 80,
fill: 0xFFFFFF,
font: "monospace"
});
nextLevelButton.anchor.set(0.5, 0.5);
nextLevelButton.x = 0;
nextLevelButton.y = 0;
nextLevelScreen.addChild(nextLevelButton);
// Next level button click handler
nextLevelButton.down = function (x, y, obj) {
nextLevelScreen.visible = false;
gamePaused = false;
// Generate new level
startLevel();
};
// Return to main menu button
var returnToMenuButton = new Text2('RETURN TO MAIN MENU', {
size: 60,
fill: 0xFFFFFF,
font: "monospace"
});
returnToMenuButton.anchor.set(0.5, 0.5);
returnToMenuButton.x = 0;
returnToMenuButton.y = 100;
nextLevelScreen.addChild(returnToMenuButton);
// Return to main menu button click handler
returnToMenuButton.down = function (x, y, obj) {
// Clear all game objects
for (var i = walls.length - 1; i >= 0; i--) {
walls[i].destroy();
}
walls = [];
for (var i = skinTanks.length - 1; i >= 0; i--) {
skinTanks[i].destroy();
}
skinTanks = [];
for (var i = redTanks.length - 1; i >= 0; i--) {
redTanks[i].destroy();
}
redTanks = [];
for (var i = greenTanks.length - 1; i >= 0; i--) {
greenTanks[i].destroy();
}
greenTanks = [];
for (var i = medkits.length - 1; i >= 0; i--) {
medkits[i].destroy();
}
medkits = [];
for (var i = playerBullets.length - 1; i >= 0; i--) {
playerBullets[i].destroy();
}
playerBullets = [];
for (var i = enemyBullets.length - 1; i >= 0; i--) {
enemyBullets[i].destroy();
}
enemyBullets = [];
for (var i = dynamites.length - 1; i >= 0; i--) {
dynamites[i].destroy();
}
dynamites = [];
for (var i = acidBombs.length - 1; i >= 0; i--) {
acidBombs[i].destroy();
}
acidBombs = [];
for (var i = explosions.length - 1; i >= 0; i--) {
explosions[i].destroy();
}
explosions = [];
for (var i = whiteTanks.length - 1; i >= 0; i--) {
whiteTanks[i].destroy();
}
whiteTanks = [];
for (var i = blackTanks.length - 1; i >= 0; i--) {
blackTanks[i].destroy();
}
blackTanks = [];
for (var i = whiteBullets.length - 1; i >= 0; i--) {
whiteBullets[i].destroy();
}
whiteBullets = [];
for (var i = blackBullets.length - 1; i >= 0; i--) {
blackBullets[i].destroy();
}
blackBullets = [];
for (var i = electricFields.length - 1; i >= 0; i--) {
electricFields[i].destroy();
}
electricFields = [];
for (var i = blackHoles.length - 1; i >= 0; i--) {
blackHoles[i].destroy();
}
blackHoles = [];
// Destroy player tank and portal if they exist
if (playerTank) {
playerTank.destroy();
playerTank = null;
}
if (portal) {
portal.destroy();
portal = null;
}
// Reset game state
currentLevel = 1;
gameStarted = false;
isDragging = false;
gamePaused = false;
showingMainMenu = true;
levelsWithoutDying = 0;
storage.levelsWithoutDying = levelsWithoutDying;
LK.setScore(0);
// Hide next level screen and show main menu
nextLevelScreen.visible = false;
mainMenu.visible = true;
};
var healthBarBackground = LK.getAsset('wall', {
anchorX: 0,
anchorY: 1,
scaleX: 4,
scaleY: 0.8,
tint: 0x333333
});
LK.gui.bottomLeft.addChild(healthBarBackground);
var healthBarFill = LK.getAsset('wall', {
anchorX: 0,
anchorY: 1,
scaleX: 4,
scaleY: 0.8,
tint: 0x00ff00
});
LK.gui.bottomLeft.addChild(healthBarFill);
var levelText = new Text2('Level: 1', {
size: 50,
fill: 0xFFFFFF,
font: "monospace"
});
levelText.anchor.set(0.5, 0);
LK.gui.top.addChild(levelText);
var scoreText = new Text2('Score: 0', {
size: 40,
fill: 0xFFFFFF,
font: "monospace"
});
scoreText.anchor.set(0.5, 0);
scoreText.x = 0;
scoreText.y = 80;
LK.gui.top.addChild(scoreText);
var bestScoreText = new Text2('Best: ' + (storage.bestScore || 0), {
size: 35,
fill: 0xFFFF00,
font: "monospace"
});
bestScoreText.anchor.set(0.5, 0);
bestScoreText.x = 0;
bestScoreText.y = 130;
LK.gui.top.addChild(bestScoreText);
// Achievement button
var achievementButton = new Text2('ACHIEVEMENTS', {
size: 30,
fill: 0xFFFFFF,
font: "monospace"
});
achievementButton.anchor.set(1, 0);
LK.gui.topRight.addChild(achievementButton);
// Achievement menu (initially hidden)
var achievementMenu = new Container();
achievementMenu.visible = false;
LK.gui.center.addChild(achievementMenu);
// Achievement menu background
var menuBackground = LK.getAsset('wall', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 15,
scaleY: 20,
tint: 0x000000,
alpha: 0.8
});
achievementMenu.addChild(menuBackground);
// Achievement title background
var titleBackground = LK.getAsset('wall', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 8,
scaleY: 1.5,
tint: 0x000000,
alpha: 0.9
});
titleBackground.x = 0;
titleBackground.y = -400;
achievementMenu.addChild(titleBackground);
// Achievement title
var achievementTitle = new Text2('ACHIEVEMENTS', {
size: 60,
fill: 0xFFFF00,
font: "monospace"
});
achievementTitle.anchor.set(0.5, 0.5);
achievementTitle.x = 0;
achievementTitle.y = -400;
achievementMenu.addChild(achievementTitle);
// Initialize achievements in storage if they don't exist
var achievements = storage.achievements || {
killAllEnemies: false,
useFirstMedkit: false,
killFirstEnemy: false,
finishWithoutDying: false,
get150Score: false,
beatPreviousBest: false,
arriveAtLevel3: false,
kill50EnemiesTotal: false,
killWhiteTank: false,
killBlackTank: false,
have1000Score: false,
pass5LevelsWithoutDying: false
};
storage.achievements = achievements;
// Achievement tracking variables
var totalEnemiesAtStart = 0;
var hasUsedMedkit = false;
var hasKilledEnemy = false;
var hasBeenHurt = false;
var totalEnemiesKilled = storage.totalEnemiesKilled || 0;
var hasKilledWhiteTank = storage.hasKilledWhiteTank || false;
var hasKilledBlackTank = storage.hasKilledBlackTank || false;
var levelsWithoutDying = storage.levelsWithoutDying || 0;
var hasReachedScore1000 = storage.hasReachedScore1000 || false;
// Achievement text elements
var achievement1Text = new Text2('', {
size: 40,
fill: 0xFFFFFF,
font: "monospace"
});
achievement1Text.anchor.set(0, 0.5);
achievement1Text.x = -300;
achievement1Text.y = -200;
achievementMenu.addChild(achievement1Text);
var achievement2Text = new Text2('', {
size: 40,
fill: 0xFFFFFF,
font: "monospace"
});
achievement2Text.anchor.set(0, 0.5);
achievement2Text.x = -300;
achievement2Text.y = -100;
achievementMenu.addChild(achievement2Text);
var achievement3Text = new Text2('', {
size: 40,
fill: 0xFFFFFF,
font: "monospace"
});
achievement3Text.anchor.set(0, 0.5);
achievement3Text.x = -300;
achievement3Text.y = 0;
achievementMenu.addChild(achievement3Text);
var achievement4Text = new Text2('', {
size: 40,
fill: 0xFFFFFF,
font: "monospace"
});
achievement4Text.anchor.set(0, 0.5);
achievement4Text.x = -300;
achievement4Text.y = 100;
achievementMenu.addChild(achievement4Text);
var achievement5Text = new Text2('', {
size: 40,
fill: 0xFFFFFF,
font: "monospace"
});
achievement5Text.anchor.set(0, 0.5);
achievement5Text.x = -300;
achievement5Text.y = 200;
achievementMenu.addChild(achievement5Text);
var achievement6Text = new Text2('', {
size: 40,
fill: 0xFFFFFF,
font: "monospace"
});
achievement6Text.anchor.set(0, 0.5);
achievement6Text.x = -300;
achievement6Text.y = 300;
achievementMenu.addChild(achievement6Text);
var achievement7Text = new Text2('', {
size: 40,
fill: 0xFFFFFF,
font: "monospace"
});
achievement7Text.anchor.set(0, 0.5);
achievement7Text.x = -300;
achievement7Text.y = 400;
achievementMenu.addChild(achievement7Text);
var achievement8Text = new Text2('', {
size: 40,
fill: 0xFFFFFF,
font: "monospace"
});
achievement8Text.anchor.set(0, 0.5);
achievement8Text.x = -300;
achievement8Text.y = 500;
achievementMenu.addChild(achievement8Text);
function updateAchievementTexts() {
achievement1Text.setText('Kill A White Tank - ' + (achievements.killWhiteTank ? 'DONE' : 'NOT DONE'));
achievement2Text.setText('Kill A Black Tank - ' + (achievements.killBlackTank ? 'DONE' : 'NOT DONE'));
achievement3Text.setText('Have 1000 Score - ' + (achievements.have1000Score ? 'DONE' : 'NOT DONE'));
achievement4Text.setText('Pass 5 Levels Without Dying - ' + (achievements.pass5LevelsWithoutDying ? 'DONE' : 'NOT DONE'));
achievement5Text.setText('Kill all enemies in map - ' + (achievements.killAllEnemies ? 'DONE' : 'NOT DONE'));
achievement6Text.setText('Use your first MedKit - ' + (achievements.useFirstMedkit ? 'DONE' : 'NOT DONE'));
achievement7Text.setText('Kill your first enemy - ' + (achievements.killFirstEnemy ? 'DONE' : 'NOT DONE'));
achievement8Text.setText('Finish a level without dying - ' + (achievements.finishWithoutDying ? 'DONE' : 'NOT DONE'));
// Set colors for achievement text - green for DONE, red for NOT DONE
if (achievements.killWhiteTank) {
achievement1Text.fill = 0x00FF00;
achievement1Text.tint = 0x00FF00;
} else {
achievement1Text.fill = 0xFF0000;
achievement1Text.tint = 0xFF0000;
}
if (achievements.killBlackTank) {
achievement2Text.fill = 0x00FF00;
achievement2Text.tint = 0x00FF00;
} else {
achievement2Text.fill = 0xFF0000;
achievement2Text.tint = 0xFF0000;
}
if (achievements.have1000Score) {
achievement3Text.fill = 0x00FF00;
achievement3Text.tint = 0x00FF00;
} else {
achievement3Text.fill = 0xFF0000;
achievement3Text.tint = 0xFF0000;
}
if (achievements.pass5LevelsWithoutDying) {
achievement4Text.fill = 0x00FF00;
achievement4Text.tint = 0x00FF00;
} else {
achievement4Text.fill = 0xFF0000;
achievement4Text.tint = 0xFF0000;
}
if (achievements.killAllEnemies) {
achievement5Text.fill = 0x00FF00;
achievement5Text.tint = 0x00FF00;
} else {
achievement5Text.fill = 0xFF0000;
achievement5Text.tint = 0xFF0000;
}
if (achievements.useFirstMedkit) {
achievement6Text.fill = 0x00FF00;
achievement6Text.tint = 0x00FF00;
} else {
achievement6Text.fill = 0xFF0000;
achievement6Text.tint = 0xFF0000;
}
if (achievements.killFirstEnemy) {
achievement7Text.fill = 0x00FF00;
achievement7Text.tint = 0x00FF00;
} else {
achievement7Text.fill = 0xFF0000;
achievement7Text.tint = 0xFF0000;
}
if (achievements.finishWithoutDying) {
achievement8Text.fill = 0x00FF00;
achievement8Text.tint = 0x00FF00;
} else {
achievement8Text.fill = 0xFF0000;
achievement8Text.tint = 0xFF0000;
}
}
// Initial text update
updateAchievementTexts();
// Achievement button click handler
achievementButton.down = function (x, y, obj) {
achievementMenu.visible = !achievementMenu.visible;
gamePaused = achievementMenu.visible;
updateAchievementTexts();
};
// Close menu when clicking background
menuBackground.down = function (x, y, obj) {
achievementMenu.visible = false;
gamePaused = false;
};
function generateMaze() {
walls = [];
var playerTankX = 1024;
var playerTankY = 1366;
for (var x = 0; x < gridWidth; x++) {
for (var y = 0; y < gridHeight; y++) {
var wallX = x * cellSize + cellSize / 2;
var wallY = y * cellSize + cellSize / 2;
// Check if this wall position would be too close to player tank position
var dx = Math.abs(wallX - playerTankX);
var dy = Math.abs(wallY - playerTankY);
var isNearPlayerTank = dx < 64 && dy < 64; // Within one cell distance
if (x === 0 || x === gridWidth - 1 || y === 0 || y === gridHeight - 1) {
if (!isNearPlayerTank) {
var wall = new Wall();
wall.x = wallX;
wall.y = wallY;
walls.push(wall);
game.addChild(wall);
}
} else if (Math.random() < 0.3 && !isNearPlayerTank) {
var wall = new Wall();
wall.x = wallX;
wall.y = wallY;
walls.push(wall);
game.addChild(wall);
}
}
}
}
function spawnEnemies() {
var skinCount = Math.floor(Math.random() * 6) + 10; // 10-15 skin tanks
var redCount = Math.floor(Math.random() * 6) + 5; // 5-10 red tanks
var greenCount = Math.floor(Math.random() * 6) + 7; // 7-12 green tanks
for (var i = 0; i < skinCount; i++) {
var tank = new SkinTank();
do {
tank.x = Math.random() * (2048 - 200) + 100;
tank.y = Math.random() * (2732 - 200) + 100;
} while (checkWallCollision(tank.x, tank.y) || getDistanceToPlayer(tank.x, tank.y) < 640);
skinTanks.push(tank);
game.addChild(tank);
}
for (var i = 0; i < redCount; i++) {
var tank = new RedTank();
do {
tank.x = Math.random() * (2048 - 200) + 100;
tank.y = Math.random() * (2732 - 200) + 100;
} while (checkWallCollision(tank.x, tank.y) || getDistanceToPlayer(tank.x, tank.y) < 640);
redTanks.push(tank);
game.addChild(tank);
}
for (var i = 0; i < greenCount; i++) {
var tank = new GreenTank();
do {
tank.x = Math.random() * (2048 - 200) + 100;
tank.y = Math.random() * (2732 - 200) + 100;
} while (checkWallCollision(tank.x, tank.y) || getDistanceToPlayer(tank.x, tank.y) < 640);
greenTanks.push(tank);
game.addChild(tank);
}
// Spawn white and black tanks if new enemies are enabled
if (newEnemiesEnabled) {
var whiteCount = Math.floor(Math.random() * 3) + 2; // 2-4 white tanks
var blackCount = Math.floor(Math.random() * 3) + 1; // 1-3 black tanks
for (var i = 0; i < whiteCount; i++) {
var tank = new WhiteTank();
do {
tank.x = Math.random() * (2048 - 200) + 100;
tank.y = Math.random() * (2732 - 200) + 100;
} while (checkWallCollision(tank.x, tank.y) || getDistanceToPlayer(tank.x, tank.y) < 640);
whiteTanks.push(tank);
game.addChild(tank);
}
for (var i = 0; i < blackCount; i++) {
var tank = new BlackTank();
do {
tank.x = Math.random() * (2048 - 200) + 100;
tank.y = Math.random() * (2732 - 200) + 100;
} while (checkWallCollision(tank.x, tank.y) || getDistanceToPlayer(tank.x, tank.y) < 640);
blackTanks.push(tank);
game.addChild(tank);
}
}
}
function checkWallCollision(x, y) {
for (var i = 0; i < walls.length; i++) {
var wall = walls[i];
var dx = Math.abs(x - wall.x);
var dy = Math.abs(y - wall.y);
if (dx < 32 && dy < 32) {
return true;
}
}
return false;
}
function getDistanceToPlayer(x, y) {
if (!playerTank) {
return 1000;
}
var dx = x - playerTank.x;
var dy = y - playerTank.y;
return Math.sqrt(dx * dx + dy * dy);
}
function spawnMedkits() {
var medkitCount = Math.floor(Math.random() * 4) + 3; // 3-6 medkits per level
for (var i = 0; i < medkitCount; i++) {
var medkit = new Medkit();
do {
medkit.x = Math.random() * (2048 - 200) + 100;
medkit.y = Math.random() * (2732 - 200) + 100;
} while (checkWallCollision(medkit.x, medkit.y) || getDistanceToPlayer(medkit.x, medkit.y) < 150);
medkits.push(medkit);
game.addChild(medkit);
}
}
function createExplosion(x, y, radius, damage) {
var explosion = LK.getAsset('explosion', {
anchorX: 0.5,
anchorY: 0.5,
x: x,
y: y,
scaleX: radius / 60,
scaleY: radius / 60,
alpha: 0.8
});
game.addChild(explosion);
explosions.push(explosion);
tween(explosion, {
alpha: 0,
scaleX: explosion.scaleX * 1.5,
scaleY: explosion.scaleY * 1.5
}, {
duration: 500,
onFinish: function onFinish() {
explosion.destroy();
var index = explosions.indexOf(explosion);
if (index > -1) {
explosions.splice(index, 1);
}
}
});
var dx = playerTank.x - x;
var dy = playerTank.y - y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < radius) {
playerTank.health -= damage;
LK.getSound('hit').play();
// Track that player has been hurt
hasBeenHurt = true;
if (playerTank.health <= 0) {
LK.showGameOver();
}
}
LK.getSound('explosion').play();
}
function startLevel() {
for (var i = walls.length - 1; i >= 0; i--) {
walls[i].destroy();
}
walls = [];
for (var i = skinTanks.length - 1; i >= 0; i--) {
skinTanks[i].destroy();
}
skinTanks = [];
for (var i = redTanks.length - 1; i >= 0; i--) {
redTanks[i].destroy();
}
redTanks = [];
for (var i = greenTanks.length - 1; i >= 0; i--) {
greenTanks[i].destroy();
}
greenTanks = [];
for (var i = medkits.length - 1; i >= 0; i--) {
medkits[i].destroy();
}
medkits = [];
for (var i = whiteTanks.length - 1; i >= 0; i--) {
whiteTanks[i].destroy();
}
whiteTanks = [];
for (var i = blackTanks.length - 1; i >= 0; i--) {
blackTanks[i].destroy();
}
blackTanks = [];
for (var i = whiteBullets.length - 1; i >= 0; i--) {
whiteBullets[i].destroy();
}
whiteBullets = [];
for (var i = blackBullets.length - 1; i >= 0; i--) {
blackBullets[i].destroy();
}
blackBullets = [];
for (var i = electricFields.length - 1; i >= 0; i--) {
electricFields[i].destroy();
}
electricFields = [];
for (var i = blackHoles.length - 1; i >= 0; i--) {
blackHoles[i].destroy();
}
blackHoles = [];
generateMaze();
spawnEnemies();
spawnMedkits();
// Track total enemies for achievement
totalEnemiesAtStart = skinTanks.length + redTanks.length + greenTanks.length + whiteTanks.length + blackTanks.length;
// Reset achievement tracking variables
hasUsedMedkit = false;
hasKilledEnemy = false;
hasBeenHurt = false;
// Only create player tank if it doesn't exist (first level)
if (!playerTank) {
playerTank = new PlayerTank();
playerTank.x = 1024;
playerTank.y = 1366;
playerTank.health = 100;
game.addChild(playerTank);
} else {
// Just reset position and health for existing player tank
playerTank.x = 1024;
playerTank.y = 1366;
playerTank.health = 100;
}
portal = new Portal();
do {
portal.x = Math.random() * (2048 - 200) + 100;
portal.y = Math.random() * (2732 - 200) + 100;
} while (checkWallCollision(portal.x, portal.y) || getDistanceToPlayer(portal.x, portal.y) < 300);
game.addChild(portal);
levelText.setText('Level: ' + currentLevel);
gameStarted = true;
// Achievement: Arrive at level 3
if (currentLevel >= 3 && !achievements.arriveAtLevel3) {
achievements.arriveAtLevel3 = true;
storage.achievements = achievements;
}
}
// Mouse functionality - player tank follows mouse position
game.down = function (x, y, obj) {
// Only start dragging if mouse is pressed on the player tank and achievements menu is not visible and next level screen is not visible
if (playerTank && playerTank.x && playerTank.y && !achievementMenu.visible && !nextLevelScreen.visible) {
var dx = x - playerTank.x;
var dy = y - playerTank.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= 60) {
// Within tank radius (tank is 120px wide, so radius ~60)
isDragging = true;
}
}
};
game.move = function (x, y, obj) {
if (!gameStarted || !playerTank || !isDragging || achievementMenu.visible || nextLevelScreen.visible) {
return;
}
// Only allow dragging if mouse is not on a wall
if (checkWallCollision(x, y)) {
isDragging = false; // Stop dragging when mouse is on wall
return;
}
// Calculate direction from tank to mouse for rotation
var dx = x - playerTank.x;
var dy = y - playerTank.y;
var targetAngle = Math.atan2(dy, dx);
// Stop any existing rotation tween
tween.stop(playerTank, {
rotation: true
});
// Smoothly rotate the tank to face the mouse direction
tween(playerTank, {
rotation: targetAngle
}, {
duration: 200,
easing: tween.easeOut
});
// Move player tank directly to mouse position if no wall collision
playerTank.x = x;
playerTank.y = y;
};
game.up = function (x, y, obj) {
isDragging = false;
if (!gameStarted || !playerTank || achievementMenu.visible || nextLevelScreen.visible) {
return;
}
if (playerTank.shootCooldown <= 0) {
var dx = x - playerTank.x;
var dy = y - playerTank.y;
var length = Math.sqrt(dx * dx + dy * dy);
if (length > 0) {
// Calculate the angle to face the shooting direction
var targetAngle = Math.atan2(dy, dx);
// Stop any existing rotation tween
tween.stop(playerTank, {
rotation: true
});
// Rotate the tank to face the shooting direction
tween(playerTank, {
rotation: targetAngle
}, {
duration: 200,
easing: tween.easeOut
});
var dirX = dx / length;
var dirY = dy / length;
var bullet = new PlayerBullet();
bullet.x = playerTank.x;
bullet.y = playerTank.y;
bullet.directionX = dirX;
bullet.directionY = dirY;
playerBullets.push(bullet);
game.addChild(bullet);
playerTank.shootCooldown = 15;
LK.getSound('shoot').play();
}
}
};
// Game Over screen setup
var gameOverHandled = false;
// Override LK.showGameOver to add custom functionality
var originalShowGameOver = LK.showGameOver;
LK.showGameOver = function () {
if (!gameOverHandled) {
gameOverHandled = true;
// Create game over screen with return to main menu button
var gameOverScreen = new Container();
gameOverScreen.visible = true;
LK.gui.center.addChild(gameOverScreen);
// Game over background
var gameOverBackground = LK.getAsset('wall', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 12,
scaleY: 8,
tint: 0x000000,
alpha: 0.9
});
gameOverScreen.addChild(gameOverBackground);
// Game Over text
var gameOverText = new Text2('GAME OVER', {
size: 80,
fill: 0xFF0000,
font: "monospace"
});
gameOverText.anchor.set(0.5, 0.5);
gameOverText.x = 0;
gameOverText.y = -50;
gameOverScreen.addChild(gameOverText);
// Return to main menu button for game over
var gameOverReturnButton = new Text2('RETURN TO MAIN MENU', {
size: 60,
fill: 0xFFFFFF,
font: "monospace"
});
gameOverReturnButton.anchor.set(0.5, 0.5);
gameOverReturnButton.x = 0;
gameOverReturnButton.y = 50;
gameOverScreen.addChild(gameOverReturnButton);
// Return to main menu button click handler for game over
gameOverReturnButton.down = function (x, y, obj) {
// Clear all game objects
for (var i = walls.length - 1; i >= 0; i--) {
walls[i].destroy();
}
walls = [];
for (var i = skinTanks.length - 1; i >= 0; i--) {
skinTanks[i].destroy();
}
skinTanks = [];
for (var i = redTanks.length - 1; i >= 0; i--) {
redTanks[i].destroy();
}
redTanks = [];
for (var i = greenTanks.length - 1; i >= 0; i--) {
greenTanks[i].destroy();
}
greenTanks = [];
for (var i = medkits.length - 1; i >= 0; i--) {
medkits[i].destroy();
}
medkits = [];
for (var i = playerBullets.length - 1; i >= 0; i--) {
playerBullets[i].destroy();
}
playerBullets = [];
for (var i = enemyBullets.length - 1; i >= 0; i--) {
enemyBullets[i].destroy();
}
enemyBullets = [];
for (var i = dynamites.length - 1; i >= 0; i--) {
dynamites[i].destroy();
}
dynamites = [];
for (var i = acidBombs.length - 1; i >= 0; i--) {
acidBombs[i].destroy();
}
acidBombs = [];
for (var i = explosions.length - 1; i >= 0; i--) {
explosions[i].destroy();
}
explosions = [];
for (var i = whiteTanks.length - 1; i >= 0; i--) {
whiteTanks[i].destroy();
}
whiteTanks = [];
for (var i = blackTanks.length - 1; i >= 0; i--) {
blackTanks[i].destroy();
}
blackTanks = [];
for (var i = whiteBullets.length - 1; i >= 0; i--) {
whiteBullets[i].destroy();
}
whiteBullets = [];
for (var i = blackBullets.length - 1; i >= 0; i--) {
blackBullets[i].destroy();
}
blackBullets = [];
for (var i = electricFields.length - 1; i >= 0; i--) {
electricFields[i].destroy();
}
electricFields = [];
for (var i = blackHoles.length - 1; i >= 0; i--) {
blackHoles[i].destroy();
}
blackHoles = [];
// Destroy player tank and portal if they exist
if (playerTank) {
playerTank.destroy();
playerTank = null;
}
if (portal) {
portal.destroy();
portal = null;
}
// Reset game state
currentLevel = 1;
gameStarted = false;
isDragging = false;
gamePaused = false;
showingMainMenu = true;
gameOverHandled = false;
levelsWithoutDying = 0;
storage.levelsWithoutDying = levelsWithoutDying;
LK.setScore(0);
// Hide game over screen and show main menu
gameOverScreen.destroy();
mainMenu.visible = true;
};
// Auto-hide after 3 seconds and call original game over
LK.setTimeout(function () {
gameOverScreen.destroy();
originalShowGameOver();
}, 3000);
} else {
originalShowGameOver();
}
};
game.update = function () {
if (showingMainMenu) {
return;
}
if (!gameStarted) {
return;
}
if (gamePaused) return;
// Movement is handled via touch/drag in game.move method
for (var i = playerBullets.length - 1; i >= 0; i--) {
var bullet = playerBullets[i];
if (bullet.x < 0 || bullet.x > 2048 || bullet.y < 0 || bullet.y > 2732) {
bullet.destroy();
playerBullets.splice(i, 1);
continue;
}
if (checkWallCollision(bullet.x, bullet.y)) {
bullet.destroy();
playerBullets.splice(i, 1);
continue;
}
for (var j = skinTanks.length - 1; j >= 0; j--) {
if (bullet.intersects(skinTanks[j])) {
skinTanks[j].health -= 3;
bullet.destroy();
playerBullets.splice(i, 1);
if (skinTanks[j].health <= 0) {
createExplosion(skinTanks[j].x, skinTanks[j].y, 100, 15);
skinTanks[j].destroy();
skinTanks.splice(j, 1);
LK.setScore(LK.getScore() + 10);
// Track total enemies killed
totalEnemiesKilled++;
storage.totalEnemiesKilled = totalEnemiesKilled;
// Achievement: Kill first enemy
if (!hasKilledEnemy) {
hasKilledEnemy = true;
achievements.killFirstEnemy = true;
storage.achievements = achievements;
}
// Achievement: Kill 50 enemies total
if (totalEnemiesKilled >= 50 && !achievements.kill50EnemiesTotal) {
achievements.kill50EnemiesTotal = true;
storage.achievements = achievements;
}
}
break;
}
}
for (var j = redTanks.length - 1; j >= 0; j--) {
if (bullet.intersects(redTanks[j])) {
redTanks[j].health -= 10;
bullet.destroy();
playerBullets.splice(i, 1);
if (redTanks[j].health <= 0) {
redTanks[j].destroy();
redTanks.splice(j, 1);
LK.setScore(LK.getScore() + 20);
// Track total enemies killed
totalEnemiesKilled++;
storage.totalEnemiesKilled = totalEnemiesKilled;
// Achievement: Kill first enemy
if (!hasKilledEnemy) {
hasKilledEnemy = true;
achievements.killFirstEnemy = true;
storage.achievements = achievements;
}
// Achievement: Kill 50 enemies total
if (totalEnemiesKilled >= 50 && !achievements.kill50EnemiesTotal) {
achievements.kill50EnemiesTotal = true;
storage.achievements = achievements;
}
}
break;
}
}
for (var j = greenTanks.length - 1; j >= 0; j--) {
if (bullet.intersects(greenTanks[j])) {
greenTanks[j].health -= 25;
bullet.destroy();
playerBullets.splice(i, 1);
if (greenTanks[j].health <= 0) {
greenTanks[j].destroy();
greenTanks.splice(j, 1);
LK.setScore(LK.getScore() + 30);
// Track total enemies killed
totalEnemiesKilled++;
storage.totalEnemiesKilled = totalEnemiesKilled;
// Achievement: Kill first enemy
if (!hasKilledEnemy) {
hasKilledEnemy = true;
achievements.killFirstEnemy = true;
storage.achievements = achievements;
}
// Achievement: Kill 50 enemies total
if (totalEnemiesKilled >= 50 && !achievements.kill50EnemiesTotal) {
achievements.kill50EnemiesTotal = true;
storage.achievements = achievements;
}
}
break;
}
}
for (var j = whiteTanks.length - 1; j >= 0; j--) {
if (bullet.intersects(whiteTanks[j])) {
whiteTanks[j].health -= 25;
bullet.destroy();
playerBullets.splice(i, 1);
if (whiteTanks[j].health <= 0) {
whiteTanks[j].destroy();
whiteTanks.splice(j, 1);
LK.setScore(LK.getScore() + 40);
totalEnemiesKilled++;
storage.totalEnemiesKilled = totalEnemiesKilled;
if (!hasKilledEnemy) {
hasKilledEnemy = true;
achievements.killFirstEnemy = true;
storage.achievements = achievements;
}
if (totalEnemiesKilled >= 50 && !achievements.kill50EnemiesTotal) {
achievements.kill50EnemiesTotal = true;
storage.achievements = achievements;
}
// Achievement: Kill a white tank
if (!hasKilledWhiteTank) {
hasKilledWhiteTank = true;
storage.hasKilledWhiteTank = hasKilledWhiteTank;
achievements.killWhiteTank = true;
storage.achievements = achievements;
}
}
break;
}
}
for (var j = blackTanks.length - 1; j >= 0; j--) {
if (bullet.intersects(blackTanks[j])) {
blackTanks[j].health -= 25;
bullet.destroy();
playerBullets.splice(i, 1);
if (blackTanks[j].health <= 0) {
blackTanks[j].destroy();
blackTanks.splice(j, 1);
LK.setScore(LK.getScore() + 50);
totalEnemiesKilled++;
storage.totalEnemiesKilled = totalEnemiesKilled;
if (!hasKilledEnemy) {
hasKilledEnemy = true;
achievements.killFirstEnemy = true;
storage.achievements = achievements;
}
if (totalEnemiesKilled >= 50 && !achievements.kill50EnemiesTotal) {
achievements.kill50EnemiesTotal = true;
storage.achievements = achievements;
}
// Achievement: Kill a black tank
if (!hasKilledBlackTank) {
hasKilledBlackTank = true;
storage.hasKilledBlackTank = hasKilledBlackTank;
achievements.killBlackTank = true;
storage.achievements = achievements;
}
}
break;
}
}
}
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var bullet = enemyBullets[i];
if (bullet.x < 0 || bullet.x > 2048 || bullet.y < 0 || bullet.y > 2732) {
bullet.destroy();
enemyBullets.splice(i, 1);
continue;
}
if (checkWallCollision(bullet.x, bullet.y)) {
bullet.destroy();
enemyBullets.splice(i, 1);
continue;
}
if (bullet.intersects(playerTank)) {
playerTank.health -= bullet.damage;
bullet.destroy();
enemyBullets.splice(i, 1);
LK.getSound('hit').play();
// Track that player has been hurt
hasBeenHurt = true;
if (playerTank.health <= 0) {
LK.showGameOver();
}
continue;
}
}
for (var i = dynamites.length - 1; i >= 0; i--) {
var dynamite = dynamites[i];
if (dynamite.x < 0 || dynamite.x > 2048 || dynamite.y < 0 || dynamite.y > 2732) {
createExplosion(dynamite.x, dynamite.y, dynamite.explosionRadius, dynamite.damage);
dynamite.destroy();
dynamites.splice(i, 1);
continue;
}
if (checkWallCollision(dynamite.x, dynamite.y)) {
createExplosion(dynamite.x, dynamite.y, dynamite.explosionRadius, dynamite.damage);
dynamite.destroy();
dynamites.splice(i, 1);
continue;
}
if (dynamite.intersects(playerTank)) {
createExplosion(dynamite.x, dynamite.y, dynamite.explosionRadius, dynamite.damage);
dynamite.destroy();
dynamites.splice(i, 1);
continue;
}
}
for (var i = acidBombs.length - 1; i >= 0; i--) {
var acidBomb = acidBombs[i];
if (acidBomb.x < 0 || acidBomb.x > 2048 || acidBomb.y < 0 || acidBomb.y > 2732) {
acidBomb.destroy();
acidBombs.splice(i, 1);
continue;
}
if (checkWallCollision(acidBomb.x, acidBomb.y)) {
acidBomb.destroy();
acidBombs.splice(i, 1);
continue;
}
if (acidBomb.intersects(playerTank)) {
playerTank.health -= acidBomb.damage;
playerTank.poisonTimer = acidBomb.poisonDuration;
playerTank.poisonDamage = acidBomb.poisonDamage;
acidBomb.destroy();
acidBombs.splice(i, 1);
LK.getSound('hit').play();
// Track that player has been hurt
hasBeenHurt = true;
if (playerTank.health <= 0) {
LK.showGameOver();
}
continue;
}
}
// Handle white bullets
for (var i = whiteBullets.length - 1; i >= 0; i--) {
var bullet = whiteBullets[i];
if (bullet.x < 0 || bullet.x > 2048 || bullet.y < 0 || bullet.y > 2732) {
bullet.destroy();
whiteBullets.splice(i, 1);
continue;
}
if (checkWallCollision(bullet.x, bullet.y)) {
bullet.destroy();
whiteBullets.splice(i, 1);
continue;
}
if (bullet.intersects(playerTank)) {
// Create electric field
var electricField = new ElectricField();
electricField.x = bullet.x;
electricField.y = bullet.y;
electricFields.push(electricField);
game.addChild(electricField);
bullet.destroy();
whiteBullets.splice(i, 1);
LK.getSound('explosion').play();
continue;
}
}
// Handle black bullets
for (var i = blackBullets.length - 1; i >= 0; i--) {
var bullet = blackBullets[i];
if (bullet.x < 0 || bullet.x > 2048 || bullet.y < 0 || bullet.y > 2732) {
bullet.destroy();
blackBullets.splice(i, 1);
continue;
}
if (checkWallCollision(bullet.x, bullet.y)) {
bullet.destroy();
blackBullets.splice(i, 1);
continue;
}
if (bullet.intersects(playerTank)) {
// Create black hole
var blackHole = new BlackHole();
blackHole.x = bullet.x;
blackHole.y = bullet.y;
blackHoles.push(blackHole);
game.addChild(blackHole);
bullet.destroy();
blackBullets.splice(i, 1);
LK.getSound('explosion').play();
continue;
}
// Check collision with white bullets
for (var j = whiteBullets.length - 1; j >= 0; j--) {
if (bullet.intersects(whiteBullets[j])) {
// Create black hole from black bullet
var blackHole = new BlackHole();
blackHole.x = bullet.x;
blackHole.y = bullet.y;
blackHoles.push(blackHole);
game.addChild(blackHole);
// Create electric field from white bullet
var electricField = new ElectricField();
electricField.x = whiteBullets[j].x;
electricField.y = whiteBullets[j].y;
electricFields.push(electricField);
game.addChild(electricField);
// Destroy both bullets
bullet.destroy();
blackBullets.splice(i, 1);
whiteBullets[j].destroy();
whiteBullets.splice(j, 1);
LK.getSound('explosion').play();
break;
}
}
}
for (var i = skinTanks.length - 1; i >= 0; i--) {
if (skinTanks[i].intersects(playerTank)) {
createExplosion(skinTanks[i].x, skinTanks[i].y, skinTanks[i].explosionRadius, 20);
skinTanks[i].destroy();
skinTanks.splice(i, 1);
}
}
for (var i = redTanks.length - 1; i >= 0; i--) {
if (redTanks[i].intersects(playerTank)) {
// Check if any part of player is within circular explosion area (radius 100)
// Player tank is 120px wide, so radius is 60px
var dx = playerTank.x - redTanks[i].x;
var dy = playerTank.y - redTanks[i].y;
var distance = Math.sqrt(dx * dx + dy * dy);
var playerRadius = 60; // Half of player tank width (120px)
var explosionRadius = 100;
// Check if there's a clear path from explosion center to player (no walls blocking)
var canDamagePlayer = true;
var stepSize = 32; // Check every 32 pixels along the path
var steps = Math.ceil(distance / stepSize);
for (var step = 1; step <= steps; step++) {
var checkX = redTanks[i].x + dx * step / steps;
var checkY = redTanks[i].y + dy * step / steps;
if (checkWallCollision(checkX, checkY)) {
canDamagePlayer = false;
break;
}
}
if (distance <= explosionRadius + playerRadius && canDamagePlayer) {
// Any part of player is within explosion radius and no walls block - deal 70 damage
playerTank.health -= 70;
LK.getSound('hit').play();
hasBeenHurt = true;
if (playerTank.health <= 0) {
LK.showGameOver();
}
}
createExplosion(redTanks[i].x, redTanks[i].y, 100, 0); // No additional damage from explosion
redTanks[i].destroy();
redTanks.splice(i, 1);
}
}
// Check medkit collision for healing
for (var i = medkits.length - 1; i >= 0; i--) {
var medkit = medkits[i];
var dx = playerTank.x - medkit.x;
var dy = playerTank.y - medkit.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 50 && playerTank.health < playerTank.maxHealth) {
// Close enough to collect medkit and player needs healing
playerTank.health = playerTank.maxHealth; // Restore to full health
medkit.destroy();
medkits.splice(i, 1);
LK.getSound('hit').play(); // Use existing sound for medkit pickup
// Achievement: Use first medkit
if (!hasUsedMedkit) {
hasUsedMedkit = true;
achievements.useFirstMedkit = true;
storage.achievements = achievements;
}
}
}
// Check if player is close to portal (within 100 pixels)
var dx = playerTank.x - portal.x;
var dy = playerTank.y - portal.y;
var distanceToPortal = Math.sqrt(dx * dx + dy * dy);
if (distanceToPortal < 100) {
// Achievement: Kill all enemies in map
var totalEnemiesRemaining = skinTanks.length + redTanks.length + greenTanks.length + whiteTanks.length + blackTanks.length;
if (totalEnemiesRemaining === 0) {
achievements.killAllEnemies = true;
storage.achievements = achievements;
}
// Achievement: Finish without dying
if (!hasBeenHurt) {
achievements.finishWithoutDying = true;
storage.achievements = achievements;
// Track consecutive levels without dying
levelsWithoutDying++;
storage.levelsWithoutDying = levelsWithoutDying;
// Achievement: Pass 5 levels without dying
if (levelsWithoutDying >= 5 && !achievements.pass5LevelsWithoutDying) {
achievements.pass5LevelsWithoutDying = true;
storage.achievements = achievements;
}
} else {
// Reset consecutive levels counter if player was hurt
levelsWithoutDying = 0;
storage.levelsWithoutDying = levelsWithoutDying;
}
LK.getSound('win').play();
// Clear current level enemies and bullets
for (var i = playerBullets.length - 1; i >= 0; i--) {
playerBullets[i].destroy();
}
playerBullets = [];
for (var i = enemyBullets.length - 1; i >= 0; i--) {
enemyBullets[i].destroy();
}
enemyBullets = [];
for (var i = dynamites.length - 1; i >= 0; i--) {
dynamites[i].destroy();
}
dynamites = [];
for (var i = acidBombs.length - 1; i >= 0; i--) {
acidBombs[i].destroy();
}
acidBombs = [];
for (var i = explosions.length - 1; i >= 0; i--) {
explosions[i].destroy();
}
explosions = [];
for (var i = whiteBullets.length - 1; i >= 0; i--) {
whiteBullets[i].destroy();
}
whiteBullets = [];
for (var i = blackBullets.length - 1; i >= 0; i--) {
blackBullets[i].destroy();
}
blackBullets = [];
for (var i = electricFields.length - 1; i >= 0; i--) {
electricFields[i].destroy();
}
electricFields = [];
for (var i = blackHoles.length - 1; i >= 0; i--) {
blackHoles[i].destroy();
}
blackHoles = [];
// Remove current portal
portal.destroy();
// Advance to next level
currentLevel++;
// Show next level screen
nextLevelScreen.visible = true;
gamePaused = true;
}
// Update score display
scoreText.setText('Score: ' + LK.getScore());
// Update best score if current score is higher
var currentScore = LK.getScore();
var bestScore = storage.bestScore || 0;
if (currentScore > bestScore) {
storage.bestScore = currentScore;
bestScoreText.setText('Best: ' + currentScore);
// Achievement: Beat previous best score
if (bestScore > 0) {
achievements.beatPreviousBest = true;
storage.achievements = achievements;
}
}
// Achievement: Get 150 Score
if (currentScore >= 150 && !achievements.get150Score) {
achievements.get150Score = true;
storage.achievements = achievements;
}
// Achievement: Have 1000 Score
if (currentScore >= 1000 && !hasReachedScore1000) {
hasReachedScore1000 = true;
storage.hasReachedScore1000 = hasReachedScore1000;
achievements.have1000Score = true;
storage.achievements = achievements;
}
var healthPercentage = Math.max(0, playerTank.health) / 100;
healthBarFill.scaleX = 4 * healthPercentage;
if (healthPercentage > 0.6) {
healthBarFill.tint = 0x00ff00; // Green
} else if (healthPercentage > 0.3) {
healthBarFill.tint = 0xffff00; // Yellow
} else {
healthBarFill.tint = 0xff0000; // Red
}
};
pixel art dynamite. In-Game asset. 2d. High contrast. No shadows
skin color tank pixel art top down. In-Game asset. 2d. High contrast. No shadows
green tank pixel art top down. In-Game asset. 2d. High contrast. No shadows
red tank pixel art top down. In-Game asset. 2d. High contrast. No shadows
blue tank pixel art top down. In-Game asset. 2d. High contrast. No shadows
pixel art bullet. In-Game asset. 2d. High contrast. No shadows
a green bomb (pixel art) writes "Acid" on it. In-Game asset. 2d. High contrast. No shadows
medkit pixel art. In-Game asset. 2d. High contrast. No shadows
dark green square 16*16 pixels pixel art. In-Game asset. 2d. High contrast. No shadows
orange circle pixel art. In-Game asset. 2d. High contrast. No shadows
A portal, outline is purple, and inside is magenta. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat pixel art
dark gray square 16*16 pixels pixel art.. In-Game asset. 2d. High contrast. No shadows
pixel art blackhole. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat