User prompt
Please fix the bug: 'Uncaught TypeError: obj.upgradeFunction is not a function' in or related to this line: 'obj.upgradeFunction();' Line Number: 347
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'apply')' in or related to this line: 'upgradeOptions[index].apply();' Line Number: 348
Code edit (1 edits merged)
Please save this source code
User prompt
Zombie XP Survival
User prompt
zombies killed to xp to levels which get you upgrades to kill more zombies
Initial prompt
zombie killer game kill zombies -
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.damage = player ? player.damage : 20;
self.direction = {
x: 0,
y: 0
};
self.update = function () {
self.x += self.direction.x * self.speed;
self.y += self.direction.y * self.speed;
if (self.x < -50 || self.x > 2098 || self.y < -50 || self.y > 2782) {
self.shouldRemove = true;
}
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 100;
self.maxHealth = 100;
self.damage = 20;
self.fireRate = 30; // Lower = faster
self.speed = 4;
self.lastShot = 0;
self.takeDamage = function (amount) {
self.health -= amount;
if (self.health <= 0) {
self.health = 0;
LK.showGameOver();
} else {
LK.effects.flashObject(self, 0xff0000, 300);
LK.getSound('playerHit').play();
}
};
self.heal = function (amount) {
self.health = Math.min(self.maxHealth, self.health + amount);
};
return self;
});
var XPOrb = Container.expand(function () {
var self = Container.call(this);
var orbGraphics = self.attachAsset('xpOrb', {
anchorX: 0.5,
anchorY: 0.5
});
self.value = 10;
self.collectDistance = 30;
self.update = function () {
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < self.collectDistance) {
self.x += dx / distance * 6;
self.y += dy / distance * 6;
if (distance < 20) {
currentXP += self.value;
checkLevelUp();
self.shouldRemove = true;
}
}
};
return self;
});
var Zombie = Container.expand(function (type) {
var self = Container.call(this);
self.type = type || 'normal';
self.speed = 1;
self.health = 40;
self.damage = 25;
self.xpValue = 10;
var assetId = 'zombie';
if (self.type === 'fast') {
assetId = 'fastZombie';
self.speed = 2.5;
self.health = 25;
self.damage = 20;
self.xpValue = 15;
} else if (self.type === 'strong') {
assetId = 'strongZombie';
self.speed = 0.8;
self.health = 80;
self.damage = 40;
self.xpValue = 25;
}
var zombieGraphics = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
self.takeDamage = function (amount) {
self.health -= amount;
LK.effects.flashObject(self, 0xffffff, 200);
if (self.health <= 0) {
self.isDead = true;
LK.getSound('zombieHit').play();
}
};
self.update = function () {
if (self.isDead) return;
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 5) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
} else {
// Attack player
if (!self.lastAttack || LK.ticks - self.lastAttack > 60) {
player.takeDamage(self.damage);
self.lastAttack = LK.ticks;
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2C3E50
});
/****
* Game Code
****/
var player;
var zombies = [];
var bullets = [];
var xpOrbs = [];
var currentXP = 0;
var currentLevel = 1;
var xpToNextLevel = 100;
var waveNumber = 1;
var zombiesSpawned = 0;
var zombiesInWave = 10;
var spawnTimer = 0;
var spawnRate = 120; // frames between spawns
var isShowingUpgrade = false;
var upgrades = [];
// UI Elements
var healthBar, xpBar, levelText, waveText, scoreText;
function initializeUI() {
// Health bar background
var healthBg = LK.getAsset('healthBg', {
width: 400,
height: 20,
color: 0x800000,
shape: 'box'
});
healthBg.x = 100;
healthBg.y = 100;
LK.gui.topLeft.addChild(healthBg);
// Health bar
healthBar = LK.getAsset('healthBar', {
width: 400,
height: 20,
color: 0x00ff00,
shape: 'box'
});
healthBar.x = 100;
healthBar.y = 100;
LK.gui.topLeft.addChild(healthBar);
// XP bar background
var xpBg = LK.getAsset('xpBg', {
width: 400,
height: 15,
color: 0x404040,
shape: 'box'
});
xpBg.x = 100;
xpBg.y = 130;
LK.gui.topLeft.addChild(xpBg);
// XP bar
xpBar = LK.getAsset('xpBar', {
width: 400,
height: 15,
color: 0x00FFFF,
shape: 'box'
});
xpBar.x = 100;
xpBar.y = 130;
LK.gui.topLeft.addChild(xpBar);
// Level text
levelText = new Text2('Level: 1', {
size: 40,
fill: '#ffffff'
});
levelText.anchor.set(0, 0);
levelText.x = 100;
levelText.y = 50;
LK.gui.topLeft.addChild(levelText);
// Wave text
waveText = new Text2('Wave: 1', {
size: 30,
fill: '#ffffff'
});
waveText.anchor.set(0.5, 0);
waveText.x = 1024;
waveText.y = 50;
LK.gui.top.addChild(waveText);
// Score text
scoreText = new Text2('Score: 0', {
size: 30,
fill: '#ffffff'
});
scoreText.anchor.set(1, 0);
scoreText.x = 1948;
scoreText.y = 50;
LK.gui.topRight.addChild(scoreText);
}
function updateUI() {
if (healthBar) {
var healthPercent = player.health / player.maxHealth;
healthBar.width = 400 * healthPercent;
}
if (xpBar) {
var xpPercent = currentXP / xpToNextLevel;
xpBar.width = 400 * Math.min(xpPercent, 1);
}
if (levelText) {
levelText.setText('Level: ' + currentLevel);
}
if (waveText) {
waveText.setText('Wave: ' + waveNumber);
}
if (scoreText) {
scoreText.setText('Score: ' + LK.getScore());
}
}
function checkLevelUp() {
if (currentXP >= xpToNextLevel) {
currentXP -= xpToNextLevel;
currentLevel++;
xpToNextLevel = Math.floor(xpToNextLevel * 1.5);
LK.getSound('levelUp').play();
showUpgradeScreen();
}
}
function showUpgradeScreen() {
isShowingUpgrade = true;
// Create upgrade options
var availableUpgrades = [{
name: 'Damage +20%',
apply: function apply() {
player.damage = Math.floor(player.damage * 1.2);
}
}, {
name: 'Fire Rate +25%',
apply: function apply() {
player.fireRate = Math.max(5, Math.floor(player.fireRate * 0.75));
}
}, {
name: 'Max Health +50',
apply: function apply() {
player.maxHealth += 50;
player.heal(50);
}
}, {
name: 'Speed +20%',
apply: function apply() {
player.speed = player.speed * 1.2;
}
}, {
name: 'Health Regen',
apply: function apply() {
player.hasRegen = true;
}
}];
// Create upgrade UI (simplified - just pick first 3)
var upgradeOptions = [];
for (var i = 0; i < 3 && i < availableUpgrades.length; i++) {
upgradeOptions.push(availableUpgrades[i]);
}
// Create upgrade buttons
var upgradeContainer = new Container();
upgradeContainer.x = 1024;
upgradeContainer.y = 1366;
var bgPanel = LK.getAsset('upgradePanel', {
width: 800,
height: 600,
color: 0x1a1a1a,
shape: 'box'
});
upgradeContainer.addChild(bgPanel);
var titleText = new Text2('LEVEL UP! Choose an upgrade:', {
size: 50,
fill: '#00FFFF'
});
titleText.anchor.set(0.5, 0.5);
titleText.y = -200;
upgradeContainer.addChild(titleText);
for (var i = 0; i < upgradeOptions.length; i++) {
var option = upgradeOptions[i];
var button = LK.getAsset('upgradeButton' + i, {
width: 600,
height: 100,
color: 0x0066CC,
shape: 'box'
});
button.y = -50 + i * 120;
button.upgradeIndex = i;
var buttonText = new Text2(option.name, {
size: 40,
fill: '#ffffff'
});
buttonText.anchor.set(0.5, 0.5);
button.addChild(buttonText);
button.down = function (x, y, obj) {
var index = obj.upgradeIndex;
upgradeOptions[index].apply();
game.removeChild(upgradeContainer);
isShowingUpgrade = false;
};
upgradeContainer.addChild(button);
}
game.addChild(upgradeContainer);
}
function spawnZombie() {
var type = 'normal';
var rand = Math.random();
if (waveNumber > 3 && rand < 0.3) type = 'fast';
if (waveNumber > 5 && rand < 0.2) type = 'strong';
var zombie = new Zombie(type);
// Spawn from edges
var edge = Math.floor(Math.random() * 4);
if (edge === 0) {
// top
zombie.x = Math.random() * 2048;
zombie.y = -50;
} else if (edge === 1) {
// right
zombie.x = 2098;
zombie.y = Math.random() * 2732;
} else if (edge === 2) {
// bottom
zombie.x = Math.random() * 2048;
zombie.y = 2782;
} else {
// left
zombie.x = -50;
zombie.y = Math.random() * 2732;
}
zombies.push(zombie);
game.addChild(zombie);
zombiesSpawned++;
}
function startNextWave() {
waveNumber++;
zombiesSpawned = 0;
zombiesInWave = Math.floor(10 + waveNumber * 2.5);
spawnRate = Math.max(30, 120 - waveNumber * 5);
}
// Initialize player
player = new Player();
player.x = 1024;
player.y = 1366;
game.addChild(player);
initializeUI();
var targetX = player.x;
var targetY = player.y;
game.move = function (x, y, obj) {
if (isShowingUpgrade) return;
targetX = x;
targetY = y;
};
game.down = function (x, y, obj) {
if (isShowingUpgrade) return;
targetX = x;
targetY = y;
};
game.update = function () {
if (isShowingUpgrade) return;
// Move player towards target
var dx = targetX - player.x;
var dy = targetY - player.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 5) {
player.x += dx / distance * player.speed;
player.y += dy / distance * player.speed;
}
// Keep player in bounds
player.x = Math.max(40, Math.min(2008, player.x));
player.y = Math.max(40, Math.min(2692, player.y));
// Player health regen
if (player.hasRegen && LK.ticks % 120 === 0) {
player.heal(5);
}
// Auto-shoot at nearest zombie
if (zombies.length > 0 && LK.ticks - player.lastShot >= player.fireRate) {
var nearestZombie = null;
var nearestDistance = Infinity;
for (var i = 0; i < zombies.length; i++) {
if (zombies[i].isDead) continue;
var zdx = zombies[i].x - player.x;
var zdy = zombies[i].y - player.y;
var zdist = Math.sqrt(zdx * zdx + zdy * zdy);
if (zdist < nearestDistance) {
nearestDistance = zdist;
nearestZombie = zombies[i];
}
}
if (nearestZombie && nearestDistance < 400) {
var bullet = new Bullet();
bullet.x = player.x;
bullet.y = player.y;
var bdx = nearestZombie.x - player.x;
var bdy = nearestZombie.y - player.y;
var bdist = Math.sqrt(bdx * bdx + bdy * bdy);
bullet.direction.x = bdx / bdist;
bullet.direction.y = bdy / bdist;
bullets.push(bullet);
game.addChild(bullet);
player.lastShot = LK.ticks;
LK.getSound('shoot').play();
}
}
// Update bullets
for (var i = bullets.length - 1; i >= 0; i--) {
var bullet = bullets[i];
if (bullet.shouldRemove) {
bullet.destroy();
bullets.splice(i, 1);
continue;
}
// Check bullet-zombie collisions
for (var j = zombies.length - 1; j >= 0; j--) {
var zombie = zombies[j];
if (zombie.isDead) continue;
if (bullet.intersects(zombie)) {
zombie.takeDamage(bullet.damage);
bullet.shouldRemove = true;
if (zombie.isDead) {
LK.setScore(LK.getScore() + zombie.xpValue);
// Create XP orb
var xpOrb = new XPOrb();
xpOrb.x = zombie.x;
xpOrb.y = zombie.y;
xpOrb.value = zombie.xpValue;
xpOrbs.push(xpOrb);
game.addChild(xpOrb);
}
break;
}
}
}
// Update zombies
for (var i = zombies.length - 1; i >= 0; i--) {
var zombie = zombies[i];
if (zombie.isDead) {
zombie.destroy();
zombies.splice(i, 1);
}
}
// Update XP orbs
for (var i = xpOrbs.length - 1; i >= 0; i--) {
var orb = xpOrbs[i];
if (orb.shouldRemove) {
orb.destroy();
xpOrbs.splice(i, 1);
}
}
// Spawn zombies
spawnTimer++;
if (spawnTimer >= spawnRate && zombiesSpawned < zombiesInWave) {
spawnZombie();
spawnTimer = 0;
}
// Check if wave is complete
if (zombiesSpawned >= zombiesInWave && zombies.length === 0) {
startNextWave();
}
updateUI();
}; ===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,490 @@
-/****
+/****
+* Plugins
+****/
+var tween = LK.import("@upit/tween.v1");
+
+/****
+* Classes
+****/
+var Bullet = Container.expand(function () {
+ var self = Container.call(this);
+ var bulletGraphics = self.attachAsset('bullet', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.speed = 8;
+ self.damage = player ? player.damage : 20;
+ self.direction = {
+ x: 0,
+ y: 0
+ };
+ self.update = function () {
+ self.x += self.direction.x * self.speed;
+ self.y += self.direction.y * self.speed;
+ if (self.x < -50 || self.x > 2098 || self.y < -50 || self.y > 2782) {
+ self.shouldRemove = true;
+ }
+ };
+ return self;
+});
+var Player = Container.expand(function () {
+ var self = Container.call(this);
+ var playerGraphics = self.attachAsset('player', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.health = 100;
+ self.maxHealth = 100;
+ self.damage = 20;
+ self.fireRate = 30; // Lower = faster
+ self.speed = 4;
+ self.lastShot = 0;
+ self.takeDamage = function (amount) {
+ self.health -= amount;
+ if (self.health <= 0) {
+ self.health = 0;
+ LK.showGameOver();
+ } else {
+ LK.effects.flashObject(self, 0xff0000, 300);
+ LK.getSound('playerHit').play();
+ }
+ };
+ self.heal = function (amount) {
+ self.health = Math.min(self.maxHealth, self.health + amount);
+ };
+ return self;
+});
+var XPOrb = Container.expand(function () {
+ var self = Container.call(this);
+ var orbGraphics = self.attachAsset('xpOrb', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.value = 10;
+ self.collectDistance = 30;
+ self.update = function () {
+ var dx = player.x - self.x;
+ var dy = player.y - self.y;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ if (distance < self.collectDistance) {
+ self.x += dx / distance * 6;
+ self.y += dy / distance * 6;
+ if (distance < 20) {
+ currentXP += self.value;
+ checkLevelUp();
+ self.shouldRemove = true;
+ }
+ }
+ };
+ return self;
+});
+var Zombie = Container.expand(function (type) {
+ var self = Container.call(this);
+ self.type = type || 'normal';
+ self.speed = 1;
+ self.health = 40;
+ self.damage = 25;
+ self.xpValue = 10;
+ var assetId = 'zombie';
+ if (self.type === 'fast') {
+ assetId = 'fastZombie';
+ self.speed = 2.5;
+ self.health = 25;
+ self.damage = 20;
+ self.xpValue = 15;
+ } else if (self.type === 'strong') {
+ assetId = 'strongZombie';
+ self.speed = 0.8;
+ self.health = 80;
+ self.damage = 40;
+ self.xpValue = 25;
+ }
+ var zombieGraphics = self.attachAsset(assetId, {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.takeDamage = function (amount) {
+ self.health -= amount;
+ LK.effects.flashObject(self, 0xffffff, 200);
+ if (self.health <= 0) {
+ self.isDead = true;
+ LK.getSound('zombieHit').play();
+ }
+ };
+ self.update = function () {
+ if (self.isDead) return;
+ var dx = player.x - self.x;
+ var dy = player.y - self.y;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ if (distance > 5) {
+ self.x += dx / distance * self.speed;
+ self.y += dy / distance * self.speed;
+ } else {
+ // Attack player
+ if (!self.lastAttack || LK.ticks - self.lastAttack > 60) {
+ player.takeDamage(self.damage);
+ self.lastAttack = LK.ticks;
+ }
+ }
+ };
+ return self;
+});
+
+/****
* Initialize Game
-****/
+****/
var game = new LK.Game({
- backgroundColor: 0x000000
-});
\ No newline at end of file
+ backgroundColor: 0x2C3E50
+});
+
+/****
+* Game Code
+****/
+var player;
+var zombies = [];
+var bullets = [];
+var xpOrbs = [];
+var currentXP = 0;
+var currentLevel = 1;
+var xpToNextLevel = 100;
+var waveNumber = 1;
+var zombiesSpawned = 0;
+var zombiesInWave = 10;
+var spawnTimer = 0;
+var spawnRate = 120; // frames between spawns
+var isShowingUpgrade = false;
+var upgrades = [];
+// UI Elements
+var healthBar, xpBar, levelText, waveText, scoreText;
+function initializeUI() {
+ // Health bar background
+ var healthBg = LK.getAsset('healthBg', {
+ width: 400,
+ height: 20,
+ color: 0x800000,
+ shape: 'box'
+ });
+ healthBg.x = 100;
+ healthBg.y = 100;
+ LK.gui.topLeft.addChild(healthBg);
+ // Health bar
+ healthBar = LK.getAsset('healthBar', {
+ width: 400,
+ height: 20,
+ color: 0x00ff00,
+ shape: 'box'
+ });
+ healthBar.x = 100;
+ healthBar.y = 100;
+ LK.gui.topLeft.addChild(healthBar);
+ // XP bar background
+ var xpBg = LK.getAsset('xpBg', {
+ width: 400,
+ height: 15,
+ color: 0x404040,
+ shape: 'box'
+ });
+ xpBg.x = 100;
+ xpBg.y = 130;
+ LK.gui.topLeft.addChild(xpBg);
+ // XP bar
+ xpBar = LK.getAsset('xpBar', {
+ width: 400,
+ height: 15,
+ color: 0x00FFFF,
+ shape: 'box'
+ });
+ xpBar.x = 100;
+ xpBar.y = 130;
+ LK.gui.topLeft.addChild(xpBar);
+ // Level text
+ levelText = new Text2('Level: 1', {
+ size: 40,
+ fill: '#ffffff'
+ });
+ levelText.anchor.set(0, 0);
+ levelText.x = 100;
+ levelText.y = 50;
+ LK.gui.topLeft.addChild(levelText);
+ // Wave text
+ waveText = new Text2('Wave: 1', {
+ size: 30,
+ fill: '#ffffff'
+ });
+ waveText.anchor.set(0.5, 0);
+ waveText.x = 1024;
+ waveText.y = 50;
+ LK.gui.top.addChild(waveText);
+ // Score text
+ scoreText = new Text2('Score: 0', {
+ size: 30,
+ fill: '#ffffff'
+ });
+ scoreText.anchor.set(1, 0);
+ scoreText.x = 1948;
+ scoreText.y = 50;
+ LK.gui.topRight.addChild(scoreText);
+}
+function updateUI() {
+ if (healthBar) {
+ var healthPercent = player.health / player.maxHealth;
+ healthBar.width = 400 * healthPercent;
+ }
+ if (xpBar) {
+ var xpPercent = currentXP / xpToNextLevel;
+ xpBar.width = 400 * Math.min(xpPercent, 1);
+ }
+ if (levelText) {
+ levelText.setText('Level: ' + currentLevel);
+ }
+ if (waveText) {
+ waveText.setText('Wave: ' + waveNumber);
+ }
+ if (scoreText) {
+ scoreText.setText('Score: ' + LK.getScore());
+ }
+}
+function checkLevelUp() {
+ if (currentXP >= xpToNextLevel) {
+ currentXP -= xpToNextLevel;
+ currentLevel++;
+ xpToNextLevel = Math.floor(xpToNextLevel * 1.5);
+ LK.getSound('levelUp').play();
+ showUpgradeScreen();
+ }
+}
+function showUpgradeScreen() {
+ isShowingUpgrade = true;
+ // Create upgrade options
+ var availableUpgrades = [{
+ name: 'Damage +20%',
+ apply: function apply() {
+ player.damage = Math.floor(player.damage * 1.2);
+ }
+ }, {
+ name: 'Fire Rate +25%',
+ apply: function apply() {
+ player.fireRate = Math.max(5, Math.floor(player.fireRate * 0.75));
+ }
+ }, {
+ name: 'Max Health +50',
+ apply: function apply() {
+ player.maxHealth += 50;
+ player.heal(50);
+ }
+ }, {
+ name: 'Speed +20%',
+ apply: function apply() {
+ player.speed = player.speed * 1.2;
+ }
+ }, {
+ name: 'Health Regen',
+ apply: function apply() {
+ player.hasRegen = true;
+ }
+ }];
+ // Create upgrade UI (simplified - just pick first 3)
+ var upgradeOptions = [];
+ for (var i = 0; i < 3 && i < availableUpgrades.length; i++) {
+ upgradeOptions.push(availableUpgrades[i]);
+ }
+ // Create upgrade buttons
+ var upgradeContainer = new Container();
+ upgradeContainer.x = 1024;
+ upgradeContainer.y = 1366;
+ var bgPanel = LK.getAsset('upgradePanel', {
+ width: 800,
+ height: 600,
+ color: 0x1a1a1a,
+ shape: 'box'
+ });
+ upgradeContainer.addChild(bgPanel);
+ var titleText = new Text2('LEVEL UP! Choose an upgrade:', {
+ size: 50,
+ fill: '#00FFFF'
+ });
+ titleText.anchor.set(0.5, 0.5);
+ titleText.y = -200;
+ upgradeContainer.addChild(titleText);
+ for (var i = 0; i < upgradeOptions.length; i++) {
+ var option = upgradeOptions[i];
+ var button = LK.getAsset('upgradeButton' + i, {
+ width: 600,
+ height: 100,
+ color: 0x0066CC,
+ shape: 'box'
+ });
+ button.y = -50 + i * 120;
+ button.upgradeIndex = i;
+ var buttonText = new Text2(option.name, {
+ size: 40,
+ fill: '#ffffff'
+ });
+ buttonText.anchor.set(0.5, 0.5);
+ button.addChild(buttonText);
+ button.down = function (x, y, obj) {
+ var index = obj.upgradeIndex;
+ upgradeOptions[index].apply();
+ game.removeChild(upgradeContainer);
+ isShowingUpgrade = false;
+ };
+ upgradeContainer.addChild(button);
+ }
+ game.addChild(upgradeContainer);
+}
+function spawnZombie() {
+ var type = 'normal';
+ var rand = Math.random();
+ if (waveNumber > 3 && rand < 0.3) type = 'fast';
+ if (waveNumber > 5 && rand < 0.2) type = 'strong';
+ var zombie = new Zombie(type);
+ // Spawn from edges
+ var edge = Math.floor(Math.random() * 4);
+ if (edge === 0) {
+ // top
+ zombie.x = Math.random() * 2048;
+ zombie.y = -50;
+ } else if (edge === 1) {
+ // right
+ zombie.x = 2098;
+ zombie.y = Math.random() * 2732;
+ } else if (edge === 2) {
+ // bottom
+ zombie.x = Math.random() * 2048;
+ zombie.y = 2782;
+ } else {
+ // left
+ zombie.x = -50;
+ zombie.y = Math.random() * 2732;
+ }
+ zombies.push(zombie);
+ game.addChild(zombie);
+ zombiesSpawned++;
+}
+function startNextWave() {
+ waveNumber++;
+ zombiesSpawned = 0;
+ zombiesInWave = Math.floor(10 + waveNumber * 2.5);
+ spawnRate = Math.max(30, 120 - waveNumber * 5);
+}
+// Initialize player
+player = new Player();
+player.x = 1024;
+player.y = 1366;
+game.addChild(player);
+initializeUI();
+var targetX = player.x;
+var targetY = player.y;
+game.move = function (x, y, obj) {
+ if (isShowingUpgrade) return;
+ targetX = x;
+ targetY = y;
+};
+game.down = function (x, y, obj) {
+ if (isShowingUpgrade) return;
+ targetX = x;
+ targetY = y;
+};
+game.update = function () {
+ if (isShowingUpgrade) return;
+ // Move player towards target
+ var dx = targetX - player.x;
+ var dy = targetY - player.y;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ if (distance > 5) {
+ player.x += dx / distance * player.speed;
+ player.y += dy / distance * player.speed;
+ }
+ // Keep player in bounds
+ player.x = Math.max(40, Math.min(2008, player.x));
+ player.y = Math.max(40, Math.min(2692, player.y));
+ // Player health regen
+ if (player.hasRegen && LK.ticks % 120 === 0) {
+ player.heal(5);
+ }
+ // Auto-shoot at nearest zombie
+ if (zombies.length > 0 && LK.ticks - player.lastShot >= player.fireRate) {
+ var nearestZombie = null;
+ var nearestDistance = Infinity;
+ for (var i = 0; i < zombies.length; i++) {
+ if (zombies[i].isDead) continue;
+ var zdx = zombies[i].x - player.x;
+ var zdy = zombies[i].y - player.y;
+ var zdist = Math.sqrt(zdx * zdx + zdy * zdy);
+ if (zdist < nearestDistance) {
+ nearestDistance = zdist;
+ nearestZombie = zombies[i];
+ }
+ }
+ if (nearestZombie && nearestDistance < 400) {
+ var bullet = new Bullet();
+ bullet.x = player.x;
+ bullet.y = player.y;
+ var bdx = nearestZombie.x - player.x;
+ var bdy = nearestZombie.y - player.y;
+ var bdist = Math.sqrt(bdx * bdx + bdy * bdy);
+ bullet.direction.x = bdx / bdist;
+ bullet.direction.y = bdy / bdist;
+ bullets.push(bullet);
+ game.addChild(bullet);
+ player.lastShot = LK.ticks;
+ LK.getSound('shoot').play();
+ }
+ }
+ // Update bullets
+ for (var i = bullets.length - 1; i >= 0; i--) {
+ var bullet = bullets[i];
+ if (bullet.shouldRemove) {
+ bullet.destroy();
+ bullets.splice(i, 1);
+ continue;
+ }
+ // Check bullet-zombie collisions
+ for (var j = zombies.length - 1; j >= 0; j--) {
+ var zombie = zombies[j];
+ if (zombie.isDead) continue;
+ if (bullet.intersects(zombie)) {
+ zombie.takeDamage(bullet.damage);
+ bullet.shouldRemove = true;
+ if (zombie.isDead) {
+ LK.setScore(LK.getScore() + zombie.xpValue);
+ // Create XP orb
+ var xpOrb = new XPOrb();
+ xpOrb.x = zombie.x;
+ xpOrb.y = zombie.y;
+ xpOrb.value = zombie.xpValue;
+ xpOrbs.push(xpOrb);
+ game.addChild(xpOrb);
+ }
+ break;
+ }
+ }
+ }
+ // Update zombies
+ for (var i = zombies.length - 1; i >= 0; i--) {
+ var zombie = zombies[i];
+ if (zombie.isDead) {
+ zombie.destroy();
+ zombies.splice(i, 1);
+ }
+ }
+ // Update XP orbs
+ for (var i = xpOrbs.length - 1; i >= 0; i--) {
+ var orb = xpOrbs[i];
+ if (orb.shouldRemove) {
+ orb.destroy();
+ xpOrbs.splice(i, 1);
+ }
+ }
+ // Spawn zombies
+ spawnTimer++;
+ if (spawnTimer >= spawnRate && zombiesSpawned < zombiesInWave) {
+ spawnZombie();
+ spawnTimer = 0;
+ }
+ // Check if wave is complete
+ if (zombiesSpawned >= zombiesInWave && zombies.length === 0) {
+ startNextWave();
+ }
+ updateUI();
+};
\ No newline at end of file