/**** * 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
ArrieΜre plan sombre d'horreur avec un angle vu depuis le haut. 2d. Blank background. High contrast. No shadows.