User prompt
And the enemy tanks can move around randomly and stop in a random time after started moving. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Don't generate walls that player can never reach to the portal
User prompt
Remove "new enemies" from the experiments, and add "hard mode". Hard Mode: In hard mode, the damages are two times than without hard mode (for example: 4 damage to 8 damage). Not for player's damage!. And when player enters the portal, the level doesn't finish immediately, the portal disappears and another portal creates in a random place (except its previous place). If player enters THAT portal, the level finishes. And the enemies NEVER attack each other (even if they damage to each other by mistake). ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Update: Now, the white and black tanks are not experiments. Now, there are 3 styles of maps: Lava, Ice, Normal. STYLES: After player clicked "play", a screen comes: CHOOSE A STYLE LAVA ICE NORMAL Normal is the map style which is filled with gray walls and green floor. Lava map style is filled with magma walls and orange floor. Ice map style is filled with ice walls and blue floor. In normal map style, there are: Skin Color Tank, Green Tank, Red Tank In lava map style, there are: White Tank, Black Tank, Orange Tank In ice map style, there are: Blue Tank, Ice Tank In lava map style, sometimes, fireballs might fall randomly. Before it falls, it creates a round and its center is the player (but if player moves after round created, the round doesn't move). 2 seconds later, the fireball falls, and it leaves a fire sign (if player enters in it, player gets damaged 2 HP every second). The firesign disappears 5 seconds later. EXPERIMENTS: "Hard Mode": In hard mode, the damages are two times than without hard mode (for example: 4 damage to 8 damage). Not for player's damage!. And when player enters the portal, the level doesn't finish immediately, the portal disappears and another portal creates in a random place (except its previous place). If player enters THAT portal, the level finishes. And the enemies NEVER attack each other (even if they damage to each other by mistake). NEW TANKS: Orange Tank: It has 450 HP. It shoots fireballs to the player. If a fireball hits the player, it damages 15 HP. If one of the player's bullets hit Orange Tank, it damages 5 HP. Blue Tank: It has 375 HP. It shoots waterballs to the player. If a waterball hits the player, it damages 5 HP, but it gets divided to 8 waterballs (smaller) and the waterballs go forward until hits a wall (it disappears) or hits a Tank (If it hits an enemy for the player, the enemy stops attacking player and starts attacking to Blue Tank until kills it or dies). If one of the player's bullets hit Blue Tank, it damages 3 HP. Ice Tank: It has 100 HP. It shoots ice blocks to the player. If an ice block hits the player, it damages 4 HP and gets broken. If one of the player's bullets hit Ice Tank, it damages 25 HP (and shows an animation of getting broken in every damage). ↪💡 Consider importing and using the following plugins: @upit/tween.v1, @upit/storage.v1
User prompt
There shouldn't be password, only "the creator of this game (GamerAliYoutube {me})" can add a notification for EVERYONE ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
And when writing the password, what is written should be visible, not "*"
User prompt
The text of keys to write the password shouldn't be on "cancel" button
User prompt
The password should be "2831"
User prompt
The "notifications" button should be more visible
User prompt
A password can be written to "enter password" part
User prompt
There should be a "NOTIFICATIONS" button on the right up corner. And when mouse clicks it, a new menu completely different from main menu appears (there should be no sign of main menu on the background in notifications menu). In that menu, in the bottom of the menu, there's an "add" button. When mouse clicks it, it asks a password to write (password is Ali58562025). If password gets written wrong, player can't add a notification for EVERYONE. If password gets written right, player can add a notification for EVERYONE. When password gets written right, a mini menu appears: TITLE: NOTIFICATION: Title is visible in the notifications menu. When mouse clicks on the notification, a menu of that notification appears. ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
There should be bear traps somewheres and when player touches it, it damages 20 HP and disappears. If player doesn't touch but near to the bear trap, a button appears in the left down corner, if player touches that button, the bear trap disappears
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'addEventListener')' in or related to this line: 'document.addEventListener('keydown', function (event) {' Line Number: 1149
User prompt
Make player controls with "W A S D"
Code edit (1 edits merged)
Please save this source code
User prompt
Add a trophy system. Players shall start with 0 trophies. And players earn 1 trophy for killing an enemy. Trophies can be seen in the main menu. And on "play" button in main menu, there shall be a button of "World Ranking". When player clicks it, the fifty player with the most trophies shall appear in a screen (can be scrolled). ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
There shall be new advancements in advancements menu: Kill A White Tank - NOT DONE/DONE Kill A Black Tank - NOT DONE/DONE Have 1000 Score - NOT DONE/DONE Pass 5 Levels Without Dying - NOT DONE/DONE ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
White Tank and Black Tank's bullets shall be like what happens when bullets touch player tank when each other's bullet touches each other ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
There can be between 1 and 3 of Black Tanks in a level. There can be between 2 and 4 of White Tanks in a level.
User prompt
New Enemies: White Tank: This tank shoots white balls at the player. If a white ball hits the player, it explodes and releases electricity in a circular area with a radius of 2 blocks. Any player tank in that area takes 2 HP damage per second. Each "Skin Color Tank" in the area takes 0.5 HP damage per second. Each "Red Tank" in the area takes 2 HP damage per second. Each "Green Tank" in the area takes 10 HP damage per second. And if an enemy takes damage in that area, it stops attacking the player and starts attacking the "White Tank." When the "White Tank" sees the "Black Tank," it stops attacking the player and starts attacking the "Black Tank." "White Tank" = 275 HP "Black Tank": This tank shoots black balls at the player. If a black ball hits the player, it explodes and creates a black hole covering a circular area with a radius of 1 block. This black hole slowly pulls in the player and enemies. If the player is in the center of the black hole, they start losing 8 HP per second. The black hole disappears after 5 seconds. The "Skin Color Tank" takes 2 HP damage per second in the black hole. The "Red Tank" takes 4 HP damage per second. The "Green Tank" takes 15 HP damage per second. The "White Tank" dies instantly upon entering the black hole. When the "Black Tank" sees the "White Tank," it stops attacking the player and starts attacking the "White Tank." "Black Tank" = 225 HP There can be between 0 and 2 of Black Tanks in a level. There can be between 0 and 2 of White Tanks in a level. (If "New Enemies" is on) ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Now, if mouse clicks "play", don't generate the level and start immediately, first, there shall a screen come. Top of screen, there shall write "Do You Wanna Activate Experiments". Under it, there shall be a button (text color red); "New Enemies - Off". If mouse clicks it, the button's text color shall be green and write "New Enemies - On". ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
The player tank shall turn to where it shot to.
User prompt
It shall be able to be seen
User prompt
In the main menu, there shall write "v.0.1.4" in the right down corner (color: yellow) A little big
User prompt
In the main menu, there shall write "v.0.1.4" in the right down corner (color: turquoise)
/**** * 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 BearTrap = Container.expand(function () { var self = Container.call(this); var trapGraphics = self.attachAsset('bearTrap', { anchorX: 0.5, anchorY: 0.5 }); self.damage = 20; self.isArmed = true; 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.randomMoveTimer = 0; self.randomMoveDirection = { x: 0, y: 0 }; self.isMovingRandomly = false; self.randomStopTimer = 0; self.update = function () { if (gamePaused) { return; } if (self.shootCooldown > 0) { self.shootCooldown--; } var target = playerTank; // Check if should target white tank instead (only if not in hard mode) if (!hardModeEnabled) { 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); // Priority movement: chase target if close 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; } self.isMovingRandomly = false; self.randomMoveTimer = 0; } else { // Random movement when not chasing target if (!self.isMovingRandomly && self.randomStopTimer <= 0) { // Start moving in random direction self.isMovingRandomly = true; self.randomMoveTimer = Math.floor(Math.random() * 120) + 60; // Move for 1-3 seconds var angle = Math.random() * Math.PI * 2; self.randomMoveDirection.x = Math.cos(angle); self.randomMoveDirection.y = Math.sin(angle); // Rotate to face random direction tween.stop(self, { rotation: true }); tween(self, { rotation: angle }, { duration: 300, easing: tween.easeOut }); } else if (self.isMovingRandomly && self.randomMoveTimer > 0) { // Continue random movement self.randomMoveTimer--; var moveX = self.randomMoveDirection.x * self.speed * 0.7; var moveY = self.randomMoveDirection.y * self.speed * 0.7; var newX = self.x + moveX; var newY = self.y + moveY; if (!checkWallCollision(newX, self.y) && newX > 50 && newX < 1998) { self.x = newX; } if (!checkWallCollision(self.x, newY) && newY > 50 && newY < 2682) { self.y = newY; } } else if (self.isMovingRandomly && self.randomMoveTimer <= 0) { // Stop moving and wait self.isMovingRandomly = false; self.randomStopTimer = Math.floor(Math.random() * 180) + 60; // Stop for 1-4 seconds } else if (!self.isMovingRandomly && self.randomStopTimer > 0) { // Continue waiting self.randomStopTimer--; } } 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 BlueTank = Container.expand(function () { var self = Container.call(this); var tankGraphics = self.attachAsset('blueTank', { anchorX: 0.5, anchorY: 0.5 }); self.health = 375; self.speed = 1; self.shootCooldown = 0; self.randomMoveTimer = 0; self.randomMoveDirection = { x: 0, y: 0 }; self.isMovingRandomly = false; self.randomStopTimer = 0; self.update = function () { if (gamePaused) { return; } if (self.shootCooldown > 0) { self.shootCooldown--; } var dx = playerTank.x - self.x; var dy = playerTank.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); // Priority movement: chase player if close 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; } self.isMovingRandomly = false; self.randomMoveTimer = 0; } else { // Random movement when not chasing player if (!self.isMovingRandomly && self.randomStopTimer <= 0) { // Start moving in random direction self.isMovingRandomly = true; self.randomMoveTimer = Math.floor(Math.random() * 120) + 60; // Move for 1-3 seconds var angle = Math.random() * Math.PI * 2; self.randomMoveDirection.x = Math.cos(angle); self.randomMoveDirection.y = Math.sin(angle); // Rotate to face random direction tween.stop(self, { rotation: true }); tween(self, { rotation: angle }, { duration: 300, easing: tween.easeOut }); } else if (self.isMovingRandomly && self.randomMoveTimer > 0) { // Continue random movement self.randomMoveTimer--; var moveX = self.randomMoveDirection.x * self.speed * 0.7; var moveY = self.randomMoveDirection.y * self.speed * 0.7; var newX = self.x + moveX; var newY = self.y + moveY; if (!checkWallCollision(newX, self.y) && newX > 50 && newX < 1998) { self.x = newX; } if (!checkWallCollision(self.x, newY) && newY > 50 && newY < 2682) { self.y = newY; } } else if (self.isMovingRandomly && self.randomMoveTimer <= 0) { // Stop moving and wait self.isMovingRandomly = false; self.randomStopTimer = Math.floor(Math.random() * 180) + 60; // Stop for 1-4 seconds } else if (!self.isMovingRandomly && self.randomStopTimer > 0) { // Continue waiting self.randomStopTimer--; } } if (distance < 300 && self.shootCooldown <= 0) { var length = Math.sqrt(dx * dx + dy * dy); var dirX = dx / length; var dirY = dy / length; var waterball = new Waterball(); waterball.x = self.x; waterball.y = self.y; waterball.directionX = dirX; waterball.directionY = dirY; waterballs.push(waterball); game.addChild(waterball); self.shootCooldown = 90; 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 FallingFireball = Container.expand(function () { var self = Container.call(this); var fireballGraphics = self.attachAsset('fireball', { anchorX: 0.5, anchorY: 0.5 }); self.targetX = 0; self.targetY = 0; self.warningTimer = 120; // 2 seconds warning self.warningCircle = null; self.hasWarned = false; self.update = function () { if (gamePaused) { return; } if (self.warningTimer > 0) { self.warningTimer--; if (!self.hasWarned) { // Create warning circle self.warningCircle = LK.getAsset('ground', { anchorX: 0.5, anchorY: 0.5, tint: 0xFF0000, alpha: 0.5, scaleX: 1.5, scaleY: 1.5 }); self.warningCircle.x = self.targetX; self.warningCircle.y = self.targetY; game.addChild(self.warningCircle); self.hasWarned = true; } } else { // Remove warning circle and drop fireball if (self.warningCircle) { self.warningCircle.destroy(); self.warningCircle = null; } self.x = self.targetX; self.y = self.targetY; // Create fire sign var fireSign = new FireSign(); fireSign.x = self.x; fireSign.y = self.y; fireSigns.push(fireSign); game.addChild(fireSign); // Remove self self.destroy(); var index = fallingFireballs.indexOf(self); if (index > -1) { fallingFireballs.splice(index, 1); } } }; return self; }); var FireSign = Container.expand(function () { var self = Container.call(this); var fireGraphics = self.attachAsset('fireSign', { anchorX: 0.5, anchorY: 0.5, alpha: 0.7 }); self.damage = 2; self.damageTimer = 0; self.lifetime = 300; // 5 seconds self.timer = 0; self.update = function () { if (gamePaused) { return; } self.timer++; self.damageTimer++; if (self.timer >= self.lifetime) { self.destroy(); var index = fireSigns.indexOf(self); if (index > -1) { fireSigns.splice(index, 1); } } }; return self; }); var Fireball = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('fireball', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 4; self.directionX = 0; self.directionY = 0; self.damage = 15; 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.randomMoveTimer = 0; self.randomMoveDirection = { x: 0, y: 0 }; self.isMovingRandomly = false; self.randomStopTimer = 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); // Priority movement: chase target if close 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; } self.isMovingRandomly = false; self.randomMoveTimer = 0; } else { // Random movement when not chasing target if (!self.isMovingRandomly && self.randomStopTimer <= 0) { // Start moving in random direction self.isMovingRandomly = true; self.randomMoveTimer = Math.floor(Math.random() * 120) + 60; // Move for 1-3 seconds var angle = Math.random() * Math.PI * 2; self.randomMoveDirection.x = Math.cos(angle); self.randomMoveDirection.y = Math.sin(angle); // Rotate to face random direction tween.stop(self, { rotation: true }); tween(self, { rotation: angle }, { duration: 300, easing: tween.easeOut }); } else if (self.isMovingRandomly && self.randomMoveTimer > 0) { // Continue random movement self.randomMoveTimer--; var moveX = self.randomMoveDirection.x * self.speed * 0.7; var moveY = self.randomMoveDirection.y * self.speed * 0.7; var newX = self.x + moveX; var newY = self.y + moveY; if (!checkWallCollision(newX, self.y) && newX > 50 && newX < 1998) { self.x = newX; } if (!checkWallCollision(self.x, newY) && newY > 50 && newY < 2682) { self.y = newY; } } else if (self.isMovingRandomly && self.randomMoveTimer <= 0) { // Stop moving and wait self.isMovingRandomly = false; self.randomStopTimer = Math.floor(Math.random() * 180) + 60; // Stop for 1-4 seconds } else if (!self.isMovingRandomly && self.randomStopTimer > 0) { // Continue waiting self.randomStopTimer--; } } 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 IceBlock = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('iceBlock', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 4; self.directionX = 0; self.directionY = 0; self.damage = 4; self.update = function () { if (gamePaused) { return; } self.x += self.directionX * self.speed; self.y += self.directionY * self.speed; }; return self; }); var IceTank = Container.expand(function () { var self = Container.call(this); var tankGraphics = self.attachAsset('iceTank', { anchorX: 0.5, anchorY: 0.5 }); self.health = 100; self.speed = 1; self.shootCooldown = 0; self.randomMoveTimer = 0; self.randomMoveDirection = { x: 0, y: 0 }; self.isMovingRandomly = false; self.randomStopTimer = 0; self.update = function () { if (gamePaused) { return; } if (self.shootCooldown > 0) { self.shootCooldown--; } var dx = playerTank.x - self.x; var dy = playerTank.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); // Priority movement: chase player if close 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; } self.isMovingRandomly = false; self.randomMoveTimer = 0; } else { // Random movement when not chasing player if (!self.isMovingRandomly && self.randomStopTimer <= 0) { // Start moving in random direction self.isMovingRandomly = true; self.randomMoveTimer = Math.floor(Math.random() * 120) + 60; // Move for 1-3 seconds var angle = Math.random() * Math.PI * 2; self.randomMoveDirection.x = Math.cos(angle); self.randomMoveDirection.y = Math.sin(angle); // Rotate to face random direction tween.stop(self, { rotation: true }); tween(self, { rotation: angle }, { duration: 300, easing: tween.easeOut }); } else if (self.isMovingRandomly && self.randomMoveTimer > 0) { // Continue random movement self.randomMoveTimer--; var moveX = self.randomMoveDirection.x * self.speed * 0.7; var moveY = self.randomMoveDirection.y * self.speed * 0.7; var newX = self.x + moveX; var newY = self.y + moveY; if (!checkWallCollision(newX, self.y) && newX > 50 && newX < 1998) { self.x = newX; } if (!checkWallCollision(self.x, newY) && newY > 50 && newY < 2682) { self.y = newY; } } else if (self.isMovingRandomly && self.randomMoveTimer <= 0) { // Stop moving and wait self.isMovingRandomly = false; self.randomStopTimer = Math.floor(Math.random() * 180) + 60; // Stop for 1-4 seconds } else if (!self.isMovingRandomly && self.randomStopTimer > 0) { // Continue waiting self.randomStopTimer--; } } if (distance < 300 && self.shootCooldown <= 0) { var length = Math.sqrt(dx * dx + dy * dy); var dirX = dx / length; var dirY = dy / length; var iceBlock = new IceBlock(); iceBlock.x = self.x; iceBlock.y = self.y; iceBlock.directionX = dirX; iceBlock.directionY = dirY; iceBlocks.push(iceBlock); game.addChild(iceBlock); self.shootCooldown = 80; 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 OrangeTank = Container.expand(function () { var self = Container.call(this); var tankGraphics = self.attachAsset('orangeTank', { anchorX: 0.5, anchorY: 0.5 }); self.health = 450; self.speed = 1; self.shootCooldown = 0; self.randomMoveTimer = 0; self.randomMoveDirection = { x: 0, y: 0 }; self.isMovingRandomly = false; self.randomStopTimer = 0; self.update = function () { if (gamePaused) { return; } if (self.shootCooldown > 0) { self.shootCooldown--; } var dx = playerTank.x - self.x; var dy = playerTank.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); // Priority movement: chase player if close 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; } self.isMovingRandomly = false; self.randomMoveTimer = 0; } else { // Random movement when not chasing player if (!self.isMovingRandomly && self.randomStopTimer <= 0) { // Start moving in random direction self.isMovingRandomly = true; self.randomMoveTimer = Math.floor(Math.random() * 120) + 60; // Move for 1-3 seconds var angle = Math.random() * Math.PI * 2; self.randomMoveDirection.x = Math.cos(angle); self.randomMoveDirection.y = Math.sin(angle); // Rotate to face random direction tween.stop(self, { rotation: true }); tween(self, { rotation: angle }, { duration: 300, easing: tween.easeOut }); } else if (self.isMovingRandomly && self.randomMoveTimer > 0) { // Continue random movement self.randomMoveTimer--; var moveX = self.randomMoveDirection.x * self.speed * 0.7; var moveY = self.randomMoveDirection.y * self.speed * 0.7; var newX = self.x + moveX; var newY = self.y + moveY; if (!checkWallCollision(newX, self.y) && newX > 50 && newX < 1998) { self.x = newX; } if (!checkWallCollision(self.x, newY) && newY > 50 && newY < 2682) { self.y = newY; } } else if (self.isMovingRandomly && self.randomMoveTimer <= 0) { // Stop moving and wait self.isMovingRandomly = false; self.randomStopTimer = Math.floor(Math.random() * 180) + 60; // Stop for 1-4 seconds } else if (!self.isMovingRandomly && self.randomStopTimer > 0) { // Continue waiting self.randomStopTimer--; } } if (distance < 300 && self.shootCooldown <= 0) { var length = Math.sqrt(dx * dx + dy * dy); var dirX = dx / length; var dirY = dy / length; var fireball = new Fireball(); fireball.x = self.x; fireball.y = self.y; fireball.directionX = dirX; fireball.directionY = dirY; fireballs.push(fireball); game.addChild(fireball); self.shootCooldown = 100; LK.getSound('shoot').play(); } }; 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.randomMoveTimer = 0; self.randomMoveDirection = { x: 0, y: 0 }; self.isMovingRandomly = false; self.randomStopTimer = 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); // Priority movement: chase target if close 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; } self.isMovingRandomly = false; self.randomMoveTimer = 0; } else { // Random movement when not chasing target if (!self.isMovingRandomly && self.randomStopTimer <= 0) { // Start moving in random direction self.isMovingRandomly = true; self.randomMoveTimer = Math.floor(Math.random() * 120) + 60; // Move for 1-3 seconds var angle = Math.random() * Math.PI * 2; self.randomMoveDirection.x = Math.cos(angle); self.randomMoveDirection.y = Math.sin(angle); // Rotate to face random direction tween.stop(self, { rotation: true }); tween(self, { rotation: angle }, { duration: 300, easing: tween.easeOut }); } else if (self.isMovingRandomly && self.randomMoveTimer > 0) { // Continue random movement self.randomMoveTimer--; var moveX = self.randomMoveDirection.x * self.speed * 0.7; var moveY = self.randomMoveDirection.y * self.speed * 0.7; var newX = self.x + moveX; var newY = self.y + moveY; if (!checkWallCollision(newX, self.y) && newX > 50 && newX < 1998) { self.x = newX; } if (!checkWallCollision(self.x, newY) && newY > 50 && newY < 2682) { self.y = newY; } } else if (self.isMovingRandomly && self.randomMoveTimer <= 0) { // Stop moving and wait self.isMovingRandomly = false; self.randomStopTimer = Math.floor(Math.random() * 180) + 60; // Stop for 1-4 seconds } else if (!self.isMovingRandomly && self.randomStopTimer > 0) { // Continue waiting self.randomStopTimer--; } } 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.randomMoveTimer = 0; self.randomMoveDirection = { x: 0, y: 0 }; self.isMovingRandomly = false; self.randomStopTimer = 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); // Priority movement: chase target if close 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; } self.isMovingRandomly = false; self.randomMoveTimer = 0; } else { // Random movement when not chasing target if (!self.isMovingRandomly && self.randomStopTimer <= 0) { // Start moving in random direction self.isMovingRandomly = true; self.randomMoveTimer = Math.floor(Math.random() * 120) + 60; // Move for 1-3 seconds var angle = Math.random() * Math.PI * 2; self.randomMoveDirection.x = Math.cos(angle); self.randomMoveDirection.y = Math.sin(angle); // Rotate to face random direction tween.stop(self, { rotation: true }); tween(self, { rotation: angle }, { duration: 300, easing: tween.easeOut }); } else if (self.isMovingRandomly && self.randomMoveTimer > 0) { // Continue random movement self.randomMoveTimer--; var moveX = self.randomMoveDirection.x * self.speed * 0.7; var moveY = self.randomMoveDirection.y * self.speed * 0.7; var newX = self.x + moveX; var newY = self.y + moveY; if (!checkWallCollision(newX, self.y) && newX > 50 && newX < 1998) { self.x = newX; } if (!checkWallCollision(self.x, newY) && newY > 50 && newY < 2682) { self.y = newY; } } else if (self.isMovingRandomly && self.randomMoveTimer <= 0) { // Stop moving and wait self.isMovingRandomly = false; self.randomStopTimer = Math.floor(Math.random() * 180) + 60; // Stop for 1-4 seconds } else if (!self.isMovingRandomly && self.randomStopTimer > 0) { // Continue waiting self.randomStopTimer--; } } 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 Waterball = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('waterball', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 4; self.directionX = 0; self.directionY = 0; self.damage = 5; self.update = function () { if (gamePaused) { return; } self.x += self.directionX * self.speed; self.y += self.directionY * self.speed; }; 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.randomMoveTimer = 0; self.randomMoveDirection = { x: 0, y: 0 }; self.isMovingRandomly = false; self.randomStopTimer = 0; 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 (only if not in hard mode) if (!hardModeEnabled) { 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); // Priority movement: chase target if close 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; } self.isMovingRandomly = false; self.randomMoveTimer = 0; } else { // Random movement when not chasing target if (!self.isMovingRandomly && self.randomStopTimer <= 0) { // Start moving in random direction self.isMovingRandomly = true; self.randomMoveTimer = Math.floor(Math.random() * 120) + 60; // Move for 1-3 seconds var angle = Math.random() * Math.PI * 2; self.randomMoveDirection.x = Math.cos(angle); self.randomMoveDirection.y = Math.sin(angle); // Rotate to face random direction tween.stop(self, { rotation: true }); tween(self, { rotation: angle }, { duration: 300, easing: tween.easeOut }); } else if (self.isMovingRandomly && self.randomMoveTimer > 0) { // Continue random movement self.randomMoveTimer--; var moveX = self.randomMoveDirection.x * self.speed * 0.7; var moveY = self.randomMoveDirection.y * self.speed * 0.7; var newX = self.x + moveX; var newY = self.y + moveY; if (!checkWallCollision(newX, self.y) && newX > 50 && newX < 1998) { self.x = newX; } if (!checkWallCollision(self.x, newY) && newY > 50 && newY < 2682) { self.y = newY; } } else if (self.isMovingRandomly && self.randomMoveTimer <= 0) { // Stop moving and wait self.isMovingRandomly = false; self.randomStopTimer = Math.floor(Math.random() * 180) + 60; // Stop for 1-4 seconds } else if (!self.isMovingRandomly && self.randomStopTimer > 0) { // Continue waiting self.randomStopTimer--; } } 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 bearTraps = []; var orangeTanks = []; var blueTanks = []; var iceTanks = []; var fireballs = []; var waterballs = []; var iceBlocks = []; var fireSigns = []; var fallingFireballs = []; var playerTank; var portal; var currentLevel = 1; var gameStarted = false; var isDragging = false; var gamePaused = false; var showingMainMenu = true; var disarmButton = null; var currentNearbyTrap = null; var firstPortalUsed = false; var previousPortalX = 0; var previousPortalY = 0; // 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 hard mode setting from storage var hardModeEnabled = storage.hardModeEnabled || false; // Hard mode toggle button var hardModeButton = new Text2(hardModeEnabled ? 'Hard Mode - On' : 'Hard Mode - Off', { size: 60, fill: hardModeEnabled ? 0x00FF00 : 0xFF0000, font: "monospace" }); hardModeButton.anchor.set(0.5, 0.5); hardModeButton.x = 0; hardModeButton.y = 0; experimentsScreen.addChild(hardModeButton); // Hard mode button click handler hardModeButton.down = function (x, y, obj) { hardModeEnabled = !hardModeEnabled; storage.hardModeEnabled = hardModeEnabled; hardModeButton.setText(hardModeEnabled ? 'Hard Mode - On' : 'Hard Mode - Off'); hardModeButton.fill = hardModeEnabled ? 0x00FF00 : 0xFF0000; hardModeButton.tint = hardModeEnabled ? 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(); }; // Style selection screen container var styleSelectionScreen = new Container(); styleSelectionScreen.visible = false; LK.gui.center.addChild(styleSelectionScreen); // Style selection screen background var styleSelectionBackground = LK.getAsset('darkGreen', { anchorX: 0.5, anchorY: 0.5, scaleX: 32, scaleY: 43, alpha: 0.8 }); styleSelectionScreen.addChild(styleSelectionBackground); // Style selection title var styleTitle = new Text2('CHOOSE A STYLE', { size: 100, fill: 0xFFFFFF, font: "monospace" }); styleTitle.anchor.set(0.5, 0.5); styleTitle.x = 0; styleTitle.y = -300; styleSelectionScreen.addChild(styleTitle); // Normal style button var normalStyleButton = new Text2('NORMAL', { size: 80, fill: 0x00FF00, font: "monospace" }); normalStyleButton.anchor.set(0.5, 0.5); normalStyleButton.x = -300; normalStyleButton.y = 0; styleSelectionScreen.addChild(normalStyleButton); // Lava style button var lavaStyleButton = new Text2('LAVA', { size: 80, fill: 0xFF4500, font: "monospace" }); lavaStyleButton.anchor.set(0.5, 0.5); lavaStyleButton.x = 0; lavaStyleButton.y = 0; styleSelectionScreen.addChild(lavaStyleButton); // Ice style button var iceStyleButton = new Text2('ICE', { size: 80, fill: 0x00BFFF, font: "monospace" }); iceStyleButton.anchor.set(0.5, 0.5); iceStyleButton.x = 300; iceStyleButton.y = 0; styleSelectionScreen.addChild(iceStyleButton); // Map style variable var mapStyle = 'normal'; // Normal style click handler normalStyleButton.down = function (x, y, obj) { mapStyle = 'normal'; styleSelectionScreen.visible = false; experimentsScreen.visible = true; }; // Lava style click handler lavaStyleButton.down = function (x, y, obj) { mapStyle = 'lava'; styleSelectionScreen.visible = false; experimentsScreen.visible = true; }; // Ice style click handler iceStyleButton.down = function (x, y, obj) { mapStyle = 'ice'; styleSelectionScreen.visible = false; experimentsScreen.visible = true; }; // Play button click handler playButton.down = function (x, y, obj) { mainMenu.visible = false; styleSelectionScreen.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 = []; for (var i = bearTraps.length - 1; i >= 0; i--) { bearTraps[i].destroy(); } bearTraps = []; for (var i = orangeTanks.length - 1; i >= 0; i--) { orangeTanks[i].destroy(); } orangeTanks = []; for (var i = blueTanks.length - 1; i >= 0; i--) { blueTanks[i].destroy(); } blueTanks = []; for (var i = iceTanks.length - 1; i >= 0; i--) { iceTanks[i].destroy(); } iceTanks = []; for (var i = fireballs.length - 1; i >= 0; i--) { fireballs[i].destroy(); } fireballs = []; for (var i = waterballs.length - 1; i >= 0; i--) { waterballs[i].destroy(); } waterballs = []; for (var i = iceBlocks.length - 1; i >= 0; i--) { iceBlocks[i].destroy(); } iceBlocks = []; for (var i = fireSigns.length - 1; i >= 0; i--) { fireSigns[i].destroy(); } fireSigns = []; for (var i = fallingFireballs.length - 1; i >= 0; i--) { if (fallingFireballs[i].warningCircle) { fallingFireballs[i].warningCircle.destroy(); } fallingFireballs[i].destroy(); } fallingFireballs = []; // 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; firstPortalUsed = false; previousPortalX = 0; previousPortalY = 0; 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; // Keyboard movement variables var keys = { w: false, a: false, s: false, d: false }; // Keyboard controls are not supported in LK sandbox environment // Movement is handled via touch/drag controls only // Create disarm button (initially hidden) disarmButton = new Text2('DISARM', { size: 40, fill: 0xFFFFFF, font: "monospace" }); disarmButton.anchor.set(0, 1); disarmButton.x = 20; disarmButton.y = -20; disarmButton.visible = false; LK.gui.bottomLeft.addChild(disarmButton); // Disarm button background var disarmButtonBg = LK.getAsset('wall', { anchorX: 0, anchorY: 1, scaleX: 2.5, scaleY: 0.8, tint: 0x333333, alpha: 0.8 }); disarmButtonBg.x = 10; disarmButtonBg.y = -10; disarmButtonBg.visible = false; LK.gui.bottomLeft.addChild(disarmButtonBg); // Disarm button click handler disarmButton.down = function (x, y, obj) { if (currentNearbyTrap && currentNearbyTrap.isArmed) { currentNearbyTrap.destroy(); var index = bearTraps.indexOf(currentNearbyTrap); if (index > -1) { bearTraps.splice(index, 1); } disarmButton.visible = false; disarmButtonBg.visible = false; currentNearbyTrap = null; LK.getSound('hit').play(); } }; // 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; // Set background color based on map style if (mapStyle === 'lava') { game.setBackgroundColor(0xFF4500); // Orange background } else if (mapStyle === 'ice') { game.setBackgroundColor(0x0000FF); // Blue background } else { game.setBackgroundColor(0x2F4F2F); // Green background } 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(); // Change wall appearance based on map style if (mapStyle === 'lava') { wall.attachAsset('lavaWall', { anchorX: 0.5, anchorY: 0.5 }); } else if (mapStyle === 'ice') { wall.attachAsset('iceWall', { anchorX: 0.5, anchorY: 0.5 }); } wall.x = wallX; wall.y = wallY; walls.push(wall); game.addChild(wall); } } else if (Math.random() < 0.3 && !isNearPlayerTank) { var wall = new Wall(); // Change wall appearance based on map style if (mapStyle === 'lava') { wall.attachAsset('lavaWall', { anchorX: 0.5, anchorY: 0.5 }); } else if (mapStyle === 'ice') { wall.attachAsset('iceWall', { anchorX: 0.5, anchorY: 0.5 }); } wall.x = wallX; wall.y = wallY; walls.push(wall); game.addChild(wall); } } } } function spawnEnemies() { if (mapStyle === 'normal') { 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); } } else if (mapStyle === 'lava') { var whiteCount = Math.floor(Math.random() * 3) + 2; // 2-4 white tanks var blackCount = Math.floor(Math.random() * 3) + 1; // 1-3 black tanks var orangeCount = Math.floor(Math.random() * 4) + 3; // 3-6 orange 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); } for (var i = 0; i < orangeCount; i++) { var tank = new OrangeTank(); 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); orangeTanks.push(tank); game.addChild(tank); } } else if (mapStyle === 'ice') { var blueCount = Math.floor(Math.random() * 4) + 3; // 3-6 blue tanks var iceCount = Math.floor(Math.random() * 5) + 5; // 5-9 ice tanks for (var i = 0; i < blueCount; i++) { var tank = new BlueTank(); 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); blueTanks.push(tank); game.addChild(tank); } for (var i = 0; i < iceCount; i++) { var tank = new IceTank(); 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); iceTanks.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 canReachPosition(startX, startY, targetX, targetY) { // Create a grid to track visited positions var visited = {}; var queue = [{ x: startX, y: startY }]; var gridSize = 32; // Step size for pathfinding var maxDistance = 100; // Maximum distance to consider reachable // Simple flood-fill algorithm to check connectivity while (queue.length > 0) { var current = queue.shift(); var key = Math.floor(current.x / gridSize) + ',' + Math.floor(current.y / gridSize); if (visited[key]) continue; visited[key] = true; // Check if we've reached the target var dx = current.x - targetX; var dy = current.y - targetY; if (Math.abs(dx) < maxDistance && Math.abs(dy) < maxDistance) { return true; } // Add neighboring positions to queue if they're not blocked var directions = [{ x: gridSize, y: 0 }, { x: -gridSize, y: 0 }, { x: 0, y: gridSize }, { x: 0, y: -gridSize }]; for (var i = 0; i < directions.length; i++) { var newX = current.x + directions[i].x; var newY = current.y + directions[i].y; // Check bounds if (newX < 100 || newX > 1948 || newY < 100 || newY > 2632) continue; // Check if position is blocked by walls if (!checkWallCollision(newX, newY)) { queue.push({ x: newX, y: newY }); } } // Limit search to prevent infinite loops if (Object.keys(visited).length > 500) break; } return false; } 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 spawnBearTraps() { var trapCount = Math.floor(Math.random() * 3) + 2; // 2-4 bear traps per level for (var i = 0; i < trapCount; i++) { var bearTrap = new BearTrap(); do { bearTrap.x = Math.random() * (2048 - 200) + 100; bearTrap.y = Math.random() * (2732 - 200) + 100; } while (checkWallCollision(bearTrap.x, bearTrap.y) || getDistanceToPlayer(bearTrap.x, bearTrap.y) < 200); bearTraps.push(bearTrap); game.addChild(bearTrap); } } 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 = []; for (var i = bearTraps.length - 1; i >= 0; i--) { bearTraps[i].destroy(); } bearTraps = []; generateMaze(); spawnEnemies(); spawnMedkits(); spawnBearTraps(); // Hide disarm button when starting new level disarmButton.visible = false; disarmButtonBg.visible = false; currentNearbyTrap = null; // Track total enemies for achievement totalEnemiesAtStart = skinTanks.length + redTanks.length + greenTanks.length + whiteTanks.length + blackTanks.length + orangeTanks.length + blueTanks.length + iceTanks.length; // Reset achievement tracking variables hasUsedMedkit = false; hasKilledEnemy = false; hasBeenHurt = false; // Reset hard mode portal tracking firstPortalUsed = false; previousPortalX = 0; previousPortalY = 0; // 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(); var attempts = 0; var maxAttempts = 50; do { portal.x = Math.random() * (2048 - 200) + 100; portal.y = Math.random() * (2732 - 200) + 100; attempts++; // If we can't find a reachable position after many attempts, reduce wall density if (attempts > maxAttempts) { // Remove some random walls to create more open paths for (var i = walls.length - 1; i >= 0 && walls.length > 20; i--) { if (Math.random() < 0.1) { walls[i].destroy(); walls.splice(i, 1); } } attempts = 0; } } while ((checkWallCollision(portal.x, portal.y) || getDistanceToPlayer(portal.x, portal.y) < 300 || !canReachPosition(playerTank.x, playerTank.y, portal.x, portal.y)) && attempts < maxAttempts); 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 = []; for (var i = bearTraps.length - 1; i >= 0; i--) { bearTraps[i].destroy(); } bearTraps = []; // 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; firstPortalUsed = false; previousPortalX = 0; previousPortalY = 0; 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 only // Keyboard controls are not supported in LK sandbox environment // Movement is handled via touch/drag in game.move method and WASD keys 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)) { var damage = hardModeEnabled ? bullet.damage * 2 : bullet.damage; playerTank.health -= 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)) { var damage = hardModeEnabled ? acidBomb.damage * 2 : acidBomb.damage; var poisonDamage = hardModeEnabled ? acidBomb.poisonDamage * 2 : acidBomb.poisonDamage; playerTank.health -= damage; playerTank.poisonTimer = acidBomb.poisonDuration; playerTank.poisonDamage = 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 bear trap collision and proximity var nearbyTrap = null; for (var i = bearTraps.length - 1; i >= 0; i--) { var bearTrap = bearTraps[i]; if (!bearTrap.isArmed) continue; var dx = playerTank.x - bearTrap.x; var dy = playerTank.y - bearTrap.y; var distance = Math.sqrt(dx * dx + dy * dy); // Direct collision - damage player and destroy trap if (distance < 40) { var damage = hardModeEnabled ? bearTrap.damage * 2 : bearTrap.damage; playerTank.health -= damage; hasBeenHurt = true; LK.getSound('hit').play(); bearTrap.destroy(); bearTraps.splice(i, 1); if (playerTank.health <= 0) { LK.showGameOver(); } continue; } // Near but not touching - show disarm button if (distance < 100 && distance >= 40) { nearbyTrap = bearTrap; } } // Update disarm button visibility if (nearbyTrap && nearbyTrap !== currentNearbyTrap) { currentNearbyTrap = nearbyTrap; disarmButton.visible = true; disarmButtonBg.visible = true; } else if (!nearbyTrap && currentNearbyTrap) { currentNearbyTrap = null; disarmButton.visible = false; disarmButtonBg.visible = false; } // 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) { if (hardModeEnabled && !firstPortalUsed) { // In hard mode, first portal disappears and creates a new one firstPortalUsed = true; previousPortalX = portal.x; previousPortalY = portal.y; portal.destroy(); // Create new portal in a different location var newPortal = new Portal(); var attempts = 0; var maxAttempts = 50; do { newPortal.x = Math.random() * (2048 - 200) + 100; newPortal.y = Math.random() * (2732 - 200) + 100; attempts++; // If we can't find a reachable position after many attempts, reduce wall density if (attempts > maxAttempts) { // Remove some random walls to create more open paths for (var i = walls.length - 1; i >= 0 && walls.length > 20; i--) { if (Math.random() < 0.1) { walls[i].destroy(); walls.splice(i, 1); } } attempts = 0; } } while ((checkWallCollision(newPortal.x, newPortal.y) || getDistanceToPlayer(newPortal.x, newPortal.y) < 300 || Math.abs(newPortal.x - previousPortalX) < 200 && Math.abs(newPortal.y - previousPortalY) < 200 || !canReachPosition(playerTank.x, playerTank.y, newPortal.x, newPortal.y)) && attempts < maxAttempts); portal = newPortal; game.addChild(portal); return; } // Achievement: Kill all enemies in map var totalEnemiesRemaining = skinTanks.length + redTanks.length + greenTanks.length + whiteTanks.length + blackTanks.length + orangeTanks.length + blueTanks.length + iceTanks.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 = []; for (var i = bearTraps.length - 1; i >= 0; i--) { bearTraps[i].destroy(); } bearTraps = []; // Hide disarm button when completing level disarmButton.visible = false; disarmButtonBg.visible = false; currentNearbyTrap = null; // Remove current portal portal.destroy(); // Reset portal tracking for next level firstPortalUsed = false; previousPortalX = 0; previousPortalY = 0; // Advance to next level currentLevel++; // Show next level screen nextLevelScreen.visible = true; gamePaused = true; } // Spawn falling fireballs in lava map style if (mapStyle === 'lava' && Math.random() < 0.001) { // Very rare spawn var fallingFireball = new FallingFireball(); fallingFireball.targetX = playerTank.x + (Math.random() - 0.5) * 200; // Around player position fallingFireball.targetY = playerTank.y + (Math.random() - 0.5) * 200; fallingFireballs.push(fallingFireball); game.addChild(fallingFireball); } // Handle fire signs damage for (var i = fireSigns.length - 1; i >= 0; i--) { var fireSign = fireSigns[i]; var dx = playerTank.x - fireSign.x; var dy = playerTank.y - fireSign.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 32 && fireSign.damageTimer >= 60) { // Every second var damage = hardModeEnabled ? fireSign.damage * 2 : fireSign.damage; playerTank.health -= damage; fireSign.damageTimer = 0; hasBeenHurt = true; LK.getSound('hit').play(); if (playerTank.health <= 0) { LK.showGameOver(); } } } // Handle fireballs for (var i = fireballs.length - 1; i >= 0; i--) { var fireball = fireballs[i]; if (fireball.x < 0 || fireball.x > 2048 || fireball.y < 0 || fireball.y > 2732) { fireball.destroy(); fireballs.splice(i, 1); continue; } if (checkWallCollision(fireball.x, fireball.y)) { fireball.destroy(); fireballs.splice(i, 1); continue; } if (fireball.intersects(playerTank)) { var damage = hardModeEnabled ? fireball.damage * 2 : fireball.damage; playerTank.health -= damage; fireball.destroy(); fireballs.splice(i, 1); LK.getSound('hit').play(); hasBeenHurt = true; if (playerTank.health <= 0) { LK.showGameOver(); } continue; } } // Handle waterballs for (var i = waterballs.length - 1; i >= 0; i--) { var waterball = waterballs[i]; if (waterball.x < 0 || waterball.x > 2048 || waterball.y < 0 || waterball.y > 2732) { waterball.destroy(); waterballs.splice(i, 1); continue; } if (checkWallCollision(waterball.x, waterball.y)) { waterball.destroy(); waterballs.splice(i, 1); continue; } if (waterball.intersects(playerTank)) { var damage = hardModeEnabled ? waterball.damage * 2 : waterball.damage; playerTank.health -= damage; // Create 8 smaller waterballs for (var j = 0; j < 8; j++) { var smallWaterball = new Waterball(); smallWaterball.x = waterball.x; smallWaterball.y = waterball.y; var angle = j / 8 * Math.PI * 2; smallWaterball.directionX = Math.cos(angle); smallWaterball.directionY = Math.sin(angle); smallWaterball.speed = 2; smallWaterball.damage = hardModeEnabled ? 2 : 1; waterballs.push(smallWaterball); game.addChild(smallWaterball); } waterball.destroy(); waterballs.splice(i, 1); LK.getSound('hit').play(); hasBeenHurt = true; if (playerTank.health <= 0) { LK.showGameOver(); } continue; } // Check if small waterballs hit other tanks for (var j = orangeTanks.length - 1; j >= 0; j--) { if (waterball.intersects(orangeTanks[j])) { orangeTanks[j].targetPlayer = false; // Stop attacking player waterball.destroy(); waterballs.splice(i, 1); break; } } } // Handle ice blocks for (var i = iceBlocks.length - 1; i >= 0; i--) { var iceBlock = iceBlocks[i]; if (iceBlock.x < 0 || iceBlock.x > 2048 || iceBlock.y < 0 || iceBlock.y > 2732) { iceBlock.destroy(); iceBlocks.splice(i, 1); continue; } if (checkWallCollision(iceBlock.x, iceBlock.y)) { iceBlock.destroy(); iceBlocks.splice(i, 1); continue; } if (iceBlock.intersects(playerTank)) { var damage = hardModeEnabled ? iceBlock.damage * 2 : iceBlock.damage; playerTank.health -= damage; iceBlock.destroy(); iceBlocks.splice(i, 1); LK.getSound('hit').play(); hasBeenHurt = true; if (playerTank.health <= 0) { LK.showGameOver(); } continue; } } // Handle orange tank collisions with player bullets for (var i = playerBullets.length - 1; i >= 0; i--) { var bullet = playerBullets[i]; for (var j = orangeTanks.length - 1; j >= 0; j--) { if (bullet.intersects(orangeTanks[j])) { orangeTanks[j].health -= 5; bullet.destroy(); playerBullets.splice(i, 1); if (orangeTanks[j].health <= 0) { orangeTanks[j].destroy(); orangeTanks.splice(j, 1); LK.setScore(LK.getScore() + 35); totalEnemiesKilled++; storage.totalEnemiesKilled = totalEnemiesKilled; if (!hasKilledEnemy) { hasKilledEnemy = true; achievements.killFirstEnemy = true; storage.achievements = achievements; } } break; } } for (var j = blueTanks.length - 1; j >= 0; j--) { if (bullet.intersects(blueTanks[j])) { blueTanks[j].health -= 3; bullet.destroy(); playerBullets.splice(i, 1); if (blueTanks[j].health <= 0) { blueTanks[j].destroy(); blueTanks.splice(j, 1); LK.setScore(LK.getScore() + 25); totalEnemiesKilled++; storage.totalEnemiesKilled = totalEnemiesKilled; if (!hasKilledEnemy) { hasKilledEnemy = true; achievements.killFirstEnemy = true; storage.achievements = achievements; } } break; } } for (var j = iceTanks.length - 1; j >= 0; j--) { if (bullet.intersects(iceTanks[j])) { iceTanks[j].health -= 25; // Show breaking animation tween(iceTanks[j], { alpha: 0.5, scaleX: 0.8, scaleY: 0.8 }, { duration: 200, onFinish: function onFinish() { tween(iceTanks[j], { alpha: 1, scaleX: 1, scaleY: 1 }, { duration: 200 }); } }); bullet.destroy(); playerBullets.splice(i, 1); if (iceTanks[j].health <= 0) { iceTanks[j].destroy(); iceTanks.splice(j, 1); LK.setScore(LK.getScore() + 15); totalEnemiesKilled++; storage.totalEnemiesKilled = totalEnemiesKilled; if (!hasKilledEnemy) { hasKilledEnemy = true; achievements.killFirstEnemy = true; storage.achievements = achievements; } } break; } } } // 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 } };
===================================================================
--- original.js
+++ change.js
@@ -174,8 +174,15 @@
});
self.health = 225;
self.speed = 1;
self.shootCooldown = 0;
+ self.randomMoveTimer = 0;
+ self.randomMoveDirection = {
+ x: 0,
+ y: 0
+ };
+ self.isMovingRandomly = false;
+ self.randomStopTimer = 0;
self.update = function () {
if (gamePaused) {
return;
}
@@ -197,9 +204,9 @@
}
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
+ // Priority movement: chase target if close
if (distance < 350) {
var moveX = dx > 0 ? self.speed : -self.speed;
var moveY = dy > 0 ? self.speed : -self.speed;
var newX = self.x + moveX;
@@ -219,8 +226,50 @@
}
if (!checkWallCollision(self.x, newY)) {
self.y = newY;
}
+ self.isMovingRandomly = false;
+ self.randomMoveTimer = 0;
+ } else {
+ // Random movement when not chasing target
+ if (!self.isMovingRandomly && self.randomStopTimer <= 0) {
+ // Start moving in random direction
+ self.isMovingRandomly = true;
+ self.randomMoveTimer = Math.floor(Math.random() * 120) + 60; // Move for 1-3 seconds
+ var angle = Math.random() * Math.PI * 2;
+ self.randomMoveDirection.x = Math.cos(angle);
+ self.randomMoveDirection.y = Math.sin(angle);
+ // Rotate to face random direction
+ tween.stop(self, {
+ rotation: true
+ });
+ tween(self, {
+ rotation: angle
+ }, {
+ duration: 300,
+ easing: tween.easeOut
+ });
+ } else if (self.isMovingRandomly && self.randomMoveTimer > 0) {
+ // Continue random movement
+ self.randomMoveTimer--;
+ var moveX = self.randomMoveDirection.x * self.speed * 0.7;
+ var moveY = self.randomMoveDirection.y * self.speed * 0.7;
+ var newX = self.x + moveX;
+ var newY = self.y + moveY;
+ if (!checkWallCollision(newX, self.y) && newX > 50 && newX < 1998) {
+ self.x = newX;
+ }
+ if (!checkWallCollision(self.x, newY) && newY > 50 && newY < 2682) {
+ self.y = newY;
+ }
+ } else if (self.isMovingRandomly && self.randomMoveTimer <= 0) {
+ // Stop moving and wait
+ self.isMovingRandomly = false;
+ self.randomStopTimer = Math.floor(Math.random() * 180) + 60; // Stop for 1-4 seconds
+ } else if (!self.isMovingRandomly && self.randomStopTimer > 0) {
+ // Continue waiting
+ self.randomStopTimer--;
+ }
}
if (distance < 300 && self.shootCooldown <= 0) {
var length = Math.sqrt(dx * dx + dy * dy);
var dirX = dx / length;
@@ -246,8 +295,15 @@
});
self.health = 375;
self.speed = 1;
self.shootCooldown = 0;
+ self.randomMoveTimer = 0;
+ self.randomMoveDirection = {
+ x: 0,
+ y: 0
+ };
+ self.isMovingRandomly = false;
+ self.randomStopTimer = 0;
self.update = function () {
if (gamePaused) {
return;
}
@@ -256,8 +312,9 @@
}
var dx = playerTank.x - self.x;
var dy = playerTank.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
+ // Priority movement: chase player if close
if (distance < 350) {
var moveX = dx > 0 ? self.speed : -self.speed;
var moveY = dy > 0 ? self.speed : -self.speed;
var newX = self.x + moveX;
@@ -277,8 +334,50 @@
}
if (!checkWallCollision(self.x, newY)) {
self.y = newY;
}
+ self.isMovingRandomly = false;
+ self.randomMoveTimer = 0;
+ } else {
+ // Random movement when not chasing player
+ if (!self.isMovingRandomly && self.randomStopTimer <= 0) {
+ // Start moving in random direction
+ self.isMovingRandomly = true;
+ self.randomMoveTimer = Math.floor(Math.random() * 120) + 60; // Move for 1-3 seconds
+ var angle = Math.random() * Math.PI * 2;
+ self.randomMoveDirection.x = Math.cos(angle);
+ self.randomMoveDirection.y = Math.sin(angle);
+ // Rotate to face random direction
+ tween.stop(self, {
+ rotation: true
+ });
+ tween(self, {
+ rotation: angle
+ }, {
+ duration: 300,
+ easing: tween.easeOut
+ });
+ } else if (self.isMovingRandomly && self.randomMoveTimer > 0) {
+ // Continue random movement
+ self.randomMoveTimer--;
+ var moveX = self.randomMoveDirection.x * self.speed * 0.7;
+ var moveY = self.randomMoveDirection.y * self.speed * 0.7;
+ var newX = self.x + moveX;
+ var newY = self.y + moveY;
+ if (!checkWallCollision(newX, self.y) && newX > 50 && newX < 1998) {
+ self.x = newX;
+ }
+ if (!checkWallCollision(self.x, newY) && newY > 50 && newY < 2682) {
+ self.y = newY;
+ }
+ } else if (self.isMovingRandomly && self.randomMoveTimer <= 0) {
+ // Stop moving and wait
+ self.isMovingRandomly = false;
+ self.randomStopTimer = Math.floor(Math.random() * 180) + 60; // Stop for 1-4 seconds
+ } else if (!self.isMovingRandomly && self.randomStopTimer > 0) {
+ // Continue waiting
+ self.randomStopTimer--;
+ }
}
if (distance < 300 && self.shootCooldown <= 0) {
var length = Math.sqrt(dx * dx + dy * dy);
var dirX = dx / length;
@@ -516,8 +615,15 @@
});
self.health = 40;
self.speed = 0.8;
self.shootCooldown = 0;
+ self.randomMoveTimer = 0;
+ self.randomMoveDirection = {
+ x: 0,
+ y: 0
+ };
+ self.isMovingRandomly = false;
+ self.randomStopTimer = 0;
self.update = function () {
if (gamePaused) {
return;
}
@@ -539,9 +645,9 @@
}
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)
+ // Priority movement: chase target if close
if (distance < 300) {
var moveX = dx > 0 ? self.speed : -self.speed;
var moveY = dy > 0 ? self.speed : -self.speed;
var newX = self.x + moveX;
@@ -564,8 +670,50 @@
}
if (!checkWallCollision(self.x, newY)) {
self.y = newY;
}
+ self.isMovingRandomly = false;
+ self.randomMoveTimer = 0;
+ } else {
+ // Random movement when not chasing target
+ if (!self.isMovingRandomly && self.randomStopTimer <= 0) {
+ // Start moving in random direction
+ self.isMovingRandomly = true;
+ self.randomMoveTimer = Math.floor(Math.random() * 120) + 60; // Move for 1-3 seconds
+ var angle = Math.random() * Math.PI * 2;
+ self.randomMoveDirection.x = Math.cos(angle);
+ self.randomMoveDirection.y = Math.sin(angle);
+ // Rotate to face random direction
+ tween.stop(self, {
+ rotation: true
+ });
+ tween(self, {
+ rotation: angle
+ }, {
+ duration: 300,
+ easing: tween.easeOut
+ });
+ } else if (self.isMovingRandomly && self.randomMoveTimer > 0) {
+ // Continue random movement
+ self.randomMoveTimer--;
+ var moveX = self.randomMoveDirection.x * self.speed * 0.7;
+ var moveY = self.randomMoveDirection.y * self.speed * 0.7;
+ var newX = self.x + moveX;
+ var newY = self.y + moveY;
+ if (!checkWallCollision(newX, self.y) && newX > 50 && newX < 1998) {
+ self.x = newX;
+ }
+ if (!checkWallCollision(self.x, newY) && newY > 50 && newY < 2682) {
+ self.y = newY;
+ }
+ } else if (self.isMovingRandomly && self.randomMoveTimer <= 0) {
+ // Stop moving and wait
+ self.isMovingRandomly = false;
+ self.randomStopTimer = Math.floor(Math.random() * 180) + 60; // Stop for 1-4 seconds
+ } else if (!self.isMovingRandomly && self.randomStopTimer > 0) {
+ // Continue waiting
+ self.randomStopTimer--;
+ }
}
if (distance < 200 && self.shootCooldown <= 0) {
var length = Math.sqrt(dx * dx + dy * dy);
var dirX = dx / length;
@@ -610,8 +758,15 @@
});
self.health = 100;
self.speed = 1;
self.shootCooldown = 0;
+ self.randomMoveTimer = 0;
+ self.randomMoveDirection = {
+ x: 0,
+ y: 0
+ };
+ self.isMovingRandomly = false;
+ self.randomStopTimer = 0;
self.update = function () {
if (gamePaused) {
return;
}
@@ -620,8 +775,9 @@
}
var dx = playerTank.x - self.x;
var dy = playerTank.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
+ // Priority movement: chase player if close
if (distance < 350) {
var moveX = dx > 0 ? self.speed : -self.speed;
var moveY = dy > 0 ? self.speed : -self.speed;
var newX = self.x + moveX;
@@ -641,8 +797,50 @@
}
if (!checkWallCollision(self.x, newY)) {
self.y = newY;
}
+ self.isMovingRandomly = false;
+ self.randomMoveTimer = 0;
+ } else {
+ // Random movement when not chasing player
+ if (!self.isMovingRandomly && self.randomStopTimer <= 0) {
+ // Start moving in random direction
+ self.isMovingRandomly = true;
+ self.randomMoveTimer = Math.floor(Math.random() * 120) + 60; // Move for 1-3 seconds
+ var angle = Math.random() * Math.PI * 2;
+ self.randomMoveDirection.x = Math.cos(angle);
+ self.randomMoveDirection.y = Math.sin(angle);
+ // Rotate to face random direction
+ tween.stop(self, {
+ rotation: true
+ });
+ tween(self, {
+ rotation: angle
+ }, {
+ duration: 300,
+ easing: tween.easeOut
+ });
+ } else if (self.isMovingRandomly && self.randomMoveTimer > 0) {
+ // Continue random movement
+ self.randomMoveTimer--;
+ var moveX = self.randomMoveDirection.x * self.speed * 0.7;
+ var moveY = self.randomMoveDirection.y * self.speed * 0.7;
+ var newX = self.x + moveX;
+ var newY = self.y + moveY;
+ if (!checkWallCollision(newX, self.y) && newX > 50 && newX < 1998) {
+ self.x = newX;
+ }
+ if (!checkWallCollision(self.x, newY) && newY > 50 && newY < 2682) {
+ self.y = newY;
+ }
+ } else if (self.isMovingRandomly && self.randomMoveTimer <= 0) {
+ // Stop moving and wait
+ self.isMovingRandomly = false;
+ self.randomStopTimer = Math.floor(Math.random() * 180) + 60; // Stop for 1-4 seconds
+ } else if (!self.isMovingRandomly && self.randomStopTimer > 0) {
+ // Continue waiting
+ self.randomStopTimer--;
+ }
}
if (distance < 300 && self.shootCooldown <= 0) {
var length = Math.sqrt(dx * dx + dy * dy);
var dirX = dx / length;
@@ -676,8 +874,15 @@
});
self.health = 450;
self.speed = 1;
self.shootCooldown = 0;
+ self.randomMoveTimer = 0;
+ self.randomMoveDirection = {
+ x: 0,
+ y: 0
+ };
+ self.isMovingRandomly = false;
+ self.randomStopTimer = 0;
self.update = function () {
if (gamePaused) {
return;
}
@@ -686,8 +891,9 @@
}
var dx = playerTank.x - self.x;
var dy = playerTank.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
+ // Priority movement: chase player if close
if (distance < 350) {
var moveX = dx > 0 ? self.speed : -self.speed;
var moveY = dy > 0 ? self.speed : -self.speed;
var newX = self.x + moveX;
@@ -707,8 +913,50 @@
}
if (!checkWallCollision(self.x, newY)) {
self.y = newY;
}
+ self.isMovingRandomly = false;
+ self.randomMoveTimer = 0;
+ } else {
+ // Random movement when not chasing player
+ if (!self.isMovingRandomly && self.randomStopTimer <= 0) {
+ // Start moving in random direction
+ self.isMovingRandomly = true;
+ self.randomMoveTimer = Math.floor(Math.random() * 120) + 60; // Move for 1-3 seconds
+ var angle = Math.random() * Math.PI * 2;
+ self.randomMoveDirection.x = Math.cos(angle);
+ self.randomMoveDirection.y = Math.sin(angle);
+ // Rotate to face random direction
+ tween.stop(self, {
+ rotation: true
+ });
+ tween(self, {
+ rotation: angle
+ }, {
+ duration: 300,
+ easing: tween.easeOut
+ });
+ } else if (self.isMovingRandomly && self.randomMoveTimer > 0) {
+ // Continue random movement
+ self.randomMoveTimer--;
+ var moveX = self.randomMoveDirection.x * self.speed * 0.7;
+ var moveY = self.randomMoveDirection.y * self.speed * 0.7;
+ var newX = self.x + moveX;
+ var newY = self.y + moveY;
+ if (!checkWallCollision(newX, self.y) && newX > 50 && newX < 1998) {
+ self.x = newX;
+ }
+ if (!checkWallCollision(self.x, newY) && newY > 50 && newY < 2682) {
+ self.y = newY;
+ }
+ } else if (self.isMovingRandomly && self.randomMoveTimer <= 0) {
+ // Stop moving and wait
+ self.isMovingRandomly = false;
+ self.randomStopTimer = Math.floor(Math.random() * 180) + 60; // Stop for 1-4 seconds
+ } else if (!self.isMovingRandomly && self.randomStopTimer > 0) {
+ // Continue waiting
+ self.randomStopTimer--;
+ }
}
if (distance < 300 && self.shootCooldown <= 0) {
var length = Math.sqrt(dx * dx + dy * dy);
var dirX = dx / length;
@@ -795,8 +1043,15 @@
});
self.health = 80;
self.speed = 1;
self.shootCooldown = 0;
+ self.randomMoveTimer = 0;
+ self.randomMoveDirection = {
+ x: 0,
+ y: 0
+ };
+ self.isMovingRandomly = false;
+ self.randomStopTimer = 0;
self.update = function () {
if (gamePaused) {
return;
}
@@ -818,9 +1073,9 @@
}
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)
+ // Priority movement: chase target if close
if (distance < 350) {
var moveX = dx > 0 ? self.speed : -self.speed;
var moveY = dy > 0 ? self.speed : -self.speed;
var newX = self.x + moveX;
@@ -843,8 +1098,50 @@
}
if (!checkWallCollision(self.x, newY)) {
self.y = newY;
}
+ self.isMovingRandomly = false;
+ self.randomMoveTimer = 0;
+ } else {
+ // Random movement when not chasing target
+ if (!self.isMovingRandomly && self.randomStopTimer <= 0) {
+ // Start moving in random direction
+ self.isMovingRandomly = true;
+ self.randomMoveTimer = Math.floor(Math.random() * 120) + 60; // Move for 1-3 seconds
+ var angle = Math.random() * Math.PI * 2;
+ self.randomMoveDirection.x = Math.cos(angle);
+ self.randomMoveDirection.y = Math.sin(angle);
+ // Rotate to face random direction
+ tween.stop(self, {
+ rotation: true
+ });
+ tween(self, {
+ rotation: angle
+ }, {
+ duration: 300,
+ easing: tween.easeOut
+ });
+ } else if (self.isMovingRandomly && self.randomMoveTimer > 0) {
+ // Continue random movement
+ self.randomMoveTimer--;
+ var moveX = self.randomMoveDirection.x * self.speed * 0.7;
+ var moveY = self.randomMoveDirection.y * self.speed * 0.7;
+ var newX = self.x + moveX;
+ var newY = self.y + moveY;
+ if (!checkWallCollision(newX, self.y) && newX > 50 && newX < 1998) {
+ self.x = newX;
+ }
+ if (!checkWallCollision(self.x, newY) && newY > 50 && newY < 2682) {
+ self.y = newY;
+ }
+ } else if (self.isMovingRandomly && self.randomMoveTimer <= 0) {
+ // Stop moving and wait
+ self.isMovingRandomly = false;
+ self.randomStopTimer = Math.floor(Math.random() * 180) + 60; // Stop for 1-4 seconds
+ } else if (!self.isMovingRandomly && self.randomStopTimer > 0) {
+ // Continue waiting
+ self.randomStopTimer--;
+ }
}
if (distance < 250 && self.shootCooldown <= 0) {
var length = Math.sqrt(dx * dx + dy * dy);
var dirX = dx / length;
@@ -873,8 +1170,15 @@
self.shootCooldown = 0;
self.explosionRadius = 100;
self.lastPlayerX = 0;
self.lastPlayerY = 0;
+ self.randomMoveTimer = 0;
+ self.randomMoveDirection = {
+ x: 0,
+ y: 0
+ };
+ self.isMovingRandomly = false;
+ self.randomStopTimer = 0;
self.update = function () {
if (gamePaused) {
return;
}
@@ -898,8 +1202,9 @@
}
var dx = target.x - self.x;
var dy = target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
+ // Priority movement: chase target if close
if (distance < 150) {
var moveX = dx > 0 ? self.speed : -self.speed;
var moveY = dy > 0 ? self.speed : -self.speed;
var newX = self.x + moveX;
@@ -922,8 +1227,50 @@
}
if (!checkWallCollision(self.x, newY)) {
self.y = newY;
}
+ self.isMovingRandomly = false;
+ self.randomMoveTimer = 0;
+ } else {
+ // Random movement when not chasing target
+ if (!self.isMovingRandomly && self.randomStopTimer <= 0) {
+ // Start moving in random direction
+ self.isMovingRandomly = true;
+ self.randomMoveTimer = Math.floor(Math.random() * 120) + 60; // Move for 1-3 seconds
+ var angle = Math.random() * Math.PI * 2;
+ self.randomMoveDirection.x = Math.cos(angle);
+ self.randomMoveDirection.y = Math.sin(angle);
+ // Rotate to face random direction
+ tween.stop(self, {
+ rotation: true
+ });
+ tween(self, {
+ rotation: angle
+ }, {
+ duration: 300,
+ easing: tween.easeOut
+ });
+ } else if (self.isMovingRandomly && self.randomMoveTimer > 0) {
+ // Continue random movement
+ self.randomMoveTimer--;
+ var moveX = self.randomMoveDirection.x * self.speed * 0.7;
+ var moveY = self.randomMoveDirection.y * self.speed * 0.7;
+ var newX = self.x + moveX;
+ var newY = self.y + moveY;
+ if (!checkWallCollision(newX, self.y) && newX > 50 && newX < 1998) {
+ self.x = newX;
+ }
+ if (!checkWallCollision(self.x, newY) && newY > 50 && newY < 2682) {
+ self.y = newY;
+ }
+ } else if (self.isMovingRandomly && self.randomMoveTimer <= 0) {
+ // Stop moving and wait
+ self.isMovingRandomly = false;
+ self.randomStopTimer = Math.floor(Math.random() * 180) + 60; // Stop for 1-4 seconds
+ } else if (!self.isMovingRandomly && self.randomStopTimer > 0) {
+ // Continue waiting
+ self.randomStopTimer--;
+ }
}
if (distance < 300 && self.shootCooldown <= 0) {
var length = Math.sqrt(dx * dx + dy * dy);
var dirX = dx / length;
@@ -997,8 +1344,15 @@
self.health = 275;
self.speed = 1;
self.shootCooldown = 0;
self.targetWhiteTank = false;
+ self.randomMoveTimer = 0;
+ self.randomMoveDirection = {
+ x: 0,
+ y: 0
+ };
+ self.isMovingRandomly = false;
+ self.randomStopTimer = 0;
self.update = function () {
if (gamePaused) {
return;
}
@@ -1022,9 +1376,9 @@
}
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
+ // Priority movement: chase target if close
if (distance < 350) {
var moveX = dx > 0 ? self.speed : -self.speed;
var moveY = dy > 0 ? self.speed : -self.speed;
var newX = self.x + moveX;
@@ -1044,8 +1398,50 @@
}
if (!checkWallCollision(self.x, newY)) {
self.y = newY;
}
+ self.isMovingRandomly = false;
+ self.randomMoveTimer = 0;
+ } else {
+ // Random movement when not chasing target
+ if (!self.isMovingRandomly && self.randomStopTimer <= 0) {
+ // Start moving in random direction
+ self.isMovingRandomly = true;
+ self.randomMoveTimer = Math.floor(Math.random() * 120) + 60; // Move for 1-3 seconds
+ var angle = Math.random() * Math.PI * 2;
+ self.randomMoveDirection.x = Math.cos(angle);
+ self.randomMoveDirection.y = Math.sin(angle);
+ // Rotate to face random direction
+ tween.stop(self, {
+ rotation: true
+ });
+ tween(self, {
+ rotation: angle
+ }, {
+ duration: 300,
+ easing: tween.easeOut
+ });
+ } else if (self.isMovingRandomly && self.randomMoveTimer > 0) {
+ // Continue random movement
+ self.randomMoveTimer--;
+ var moveX = self.randomMoveDirection.x * self.speed * 0.7;
+ var moveY = self.randomMoveDirection.y * self.speed * 0.7;
+ var newX = self.x + moveX;
+ var newY = self.y + moveY;
+ if (!checkWallCollision(newX, self.y) && newX > 50 && newX < 1998) {
+ self.x = newX;
+ }
+ if (!checkWallCollision(self.x, newY) && newY > 50 && newY < 2682) {
+ self.y = newY;
+ }
+ } else if (self.isMovingRandomly && self.randomMoveTimer <= 0) {
+ // Stop moving and wait
+ self.isMovingRandomly = false;
+ self.randomStopTimer = Math.floor(Math.random() * 180) + 60; // Stop for 1-4 seconds
+ } else if (!self.isMovingRandomly && self.randomStopTimer > 0) {
+ // Continue waiting
+ self.randomStopTimer--;
+ }
}
if (distance < 300 && self.shootCooldown <= 0) {
var length = Math.sqrt(dx * dx + dy * dy);
var dirX = dx / length;
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
Pixel art bear trap top down. In-Game asset. 2d. High contrast. No shadows