/**** * Plugins ****/ var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var AmmoDisplay = Container.expand(function () { var self = Container.call(this); self.ammoText = new Text2('Ammo: 20', { size: 100, fill: 0xFFFFFF }); self.ammoText.anchor.set(1, 1); self.updateAmmo = function (ammoCount) { self.ammoText.setText('Ammo: ' + ammoCount); }; LK.gui.bottomRight.addChild(self.ammoText); }); var BloodSplatter = Container.expand(function (type) { var self = Container.call(this); self.createBloodSplatter = function (type) { var assetName; switch (type) { case 1: assetName = 'bloodSplatter1'; break; case 2: assetName = 'bloodSplatter2'; break; case 3: assetName = 'bloodSplatter3'; break; default: assetName = 'bloodSplatter1'; } return self.createAsset(assetName, { anchorX: 0.5, anchorY: 0.5 }); }; var bloodGraphics = self.createBloodSplatter(type); bloodGraphics.rotation = Math.random() * Math.PI * 2; self.visible = false; }); var BuyRobotButton = Container.expand(function (buttonAsset, cost, robotType) { var self = Container.call(this); self.buttonGraphics = self.createAsset(buttonAsset, { anchorX: 0.5, anchorY: 0.5 }); self.buttonGraphics.interactive = true; self.buttonGraphics.buttonMode = true; self.buttonGraphics.tint = 0x808080; // Set the background color to grey self.buttonGraphics.zIndex = 100; self.cost = cost; self.costText = new Text2(self.cost + ' credits', { size: 50, fill: 0xFFFFFF }); self.costText.anchor.set(0.5, 0); self.costText.y = 80; // Position below the button self.addChild(self.costText); self.on('down', function (x, y, obj) { if (credits >= self.cost) { var newRobot = new Robot(robotType); newRobot.y = 2732; // Start at the bottom of the screen // Define target X positions to 25%, 50%, and 75% of the width var targetXPositions = [2048 * 0.25, 2048 * 0.5, 2048 * 0.75]; var lowestLevelRobotIndex = -1; var lowestLevel = Infinity; var robotAdded = false; // Flag to check if robot is added // Check if the target position is free before placing the robot or find the lowest level robot for (var i = 0; i < targetXPositions.length; i++) { var positionFree = true; for (var j = 0; j < robot.length; j++) { if (robot[j].x === targetXPositions[i]) { positionFree = false; // Check if the current robot is of a lower level than the one being purchased if (robot[j].robotType < robotType) { if (robot[j].robotType < lowestLevel) { lowestLevel = robot[j].robotType; lowestLevelRobotIndex = j; } } break; } } if (positionFree) { newRobot.x = targetXPositions[i]; robot = robot ? robot.concat(newRobot) : [newRobot]; game.addChild(newRobot); robotAdded = true; break; } else if (lowestLevelRobotIndex !== -1 && robot.length === 3) { // Replace the lowest level robot with the new one robot[lowestLevelRobotIndex].destroy(); robot.splice(lowestLevelRobotIndex, 1, newRobot); newRobot.x = targetXPositions[lowestLevelRobotIndex]; game.addChild(newRobot); robotAdded = true; break; } } if (robotAdded) { credits -= self.cost; creditDisplay.updateCredits(credits); } // Call updateButtonOpacity initially to set the correct opacity updateButtonOpacity(); } }); }); // Define the BuyTrencherButton class var BuyTrencherButton = Container.expand(function (buttonAsset, cost) { var self = Container.call(this); self.buttonGraphics = self.createAsset(buttonAsset, { anchorX: 0.5, anchorY: 0.5 }); self.buttonGraphics.interactive = true; self.buttonGraphics.buttonMode = true; self.buttonGraphics.tint = 0x808080; // Set the background color to grey self.buttonGraphics.zIndex = 100; self.cost = cost; self.costText = new Text2(self.cost + ' credits', { size: 50, fill: 0xFFFFFF }); self.costText.anchor.set(0.5, 0); self.costText.y = 80; // Position below the button self.addChild(self.costText); self.on('down', function (x, y, obj) { if (credits >= self.cost) { // Implement the logic to add a Trencher to the game credits -= self.cost; creditDisplay.updateCredits(credits); updateButtonOpacity(); } }); }); var CreditDisplay = Container.expand(function () { var self = Container.call(this); self.creditText = new Text2('Credits: 0', { size: 100, fill: 0xFFFFFF }); self.creditText.anchor.set(1, 0); self.creditText.y = 120; // Position below the score display self.updateCredits = function (credits) { self.creditText.setText('Credits: ' + credits); }; LK.gui.topRight.addChild(self.creditText); }); // Define the Hero class var Hero = Container.expand(function () { var self = Container.call(this); var heroGraphics = self.attachAsset('hero', { anchorX: 0.5, anchorY: 0.5 }); self.ammo = 20; self.reloadTime = null; self.torchGraphics = self.attachAsset('torch', { anchorX: 0.5 }); self.torchGraphics.visible = false; self.orientTorch = function (mousePos) { var angle = Math.atan2(mousePos.y - self.y, mousePos.x - self.x); self.torchGraphics.rotation = angle; self.torchGraphics.visible = false; heroGraphics.rotation = angle; }; self.speed = 5; self._move_migrated = function (direction) { self.x += direction.x * self.speed; self.y += direction.y * self.speed; }; self.shoot = function (mousePos) { if (self.ammo > 0 && (!self.lastShotTime || LK.ticks - self.lastShotTime >= 10) && (!self.reloadTime || LK.ticks - self.reloadTime >= 90)) { var bullet = new HeroBullet(); bullet.x = self.x + 5; bullet.y = self.y - 80; var angle = Math.atan2(mousePos.y - self.y, mousePos.x - self.x); bullet.rotation = angle; self.torchGraphics.rotation = angle; heroGraphics.rotation = angle; bullets.push(bullet); game.addChild(bullet); self.lastShotTime = LK.ticks; LK.getSound('gun_fire').play(); self.ammo--; ammoDisplay.updateAmmo(self.ammo); var muzzleFlash = new MuzzleFlash(); var flashOffsetX = 80 * Math.cos(angle); // Offset for muzzle flash to align with the barrel var flashOffsetY = 80 * Math.sin(angle); // Offset for muzzle flash to align with the barrel muzzleFlash.x = self.x + flashOffsetX; muzzleFlash.y = self.y + flashOffsetY; muzzleFlash.rotation = angle; // Orient MuzzleFlash in the same direction as the torch muzzleFlash.zIndex = 1; // Ensure MuzzleFlash appears above other game elements muzzleFlash.visible = true; // Make MuzzleFlash visible when shooting game.addChildAt(muzzleFlash, 0); globalLightShow = true; LK.setTimeout(function () { muzzleFlash.destroy(); globalLightShow = false; }, 100); // Flash the screen for 100ms when the hero shoots LK.effects.flashScreen(0xffffff, 100); } else if (self.ammo === 0 && (!self.reloadTime || LK.ticks - self.reloadTime >= 90)) { self.ammo = 20; ammoDisplay.updateAmmo(self.ammo); self.reloadTime = LK.ticks; LK.getSound('reloading').play(); var reloadIcon = new ReloadIcon(); var reloadingText = new Text2('Reloading...', { size: 90, fill: '#ffffff', fontWeight: 'bold' }); reloadingText.x = self.x; reloadingText.y = self.y - 250; // Position above the reload icon reloadingText.anchor.set(0.5, 0.5); game.addChild(reloadIcon); game.addChild(reloadingText); reloadIcon.show(self.x, self.y); LK.setTimeout(function () { reloadingText.destroy(); }, 1500); // Destroy the text after 1.5 seconds (reload time) } }; }); // Define the HeroBullet class var HeroBullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('heroBullet', { anchorX: 0.5, anchorY: 1 }); self.speed = 50; self._move_migrated = function () { self.x += Math.cos(self.rotation) * self.speed; self.y += Math.sin(self.rotation) * self.speed; }; }); var MuzzleFlash = Container.expand(function () { var self = Container.call(this); var flashGraphics = self.attachAsset('muzzleFlash', { anchorX: 0.5, anchorY: 0.5 }); flashGraphics.alpha = 0.5; self.zIndex = -5; }); var ReloadIcon = Container.expand(function () { var self = Container.call(this); var reloadGraphics = self.attachAsset('reloadIcon', { anchorX: 0.5, anchorY: 0.5 }); self.show = function (heroX, heroY) { self.x = heroX; self.y = heroY - 450; self.visible = true; self.rotationSpeed = Math.PI * 2; // One full rotation per second self.lastRotationTime = LK.ticks; LK.on('tick', function () { if (self.visible && LK.ticks - self.lastRotationTime >= 1) { self.rotation += self.rotationSpeed / 60; // Divide by 60 because 'tick' operates at 60FPS self.lastRotationTime = LK.ticks; } }); LK.setTimeout(function () { self.visible = false; }, 1500); // Hide the icon after 1.5 seconds (reload time) }; }); // Define the Robot class var Robot = Container.expand(function (robotType) { var self = Container.call(this); var speedFireMultiplicator = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1; var robotGraphics = self.attachAsset('robot', { anchorX: 0.5, anchorY: 0.5 }); // Display the robot level below the robot self.levelDisplay = new Text2('Level: ' + robotType, { size: 50, fill: 0xFFFFFF }); self.robotType = robotType; self.levelDisplay.anchor.set(0.5, 0); self.levelDisplay.y = robotGraphics.height / 2 + 10; // Position below the robot graphics self.addChild(self.levelDisplay); self.healthBar = self.attachAsset('healthBarRobot', { anchorX: 0.5, anchorY: 1 }); self.healthBar.width = 100; self.healthBar.height = 10; self.healthBar.y = -robotGraphics.height / 2 - 20; // Position the health bar above the robot self.speed = 2; self.health = 50; self.lastShotTime = 0; self._move_migrated = function (targetY) { var stopPosition = 2732 * 0.65; // 40% from the bottom of the screen if (self.y > stopPosition) { self.y -= self.speed; } else { self.speed = 0; } }; self.shoot = function () { if (LK.ticks - self.lastShotTime >= 100 / speedFireMultiplicator) { var closestZombie = null; var closestDistance = Number.MAX_VALUE; for (var i = 0; i < zombies.length; i++) { var dx = self.x - zombies[i].x; var dy = self.y - zombies[i].y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < closestDistance) { closestDistance = distance; closestZombie = zombies[i]; } } if (closestZombie) { var angle = Math.atan2(closestZombie.y - self.y, closestZombie.x - self.x); robotGraphics.rotation = angle; // Orient the robot towards the target var dmgMultiplicator = 1; // Define a default damage multiplier var bullet = new HeroBullet(speedFireMultiplicator); // Use HeroBullet for robot shooting bullet.x = self.x + Math.cos(angle) * 40; // Position the bullet at the robot's gun bullet.y = self.y + Math.sin(angle) * 40; // Position the bullet at the robot's gun bullet.rotation = angle; robotBullets.push(bullet); // Add to robotBullets array self.healthBar.width = self.health / 20 * 100; // Update health bar width based on health var muzzleFlash = new MuzzleFlash(); var flashOffsetX = 150 * Math.cos(angle); // Offset for muzzle flash to align with a longer barrel var flashOffsetY = 150 * Math.sin(angle); // Offset for muzzle flash to align with a longer barrel muzzleFlash.x = self.x + flashOffsetX; muzzleFlash.y = self.y + flashOffsetY; muzzleFlash.rotation = angle; // Orient MuzzleFlash in the same direction as the robot muzzleFlash.zIndex = 1; // Ensure MuzzleFlash appears above other game elements muzzleFlash.visible = true; // Make MuzzleFlash visible when shooting game.addChildAt(muzzleFlash, 0); globalLightShow = true; LK.setTimeout(function () { muzzleFlash.destroy(); globalLightShow = false; }, 100); game.addChild(bullet); LK.getSound('robot_shoot').play(); LK.effects.flashScreen(0xffffff, 100); } self.lastShotTime = LK.ticks; } }; }); // Define the RobotBullet class var RobotBullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('robotBullet', { anchorX: 0.5, anchorY: 1 }); self.speed = 10; self._move_migrated = function () { self.y -= self.speed; }; }); var ScoreDisplay = Container.expand(function () { var self = Container.call(this); self.scoreText = new Text2('Kills: 0', { size: 100, fill: 0xFFFFFF }); self.scoreText.anchor.set(1, 0); self.updateScore = function (score) { self.scoreText.setText('Kills: ' + score); }; LK.gui.topRight.addChild(self.scoreText); }); // Define the TorchLight class var TorchLight = Container.expand(function () { var self = Container.call(this); var lightGraphics = self.attachAsset('torchLight', { anchorX: 0.5, anchorY: 1 }); self.rotation = -90; self.updatePosition = function (heroPos, torchAngle) { self.x = heroPos.x; self.y = heroPos.y; self.rotation = torchAngle + Math.PI / 2; // Adjust the size and shape of the light zone // Adjust the size and shape of the light zone to simulate a cone of light lightGraphics.width = 600; // Width of the light cone lightGraphics.height = 8000; // Length of the light cone // Set the alpha to a lower value to simulate light lightGraphics.alpha = 0.3; // Set the pivot to the bottom center of the light cone lightGraphics.pivot.x = 0; lightGraphics.pivot.y = 0; }; }); // Define the Zombie class var Zombie = Container.expand(function (isBoss) { var self = Container.call(this); Zombie.prototype.calculateTargetPosition = function (heroPos, robots) { var targetPos = heroPos; if (robots && robots.length > 0) { var closestRobot = null; var closestDistance = Number.MAX_VALUE; for (var i = 0; i < robots.length; i++) { if (robots[i].health > 0) { var dx = this.x - robots[i].x; var dy = this.y - robots[i].y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < closestDistance) { closestDistance = distance; closestRobot = robots[i]; } } } if (closestRobot) { targetPos = { x: closestRobot.x, y: closestRobot.y }; } } return targetPos; }; self.isBoss = isBoss; if (isBoss) { var zombieGraphics = self.attachAsset('bossZombie', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 0.5 + Math.floor(score / 50); self.health = Math.floor(Math.random() * (120 - 60 + 1)) + 60; } else { var zombieGraphics = self.attachAsset('zombie', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 0.8 + Math.floor(score / 30); self.health = 50; } self.healthBar = self.attachAsset('healthBar', { anchorX: 0.5 }); self.healthBar.width = self.health * 7; self.healthBar.height = 10; self.healthBar.y = -110; self._move_migrated = function (heroPos, torchAngle) { var targetPos = this.calculateTargetPosition(heroPos, robot); var angleToTarget = Math.atan2(targetPos.y - self.y, targetPos.x - self.x); self.x += Math.cos(angleToTarget) * self.speed; self.y += Math.sin(angleToTarget) * self.speed; if (heroPos) { var angleToZombie = Math.atan2(self.y - heroPos.y, self.x - heroPos.x); var angleDifference = Math.abs(torchAngle - angleToZombie); var distanceToHero = Math.sqrt(Math.pow(self.x - heroPos.x, 2) + Math.pow(self.y - heroPos.y, 2)); if (distanceToHero <= 400) { self.visible = true; self.alpha = 1; } else if (angleDifference < 0.12) { // Assuming torch has a cone of visibility of 0.5 radians self.visible = true; self.alpha = 1; } else { if (globalLightShow) { self.visible = true; self.alpha = 0.5; } else { self.visible = false; } } } self.healthBar.width = self.health * 10; }; }); var ZombieCountDisplay = Container.expand(function () { var self = Container.call(this); self.zombieCountText = new Text2('Zombies: 0', { size: 100, fill: 0xFFFFFF }); self.zombieCountText.anchor.set(1, 0); self.zombieCountText.y = 240; // Position below the credit display self.updateZombieCount = function (zombieCount) { self.zombieCountText.setText('Zombies: ' + zombieCount); }; LK.gui.topRight.addChild(self.zombieCountText); }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundAsset: 'nightBackground' // Set night background image for the game }); /**** * Game Code ****/ // Initialize important asset arrays var zombiesSpawnedCount = 0; LK.playMusic('background_music', { loop: true }); function showCustomGameOverScreen() { var gameOverContainer = new Container(); var scoreText = new Text2('Score: ' + score, { size: 200, fill: 0xFFFFFF }); scoreText.anchor.set(0.5, 0); scoreText.x = 2048 / 2; scoreText.y = 200; gameOverContainer.addChild(scoreText); // Hide AmmoDisplay, CreditDisplay, and ZombieCountDisplay zombieCountDisplay.zombieCountText.visible = false; creditDisplay.creditText.visible = false; ammoDisplay.ammoText.visible = false; scoreDisplay.scoreText.visible = false; // Hide all other game elements for (var i = 0; i < game.children.length; i++) { if (game.children[i] !== gameOverContainer) { game.children[i].visible = false; } } // TODO: Implement score history display var closeButton = new Container(); var closeButtonText = new Text2('Close', { size: 100, fill: 0xFFFFFF }); closeButtonText.anchor.set(0.5, 0.5); closeButton.addChild(closeButtonText); closeButton.x = 2048 / 2; closeButton.y = 2732 - 200; closeButton.interactive = true; closeButton.buttonMode = true; closeButton.on('down', function () { gameOverContainer.destroy(); LK.showGameOver(); }); // Create a 'Game Over' text object var gameOverText = new Text2('Game Over', { size: 200, fill: 0xFFFFFF }); gameOverText.anchor.set(0.5, 0.5); gameOverText.x = 2048 / 2; gameOverText.y = 2732 * 0.3; gameOverContainer.addChild(gameOverText); var gameOverSprite = LK.getAsset('gameOverSprite', { anchorX: 0.5, anchorY: 0.5 }); gameOverSprite.x = 50 / 2; gameOverSprite.y = gameOverText.y + 20; gameOverContainer.addChild(gameOverSprite); LK.getSound('game_over').play(); // Play game over sound gameOverContainer.addChild(closeButton); // Save the score online storage.score = score; // Save the score to the leaderboard if (!storage.leaderboard) { storage.leaderboard = []; } storage.leaderboard.push(score); storage.leaderboard.sort(function (a, b) { return b - a; }); // Sort scores in descending order // Save the score online storage.score = score; game.addChild(gameOverContainer); } var robot = []; var robotBullets = []; var torchLight = game.addChild(new TorchLight()); var bullets = []; var zombies = []; var hero; var isGameOver = false; var score = 0; var ammoDisplay = new AmmoDisplay(); var credits = 0; var creditDisplay = new CreditDisplay(); var zombieCountDisplay = new ZombieCountDisplay(); var scoreDisplay = new ScoreDisplay(); var globalLightShow = false; // Add ground to the game var ground = LK.getAsset('ground', { anchorX: 0.5, anchorY: 1 }); ground.x = 2048 / 2; ground.y = 2732; ground.alpha = 0.8; // Set the opacity of the background to 20% game.addChildAt(ground, 0); // Create the hero hero = game.addChild(new Hero()); hero.x = 2048 / 2; hero.y = 2732 - 100; // Position hero near the bottom of the screen // Function to update button opacity based on available credits function updateButtonOpacity() { var buttons = [buyRobotButton1, buyRobotButton2, buyRobotButton3]; buttons.forEach(function (button) { if (button && button.buttonGraphics) { button.buttonGraphics.alpha = credits >= button.cost ? 1 : 0.3; } }); } // Add BuyRobotButton to the game var buyRobotButton1 = game.addChild(new BuyRobotButton('robotButton1', 40, '1')); buyRobotButton1.x = 150; // Position button at the bottom left buyRobotButton1.y = 2732 - 250; // Add BuyRobotButton3 to the game var buyRobotButton2 = game.addChild(new BuyRobotButton('robotButton2', 100, '2')); buyRobotButton2.x = 150; // Position button at the bottom left, aligned with the first button buyRobotButton2.y = 2732 - 500; // Position the third button above the second button // Add BuyRobotButton2 to the game var buyRobotButton3 = game.addChild(new BuyRobotButton('robotButton3', 200, '3')); buyRobotButton3.x = 150; // Position button at the bottom left, aligned with the first button buyRobotButton3.y = 2732 - 750; // Position the second button above the first button // Add TrencherButton to the game //var buyTrencherButton1 = game.addChild(new BuyTrencherButton('trencherButton', 10)); //buyTrencherButton1.x = buyRobotButton1.x + 280; // Position button next to the RobotButton3 //buyTrencherButton1.y = buyRobotButton1.y; // Position the Trencher button below the RobotButton3 with a 50px gap // Call updateButtonOpacity initially to set the correct opacity updateButtonOpacity(); // Game logic and event handlers LK.on('keydown', function (obj) { var direction = { x: 0, y: 0 }; var e = obj.event; switch (e.keyCode) { case 37: // left arrow direction.x = -1; break; case 39: // right arrow direction.x = 1; break; case 38: // up arrow direction.y = -1; break; case 40: // down arrow direction.y = 1; break; } hero._move_migrated(direction); }); LK.on('tick', function () { if (isGameOver) { showCustomGameOverScreen(); return; } // Move bullets and check for off-screen for (var i = bullets.length - 1; i >= 0; i--) { if (bullets[i]) { bullets[i]._move_migrated(); for (var j = zombies.length - 1; j >= 0; j--) { if (bullets[i] && bullets[i].intersects(zombies[j])) { bullets[i].destroy(); bullets.splice(i, 1); zombies[j].health -= Math.floor(Math.random() * (20 + 1)) + 20; if (zombies[j].health <= 0) { LK.getSound('zombie_death').play(); var bloodSplatterType = Math.floor(Math.random() * 3) + 1; // Randomly choose a blood splatter type between 1 and 3 var bloodSplatter = new BloodSplatter(bloodSplatterType); bloodSplatter.x = zombies[j].x; bloodSplatter.y = zombies[j].y; game.addChildAt(bloodSplatter, 0); zombies[j].destroy(); zombies.splice(j, 1); score++; if (zombies[j]) { credits += zombies[j].isBoss ? 4 : 2; // Boss zombies give double credits } scoreDisplay.updateScore(score); creditDisplay.updateCredits(credits); updateButtonOpacity(); zombieCountDisplay.updateZombieCount(zombies.length); } break; } } if (bullets[i] && (bullets[i].x < 0 || bullets[i].x > 2048 || bullets[i].y < 0 || bullets[i].y > 2732)) { bullets[i].destroy(); bullets.splice(i, 1); } } } // Handle torch orientation and make zombies visible if illuminated var torchPos = { x: hero.x, y: hero.y }; var torchAngle = hero.torchGraphics.rotation; // Update torch light position var heroPos = { x: hero.x, y: hero.y }; var torchAngle = hero.torchGraphics.rotation; torchLight.updatePosition(heroPos, torchAngle); // Update visibility of blood splatters based on torch light for (var i = game.children.length - 1; i >= 0; i--) { var obj = game.children[i]; if (obj instanceof BloodSplatter) { var distanceToTorch = Math.sqrt(Math.pow(obj.x - hero.x, 2) + Math.pow(obj.y - hero.y, 2)); var angleToTorch = Math.atan2(obj.y - hero.y, obj.x - hero.x) - torchAngle; // Check if within torch light angle and range if (distanceToTorch <= 8000 && Math.abs(angleToTorch) <= 0.12) { obj.visible = true; } else { obj.visible = false; } } } // Move and shoot with the robot if (robot && robot.length > 0) { for (var i = robot.length - 1; i >= 0; i--) { robot[i]._move_migrated(robot[i].targetY); robot[i].shoot(); if (robot[i].y < -50 || robot[i].health <= 0) { // If the robot moves off-screen or dies robot[i].destroy(); robot.splice(i, 1); } } } // Move robot bullets, check for off-screen, and apply damage to zombies for (var i = robotBullets.length - 1; i >= 0; i--) { if (robotBullets[i]) { robotBullets[i]._move_migrated(); for (var j = zombies.length - 1; j >= 0; j--) { if (robotBullets[i] && robotBullets[i].intersects(zombies[j])) { robotBullets[i].destroy(); robotBullets.splice(i, 1); zombies[j].health -= Math.floor(Math.random() * (20 + 1)) + 20; if (zombies[j].health <= 0) { if (zombies[j].isBoss) { LK.getSound('boss_death').play(); } else { LK.getSound('zombie_death').play(); } var bloodSplatterType = Math.floor(Math.random() * 3) + 1; var bloodSplatter = new BloodSplatter(bloodSplatterType); bloodSplatter.x = zombies[j].x; bloodSplatter.y = zombies[j].y; game.addChildAt(bloodSplatter, 0); zombies[j].destroy(); zombies.splice(j, 1); score++; if (zombies[j]) { credits += zombies[j].isBoss ? 2 : 1; // Double credits for boss kills by robots } scoreDisplay.updateScore(score); creditDisplay.updateCredits(credits); zombieCountDisplay.updateZombieCount(zombies.length); updateButtonOpacity(); } break; } } if (robotBullets[i] && robotBullets[i].y < 0) { robotBullets[i].destroy(); robotBullets.splice(i, 1); } } } // Move zombies and check for collision with hero and robot for (var j = zombies.length - 1; j >= 0; j--) { zombies[j]._move_migrated(torchPos, torchAngle); if (zombies[j].y > 2732) { zombies[j].destroy(); zombies.splice(j, 1); } else if (zombies[j].intersects(hero) && zombies[j].visible) { isGameOver = true; } else if (robot) { for (var k = robot.length - 1; k >= 0; k--) { if (zombies[j].intersects(robot[k])) { robot[k].health -= 10; robot[k].healthBar.width = robot[k].health / 20 * 100; // Update health bar width based on health if (robot[k].health <= 0) { LK.getSound('robot_destruction').play(); robot[k].destroy(); robot.splice(k, 1); } zombies[j].destroy(); zombies.splice(j, 1); } } } } game.on('move', function (x, y, obj) { var mousePos = game.toLocal(obj.global); hero.orientTorch(mousePos); }); game.on('down', function (x, y, obj) { var mousePos = game.toLocal(obj.global); hero.shoot(mousePos); }); // Spawn the robot reinforcement when the player purchases it // Removed the automatic robot spawn code block // Spawn zombies var spawnRate = Math.max(30, 120 - Math.floor(score / 8) * 5); if (LK.ticks % spawnRate == 0) { // Spawn a zombie every 2 seconds var zombie; if (zombiesSpawnedCount % 20 == 0 && zombiesSpawnedCount !== 0) { // Spawn a boss zombie every 15 zombies spawned zombie = new Zombie(true); LK.getSound('boss_spawn').play(); // Play sound when a boss spawns } else { zombie = new Zombie(); } zombiesSpawnedCount++; zombie.x = Math.random() * 2048; zombie.y = -50; // Start off-screen zombies.push(zombie); game.addChild(zombie); zombieCountDisplay.updateZombieCount(zombies.length); } /* if (LK.ticks == 0) { // Spawn a zombie every 2 seconds var zombie; zombie = new Zombie(); zombiesSpawnedCount++; zombie.x = hero.x; zombie.y = hero.y - 300; // Start off-screen zombies.push(zombie); game.addChild(zombie); zombieCountDisplay.updateZombieCount(zombies.length); } */ });
/****
* Plugins
****/
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var AmmoDisplay = Container.expand(function () {
var self = Container.call(this);
self.ammoText = new Text2('Ammo: 20', {
size: 100,
fill: 0xFFFFFF
});
self.ammoText.anchor.set(1, 1);
self.updateAmmo = function (ammoCount) {
self.ammoText.setText('Ammo: ' + ammoCount);
};
LK.gui.bottomRight.addChild(self.ammoText);
});
var BloodSplatter = Container.expand(function (type) {
var self = Container.call(this);
self.createBloodSplatter = function (type) {
var assetName;
switch (type) {
case 1:
assetName = 'bloodSplatter1';
break;
case 2:
assetName = 'bloodSplatter2';
break;
case 3:
assetName = 'bloodSplatter3';
break;
default:
assetName = 'bloodSplatter1';
}
return self.createAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
};
var bloodGraphics = self.createBloodSplatter(type);
bloodGraphics.rotation = Math.random() * Math.PI * 2;
self.visible = false;
});
var BuyRobotButton = Container.expand(function (buttonAsset, cost, robotType) {
var self = Container.call(this);
self.buttonGraphics = self.createAsset(buttonAsset, {
anchorX: 0.5,
anchorY: 0.5
});
self.buttonGraphics.interactive = true;
self.buttonGraphics.buttonMode = true;
self.buttonGraphics.tint = 0x808080; // Set the background color to grey
self.buttonGraphics.zIndex = 100;
self.cost = cost;
self.costText = new Text2(self.cost + ' credits', {
size: 50,
fill: 0xFFFFFF
});
self.costText.anchor.set(0.5, 0);
self.costText.y = 80; // Position below the button
self.addChild(self.costText);
self.on('down', function (x, y, obj) {
if (credits >= self.cost) {
var newRobot = new Robot(robotType);
newRobot.y = 2732; // Start at the bottom of the screen
// Define target X positions to 25%, 50%, and 75% of the width
var targetXPositions = [2048 * 0.25, 2048 * 0.5, 2048 * 0.75];
var lowestLevelRobotIndex = -1;
var lowestLevel = Infinity;
var robotAdded = false; // Flag to check if robot is added
// Check if the target position is free before placing the robot or find the lowest level robot
for (var i = 0; i < targetXPositions.length; i++) {
var positionFree = true;
for (var j = 0; j < robot.length; j++) {
if (robot[j].x === targetXPositions[i]) {
positionFree = false;
// Check if the current robot is of a lower level than the one being purchased
if (robot[j].robotType < robotType) {
if (robot[j].robotType < lowestLevel) {
lowestLevel = robot[j].robotType;
lowestLevelRobotIndex = j;
}
}
break;
}
}
if (positionFree) {
newRobot.x = targetXPositions[i];
robot = robot ? robot.concat(newRobot) : [newRobot];
game.addChild(newRobot);
robotAdded = true;
break;
} else if (lowestLevelRobotIndex !== -1 && robot.length === 3) {
// Replace the lowest level robot with the new one
robot[lowestLevelRobotIndex].destroy();
robot.splice(lowestLevelRobotIndex, 1, newRobot);
newRobot.x = targetXPositions[lowestLevelRobotIndex];
game.addChild(newRobot);
robotAdded = true;
break;
}
}
if (robotAdded) {
credits -= self.cost;
creditDisplay.updateCredits(credits);
}
// Call updateButtonOpacity initially to set the correct opacity
updateButtonOpacity();
}
});
});
// Define the BuyTrencherButton class
var BuyTrencherButton = Container.expand(function (buttonAsset, cost) {
var self = Container.call(this);
self.buttonGraphics = self.createAsset(buttonAsset, {
anchorX: 0.5,
anchorY: 0.5
});
self.buttonGraphics.interactive = true;
self.buttonGraphics.buttonMode = true;
self.buttonGraphics.tint = 0x808080; // Set the background color to grey
self.buttonGraphics.zIndex = 100;
self.cost = cost;
self.costText = new Text2(self.cost + ' credits', {
size: 50,
fill: 0xFFFFFF
});
self.costText.anchor.set(0.5, 0);
self.costText.y = 80; // Position below the button
self.addChild(self.costText);
self.on('down', function (x, y, obj) {
if (credits >= self.cost) {
// Implement the logic to add a Trencher to the game
credits -= self.cost;
creditDisplay.updateCredits(credits);
updateButtonOpacity();
}
});
});
var CreditDisplay = Container.expand(function () {
var self = Container.call(this);
self.creditText = new Text2('Credits: 0', {
size: 100,
fill: 0xFFFFFF
});
self.creditText.anchor.set(1, 0);
self.creditText.y = 120; // Position below the score display
self.updateCredits = function (credits) {
self.creditText.setText('Credits: ' + credits);
};
LK.gui.topRight.addChild(self.creditText);
});
// Define the Hero class
var Hero = Container.expand(function () {
var self = Container.call(this);
var heroGraphics = self.attachAsset('hero', {
anchorX: 0.5,
anchorY: 0.5
});
self.ammo = 20;
self.reloadTime = null;
self.torchGraphics = self.attachAsset('torch', {
anchorX: 0.5
});
self.torchGraphics.visible = false;
self.orientTorch = function (mousePos) {
var angle = Math.atan2(mousePos.y - self.y, mousePos.x - self.x);
self.torchGraphics.rotation = angle;
self.torchGraphics.visible = false;
heroGraphics.rotation = angle;
};
self.speed = 5;
self._move_migrated = function (direction) {
self.x += direction.x * self.speed;
self.y += direction.y * self.speed;
};
self.shoot = function (mousePos) {
if (self.ammo > 0 && (!self.lastShotTime || LK.ticks - self.lastShotTime >= 10) && (!self.reloadTime || LK.ticks - self.reloadTime >= 90)) {
var bullet = new HeroBullet();
bullet.x = self.x + 5;
bullet.y = self.y - 80;
var angle = Math.atan2(mousePos.y - self.y, mousePos.x - self.x);
bullet.rotation = angle;
self.torchGraphics.rotation = angle;
heroGraphics.rotation = angle;
bullets.push(bullet);
game.addChild(bullet);
self.lastShotTime = LK.ticks;
LK.getSound('gun_fire').play();
self.ammo--;
ammoDisplay.updateAmmo(self.ammo);
var muzzleFlash = new MuzzleFlash();
var flashOffsetX = 80 * Math.cos(angle); // Offset for muzzle flash to align with the barrel
var flashOffsetY = 80 * Math.sin(angle); // Offset for muzzle flash to align with the barrel
muzzleFlash.x = self.x + flashOffsetX;
muzzleFlash.y = self.y + flashOffsetY;
muzzleFlash.rotation = angle; // Orient MuzzleFlash in the same direction as the torch
muzzleFlash.zIndex = 1; // Ensure MuzzleFlash appears above other game elements
muzzleFlash.visible = true; // Make MuzzleFlash visible when shooting
game.addChildAt(muzzleFlash, 0);
globalLightShow = true;
LK.setTimeout(function () {
muzzleFlash.destroy();
globalLightShow = false;
}, 100);
// Flash the screen for 100ms when the hero shoots
LK.effects.flashScreen(0xffffff, 100);
} else if (self.ammo === 0 && (!self.reloadTime || LK.ticks - self.reloadTime >= 90)) {
self.ammo = 20;
ammoDisplay.updateAmmo(self.ammo);
self.reloadTime = LK.ticks;
LK.getSound('reloading').play();
var reloadIcon = new ReloadIcon();
var reloadingText = new Text2('Reloading...', {
size: 90,
fill: '#ffffff',
fontWeight: 'bold'
});
reloadingText.x = self.x;
reloadingText.y = self.y - 250; // Position above the reload icon
reloadingText.anchor.set(0.5, 0.5);
game.addChild(reloadIcon);
game.addChild(reloadingText);
reloadIcon.show(self.x, self.y);
LK.setTimeout(function () {
reloadingText.destroy();
}, 1500); // Destroy the text after 1.5 seconds (reload time)
}
};
});
// Define the HeroBullet class
var HeroBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('heroBullet', {
anchorX: 0.5,
anchorY: 1
});
self.speed = 50;
self._move_migrated = function () {
self.x += Math.cos(self.rotation) * self.speed;
self.y += Math.sin(self.rotation) * self.speed;
};
});
var MuzzleFlash = Container.expand(function () {
var self = Container.call(this);
var flashGraphics = self.attachAsset('muzzleFlash', {
anchorX: 0.5,
anchorY: 0.5
});
flashGraphics.alpha = 0.5;
self.zIndex = -5;
});
var ReloadIcon = Container.expand(function () {
var self = Container.call(this);
var reloadGraphics = self.attachAsset('reloadIcon', {
anchorX: 0.5,
anchorY: 0.5
});
self.show = function (heroX, heroY) {
self.x = heroX;
self.y = heroY - 450;
self.visible = true;
self.rotationSpeed = Math.PI * 2; // One full rotation per second
self.lastRotationTime = LK.ticks;
LK.on('tick', function () {
if (self.visible && LK.ticks - self.lastRotationTime >= 1) {
self.rotation += self.rotationSpeed / 60; // Divide by 60 because 'tick' operates at 60FPS
self.lastRotationTime = LK.ticks;
}
});
LK.setTimeout(function () {
self.visible = false;
}, 1500); // Hide the icon after 1.5 seconds (reload time)
};
});
// Define the Robot class
var Robot = Container.expand(function (robotType) {
var self = Container.call(this);
var speedFireMultiplicator = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
var robotGraphics = self.attachAsset('robot', {
anchorX: 0.5,
anchorY: 0.5
});
// Display the robot level below the robot
self.levelDisplay = new Text2('Level: ' + robotType, {
size: 50,
fill: 0xFFFFFF
});
self.robotType = robotType;
self.levelDisplay.anchor.set(0.5, 0);
self.levelDisplay.y = robotGraphics.height / 2 + 10; // Position below the robot graphics
self.addChild(self.levelDisplay);
self.healthBar = self.attachAsset('healthBarRobot', {
anchorX: 0.5,
anchorY: 1
});
self.healthBar.width = 100;
self.healthBar.height = 10;
self.healthBar.y = -robotGraphics.height / 2 - 20; // Position the health bar above the robot
self.speed = 2;
self.health = 50;
self.lastShotTime = 0;
self._move_migrated = function (targetY) {
var stopPosition = 2732 * 0.65; // 40% from the bottom of the screen
if (self.y > stopPosition) {
self.y -= self.speed;
} else {
self.speed = 0;
}
};
self.shoot = function () {
if (LK.ticks - self.lastShotTime >= 100 / speedFireMultiplicator) {
var closestZombie = null;
var closestDistance = Number.MAX_VALUE;
for (var i = 0; i < zombies.length; i++) {
var dx = self.x - zombies[i].x;
var dy = self.y - zombies[i].y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < closestDistance) {
closestDistance = distance;
closestZombie = zombies[i];
}
}
if (closestZombie) {
var angle = Math.atan2(closestZombie.y - self.y, closestZombie.x - self.x);
robotGraphics.rotation = angle; // Orient the robot towards the target
var dmgMultiplicator = 1; // Define a default damage multiplier
var bullet = new HeroBullet(speedFireMultiplicator); // Use HeroBullet for robot shooting
bullet.x = self.x + Math.cos(angle) * 40; // Position the bullet at the robot's gun
bullet.y = self.y + Math.sin(angle) * 40; // Position the bullet at the robot's gun
bullet.rotation = angle;
robotBullets.push(bullet); // Add to robotBullets array
self.healthBar.width = self.health / 20 * 100; // Update health bar width based on health
var muzzleFlash = new MuzzleFlash();
var flashOffsetX = 150 * Math.cos(angle); // Offset for muzzle flash to align with a longer barrel
var flashOffsetY = 150 * Math.sin(angle); // Offset for muzzle flash to align with a longer barrel
muzzleFlash.x = self.x + flashOffsetX;
muzzleFlash.y = self.y + flashOffsetY;
muzzleFlash.rotation = angle; // Orient MuzzleFlash in the same direction as the robot
muzzleFlash.zIndex = 1; // Ensure MuzzleFlash appears above other game elements
muzzleFlash.visible = true; // Make MuzzleFlash visible when shooting
game.addChildAt(muzzleFlash, 0);
globalLightShow = true;
LK.setTimeout(function () {
muzzleFlash.destroy();
globalLightShow = false;
}, 100);
game.addChild(bullet);
LK.getSound('robot_shoot').play();
LK.effects.flashScreen(0xffffff, 100);
}
self.lastShotTime = LK.ticks;
}
};
});
// Define the RobotBullet class
var RobotBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('robotBullet', {
anchorX: 0.5,
anchorY: 1
});
self.speed = 10;
self._move_migrated = function () {
self.y -= self.speed;
};
});
var ScoreDisplay = Container.expand(function () {
var self = Container.call(this);
self.scoreText = new Text2('Kills: 0', {
size: 100,
fill: 0xFFFFFF
});
self.scoreText.anchor.set(1, 0);
self.updateScore = function (score) {
self.scoreText.setText('Kills: ' + score);
};
LK.gui.topRight.addChild(self.scoreText);
});
// Define the TorchLight class
var TorchLight = Container.expand(function () {
var self = Container.call(this);
var lightGraphics = self.attachAsset('torchLight', {
anchorX: 0.5,
anchorY: 1
});
self.rotation = -90;
self.updatePosition = function (heroPos, torchAngle) {
self.x = heroPos.x;
self.y = heroPos.y;
self.rotation = torchAngle + Math.PI / 2;
// Adjust the size and shape of the light zone
// Adjust the size and shape of the light zone to simulate a cone of light
lightGraphics.width = 600; // Width of the light cone
lightGraphics.height = 8000; // Length of the light cone
// Set the alpha to a lower value to simulate light
lightGraphics.alpha = 0.3;
// Set the pivot to the bottom center of the light cone
lightGraphics.pivot.x = 0;
lightGraphics.pivot.y = 0;
};
});
// Define the Zombie class
var Zombie = Container.expand(function (isBoss) {
var self = Container.call(this);
Zombie.prototype.calculateTargetPosition = function (heroPos, robots) {
var targetPos = heroPos;
if (robots && robots.length > 0) {
var closestRobot = null;
var closestDistance = Number.MAX_VALUE;
for (var i = 0; i < robots.length; i++) {
if (robots[i].health > 0) {
var dx = this.x - robots[i].x;
var dy = this.y - robots[i].y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < closestDistance) {
closestDistance = distance;
closestRobot = robots[i];
}
}
}
if (closestRobot) {
targetPos = {
x: closestRobot.x,
y: closestRobot.y
};
}
}
return targetPos;
};
self.isBoss = isBoss;
if (isBoss) {
var zombieGraphics = self.attachAsset('bossZombie', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 0.5 + Math.floor(score / 50);
self.health = Math.floor(Math.random() * (120 - 60 + 1)) + 60;
} else {
var zombieGraphics = self.attachAsset('zombie', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 0.8 + Math.floor(score / 30);
self.health = 50;
}
self.healthBar = self.attachAsset('healthBar', {
anchorX: 0.5
});
self.healthBar.width = self.health * 7;
self.healthBar.height = 10;
self.healthBar.y = -110;
self._move_migrated = function (heroPos, torchAngle) {
var targetPos = this.calculateTargetPosition(heroPos, robot);
var angleToTarget = Math.atan2(targetPos.y - self.y, targetPos.x - self.x);
self.x += Math.cos(angleToTarget) * self.speed;
self.y += Math.sin(angleToTarget) * self.speed;
if (heroPos) {
var angleToZombie = Math.atan2(self.y - heroPos.y, self.x - heroPos.x);
var angleDifference = Math.abs(torchAngle - angleToZombie);
var distanceToHero = Math.sqrt(Math.pow(self.x - heroPos.x, 2) + Math.pow(self.y - heroPos.y, 2));
if (distanceToHero <= 400) {
self.visible = true;
self.alpha = 1;
} else if (angleDifference < 0.12) {
// Assuming torch has a cone of visibility of 0.5 radians
self.visible = true;
self.alpha = 1;
} else {
if (globalLightShow) {
self.visible = true;
self.alpha = 0.5;
} else {
self.visible = false;
}
}
}
self.healthBar.width = self.health * 10;
};
});
var ZombieCountDisplay = Container.expand(function () {
var self = Container.call(this);
self.zombieCountText = new Text2('Zombies: 0', {
size: 100,
fill: 0xFFFFFF
});
self.zombieCountText.anchor.set(1, 0);
self.zombieCountText.y = 240; // Position below the credit display
self.updateZombieCount = function (zombieCount) {
self.zombieCountText.setText('Zombies: ' + zombieCount);
};
LK.gui.topRight.addChild(self.zombieCountText);
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundAsset: 'nightBackground' // Set night background image for the game
});
/****
* Game Code
****/
// Initialize important asset arrays
var zombiesSpawnedCount = 0;
LK.playMusic('background_music', {
loop: true
});
function showCustomGameOverScreen() {
var gameOverContainer = new Container();
var scoreText = new Text2('Score: ' + score, {
size: 200,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
scoreText.x = 2048 / 2;
scoreText.y = 200;
gameOverContainer.addChild(scoreText);
// Hide AmmoDisplay, CreditDisplay, and ZombieCountDisplay
zombieCountDisplay.zombieCountText.visible = false;
creditDisplay.creditText.visible = false;
ammoDisplay.ammoText.visible = false;
scoreDisplay.scoreText.visible = false;
// Hide all other game elements
for (var i = 0; i < game.children.length; i++) {
if (game.children[i] !== gameOverContainer) {
game.children[i].visible = false;
}
}
// TODO: Implement score history display
var closeButton = new Container();
var closeButtonText = new Text2('Close', {
size: 100,
fill: 0xFFFFFF
});
closeButtonText.anchor.set(0.5, 0.5);
closeButton.addChild(closeButtonText);
closeButton.x = 2048 / 2;
closeButton.y = 2732 - 200;
closeButton.interactive = true;
closeButton.buttonMode = true;
closeButton.on('down', function () {
gameOverContainer.destroy();
LK.showGameOver();
});
// Create a 'Game Over' text object
var gameOverText = new Text2('Game Over', {
size: 200,
fill: 0xFFFFFF
});
gameOverText.anchor.set(0.5, 0.5);
gameOverText.x = 2048 / 2;
gameOverText.y = 2732 * 0.3;
gameOverContainer.addChild(gameOverText);
var gameOverSprite = LK.getAsset('gameOverSprite', {
anchorX: 0.5,
anchorY: 0.5
});
gameOverSprite.x = 50 / 2;
gameOverSprite.y = gameOverText.y + 20;
gameOverContainer.addChild(gameOverSprite);
LK.getSound('game_over').play(); // Play game over sound
gameOverContainer.addChild(closeButton);
// Save the score online
storage.score = score;
// Save the score to the leaderboard
if (!storage.leaderboard) {
storage.leaderboard = [];
}
storage.leaderboard.push(score);
storage.leaderboard.sort(function (a, b) {
return b - a;
}); // Sort scores in descending order
// Save the score online
storage.score = score;
game.addChild(gameOverContainer);
}
var robot = [];
var robotBullets = [];
var torchLight = game.addChild(new TorchLight());
var bullets = [];
var zombies = [];
var hero;
var isGameOver = false;
var score = 0;
var ammoDisplay = new AmmoDisplay();
var credits = 0;
var creditDisplay = new CreditDisplay();
var zombieCountDisplay = new ZombieCountDisplay();
var scoreDisplay = new ScoreDisplay();
var globalLightShow = false;
// Add ground to the game
var ground = LK.getAsset('ground', {
anchorX: 0.5,
anchorY: 1
});
ground.x = 2048 / 2;
ground.y = 2732;
ground.alpha = 0.8; // Set the opacity of the background to 20%
game.addChildAt(ground, 0);
// Create the hero
hero = game.addChild(new Hero());
hero.x = 2048 / 2;
hero.y = 2732 - 100; // Position hero near the bottom of the screen
// Function to update button opacity based on available credits
function updateButtonOpacity() {
var buttons = [buyRobotButton1, buyRobotButton2, buyRobotButton3];
buttons.forEach(function (button) {
if (button && button.buttonGraphics) {
button.buttonGraphics.alpha = credits >= button.cost ? 1 : 0.3;
}
});
}
// Add BuyRobotButton to the game
var buyRobotButton1 = game.addChild(new BuyRobotButton('robotButton1', 40, '1'));
buyRobotButton1.x = 150; // Position button at the bottom left
buyRobotButton1.y = 2732 - 250;
// Add BuyRobotButton3 to the game
var buyRobotButton2 = game.addChild(new BuyRobotButton('robotButton2', 100, '2'));
buyRobotButton2.x = 150; // Position button at the bottom left, aligned with the first button
buyRobotButton2.y = 2732 - 500; // Position the third button above the second button
// Add BuyRobotButton2 to the game
var buyRobotButton3 = game.addChild(new BuyRobotButton('robotButton3', 200, '3'));
buyRobotButton3.x = 150; // Position button at the bottom left, aligned with the first button
buyRobotButton3.y = 2732 - 750; // Position the second button above the first button
// Add TrencherButton to the game
//var buyTrencherButton1 = game.addChild(new BuyTrencherButton('trencherButton', 10));
//buyTrencherButton1.x = buyRobotButton1.x + 280; // Position button next to the RobotButton3
//buyTrencherButton1.y = buyRobotButton1.y; // Position the Trencher button below the RobotButton3 with a 50px gap
// Call updateButtonOpacity initially to set the correct opacity
updateButtonOpacity();
// Game logic and event handlers
LK.on('keydown', function (obj) {
var direction = {
x: 0,
y: 0
};
var e = obj.event;
switch (e.keyCode) {
case 37:
// left arrow
direction.x = -1;
break;
case 39:
// right arrow
direction.x = 1;
break;
case 38:
// up arrow
direction.y = -1;
break;
case 40:
// down arrow
direction.y = 1;
break;
}
hero._move_migrated(direction);
});
LK.on('tick', function () {
if (isGameOver) {
showCustomGameOverScreen();
return;
}
// Move bullets and check for off-screen
for (var i = bullets.length - 1; i >= 0; i--) {
if (bullets[i]) {
bullets[i]._move_migrated();
for (var j = zombies.length - 1; j >= 0; j--) {
if (bullets[i] && bullets[i].intersects(zombies[j])) {
bullets[i].destroy();
bullets.splice(i, 1);
zombies[j].health -= Math.floor(Math.random() * (20 + 1)) + 20;
if (zombies[j].health <= 0) {
LK.getSound('zombie_death').play();
var bloodSplatterType = Math.floor(Math.random() * 3) + 1; // Randomly choose a blood splatter type between 1 and 3
var bloodSplatter = new BloodSplatter(bloodSplatterType);
bloodSplatter.x = zombies[j].x;
bloodSplatter.y = zombies[j].y;
game.addChildAt(bloodSplatter, 0);
zombies[j].destroy();
zombies.splice(j, 1);
score++;
if (zombies[j]) {
credits += zombies[j].isBoss ? 4 : 2; // Boss zombies give double credits
}
scoreDisplay.updateScore(score);
creditDisplay.updateCredits(credits);
updateButtonOpacity();
zombieCountDisplay.updateZombieCount(zombies.length);
}
break;
}
}
if (bullets[i] && (bullets[i].x < 0 || bullets[i].x > 2048 || bullets[i].y < 0 || bullets[i].y > 2732)) {
bullets[i].destroy();
bullets.splice(i, 1);
}
}
}
// Handle torch orientation and make zombies visible if illuminated
var torchPos = {
x: hero.x,
y: hero.y
};
var torchAngle = hero.torchGraphics.rotation;
// Update torch light position
var heroPos = {
x: hero.x,
y: hero.y
};
var torchAngle = hero.torchGraphics.rotation;
torchLight.updatePosition(heroPos, torchAngle);
// Update visibility of blood splatters based on torch light
for (var i = game.children.length - 1; i >= 0; i--) {
var obj = game.children[i];
if (obj instanceof BloodSplatter) {
var distanceToTorch = Math.sqrt(Math.pow(obj.x - hero.x, 2) + Math.pow(obj.y - hero.y, 2));
var angleToTorch = Math.atan2(obj.y - hero.y, obj.x - hero.x) - torchAngle;
// Check if within torch light angle and range
if (distanceToTorch <= 8000 && Math.abs(angleToTorch) <= 0.12) {
obj.visible = true;
} else {
obj.visible = false;
}
}
}
// Move and shoot with the robot
if (robot && robot.length > 0) {
for (var i = robot.length - 1; i >= 0; i--) {
robot[i]._move_migrated(robot[i].targetY);
robot[i].shoot();
if (robot[i].y < -50 || robot[i].health <= 0) {
// If the robot moves off-screen or dies
robot[i].destroy();
robot.splice(i, 1);
}
}
}
// Move robot bullets, check for off-screen, and apply damage to zombies
for (var i = robotBullets.length - 1; i >= 0; i--) {
if (robotBullets[i]) {
robotBullets[i]._move_migrated();
for (var j = zombies.length - 1; j >= 0; j--) {
if (robotBullets[i] && robotBullets[i].intersects(zombies[j])) {
robotBullets[i].destroy();
robotBullets.splice(i, 1);
zombies[j].health -= Math.floor(Math.random() * (20 + 1)) + 20;
if (zombies[j].health <= 0) {
if (zombies[j].isBoss) {
LK.getSound('boss_death').play();
} else {
LK.getSound('zombie_death').play();
}
var bloodSplatterType = Math.floor(Math.random() * 3) + 1;
var bloodSplatter = new BloodSplatter(bloodSplatterType);
bloodSplatter.x = zombies[j].x;
bloodSplatter.y = zombies[j].y;
game.addChildAt(bloodSplatter, 0);
zombies[j].destroy();
zombies.splice(j, 1);
score++;
if (zombies[j]) {
credits += zombies[j].isBoss ? 2 : 1; // Double credits for boss kills by robots
}
scoreDisplay.updateScore(score);
creditDisplay.updateCredits(credits);
zombieCountDisplay.updateZombieCount(zombies.length);
updateButtonOpacity();
}
break;
}
}
if (robotBullets[i] && robotBullets[i].y < 0) {
robotBullets[i].destroy();
robotBullets.splice(i, 1);
}
}
}
// Move zombies and check for collision with hero and robot
for (var j = zombies.length - 1; j >= 0; j--) {
zombies[j]._move_migrated(torchPos, torchAngle);
if (zombies[j].y > 2732) {
zombies[j].destroy();
zombies.splice(j, 1);
} else if (zombies[j].intersects(hero) && zombies[j].visible) {
isGameOver = true;
} else if (robot) {
for (var k = robot.length - 1; k >= 0; k--) {
if (zombies[j].intersects(robot[k])) {
robot[k].health -= 10;
robot[k].healthBar.width = robot[k].health / 20 * 100; // Update health bar width based on health
if (robot[k].health <= 0) {
LK.getSound('robot_destruction').play();
robot[k].destroy();
robot.splice(k, 1);
}
zombies[j].destroy();
zombies.splice(j, 1);
}
}
}
}
game.on('move', function (x, y, obj) {
var mousePos = game.toLocal(obj.global);
hero.orientTorch(mousePos);
});
game.on('down', function (x, y, obj) {
var mousePos = game.toLocal(obj.global);
hero.shoot(mousePos);
});
// Spawn the robot reinforcement when the player purchases it
// Removed the automatic robot spawn code block
// Spawn zombies
var spawnRate = Math.max(30, 120 - Math.floor(score / 8) * 5);
if (LK.ticks % spawnRate == 0) {
// Spawn a zombie every 2 seconds
var zombie;
if (zombiesSpawnedCount % 20 == 0 && zombiesSpawnedCount !== 0) {
// Spawn a boss zombie every 15 zombies spawned
zombie = new Zombie(true);
LK.getSound('boss_spawn').play(); // Play sound when a boss spawns
} else {
zombie = new Zombie();
}
zombiesSpawnedCount++;
zombie.x = Math.random() * 2048;
zombie.y = -50; // Start off-screen
zombies.push(zombie);
game.addChild(zombie);
zombieCountDisplay.updateZombieCount(zombies.length);
}
/*
if (LK.ticks == 0) {
// Spawn a zombie every 2 seconds
var zombie;
zombie = new Zombie();
zombiesSpawnedCount++;
zombie.x = hero.x;
zombie.y = hero.y - 300; // Start off-screen
zombies.push(zombie);
game.addChild(zombie);
zombieCountDisplay.updateZombieCount(zombies.length);
}
*/
});
Un zombie en 2D vue du dessus. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
Bullet. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
top down shooter blood. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
top down shooter blood texture. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
top down character with gun de dos. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows. topdown shooter
top down robot with gun. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows. topdown shooter
2d top down zombie boss. Single Game Texture. In-Game asset. 2d. no background. High contrast. No shadows.
weapon reload 2d icon. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
Dark background horror. 2d. Blank background. High contrast. No shadows.
replace robot by wall
barbelé militaire 2d
Arrière plan sombre d'horreur avec un angle vu depuis le haut. 2d. Blank background. High contrast. No shadows.