User prompt
thats on top of gold now, put the wave at the bottom instead
User prompt
move the wave text to inside the right bar
User prompt
Please fix the bug: 'LK.getMusic is not a function' in or related to this line: 'if (waveStartText.alpha <= 0) {' Line Number: 563
User prompt
Please fix the bug: 'LK.getMusic is not a function' in or related to this line: 'LK.getMusic('background').play();' Line Number: 528
User prompt
Please fix the bug: 'self.createUpgradeButton is not a function' in or related to this line: 'var buttons = {' Line Number: 330
User prompt
Please fix the bug: 'LK.Sprite is not a constructor' in or related to this line: 'background = new LK.Sprite('background');' Line Number: 573
User prompt
Please fix the bug: 'LK.getMusic is not a function' in or related to this line: 'LK.getMusic('background').play();' Line Number: 571
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'LK.getMusic is not a function' in or related to this line: 'if (waveStartText.alpha <= 0) {' Line Number: 560
Code edit (4 edits merged)
Please save this source code
User prompt
Please fix the bug: 'bonusText is not defined' in or related to this line: 'if (bonusText) {' Line Number: 548
User prompt
Please fix the bug: 'waveCompleteText is not defined' in or related to this line: 'if (waveCompleteText) {' Line Number: 544
User prompt
the wave completed text from last round should get removed when have starts
User prompt
the wave completed text should get removed after the wave end
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'x')' in or related to this line: 'var dx = tower.x - self.x;' Line Number: 449
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'length')' in or related to this line: 'for (var i = 0; i < zombies.length; i++) {' Line Number: 128
Code edit (1 edits merged)
Please save this source code
Initial prompt
Horde Defence
/****
* Classes
****/
var Bullet = Container.expand(function (damage) {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.vx = 0;
self.vy = 0;
self.damage = damage || 10;
self.lifetime = 60; // Bullets disappear after 1 second
self.update = function () {
// Move bullet
self.x += self.vx;
self.y += self.vy;
// Decrease lifetime
self.lifetime--;
return self.lifetime <= 0;
};
return self;
});
var CooldownIndicator = Container.expand(function () {
var self = Container.call(this);
var bgCircle = self.attachAsset('cooldownIndicator', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.5
});
var fillCircle = new Container();
var fillGraphics = fillCircle.attachAsset('manualTarget', {
anchorX: 0.5,
anchorY: 0.5,
width: 70,
height: 70
});
self.addChild(fillCircle);
var cooldownText = new Text2("READY", {
size: 20,
fill: 0xffffff
});
cooldownText.anchor.set(0.5);
self.addChild(cooldownText);
self.update = function (cooldown, maxCooldown) {
if (cooldown <= 0) {
fillCircle.alpha = 1;
cooldownText.text = "READY";
} else {
fillCircle.alpha = 0.3;
cooldownText.text = Math.ceil(cooldown / 60) + "s";
}
};
return self;
});
var Explosion = Container.expand(function () {
var self = Container.call(this);
var explosionGraphics = self.attachAsset('explosion', {
anchorX: 0.5,
anchorY: 0.5
});
self.lifetime = 15;
self.scale.set(0.2);
self.update = function () {
self.lifetime--;
self.scale.set(1 - self.lifetime / 20);
self.alpha = self.lifetime / 15;
return self.lifetime <= 0;
};
return self;
});
var ManualTarget = Container.expand(function () {
var self = Container.call(this);
var targetGraphics = self.attachAsset('manualTarget', {
anchorX: 0.5,
anchorY: 0.5
});
self.lifetime = 15;
self.alpha = 0.5;
self.update = function () {
self.lifetime--;
self.alpha = self.lifetime / 15;
self.rotation += 0.1;
return self.lifetime <= 0;
};
return self;
});
var StatusBar = Container.expand(function () {
var self = Container.call(this);
// Top bar background
var barBg = self.attachAsset('topBar', {
anchorX: 0.5,
anchorY: 0
});
// Wave indicator
var waveDisplay = new Container();
var waveIndicator = waveDisplay.attachAsset('waveIndicator', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.8
});
var waveText = new Text2("WAVE 1", {
size: 40,
fill: 0xffffff
});
waveText.anchor.set(0.5);
waveDisplay.addChild(waveText);
waveDisplay.x = 0;
waveDisplay.y = 60;
self.addChild(waveDisplay);
// Stats display
var statsContainer = new Container();
var statsBg = statsContainer.attachAsset('statDisplay', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.7
});
var killsText = new Text2("Kills: 0", {
size: 30,
fill: 0xffffff
});
killsText.anchor.set(0.5);
killsText.y = -20;
statsContainer.addChild(killsText);
var scoreText = new Text2("Score: 0", {
size: 30,
fill: 0xffffff
});
scoreText.anchor.set(0.5);
scoreText.y = 20;
statsContainer.addChild(scoreText);
statsContainer.x = 500;
statsContainer.y = 60;
self.addChild(statsContainer);
self.updateWave = function (waveNum) {
waveText.text = "WAVE " + waveNum;
};
self.updateStats = function (kills, score) {
killsText.text = "Kills: " + kills;
scoreText.text = "Score: " + score;
};
return self;
});
var Tower = Container.expand(function () {
var self = Container.call(this);
// Tower base (doesn't rotate)
var base = self.attachAsset('towerBase', {
anchorX: 0.5,
anchorY: 0.5
});
// Tower turret (rotates to aim)
var turret = new Container();
var turretGraphics = turret.attachAsset('tower', {
anchorX: 0.5,
anchorY: 0.5
});
self.addChild(turret);
// Tower stats
self.health = 100;
self.maxHealth = 100;
self.damage = 10;
self.fireRate = 60; // frames between shots
self.fireTimer = 0;
self.range = 800;
self.upgradeLevel = {
damage: 1,
fireRate: 1,
range: 1,
health: 1
};
// Health bar - moved above tower for better visibility
var healthBarContainer = new Container();
var healthBarBg = healthBarContainer.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5,
width: 200
});
var healthBarFill = new Container();
var healthBarGraphics = healthBarFill.attachAsset('healthBar', {
anchorX: 0,
anchorY: 0.5,
width: 200
});
healthBarContainer.addChild(healthBarFill);
healthBarContainer.y = -150;
self.addChild(healthBarContainer);
// Add health text
var healthText = new Text2("", {
size: 24,
fill: 0xffffff
});
healthText.anchor.set(0.5);
healthText.y = -150;
self.addChild(healthText);
// Methods
self.update = function () {
// Decrease fire timer
if (self.fireTimer > 0) {
self.fireTimer--;
}
// Update health bar
healthBarFill.scale.x = self.health / self.maxHealth;
healthText.text = self.health + "/" + self.maxHealth;
// Find target if none currently
var target = null;
var closestDist = self.range;
for (var i = 0; i < zombies.length; i++) {
var zombie = zombies[i];
var dx = zombie.x - self.x;
var dy = zombie.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < closestDist) {
closestDist = dist;
target = zombie;
}
}
// Aim at target
if (target) {
var angle = Math.atan2(target.y - self.y, target.x - self.x);
turret.rotation = angle;
// Fire if ready
if (self.fireTimer <= 0) {
var bullet = new Bullet(self.damage);
bullet.x = self.x;
bullet.y = self.y;
bullet.rotation = angle;
bullet.vx = Math.cos(angle) * 15;
bullet.vy = Math.sin(angle) * 15;
game.addChild(bullet);
bullets.push(bullet);
self.fireTimer = self.fireRate;
LK.getSound('shoot').play();
}
}
};
self.manualShoot = function (x, y) {
var angle = Math.atan2(y - self.y, x - self.x);
turret.rotation = angle;
var bullet = new Bullet(self.damage * 2); // Manual shots do double damage
bullet.x = self.x;
bullet.y = self.y;
bullet.rotation = angle;
bullet.vx = Math.cos(angle) * 15;
bullet.vy = Math.sin(angle) * 15;
game.addChild(bullet);
bullets.push(bullet);
LK.getSound('shoot').play();
};
self.takeDamage = function (amount) {
self.health -= amount;
// Flash the tower when hit
LK.effects.flashObject(self, 0xff0000, 300);
LK.getSound('towerHit').play();
if (self.health <= 0) {
return true; // Tower destroyed
}
return false;
};
self.upgrade = function (stat) {
var maxLevel = 10; // Maximum upgrade level
if (self.upgradeLevel[stat] >= maxLevel) {
return 0; // Already at max level
}
var cost = 0;
switch (stat) {
case 'damage':
cost = 50 * self.upgradeLevel.damage;
self.damage += 5;
self.upgradeLevel.damage++;
break;
case 'fireRate':
cost = 75 * self.upgradeLevel.fireRate;
self.fireRate = Math.max(10, self.fireRate - 5); // Min fire rate of 10 frames
self.upgradeLevel.fireRate++;
break;
case 'range':
cost = 100 * self.upgradeLevel.range;
self.range += 50;
self.upgradeLevel.range++;
break;
case 'health':
cost = 60 * self.upgradeLevel.health;
self.maxHealth += 25;
self.health += 25;
self.upgradeLevel.health++;
break;
}
// Flash effect on upgrade
LK.effects.flashObject(self, 0x00ff00, 500);
LK.getSound('upgrade').play();
return cost;
};
return self;
});
var UpgradePanel = Container.expand(function () {
var self = Container.call(this);
// Panel background
var panelBg = self.attachAsset('upgradePanel', {
anchorX: 0.5,
anchorY: 1
});
// Create upgrade buttons
var buttons = {
damage: self.createUpgradeButton("Damage", 0),
fireRate: self.createUpgradeButton("Fire Rate", 1),
range: self.createUpgradeButton("Range", 2),
health: self.createUpgradeButton("Health", 3)
};
// Gold display
var goldContainer = new Container();
var goldIcon = goldContainer.attachAsset('goldIcon', {
anchorX: 0.5,
anchorY: 0.5
});
var goldText = new Text2("0", {
size: 40,
fill: 0xffcc00
});
goldText.x = 50;
goldText.y = 0;
goldText.anchor.set(0, 0.5);
goldContainer.addChild(goldText);
goldContainer.x = -160;
goldContainer.y = -300;
self.addChild(goldContainer);
// Upgrade costs
var upgradeCosts = {
damage: function damage() {
return 50 * tower.upgradeLevel.damage;
},
fireRate: function fireRate() {
return 75 * tower.upgradeLevel.fireRate;
},
range: function range() {
return 100 * tower.upgradeLevel.range;
},
health: function health() {
return 60 * tower.upgradeLevel.health;
}
};
self.createUpgradeButton = function (label, position) {
var button = new Container();
var buttonGraphics = button.attachAsset('upgradeButton', {
anchorX: 0.5,
anchorY: 0.5
});
var buttonText = new Text2(label, {
size: 30,
fill: 0xffffff
});
buttonText.anchor.set(0.5);
buttonText.y = -20;
button.addChild(buttonText);
var costText = new Text2("", {
size: 24,
fill: 0xffcc00
});
costText.anchor.set(0.5);
costText.y = 20;
button.addChild(costText);
button.x = -670 + position * 450;
button.y = -200;
self.addChild(button);
return {
container: button,
costText: costText,
bounds: {
x: button.x - 225,
y: button.y - 50,
width: 450,
height: 100
}
};
};
self.updateGold = function (amount) {
goldText.text = amount;
};
self.update = function () {
// Update cost displays
buttons.damage.costText.text = upgradeCosts.damage() + " Gold";
buttons.fireRate.costText.text = upgradeCosts.fireRate() + " Gold";
buttons.range.costText.text = upgradeCosts.range() + " Gold";
buttons.health.costText.text = upgradeCosts.health() + " Gold";
// Change button colors based on affordability
self.updateButtonAppearance(buttons.damage, upgradeCosts.damage() <= gold);
self.updateButtonAppearance(buttons.fireRate, upgradeCosts.fireRate() <= gold);
self.updateButtonAppearance(buttons.range, upgradeCosts.range() <= gold);
self.updateButtonAppearance(buttons.health, upgradeCosts.health() <= gold);
};
self.updateButtonAppearance = function (button, canAfford) {
var color = canAfford ? 0x3366ff : 0x444444;
button.container.children[0].tint = color;
};
self.checkUpgradeClick = function (x, y, currentGold) {
var relativeX = x - self.x;
var relativeY = y - self.y;
// Check each button
if (self.isPointInButton(relativeX, relativeY, buttons.damage.bounds)) {
var cost = upgradeCosts.damage();
if (currentGold >= cost) {
return tower.upgrade('damage');
}
} else if (self.isPointInButton(relativeX, relativeY, buttons.fireRate.bounds)) {
var cost = upgradeCosts.fireRate();
if (currentGold >= cost) {
return tower.upgrade('fireRate');
}
} else if (self.isPointInButton(relativeX, relativeY, buttons.range.bounds)) {
var cost = upgradeCosts.range();
if (currentGold >= cost) {
return tower.upgrade('range');
}
} else if (self.isPointInButton(relativeX, relativeY, buttons.health.bounds)) {
var cost = upgradeCosts.health();
if (currentGold >= cost) {
return tower.upgrade('health');
}
}
return 0; // No upgrade performed
};
self.isPointInButton = function (x, y, bounds) {
return x >= bounds.x && x <= bounds.x + bounds.width && y >= bounds.y && y <= bounds.y + bounds.height;
};
return self;
});
var Zombie = Container.expand(function (level) {
var self = Container.call(this);
level = level || 1;
// Scale color from green to red based on level
var colorValue = Math.min(255, 50 + level * 20);
var zombieColor = colorValue << 16 | 255 - colorValue << 8;
var zombieGraphics = self.attachAsset('zombie', {
anchorX: 0.5,
anchorY: 0.5,
color: zombieColor
});
// Zombie stats
self.health = 20 + level * 10;
self.maxHealth = self.health;
self.damage = 5 + level;
self.speed = 1 + level * 0.1;
self.value = 10 + level * 5; // Gold value when killed
// Health bar
var healthBarContainer = new Container();
var healthBarBg = healthBarContainer.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
var healthBarFill = new Container();
var healthBarGraphics = healthBarFill.attachAsset('healthBar', {
anchorX: 0,
anchorY: 0.5
});
healthBarContainer.addChild(healthBarFill);
healthBarContainer.y = -50;
self.addChild(healthBarContainer);
// Movement variables
var targetX = CENTER_X;
var targetY = CENTER_Y;
self.update = function () {
// Move towards tower
var dx = targetX - self.x;
var dy = targetY - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < 50) {
// Attack tower
if (tower.takeDamage(self.damage)) {
return "gameover"; // Tower destroyed
}
// Move away slightly to prevent continuous damage
self.x -= dx * 0.5;
self.y -= dy * 0.5;
} else {
// Move towards tower
self.x += dx / dist * self.speed;
self.y += dy / dist * self.speed;
}
// Update health bar
healthBarFill.scale.x = self.health / self.maxHealth;
return null;
};
self.takeDamage = function (amount) {
self.health -= amount;
return self.health <= 0; // Return true if zombie is killed
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
/****
* Game Variables
****/
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
var CENTER_X = GAME_WIDTH / 2;
var CENTER_Y = GAME_HEIGHT / 2;
// Game state
var isGameActive = false;
var waitingForNextWave = false;
var waveCompleteText;
var bonusText;
var waveTextInterval;
// Game objects
var tower;
var upgradePanel;
var statusBar;
var cooldownIndicator;
var background;
// Game arrays
var zombies = [];
var bullets = [];
var explosions = [];
var targets = [];
// Game stats
var wave = 1;
var zombiesInWave = 0;
var waveInterval = 60; // Frames between zombie spawns
var zombiesKilled = 0;
var gold = 200; // Starting gold
var manualCooldown = 0;
/****
* Game Functions
****/
function startGame() {
// Reset game variables
isGameActive = true;
waitingForNextWave = false;
wave = 1;
zombiesKilled = 0;
gold = 200;
zombies = [];
bullets = [];
explosions = [];
targets = [];
LK.getMusic('background').play();
// Create game objects
background = new LK.Sprite('background');
game.addChild(background);
// Create tower in center
tower = new Tower();
tower.x = CENTER_X;
tower.y = CENTER_Y;
game.addChild(tower);
// Create upgrade panel at bottom
upgradePanel = new UpgradePanel();
upgradePanel.x = CENTER_X;
upgradePanel.y = GAME_HEIGHT;
upgradePanel.updateGold(gold);
game.addChild(upgradePanel);
// Create status bar at top
statusBar = new StatusBar();
statusBar.x = CENTER_X;
statusBar.y = 0;
game.addChild(statusBar);
// Create cooldown indicator for manual shooting
cooldownIndicator = new CooldownIndicator();
cooldownIndicator.x = CENTER_X;
cooldownIndicator.y = GAME_HEIGHT - 480; // Position above upgrade panel
game.addChild(cooldownIndicator);
// Start first wave
startWave();
}
function startWave() {
// Clean up any previous wave text elements
if (waveCompleteText) {
waveCompleteText.destroy();
waveCompleteText = null;
}
if (bonusText) {
bonusText.destroy();
bonusText = null;
}
if (waveTextInterval) {
LK.clearInterval(waveTextInterval);
waveTextInterval = null;
}
// Reset wave flag
waitingForNextWave = false;
// Update status bar
statusBar.updateWave(wave);
// Calculate zombies for this wave
zombiesInWave = 10 + wave * 5;
waveInterval = Math.max(20, 60 - wave * 2); // Spawn faster in later waves
// Show wave start message
var waveText = new Text2("WAVE " + wave + " INCOMING!", {
size: 80,
fill: 0xff3333
});
waveText.x = CENTER_X;
waveText.y = CENTER_Y;
waveText.anchor.set(0.5);
game.addChild(waveText);
var zombiesText = new Text2(zombiesInWave + " ZOMBIES", {
size: 60,
fill: 0xff3333
});
zombiesText.x = CENTER_X;
zombiesText.y = CENTER_Y + 100;
zombiesText.anchor.set(0.5);
game.addChild(zombiesText);
LK.getSound('waveStart').play();
// Fade out wave text
var fadeInterval = LK.setInterval(function () {
waveText.alpha -= 0.02;
zombiesText.alpha -= 0.02;
if (waveText.alpha <= 0) {
waveText.destroy();
zombiesText.destroy();
LK.clearInterval(fadeInterval);
}
}, 30);
}
function spawnZombie() {
if (zombiesInWave <= 0) {
return;
}
// Spawn a zombie at random edge position
var zombie = new Zombie(wave);
// Calculate spawn position (edge of screen)
var side = Math.floor(Math.random() * 4); // 0: top, 1: right, 2: bottom, 3: left
switch (side) {
case 0:
// Top
zombie.x = Math.random() * GAME_WIDTH;
zombie.y = 0;
break;
case 1:
// Right
zombie.x = GAME_WIDTH;
zombie.y = Math.random() * GAME_HEIGHT;
break;
case 2:
// Bottom
zombie.x = Math.random() * GAME_WIDTH;
zombie.y = GAME_HEIGHT;
break;
case 3:
// Left
zombie.x = 0;
zombie.y = Math.random() * GAME_HEIGHT;
break;
}
game.addChild(zombie);
zombies.push(zombie);
zombiesInWave--;
}
function gameOver() {
isGameActive = false;
LK.getSound('gameOver').play();
// Show game over text
var gameOverText = new Text2("GAME OVER", {
size: 100,
fill: 0xff0000
});
gameOverText.x = CENTER_X;
gameOverText.y = CENTER_Y;
gameOverText.anchor.set(0.5);
game.addChild(gameOverText);
var waveText = new Text2("Survived to Wave " + wave, {
size: 60,
fill: 0xffffff
});
waveText.x = CENTER_X;
waveText.y = CENTER_Y + 80;
waveText.anchor.set(0.5);
game.addChild(waveText);
var scoreText = new Text2("Zombies Killed: " + zombiesKilled, {
size: 50,
fill: 0xffffff
});
scoreText.x = CENTER_X;
scoreText.y = CENTER_Y + 150;
scoreText.anchor.set(0.5);
game.addChild(scoreText);
// Set final score (waves survived * zombies killed)
LK.setScore(wave * zombiesKilled);
// Show game over screen after delay
LK.setTimeout(function () {
LK.showGameOver();
}, 3000);
}
/****
* Event Handlers
****/
game.on('down', function (x, y, obj) {
if (!isGameActive) {
return;
}
var event = obj;
var pos = game.toLocal(event.global);
// Check if clicking in upgrade panel area
if (pos.y > GAME_HEIGHT - 400) {
var upgradeCost = upgradePanel.checkUpgradeClick(pos.x, pos.y, gold);
if (upgradeCost > 0) {
gold -= upgradeCost;
upgradePanel.updateGold(gold);
}
} else {
// Manual targeting - can only fire once per second
if (manualCooldown <= 0) {
// Create target indicator
var target = new ManualTarget();
target.x = pos.x;
target.y = pos.y;
game.addChild(target);
targets.push(target);
// Fire at clicked location
tower.manualShoot(pos.x, pos.y);
manualCooldown = 60; // 1 second cooldown
}
}
});
/****
* Game Loop
****/
LK.on('tick', function () {
if (!isGameActive) {
return;
}
// Update tower
tower.update();
// Update upgrade panel
upgradePanel.update();
// Update cooldown indicator
cooldownIndicator.update(manualCooldown, 60);
// Update status bar stats
statusBar.updateStats(zombiesKilled, wave * zombiesKilled);
// Update bullets
for (var i = bullets.length - 1; i >= 0; i--) {
if (bullets[i].update()) {
bullets[i].destroy();
bullets.splice(i, 1);
continue;
}
// Check for zombie hits
for (var j = zombies.length - 1; j >= 0; j--) {
if (bullets[i] && bullets[i].intersects(zombies[j])) {
if (zombies[j].takeDamage(bullets[i].damage)) {
// Zombie killed
var explosion = new Explosion();
explosion.x = zombies[j].x;
explosion.y = zombies[j].y;
game.addChild(explosion);
explosions.push(explosion);
// Add gold
gold += zombies[j].value;
upgradePanel.updateGold(gold);
// Show gold pop-up
var goldPop = new Text2("+" + zombies[j].value, {
size: 30,
fill: 0xffcc00
});
goldPop.x = zombies[j].x;
goldPop.y = zombies[j].y - 50;
goldPop.anchor.set(0.5);
game.addChild(goldPop);
// Fade out gold text
var fadeInterval = LK.setInterval(function () {
goldPop.alpha -= 0.05;
goldPop.y -= 1;
if (goldPop.alpha <= 0) {
goldPop.destroy();
LK.clearInterval(fadeInterval);
}
}, 30);
LK.getSound('zombieDeath').play();
zombies[j].destroy();
zombies.splice(j, 1);
zombiesKilled++;
}
// Remove bullet
bullets[i].destroy();
bullets.splice(i, 1);
break;
}
}
}
// Update zombies
for (var k = zombies.length - 1; k >= 0; k--) {
var result = zombies[k].update();
if (result === "gameover") {
gameOver();
return;
}
}
// Update explosions
for (var l = explosions.length - 1; l >= 0; l--) {
if (explosions[l].update()) {
explosions[l].destroy();
explosions.splice(l, 1);
}
}
// Update targets
for (var m = targets.length - 1; m >= 0; m--) {
if (targets[m].update()) {
targets[m].destroy();
targets.splice(m, 1);
}
}
// Spawn zombies
if (LK.ticks % waveInterval === 0 && zombiesInWave > 0) {
spawnZombie();
}
// Check if wave is complete
if (zombiesInWave <= 0 && zombies.length === 0 && !waitingForNextWave) {
// Set flag to prevent multiple wave completions
waitingForNextWave = true;
// Start next wave after delay
wave++;
LK.setTimeout(function () {
startWave();
}, 3000);
// Grant bonus gold between waves
var bonus = 50 + (wave - 1) * 10;
gold += bonus;
upgradePanel.updateGold(gold);
// Show wave complete message
waveCompleteText = new Text2("WAVE " + (wave - 1) + " COMPLETE!", {
size: 80,
fill: 0x33ff33
});
waveCompleteText.x = CENTER_X;
waveCompleteText.y = CENTER_Y;
waveCompleteText.anchor.set(0.5);
game.addChild(waveCompleteText);
bonusText = new Text2("BONUS: +" + bonus + " GOLD", {
size: 60,
fill: 0xffcc00
});
bonusText.x = CENTER_X;
bonusText.y = CENTER_Y + 100;
bonusText.anchor.set(0.5);
game.addChild(bonusText);
// Fade out text
waveTextInterval = LK.setInterval(function () {
waveCompleteText.alpha -= 0.02;
bonusText.alpha -= 0.02;
if (waveCompleteText.alpha <= 0) {
waveCompleteText.destroy();
bonusText.destroy();
LK.clearInterval(waveTextInterval);
waveCompleteText = null;
bonusText = null;
waveTextInterval = null;
}
}, 30);
}
// Update manual cooldown
if (manualCooldown > 0) {
manualCooldown--;
}
});
// Start the game
startGame(); ===================================================================
--- original.js
+++ change.js
@@ -20,8 +20,40 @@
return self.lifetime <= 0;
};
return self;
});
+var CooldownIndicator = Container.expand(function () {
+ var self = Container.call(this);
+ var bgCircle = self.attachAsset('cooldownIndicator', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.5
+ });
+ var fillCircle = new Container();
+ var fillGraphics = fillCircle.attachAsset('manualTarget', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ width: 70,
+ height: 70
+ });
+ self.addChild(fillCircle);
+ var cooldownText = new Text2("READY", {
+ size: 20,
+ fill: 0xffffff
+ });
+ cooldownText.anchor.set(0.5);
+ self.addChild(cooldownText);
+ self.update = function (cooldown, maxCooldown) {
+ if (cooldown <= 0) {
+ fillCircle.alpha = 1;
+ cooldownText.text = "READY";
+ } else {
+ fillCircle.alpha = 0.3;
+ cooldownText.text = Math.ceil(cooldown / 60) + "s";
+ }
+ };
+ return self;
+});
var Explosion = Container.expand(function () {
var self = Container.call(this);
var explosionGraphics = self.attachAsset('explosion', {
anchorX: 0.5,
@@ -52,8 +84,64 @@
return self.lifetime <= 0;
};
return self;
});
+var StatusBar = Container.expand(function () {
+ var self = Container.call(this);
+ // Top bar background
+ var barBg = self.attachAsset('topBar', {
+ anchorX: 0.5,
+ anchorY: 0
+ });
+ // Wave indicator
+ var waveDisplay = new Container();
+ var waveIndicator = waveDisplay.attachAsset('waveIndicator', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.8
+ });
+ var waveText = new Text2("WAVE 1", {
+ size: 40,
+ fill: 0xffffff
+ });
+ waveText.anchor.set(0.5);
+ waveDisplay.addChild(waveText);
+ waveDisplay.x = 0;
+ waveDisplay.y = 60;
+ self.addChild(waveDisplay);
+ // Stats display
+ var statsContainer = new Container();
+ var statsBg = statsContainer.attachAsset('statDisplay', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.7
+ });
+ var killsText = new Text2("Kills: 0", {
+ size: 30,
+ fill: 0xffffff
+ });
+ killsText.anchor.set(0.5);
+ killsText.y = -20;
+ statsContainer.addChild(killsText);
+ var scoreText = new Text2("Score: 0", {
+ size: 30,
+ fill: 0xffffff
+ });
+ scoreText.anchor.set(0.5);
+ scoreText.y = 20;
+ statsContainer.addChild(scoreText);
+ statsContainer.x = 500;
+ statsContainer.y = 60;
+ self.addChild(statsContainer);
+ self.updateWave = function (waveNum) {
+ waveText.text = "WAVE " + waveNum;
+ };
+ self.updateStats = function (kills, score) {
+ killsText.text = "Kills: " + kills;
+ scoreText.text = "Score: " + score;
+ };
+ return self;
+});
var Tower = Container.expand(function () {
var self = Container.call(this);
// Tower base (doesn't rotate)
var base = self.attachAsset('towerBase', {
@@ -79,9 +167,9 @@
fireRate: 1,
range: 1,
health: 1
};
- // Health bar
+ // Health bar - moved above tower for better visibility
var healthBarContainer = new Container();
var healthBarBg = healthBarContainer.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5,
@@ -95,16 +183,25 @@
});
healthBarContainer.addChild(healthBarFill);
healthBarContainer.y = -150;
self.addChild(healthBarContainer);
+ // Add health text
+ var healthText = new Text2("", {
+ size: 24,
+ fill: 0xffffff
+ });
+ healthText.anchor.set(0.5);
+ healthText.y = -150;
+ self.addChild(healthText);
// Methods
self.update = function () {
// Decrease fire timer
if (self.fireTimer > 0) {
self.fireTimer--;
}
// Update health bar
healthBarFill.scale.x = self.health / self.maxHealth;
+ healthText.text = self.health + "/" + self.maxHealth;
// Find target if none currently
var target = null;
var closestDist = self.range;
for (var i = 0; i < zombies.length; i++) {
@@ -158,39 +255,58 @@
return true; // Tower destroyed
}
return false;
};
- self.upgradeDamage = function () {
- self.upgradeLevel.damage++;
- self.damage += 5;
+ self.upgrade = function (stat) {
+ var maxLevel = 10; // Maximum upgrade level
+ if (self.upgradeLevel[stat] >= maxLevel) {
+ return 0; // Already at max level
+ }
+ var cost = 0;
+ switch (stat) {
+ case 'damage':
+ cost = 50 * self.upgradeLevel.damage;
+ self.damage += 5;
+ self.upgradeLevel.damage++;
+ break;
+ case 'fireRate':
+ cost = 75 * self.upgradeLevel.fireRate;
+ self.fireRate = Math.max(10, self.fireRate - 5); // Min fire rate of 10 frames
+ self.upgradeLevel.fireRate++;
+ break;
+ case 'range':
+ cost = 100 * self.upgradeLevel.range;
+ self.range += 50;
+ self.upgradeLevel.range++;
+ break;
+ case 'health':
+ cost = 60 * self.upgradeLevel.health;
+ self.maxHealth += 25;
+ self.health += 25;
+ self.upgradeLevel.health++;
+ break;
+ }
+ // Flash effect on upgrade
+ LK.effects.flashObject(self, 0x00ff00, 500);
LK.getSound('upgrade').play();
+ return cost;
};
- self.upgradeFireRate = function () {
- self.upgradeLevel.fireRate++;
- self.fireRate = Math.max(10, self.fireRate - 10);
- LK.getSound('upgrade').play();
- };
- self.upgradeRange = function () {
- self.upgradeLevel.range++;
- self.range += 100;
- LK.getSound('upgrade').play();
- };
- self.upgradeHealth = function () {
- self.upgradeLevel.health++;
- var oldMaxHealth = self.maxHealth;
- self.maxHealth += 50;
- self.health += self.maxHealth - oldMaxHealth;
- LK.getSound('upgrade').play();
- };
return self;
});
-var UpgradePanel = Container.expand(function (tower) {
+var UpgradePanel = Container.expand(function () {
var self = Container.call(this);
// Panel background
var panelBg = self.attachAsset('upgradePanel', {
- anchorX: 0,
- anchorY: 0
+ anchorX: 0.5,
+ anchorY: 1
});
+ // Create upgrade buttons
+ var buttons = {
+ damage: self.createUpgradeButton("Damage", 0),
+ fireRate: self.createUpgradeButton("Fire Rate", 1),
+ range: self.createUpgradeButton("Range", 2),
+ health: self.createUpgradeButton("Health", 3)
+ };
// Gold display
var goldContainer = new Container();
var goldIcon = goldContainer.attachAsset('goldIcon', {
anchorX: 0.5,
@@ -199,179 +315,132 @@
var goldText = new Text2("0", {
size: 40,
fill: 0xffcc00
});
- goldText.x = 60;
+ goldText.x = 50;
+ goldText.y = 0;
goldText.anchor.set(0, 0.5);
goldContainer.addChild(goldText);
- goldContainer.x = 100;
- goldContainer.y = 100;
+ goldContainer.x = -160;
+ goldContainer.y = -300;
self.addChild(goldContainer);
- // Tower stats display
- var statsContainer = new Container();
- var damageText = new Text2("Damage: " + tower.damage, {
- size: 30,
- fill: 0xffffff
- });
- damageText.y = 0;
- statsContainer.addChild(damageText);
- var fireRateText = new Text2("Fire Rate: " + (60 / tower.fireRate).toFixed(1) + "/s", {
- size: 30,
- fill: 0xffffff
- });
- fireRateText.y = 40;
- statsContainer.addChild(fireRateText);
- var rangeText = new Text2("Range: " + tower.range, {
- size: 30,
- fill: 0xffffff
- });
- rangeText.y = 80;
- statsContainer.addChild(rangeText);
- var healthText = new Text2("Health: " + tower.health + "/" + tower.maxHealth, {
- size: 30,
- fill: 0xffffff
- });
- healthText.y = 120;
- statsContainer.addChild(healthText);
- statsContainer.x = 100;
- statsContainer.y = 200;
- self.addChild(statsContainer);
- // Upgrade buttons
- var upgradeButtons = [];
+ // Upgrade costs
var upgradeCosts = {
damage: function damage() {
- return tower.upgradeLevel.damage * 50;
+ return 50 * tower.upgradeLevel.damage;
},
fireRate: function fireRate() {
- return tower.upgradeLevel.fireRate * 75;
+ return 75 * tower.upgradeLevel.fireRate;
},
range: function range() {
- return tower.upgradeLevel.range * 40;
+ return 100 * tower.upgradeLevel.range;
},
health: function health() {
- return tower.upgradeLevel.health * 60;
+ return 60 * tower.upgradeLevel.health;
}
};
- function createUpgradeButton(label, y, upgradeFunc, getCostFunc) {
+ self.createUpgradeButton = function (label, position) {
var button = new Container();
- var buttonBg = button.attachAsset('upgradeButton', {
+ var buttonGraphics = button.attachAsset('upgradeButton', {
anchorX: 0.5,
anchorY: 0.5
});
var buttonText = new Text2(label, {
size: 30,
fill: 0xffffff
});
- buttonText.anchor.set(0, 0.5);
- buttonText.x = -buttonBg.width / 2 + 20;
+ buttonText.anchor.set(0.5);
+ buttonText.y = -20;
button.addChild(buttonText);
- var costText = new Text2("Cost: " + getCostFunc() + " Gold", {
- size: 25,
+ var costText = new Text2("", {
+ size: 24,
fill: 0xffcc00
});
- costText.anchor.set(1, 0.5);
- costText.x = buttonBg.width / 2 - 20;
+ costText.anchor.set(0.5);
+ costText.y = 20;
button.addChild(costText);
- button.x = 250;
- button.y = y;
- button.upgrade = upgradeFunc;
- button.getCost = getCostFunc;
- button.updateCost = function () {
- costText.setText("Cost: " + getCostFunc() + " Gold");
- };
+ button.x = -670 + position * 450;
+ button.y = -200;
self.addChild(button);
- upgradeButtons.push(button);
- return button;
- }
- var damageButton = createUpgradeButton("Upgrade Damage", 400, function () {
- tower.upgradeDamage();
- }, upgradeCosts.damage);
- var fireRateButton = createUpgradeButton("Upgrade Fire Rate", 520, function () {
- tower.upgradeFireRate();
- }, upgradeCosts.fireRate);
- var rangeButton = createUpgradeButton("Upgrade Range", 640, function () {
- tower.upgradeRange();
- }, upgradeCosts.range);
- var healthButton = createUpgradeButton("Upgrade Health", 760, function () {
- tower.upgradeHealth();
- }, upgradeCosts.health);
- self.checkUpgradeClick = function (x, y, gold) {
- var localX = x - self.x;
- var localY = y - self.y;
- for (var i = 0; i < upgradeButtons.length; i++) {
- var button = upgradeButtons[i];
- var buttonX = button.x;
- var buttonY = button.y;
- var buttonWidth = 450;
- var buttonHeight = 100;
- if (localX >= buttonX - buttonWidth / 2 && localX <= buttonX + buttonWidth / 2 && localY >= buttonY - buttonHeight / 2 && localY <= buttonY + buttonHeight / 2) {
- var cost = button.getCost();
- if (gold >= cost) {
- button.upgrade();
- self.updateStats();
- return cost;
- } else {
- // Not enough gold
- button.alpha = 0.5;
- LK.setTimeout(function () {
- button.alpha = 1;
- }, 300);
- return 0;
- }
+ return {
+ container: button,
+ costText: costText,
+ bounds: {
+ x: button.x - 225,
+ y: button.y - 50,
+ width: 450,
+ height: 100
}
- }
- return 0;
+ };
};
- self.updateGold = function (gold) {
- goldText.setText(gold.toString());
+ self.updateGold = function (amount) {
+ goldText.text = amount;
};
- self.updateStats = function () {
- damageText.setText("Damage: " + tower.damage);
- fireRateText.setText("Fire Rate: " + (60 / tower.fireRate).toFixed(1) + "/s");
- rangeText.setText("Range: " + tower.range);
- healthText.setText("Health: " + tower.health + "/" + tower.maxHealth);
- // Update costs
- for (var i = 0; i < upgradeButtons.length; i++) {
- upgradeButtons[i].updateCost();
+ self.update = function () {
+ // Update cost displays
+ buttons.damage.costText.text = upgradeCosts.damage() + " Gold";
+ buttons.fireRate.costText.text = upgradeCosts.fireRate() + " Gold";
+ buttons.range.costText.text = upgradeCosts.range() + " Gold";
+ buttons.health.costText.text = upgradeCosts.health() + " Gold";
+ // Change button colors based on affordability
+ self.updateButtonAppearance(buttons.damage, upgradeCosts.damage() <= gold);
+ self.updateButtonAppearance(buttons.fireRate, upgradeCosts.fireRate() <= gold);
+ self.updateButtonAppearance(buttons.range, upgradeCosts.range() <= gold);
+ self.updateButtonAppearance(buttons.health, upgradeCosts.health() <= gold);
+ };
+ self.updateButtonAppearance = function (button, canAfford) {
+ var color = canAfford ? 0x3366ff : 0x444444;
+ button.container.children[0].tint = color;
+ };
+ self.checkUpgradeClick = function (x, y, currentGold) {
+ var relativeX = x - self.x;
+ var relativeY = y - self.y;
+ // Check each button
+ if (self.isPointInButton(relativeX, relativeY, buttons.damage.bounds)) {
+ var cost = upgradeCosts.damage();
+ if (currentGold >= cost) {
+ return tower.upgrade('damage');
+ }
+ } else if (self.isPointInButton(relativeX, relativeY, buttons.fireRate.bounds)) {
+ var cost = upgradeCosts.fireRate();
+ if (currentGold >= cost) {
+ return tower.upgrade('fireRate');
+ }
+ } else if (self.isPointInButton(relativeX, relativeY, buttons.range.bounds)) {
+ var cost = upgradeCosts.range();
+ if (currentGold >= cost) {
+ return tower.upgrade('range');
+ }
+ } else if (self.isPointInButton(relativeX, relativeY, buttons.health.bounds)) {
+ var cost = upgradeCosts.health();
+ if (currentGold >= cost) {
+ return tower.upgrade('health');
+ }
}
+ return 0; // No upgrade performed
};
- self.update = function () {
- self.updateStats();
+ self.isPointInButton = function (x, y, bounds) {
+ return x >= bounds.x && x <= bounds.x + bounds.width && y >= bounds.y && y <= bounds.y + bounds.height;
};
return self;
});
-var Zombie = Container.expand(function (waveNumber) {
+var Zombie = Container.expand(function (level) {
var self = Container.call(this);
+ level = level || 1;
+ // Scale color from green to red based on level
+ var colorValue = Math.min(255, 50 + level * 20);
+ var zombieColor = colorValue << 16 | 255 - colorValue << 8;
var zombieGraphics = self.attachAsset('zombie', {
anchorX: 0.5,
- anchorY: 0.5
+ anchorY: 0.5,
+ color: zombieColor
});
- // Stats scale with wave number
- var waveMultiplier = 1 + waveNumber * 0.2;
- self.health = 20 * waveMultiplier;
+ // Zombie stats
+ self.health = 20 + level * 10;
self.maxHealth = self.health;
- self.speed = 2 + Math.random() * 1;
- self.damage = 5 * waveMultiplier;
- self.value = 10 + Math.floor(waveNumber * 5);
- // Chance to be a special zombie
- if (Math.random() < 0.2) {
- // Tank zombie - slower but more health
- self.health *= 3;
- self.maxHealth = self.health;
- self.speed *= 0.5;
- self.damage *= 2;
- self.value *= 3;
- zombieGraphics.tint = 0xff0000;
- zombieGraphics.width = 80;
- zombieGraphics.height = 80;
- } else if (Math.random() < 0.3) {
- // Fast zombie - faster but less health
- self.health *= 0.7;
- self.maxHealth = self.health;
- self.speed *= 2;
- self.value *= 2;
- zombieGraphics.tint = 0xffff00;
- }
+ self.damage = 5 + level;
+ self.speed = 1 + level * 0.1;
+ self.value = 10 + level * 5; // Gold value when killed
// Health bar
var healthBarContainer = new Container();
var healthBarBg = healthBarContainer.attachAsset('healthBarBg', {
anchorX: 0.5,
@@ -384,35 +453,36 @@
});
healthBarContainer.addChild(healthBarFill);
healthBarContainer.y = -50;
self.addChild(healthBarContainer);
+ // Movement variables
+ var targetX = CENTER_X;
+ var targetY = CENTER_Y;
self.update = function () {
// Move towards tower
- var dx = CENTER_X - self.x;
- var dy = CENTER_Y - self.y;
+ var dx = targetX - self.x;
+ var dy = targetY - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < 50) {
// Attack tower
if (tower.takeDamage(self.damage)) {
- return "gameover";
+ return "gameover"; // Tower destroyed
}
- // Destroy self
- self.destroy();
- zombies.splice(zombies.indexOf(self), 1);
+ // Move away slightly to prevent continuous damage
+ self.x -= dx * 0.5;
+ self.y -= dy * 0.5;
} else {
// Move towards tower
self.x += dx / dist * self.speed;
self.y += dy / dist * self.speed;
}
// Update health bar
healthBarFill.scale.x = self.health / self.maxHealth;
- // Zombie looks where it's going
- self.rotation = Math.atan2(dy, dx);
- return "ok";
+ return null;
};
self.takeDamage = function (amount) {
self.health -= amount;
- return self.health <= 0;
+ return self.health <= 0; // Return true if zombie is killed
};
return self;
});
@@ -435,73 +505,70 @@
var CENTER_Y = GAME_HEIGHT / 2;
// Game state
var isGameActive = false;
var waitingForNextWave = false;
-// Game objects
-var tower;
-var upgradePanel;
-var waveIndicator;
var waveCompleteText;
var bonusText;
var waveTextInterval;
-// Collections
+// Game objects
+var tower;
+var upgradePanel;
+var statusBar;
+var cooldownIndicator;
+var background;
+// Game arrays
var zombies = [];
var bullets = [];
var explosions = [];
var targets = [];
// Game stats
-var wave = 0;
+var wave = 1;
var zombiesInWave = 0;
var waveInterval = 60; // Frames between zombie spawns
var zombiesKilled = 0;
-var gold = 100;
+var gold = 200; // Starting gold
var manualCooldown = 0;
/****
* Game Functions
****/
function startGame() {
- // Create background
- var background = new Container();
- var backgroundGraphics = background.attachAsset('background', {
- anchorX: 0.5,
- anchorY: 0.5
- });
- background.x = CENTER_X;
- background.y = CENTER_Y;
+ // Reset game variables
+ isGameActive = true;
+ waitingForNextWave = false;
+ wave = 1;
+ zombiesKilled = 0;
+ gold = 200;
+ zombies = [];
+ bullets = [];
+ explosions = [];
+ targets = [];
+ LK.getMusic('background').play();
+ // Create game objects
+ background = new LK.Sprite('background');
game.addChild(background);
- // Create tower
+ // Create tower in center
tower = new Tower();
tower.x = CENTER_X;
tower.y = CENTER_Y;
game.addChild(tower);
- // Create upgrade panel
- upgradePanel = new UpgradePanel(tower);
- upgradePanel.x = GAME_WIDTH - 500;
- upgradePanel.y = 0;
+ // Create upgrade panel at bottom
+ upgradePanel = new UpgradePanel();
+ upgradePanel.x = CENTER_X;
+ upgradePanel.y = GAME_HEIGHT;
+ upgradePanel.updateGold(gold);
game.addChild(upgradePanel);
- // Create wave indicator
- waveIndicator = new Container();
- var waveIndicatorBg = waveIndicator.attachAsset('waveIndicator', {
- anchorX: 0.5,
- anchorY: 0.5
- });
- var waveText = new Text2("WAVE 1", {
- size: 40,
- fill: 0xffffff
- });
- waveText.anchor.set(0.5);
- waveIndicator.addChild(waveText);
- waveIndicator.x = 200;
- waveIndicator.y = 50;
- game.addChild(waveIndicator);
- // Start the game
- isGameActive = true;
+ // Create status bar at top
+ statusBar = new StatusBar();
+ statusBar.x = CENTER_X;
+ statusBar.y = 0;
+ game.addChild(statusBar);
+ // Create cooldown indicator for manual shooting
+ cooldownIndicator = new CooldownIndicator();
+ cooldownIndicator.x = CENTER_X;
+ cooldownIndicator.y = GAME_HEIGHT - 480; // Position above upgrade panel
+ game.addChild(cooldownIndicator);
// Start first wave
startWave();
- // Start background music
- LK.getSound('background').play();
- // Update gold display
- upgradePanel.updateGold(gold);
}
function startWave() {
// Clean up any previous wave text elements
if (waveCompleteText) {
@@ -515,62 +582,102 @@
if (waveTextInterval) {
LK.clearInterval(waveTextInterval);
waveTextInterval = null;
}
+ // Reset wave flag
waitingForNextWave = false;
- waveIndicator.children[1].setText("WAVE " + wave);
+ // Update status bar
+ statusBar.updateWave(wave);
+ // Calculate zombies for this wave
zombiesInWave = 10 + wave * 5;
- waveInterval = Math.max(20, 60 - wave * 5); // Spawn zombies faster in later waves
+ waveInterval = Math.max(20, 60 - wave * 2); // Spawn faster in later waves
// Show wave start message
- var waveStartText = new Text2("WAVE " + wave + " STARTING!", {
+ var waveText = new Text2("WAVE " + wave + " INCOMING!", {
size: 80,
- fill: 0xff9900
+ fill: 0xff3333
});
- waveStartText.x = CENTER_X;
- waveStartText.y = CENTER_Y;
- waveStartText.anchor.set(0.5);
- game.addChild(waveStartText);
+ waveText.x = CENTER_X;
+ waveText.y = CENTER_Y;
+ waveText.anchor.set(0.5);
+ game.addChild(waveText);
+ var zombiesText = new Text2(zombiesInWave + " ZOMBIES", {
+ size: 60,
+ fill: 0xff3333
+ });
+ zombiesText.x = CENTER_X;
+ zombiesText.y = CENTER_Y + 100;
+ zombiesText.anchor.set(0.5);
+ game.addChild(zombiesText);
LK.getSound('waveStart').play();
- // Fade out text
+ // Fade out wave text
var fadeInterval = LK.setInterval(function () {
- waveStartText.alpha -= 0.05;
- if (waveStartText.alpha <= 0) {
- waveStartText.destroy();
+ waveText.alpha -= 0.02;
+ zombiesText.alpha -= 0.02;
+ if (waveText.alpha <= 0) {
+ waveText.destroy();
+ zombiesText.destroy();
LK.clearInterval(fadeInterval);
}
}, 30);
}
function spawnZombie() {
if (zombiesInWave <= 0) {
return;
}
+ // Spawn a zombie at random edge position
var zombie = new Zombie(wave);
- // Spawn at random edge position
- var angle = Math.random() * Math.PI * 2;
- var distance = 1200; // Spawn outside visible area
- zombie.x = CENTER_X + Math.cos(angle) * distance;
- zombie.y = CENTER_Y + Math.sin(angle) * distance;
+ // Calculate spawn position (edge of screen)
+ var side = Math.floor(Math.random() * 4); // 0: top, 1: right, 2: bottom, 3: left
+ switch (side) {
+ case 0:
+ // Top
+ zombie.x = Math.random() * GAME_WIDTH;
+ zombie.y = 0;
+ break;
+ case 1:
+ // Right
+ zombie.x = GAME_WIDTH;
+ zombie.y = Math.random() * GAME_HEIGHT;
+ break;
+ case 2:
+ // Bottom
+ zombie.x = Math.random() * GAME_WIDTH;
+ zombie.y = GAME_HEIGHT;
+ break;
+ case 3:
+ // Left
+ zombie.x = 0;
+ zombie.y = Math.random() * GAME_HEIGHT;
+ break;
+ }
game.addChild(zombie);
zombies.push(zombie);
zombiesInWave--;
}
function gameOver() {
isGameActive = false;
- // Play game over sound
LK.getSound('gameOver').play();
- // Display message
- var gameOverText = new Text2("GAME OVER!", {
- size: 120,
+ // Show game over text
+ var gameOverText = new Text2("GAME OVER", {
+ size: 100,
fill: 0xff0000
});
gameOverText.x = CENTER_X;
gameOverText.y = CENTER_Y;
gameOverText.anchor.set(0.5);
game.addChild(gameOverText);
- var scoreText = new Text2("Waves Survived: " + wave + "\nZombies Killed: " + zombiesKilled, {
+ var waveText = new Text2("Survived to Wave " + wave, {
size: 60,
fill: 0xffffff
});
+ waveText.x = CENTER_X;
+ waveText.y = CENTER_Y + 80;
+ waveText.anchor.set(0.5);
+ game.addChild(waveText);
+ var scoreText = new Text2("Zombies Killed: " + zombiesKilled, {
+ size: 50,
+ fill: 0xffffff
+ });
scoreText.x = CENTER_X;
scoreText.y = CENTER_Y + 150;
scoreText.anchor.set(0.5);
game.addChild(scoreText);
@@ -589,10 +696,10 @@
return;
}
var event = obj;
var pos = game.toLocal(event.global);
- // Check if clicking on upgrade panel
- if (pos.x > GAME_WIDTH - 500) {
+ // Check if clicking in upgrade panel area
+ if (pos.y > GAME_HEIGHT - 400) {
var upgradeCost = upgradePanel.checkUpgradeClick(pos.x, pos.y, gold);
if (upgradeCost > 0) {
gold -= upgradeCost;
upgradePanel.updateGold(gold);
@@ -622,8 +729,12 @@
// Update tower
tower.update();
// Update upgrade panel
upgradePanel.update();
+ // Update cooldown indicator
+ cooldownIndicator.update(manualCooldown, 60);
+ // Update status bar stats
+ statusBar.updateStats(zombiesKilled, wave * zombiesKilled);
// Update bullets
for (var i = bullets.length - 1; i >= 0; i--) {
if (bullets[i].update()) {
bullets[i].destroy();