User prompt
Please fix the bug: 'window.addEventListener is not a function' in or related to this line: 'window.addEventListener('keydown', function (e) {' Line Number: 444
User prompt
Player shall move with "W/A/S/D" or arrow keys.
Code edit (1 edits merged)
Please save this source code
User prompt
Tank Battle
Initial prompt
Make a game for me. First, this game shall be 2D. The name is Tank Battle. Player has 100 HP (this means the health). There is a health bar in the left down corner. This game is pixel art. This game has levels. The player is a tank. The player shoots normal shells. The player has infinite shells. Every one of shells hit the skin color tank 3 HP. Every one of shells hit the red tank 10 HP. Every one of shells hit the green tank 25 HP. There are the tank enemies: Skin Color Tank: This tank has 50 shells (After finished all the shells, doesn't shoot anymore and destroys itself with explode {It explodes in a circular area, the radius of the circle is 2 meters. {1 meter = 16 pixels, 1 block [ground] = Sixteen by sixteen pixels} Depending on the distance, if the player is directly next to the center of the circle, the player takes 95 HP damage. If the player is less than 1 meter and more than 0.5 meters from the center of the circle, the player takes 65 HP damage. If the player is less than 1.5 meters and more than 1 meter away, the player takes 40 HP damage. If the player is less than 2 meters and more than 1.5 meters away, they take 20 HP damage. }). This tank is skin color. This tank has 50 HP. And shoots armor-piercing and explosive shells. Every one of shells damage 5 HP when they touch the player. Red Tank: This tank has 75 dynamites (After finished all the dynamites, doesn't shoot anymore, gets faster, when catches the player, explodes itself {It damages 75 HP}). This tank is red. This tank has 80 HP. If this tank is so close to player, it exploses and damages the player 50 HP. Every one of dynamites damage 15 HP when they touch the player. Green Tank: This tank has 150 asid bombs (After finished all the asid bombs, doesn't shoot anymore, gets faster, when catches the player, explodes itself {It damages 75 HP}). When an asid bomb hit the player, it damages 45 HP and posions for 3 seconds. Every one second, it hits player 1 HP and stops after three seconds. In the levels, there is a portal. If player enters that portal, the level finishes and the player passes to the next level. There is a labyrinth created with walls. But there are random counted tank enemies random places. There can be spawned Skin Color Tanks between 5 and 20, there can be spawned Red Tanks between 10 and 30, there can be spawned Green Tanks between 20 and 25 in a level.
/**** * 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