/****
* 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.