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 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 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
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);
// Methods
self.update = function () {
// Decrease fire timer
if (self.fireTimer > 0) {
self.fireTimer--;
}
// Update health bar
healthBarFill.scale.x = 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.upgradeDamage = function () {
self.upgradeLevel.damage++;
self.damage += 5;
LK.getSound('upgrade').play();
};
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 self = Container.call(this);
// Panel background
var panelBg = self.attachAsset('upgradePanel', {
anchorX: 0,
anchorY: 0
});
// 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 = 60;
goldText.anchor.set(0, 0.5);
goldContainer.addChild(goldText);
goldContainer.x = 100;
goldContainer.y = 100;
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 = [];
var upgradeCosts = {
damage: function damage() {
return tower.upgradeLevel.damage * 50;
},
fireRate: function fireRate() {
return tower.upgradeLevel.fireRate * 75;
},
range: function range() {
return tower.upgradeLevel.range * 40;
},
health: function health() {
return tower.upgradeLevel.health * 60;
}
};
function createUpgradeButton(label, y, upgradeFunc, getCostFunc) {
var button = new Container();
var buttonBg = 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;
button.addChild(buttonText);
var costText = new Text2("Cost: " + getCostFunc() + " Gold", {
size: 25,
fill: 0xffcc00
});
costText.anchor.set(1, 0.5);
costText.x = buttonBg.width / 2 - 20;
button.addChild(costText);
button.x = 250;
button.y = y;
button.upgrade = upgradeFunc;
button.getCost = getCostFunc;
button.updateCost = function () {
costText.setText("Cost: " + getCostFunc() + " Gold");
};
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 0;
};
self.updateGold = function (gold) {
goldText.setText(gold.toString());
};
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 () {
self.updateStats();
};
return self;
});
var Zombie = Container.expand(function (waveNumber) {
var self = Container.call(this);
var zombieGraphics = self.attachAsset('zombie', {
anchorX: 0.5,
anchorY: 0.5
});
// Stats scale with wave number
var waveMultiplier = 1 + waveNumber * 0.2;
self.health = 20 * waveMultiplier;
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;
}
// 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);
self.update = function () {
// Move towards tower
var dx = CENTER_X - self.x;
var dy = CENTER_Y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < 50) {
// Attack tower
if (tower.takeDamage(self.damage)) {
return "gameover";
}
// Destroy self
self.destroy();
zombies.splice(zombies.indexOf(self), 1);
} 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";
};
self.takeDamage = function (amount) {
self.health -= amount;
return self.health <= 0;
};
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;
// Game objects
var tower;
var upgradePanel;
var waveIndicator;
var waveCompleteText;
var bonusText;
var waveTextInterval;
// Collections
var zombies = [];
var bullets = [];
var explosions = [];
var targets = [];
// Game stats
var wave = 0;
var zombiesInWave = 0;
var waveInterval = 60; // Frames between zombie spawns
var zombiesKilled = 0;
var gold = 100;
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;
game.addChild(background);
// Create tower
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;
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;
// Start first wave
startWave();
// Start background music
LK.getMusic('background').play();
// Update gold display
upgradePanel.updateGold(gold);
}
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;
}
waitingForNextWave = false;
waveIndicator.children[1].setText("WAVE " + wave);
zombiesInWave = 10 + wave * 5;
waveInterval = Math.max(20, 60 - wave * 5); // Spawn zombies faster in later waves
// Show wave start message
var waveStartText = new Text2("WAVE " + wave + " STARTING!", {
size: 80,
fill: 0xff9900
});
waveStartText.x = CENTER_X;
waveStartText.y = CENTER_Y;
waveStartText.anchor.set(0.5);
game.addChild(waveStartText);
LK.getSound('waveStart').play();
// Fade out text
var fadeInterval = LK.setInterval(function () {
waveStartText.alpha -= 0.05;
if (waveStartText.alpha <= 0) {
waveStartText.destroy();
LK.clearInterval(fadeInterval);
}
}, 30);
}
function spawnZombie() {
if (zombiesInWave <= 0) {
return;
}
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;
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,
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, {
size: 60,
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 on upgrade panel
if (pos.x > GAME_WIDTH - 500) {
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 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
@@ -185,221 +185,193 @@
});
var UpgradePanel = Container.expand(function (tower) {
var self = Container.call(this);
// Panel background
- var panel = self.attachAsset('upgradePanel', {
+ var panelBg = self.attachAsset('upgradePanel', {
anchorX: 0,
anchorY: 0
});
- // Title
- var title = new Text2("UPGRADES", {
- size: 60,
- fill: 0xffffff
- });
- title.x = 250;
- title.y = 100;
- title.anchor.set(0.5);
- self.addChild(title);
// Gold display
- var goldIcon = new Container();
- var goldIconGraphics = goldIcon.attachAsset('goldIcon', {
+ var goldContainer = new Container();
+ var goldIcon = goldContainer.attachAsset('goldIcon', {
anchorX: 0.5,
anchorY: 0.5
});
- goldIcon.x = 100;
- goldIcon.y = 200;
- self.addChild(goldIcon);
var goldText = new Text2("0", {
- size: 50,
+ size: 40,
fill: 0xffcc00
});
- goldText.x = 180;
- goldText.y = 200;
+ goldText.x = 60;
goldText.anchor.set(0, 0.5);
- self.addChild(goldText);
+ goldContainer.addChild(goldText);
+ goldContainer.x = 100;
+ goldContainer.y = 100;
+ 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 upgrades = [{
- name: "Damage",
- action: "upgradeDamage",
- cost: 50,
- desc: "+5 damage per shot"
- }, {
- name: "Fire Rate",
- action: "upgradeFireRate",
- cost: 75,
- desc: "Shoot faster"
- }, {
- name: "Range",
- action: "upgradeRange",
- cost: 100,
- desc: "+100 targeting range"
- }, {
- name: "Health",
- action: "upgradeHealth",
- cost: 150,
- desc: "+50 max health"
- }];
- var buttons = [];
- for (var i = 0; i < upgrades.length; i++) {
- var y = 300 + i * 150;
+ var upgradeButtons = [];
+ var upgradeCosts = {
+ damage: function damage() {
+ return tower.upgradeLevel.damage * 50;
+ },
+ fireRate: function fireRate() {
+ return tower.upgradeLevel.fireRate * 75;
+ },
+ range: function range() {
+ return tower.upgradeLevel.range * 40;
+ },
+ health: function health() {
+ return tower.upgradeLevel.health * 60;
+ }
+ };
+ function createUpgradeButton(label, y, upgradeFunc, getCostFunc) {
var button = new Container();
- var buttonGraphics = button.attachAsset('upgradeButton', {
+ var buttonBg = button.attachAsset('upgradeButton', {
anchorX: 0.5,
anchorY: 0.5
});
- button.x = 250;
- button.y = y;
- var nameText = new Text2(upgrades[i].name, {
- size: 40,
+ var buttonText = new Text2(label, {
+ size: 30,
fill: 0xffffff
});
- nameText.x = 0;
- nameText.y = -30;
- nameText.anchor.set(0.5);
- button.addChild(nameText);
- var costText = new Text2(upgrades[i].cost + " gold", {
- size: 30,
+ buttonText.anchor.set(0, 0.5);
+ buttonText.x = -buttonBg.width / 2 + 20;
+ button.addChild(buttonText);
+ var costText = new Text2("Cost: " + getCostFunc() + " Gold", {
+ size: 25,
fill: 0xffcc00
});
- costText.x = 0;
- costText.y = 0;
- costText.anchor.set(0.5);
+ costText.anchor.set(1, 0.5);
+ costText.x = buttonBg.width / 2 - 20;
button.addChild(costText);
- var descText = new Text2(upgrades[i].desc, {
- size: 25,
- fill: 0xcccccc
- });
- descText.x = 0;
- descText.y = 30;
- descText.anchor.set(0.5);
- button.addChild(descText);
- button.upgrade = upgrades[i];
- buttons.push(button);
+ button.x = 250;
+ button.y = y;
+ button.upgrade = upgradeFunc;
+ button.getCost = getCostFunc;
+ button.updateCost = function () {
+ costText.setText("Cost: " + getCostFunc() + " Gold");
+ };
self.addChild(button);
+ upgradeButtons.push(button);
+ return button;
}
- // Wave info
- var waveInfo = new Container();
- var waveInfoGraphics = waveInfo.attachAsset('waveIndicator', {
- anchorX: 0.5,
- anchorY: 0.5
- });
- waveInfo.x = 250;
- waveInfo.y = 1000;
- self.addChild(waveInfo);
- var waveText = new Text2("WAVE 1", {
- size: 40,
- fill: 0xffffff
- });
- waveText.x = 0;
- waveText.y = 0;
- waveText.anchor.set(0.5);
- waveInfo.addChild(waveText);
- // Stats display
- var statsTitle = new Text2("TOWER STATS", {
- size: 50,
- fill: 0xffffff
- });
- statsTitle.x = 250;
- statsTitle.y = 1200;
- statsTitle.anchor.set(0.5);
- self.addChild(statsTitle);
- var stats = [{
- name: "Damage",
- getValue: function getValue() {
- return tower.damage;
- }
- }, {
- name: "Fire Rate",
- getValue: function getValue() {
- return (60 / tower.fireRate).toFixed(1) + "/sec";
- }
- }, {
- name: "Range",
- getValue: function getValue() {
- return tower.range;
- }
- }, {
- name: "Health",
- getValue: function getValue() {
- return tower.health + "/" + tower.maxHealth;
- }
- }];
- var statTexts = [];
- for (var j = 0; j < stats.length; j++) {
- var statY = 1300 + j * 70;
- var statName = new Text2(stats[j].name + ":", {
- size: 35,
- fill: 0xcccccc
- });
- statName.x = 100;
- statName.y = statY;
- statName.anchor.set(0, 0.5);
- self.addChild(statName);
- var statValue = new Text2("0", {
- size: 35,
- fill: 0xffffff
- });
- statValue.x = 400;
- statValue.y = statY;
- statValue.anchor.set(1, 0.5);
- statValue.getValue = stats[j].getValue;
- statTexts.push(statValue);
- self.addChild(statValue);
- }
- // Methods
- self.updateGold = function (amount) {
- goldText.setText(amount.toString());
- // Update button states based on available gold
- for (var i = 0; i < buttons.length; i++) {
- var button = buttons[i];
- // Make buttons grey if can't afford
- if (button.upgrade.cost > amount) {
- button.getChildAt(0).tint = 0x888888;
- } else {
- button.getChildAt(0).tint = 0xffffff;
+ 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 0;
};
- self.updateWave = function (wave) {
- waveText.setText("WAVE " + wave);
+ self.updateGold = function (gold) {
+ goldText.setText(gold.toString());
};
- self.update = function () {
- // Update stat displays
- for (var i = 0; i < statTexts.length; i++) {
- statTexts[i].setText(statTexts[i].getValue());
+ 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.checkUpgradeClick = function (x, y, gold) {
- for (var i = 0; i < buttons.length; i++) {
- var button = buttons[i];
- var dx = x - (button.x + self.x);
- var dy = y - (button.y + self.y);
- var dist = Math.sqrt(dx * dx + dy * dy);
- if (dist < 200) {
- // Check if can afford
- if (gold >= button.upgrade.cost) {
- tower[button.upgrade.action]();
- return button.upgrade.cost;
- }
- }
- }
- return 0;
+ self.update = function () {
+ self.updateStats();
};
return self;
});
-var Zombie = Container.expand(function (level) {
+var Zombie = Container.expand(function (waveNumber) {
var self = Container.call(this);
- // Scale difficulty with level
- level = level || 1;
- // Zombie graphics
var zombieGraphics = self.attachAsset('zombie', {
anchorX: 0.5,
anchorY: 0.5
});
- // Randomize color slightly
- var green = 0x00ff00;
- var colorVariation = Math.floor(Math.random() * 0x303030);
- zombieGraphics.tint = green - colorVariation;
+ // Stats scale with wave number
+ var waveMultiplier = 1 + waveNumber * 0.2;
+ self.health = 20 * waveMultiplier;
+ 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;
+ }
// Health bar
var healthBarContainer = new Container();
var healthBarBg = healthBarContainer.attachAsset('healthBarBg', {
anchorX: 0.5,
@@ -412,95 +384,91 @@
});
healthBarContainer.addChild(healthBarFill);
healthBarContainer.y = -50;
self.addChild(healthBarContainer);
- // Zombie stats
- self.health = 20 + level * 5;
- self.maxHealth = self.health;
- self.damage = 5 + level;
- self.speed = 1 + level * 0.1;
- self.value = 5 + level; // Gold value
- // Update
self.update = function () {
// Move towards tower
- var dx = tower.x - self.x;
- var dy = tower.y - self.y;
+ var dx = CENTER_X - self.x;
+ var dy = CENTER_Y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
- // Normalize and apply speed
- if (dist > 0) {
+ if (dist < 50) {
+ // Attack tower
+ if (tower.takeDamage(self.damage)) {
+ return "gameover";
+ }
+ // Destroy self
+ self.destroy();
+ zombies.splice(zombies.indexOf(self), 1);
+ } else {
+ // Move towards tower
self.x += dx / dist * self.speed;
self.y += dy / dist * self.speed;
- // Rotate zombie to face movement direction
- self.rotation = Math.atan2(dy, dx);
}
// Update health bar
healthBarFill.scale.x = self.health / self.maxHealth;
- // Attack tower if close enough
- if (dist < 150) {
- if (tower.takeDamage(self.damage / 60)) {
- // Damage per second
- return "gameover";
- }
- }
- return false;
+ // Zombie looks where it's going
+ self.rotation = Math.atan2(dy, dx);
+ return "ok";
};
self.takeDamage = function (amount) {
self.health -= amount;
- // Flash when hit
- LK.effects.flashObject(self, 0xffffff, 100);
- if (self.health <= 0) {
- return true; // Zombie destroyed
- }
- return false;
+ return self.health <= 0;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
- backgroundColor: 0x001100
+ backgroundColor: 0x000000
});
/****
* Game Code
****/
-// Constants
+/****
+* Game Variables
+****/
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
var CENTER_X = GAME_WIDTH / 2;
var CENTER_Y = GAME_HEIGHT / 2;
-// Game variables
-var waveCompleteText;
-var bonusText;
+// Game state
+var isGameActive = false;
+var waitingForNextWave = false;
+// Game objects
var tower;
var upgradePanel;
-var bullets = [];
+var waveIndicator;
+var waveCompleteText;
+var bonusText;
+var waveTextInterval;
+// Collections
var zombies = [];
+var bullets = [];
var explosions = [];
var targets = [];
-var gold = 100;
-var wave = 1;
-var zombiesKilled = 0;
-var waveSize = 10;
+// Game stats
+var wave = 0;
var zombiesInWave = 0;
-var waveInterval = 0;
-var isGameActive = false;
-var waitingForNextWave = false;
+var waveInterval = 60; // Frames between zombie spawns
+var zombiesKilled = 0;
+var gold = 100;
var manualCooldown = 0;
+/****
+* Game Functions
+****/
function startGame() {
- // Play background music
- LK.playMusic('background', {
- loop: true
- });
// Create background
- var background = game.attachAsset('background', {
+ var background = new Container();
+ var backgroundGraphics = background.attachAsset('background', {
anchorX: 0.5,
anchorY: 0.5
});
background.x = CENTER_X;
background.y = CENTER_Y;
+ game.addChild(background);
// Create tower
tower = new Tower();
tower.x = CENTER_X;
tower.y = CENTER_Y;
@@ -509,43 +477,65 @@
upgradePanel = new UpgradePanel(tower);
upgradePanel.x = GAME_WIDTH - 500;
upgradePanel.y = 0;
game.addChild(upgradePanel);
- // Initialize UI
- upgradePanel.updateGold(gold);
- upgradePanel.updateWave(wave);
+ // 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;
// Start first wave
startWave();
- isGameActive = true;
+ // Start background music
+ LK.getMusic('background').play();
+ // Update gold display
+ upgradePanel.updateGold(gold);
}
function startWave() {
- // Remove any existing wave complete text
+ // 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;
+ }
waitingForNextWave = false;
- waveSize = 10 + wave * 5;
- zombiesInWave = waveSize;
- waveInterval = Math.max(30, 120 - wave * 5); // Spawn interval decreases with each wave
- upgradePanel.updateWave(wave);
- LK.getSound('waveStart').play();
- // Flash wave indicator
- var waveText = new Text2("WAVE " + wave + " INCOMING!", {
+ waveIndicator.children[1].setText("WAVE " + wave);
+ zombiesInWave = 10 + wave * 5;
+ waveInterval = Math.max(20, 60 - wave * 5); // Spawn zombies faster in later waves
+ // Show wave start message
+ var waveStartText = new Text2("WAVE " + wave + " STARTING!", {
size: 80,
- fill: 0xff0000
+ fill: 0xff9900
});
- waveText.x = CENTER_X;
- waveText.y = 200;
- waveText.anchor.set(0.5);
- game.addChild(waveText);
- // Fade out wave text
+ waveStartText.x = CENTER_X;
+ waveStartText.y = CENTER_Y;
+ waveStartText.anchor.set(0.5);
+ game.addChild(waveStartText);
+ LK.getSound('waveStart').play();
+ // Fade out text
var fadeInterval = LK.setInterval(function () {
- waveText.alpha -= 0.02;
- if (waveText.alpha <= 0) {
- waveText.destroy();
+ waveStartText.alpha -= 0.05;
+ if (waveStartText.alpha <= 0) {
+ waveStartText.destroy();
LK.clearInterval(fadeInterval);
}
}, 30);
}
@@ -718,36 +708,39 @@
LK.setTimeout(function () {
startWave();
}, 3000);
// Grant bonus gold between waves
- var bonus = 50 + wave * 10;
+ var bonus = 50 + (wave - 1) * 10;
gold += bonus;
upgradePanel.updateGold(gold);
// Show wave complete message
- var waveCompleteText = new Text2("WAVE " + (wave - 1) + " COMPLETE!", {
+ 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);
- var bonusText = new Text2("BONUS: +" + bonus + " GOLD", {
+ 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
- var fadeInterval = LK.setInterval(function () {
+ waveTextInterval = LK.setInterval(function () {
waveCompleteText.alpha -= 0.02;
bonusText.alpha -= 0.02;
if (waveCompleteText.alpha <= 0) {
waveCompleteText.destroy();
bonusText.destroy();
- LK.clearInterval(fadeInterval);
+ LK.clearInterval(waveTextInterval);
+ waveCompleteText = null;
+ bonusText = null;
+ waveTextInterval = null;
}
}, 30);
}
// Update manual cooldown