/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Bullet = Container.expand(function (damage, speed, isEnemy) {
var self = Container.call(this);
self.damage = damage || 25;
self.speed = speed || 8;
self.isEnemy = isEnemy || false;
var bulletGraphics = self.attachAsset(isEnemy ? 'enemyBullet' : 'bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.direction = {
x: 0,
y: 0
};
self.update = function () {
self.x += self.direction.x * self.speed;
self.y += self.direction.y * self.speed;
};
return self;
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 75;
self.maxHealth = 75;
self.speed = 2;
self.lastFired = 0;
self.fireRate = 60;
self.detectionRange = 300;
self.damage = 20;
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.detectionRange) {
// Move towards player
var moveX = dx / distance * self.speed;
var moveY = dy / distance * self.speed;
self.x += moveX;
self.y += moveY;
// Fire at player
if (LK.ticks - self.lastFired >= self.fireRate) {
var bullet = new Bullet(self.damage, 6, true);
bullet.x = self.x;
bullet.y = self.y;
bullet.direction.x = dx / distance;
bullet.direction.y = dy / distance;
enemyBullets.push(bullet);
game.addChild(bullet);
self.lastFired = LK.ticks;
}
}
};
return self;
});
var Item = Container.expand(function (type) {
var self = Container.call(this);
self.type = type;
var itemGraphics = self.attachAsset(type, {
anchorX: 0.5,
anchorY: 0.5
});
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.weapon = null;
self.speed = 4;
return self;
});
var Weapon = Container.expand(function (type) {
var self = Container.call(this);
self.type = type || 'pistol';
self.damage = 25;
self.fireRate = 15;
self.maxAmmo = 12;
self.reloadTime = 60;
if (self.type === 'rifle') {
self.damage = 35;
self.fireRate = 8;
self.maxAmmo = 30;
self.reloadTime = 90;
} else if (self.type === 'shotgun') {
self.damage = 60;
self.fireRate = 25;
self.maxAmmo = 8;
self.reloadTime = 120;
}
self.ammo = self.maxAmmo;
self.lastFired = 0;
self.reloading = false;
self.reloadStart = 0;
var weaponGraphics = self.attachAsset(self.type, {
anchorX: 0.5,
anchorY: 0.5
});
self.canFire = function () {
return !self.reloading && self.ammo > 0 && LK.ticks - self.lastFired >= self.fireRate;
};
self.fire = function () {
if (self.canFire()) {
self.ammo--;
self.lastFired = LK.ticks;
LK.getSound('shoot').play();
return true;
}
return false;
};
self.reload = function () {
if (!self.reloading && self.ammo < self.maxAmmo) {
self.reloading = true;
self.reloadStart = LK.ticks;
LK.getSound('reload').play();
}
};
self.update = function () {
if (self.reloading && LK.ticks - self.reloadStart >= self.reloadTime) {
self.ammo = self.maxAmmo;
self.reloading = false;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2d5a3d
});
/****
* Game Code
****/
// Game variables
var player;
var enemies = [];
var playerBullets = [];
var enemyBullets = [];
var items = [];
var dragNode = null;
var shootTarget = null;
var zoneRadius = 1200;
var zoneCenter = {
x: 1024,
y: 1366
};
var zoneShrinkRate = 0.5;
var waveNumber = 1;
var enemiesKilled = 0;
var nextWaveTimer = 0;
// Create UI elements
var healthBar = LK.getAsset('healthPack', {
anchorX: 0,
anchorY: 0,
scaleX: 6,
scaleY: 1
});
LK.gui.topLeft.addChild(healthBar);
healthBar.x = 120;
healthBar.y = 20;
var healthText = new Text2('100/100', {
size: 40,
fill: 0xFFFFFF
});
healthText.anchor.set(0, 0);
LK.gui.topLeft.addChild(healthText);
healthText.x = 120;
healthText.y = 60;
var ammoText = new Text2('12/12', {
size: 40,
fill: 0xFFFFFF
});
ammoText.anchor.set(0, 0);
LK.gui.topLeft.addChild(ammoText);
ammoText.x = 120;
ammoText.y = 100;
var scoreText = new Text2('Kills: 0', {
size: 50,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
var waveText = new Text2('Wave: 1', {
size: 45,
fill: 0xFFFFFF
});
waveText.anchor.set(1, 0);
LK.gui.topRight.addChild(waveText);
waveText.x = -20;
waveText.y = 20;
// Initialize player
player = game.addChild(new Player());
player.x = 1024;
player.y = 1366;
// Give player starting weapon
var startWeapon = new Weapon('pistol');
startWeapon.x = player.x;
startWeapon.y = player.y - 50;
player.weapon = startWeapon;
game.addChild(startWeapon);
// Spawn initial enemies
function spawnWave() {
var enemiesToSpawn = Math.min(3 + waveNumber, 8);
for (var i = 0; i < enemiesToSpawn; i++) {
var enemy = new Enemy();
var angle = Math.random() * Math.PI * 2;
var distance = 400 + Math.random() * 400;
enemy.x = player.x + Math.cos(angle) * distance;
enemy.y = player.y + Math.sin(angle) * distance;
// Keep enemies within bounds
enemy.x = Math.max(100, Math.min(1948, enemy.x));
enemy.y = Math.max(100, Math.min(2632, enemy.y));
enemies.push(enemy);
game.addChild(enemy);
}
}
// Spawn initial items
function spawnItems() {
// Spawn weapons
for (var i = 0; i < 3; i++) {
var weaponTypes = ['pistol', 'rifle', 'shotgun'];
var weaponType = weaponTypes[Math.floor(Math.random() * weaponTypes.length)];
var weapon = new Item(weaponType);
weapon.x = Math.random() * 1800 + 124;
weapon.y = Math.random() * 2400 + 166;
items.push(weapon);
game.addChild(weapon);
}
// Spawn health packs
for (var i = 0; i < 4; i++) {
var health = new Item('healthPack');
health.x = Math.random() * 1800 + 124;
health.y = Math.random() * 2400 + 166;
items.push(health);
game.addChild(health);
}
// Spawn ammo boxes
for (var i = 0; i < 3; i++) {
var ammo = new Item('ammoBox');
ammo.x = Math.random() * 1800 + 124;
ammo.y = Math.random() * 2400 + 166;
items.push(ammo);
game.addChild(ammo);
}
}
spawnWave();
spawnItems();
// Event handlers
function handleMove(x, y, obj) {
if (dragNode) {
dragNode.x = x;
dragNode.y = y;
// Move weapon with player
if (player.weapon) {
player.weapon.x = player.x;
player.weapon.y = player.y;
}
}
}
game.move = handleMove;
game.down = function (x, y, obj) {
var distanceToPlayer = Math.sqrt((x - player.x) * (x - player.x) + (y - player.y) * (y - player.y));
if (distanceToPlayer < 100) {
dragNode = player;
handleMove(x, y, obj);
} else {
// Shoot towards tap location
shootTarget = {
x: x,
y: y
};
}
};
game.up = function (x, y, obj) {
if (shootTarget && player.weapon && player.weapon.fire()) {
var dx = shootTarget.x - player.x;
var dy = shootTarget.y - player.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var bullet = new Bullet(player.weapon.damage, 10, false);
bullet.x = player.x;
bullet.y = player.y;
bullet.direction.x = dx / distance;
bullet.direction.y = dy / distance;
playerBullets.push(bullet);
game.addChild(bullet);
// Auto reload if empty
if (player.weapon.ammo === 0) {
player.weapon.reload();
}
}
dragNode = null;
shootTarget = null;
};
// Main game loop
game.update = function () {
// Update player weapon
if (player.weapon) {
player.weapon.update();
}
// Update enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
enemy.update();
// Check if enemy is outside zone
var distanceFromCenter = Math.sqrt((enemy.x - zoneCenter.x) * (enemy.x - zoneCenter.x) + (enemy.y - zoneCenter.y) * (enemy.y - zoneCenter.y));
if (distanceFromCenter > zoneRadius) {
enemy.health -= 2;
LK.effects.flashObject(enemy, 0xff0000, 100);
}
}
// Update player bullets
for (var i = playerBullets.length - 1; i >= 0; i--) {
var bullet = playerBullets[i];
bullet.update();
// Check bounds
if (bullet.x < 0 || bullet.x > 2048 || bullet.y < 0 || bullet.y > 2732) {
bullet.destroy();
playerBullets.splice(i, 1);
continue;
}
// Check enemy collisions
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (bullet.intersects(enemy)) {
enemy.health -= bullet.damage;
LK.effects.flashObject(enemy, 0xff0000, 200);
LK.getSound('hit').play();
bullet.destroy();
playerBullets.splice(i, 1);
if (enemy.health <= 0) {
enemy.destroy();
enemies.splice(j, 1);
enemiesKilled++;
LK.setScore(enemiesKilled);
scoreText.setText('Kills: ' + enemiesKilled);
}
break;
}
}
}
// Update enemy bullets
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var bullet = enemyBullets[i];
bullet.update();
// Check bounds
if (bullet.x < 0 || bullet.x > 2048 || bullet.y < 0 || bullet.y > 2732) {
bullet.destroy();
enemyBullets.splice(i, 1);
continue;
}
// Check player collision
if (bullet.intersects(player)) {
player.health -= bullet.damage;
LK.effects.flashObject(player, 0xff0000, 300);
LK.getSound('hit').play();
bullet.destroy();
enemyBullets.splice(i, 1);
if (player.health <= 0) {
LK.showGameOver();
return;
}
}
}
// Check item pickups
for (var i = items.length - 1; i >= 0; i--) {
var item = items[i];
var distance = Math.sqrt((player.x - item.x) * (player.x - item.x) + (player.y - item.y) * (player.y - item.y));
if (distance < 60) {
if (item.type === 'healthPack') {
player.health = Math.min(player.maxHealth, player.health + 30);
LK.getSound('pickup').play();
} else if (item.type === 'ammoBox' && player.weapon) {
player.weapon.ammo = player.weapon.maxAmmo;
LK.getSound('pickup').play();
} else if (item.type === 'pistol' || item.type === 'rifle' || item.type === 'shotgun') {
if (player.weapon) {
player.weapon.destroy();
}
player.weapon = new Weapon(item.type);
player.weapon.x = player.x;
player.weapon.y = player.y;
game.addChild(player.weapon);
LK.getSound('pickup').play();
}
item.destroy();
items.splice(i, 1);
}
}
// Check zone damage for player
var playerDistanceFromCenter = Math.sqrt((player.x - zoneCenter.x) * (player.x - zoneCenter.x) + (player.y - zoneCenter.y) * (player.y - zoneCenter.y));
if (playerDistanceFromCenter > zoneRadius) {
player.health -= 1;
LK.effects.flashScreen(0xff0000, 100);
}
// Shrink zone
if (LK.ticks % 180 === 0) {
zoneRadius = Math.max(200, zoneRadius - zoneShrinkRate);
}
// Spawn new wave when all enemies are dead
if (enemies.length === 0) {
nextWaveTimer++;
if (nextWaveTimer >= 120) {
waveNumber++;
spawnWave();
spawnItems();
nextWaveTimer = 0;
waveText.setText('Wave: ' + waveNumber);
}
}
// Update UI
healthText.setText(Math.max(0, player.health) + '/' + player.maxHealth);
if (player.weapon) {
ammoText.setText(player.weapon.ammo + '/' + player.weapon.maxAmmo + (player.weapon.reloading ? ' (Reloading...)' : ''));
}
// Update health bar scale
var healthPercent = Math.max(0, player.health) / player.maxHealth;
healthBar.scaleX = 6 * healthPercent;
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Bullet = Container.expand(function (damage, speed, isEnemy) {
var self = Container.call(this);
self.damage = damage || 25;
self.speed = speed || 8;
self.isEnemy = isEnemy || false;
var bulletGraphics = self.attachAsset(isEnemy ? 'enemyBullet' : 'bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.direction = {
x: 0,
y: 0
};
self.update = function () {
self.x += self.direction.x * self.speed;
self.y += self.direction.y * self.speed;
};
return self;
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 75;
self.maxHealth = 75;
self.speed = 2;
self.lastFired = 0;
self.fireRate = 60;
self.detectionRange = 300;
self.damage = 20;
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.detectionRange) {
// Move towards player
var moveX = dx / distance * self.speed;
var moveY = dy / distance * self.speed;
self.x += moveX;
self.y += moveY;
// Fire at player
if (LK.ticks - self.lastFired >= self.fireRate) {
var bullet = new Bullet(self.damage, 6, true);
bullet.x = self.x;
bullet.y = self.y;
bullet.direction.x = dx / distance;
bullet.direction.y = dy / distance;
enemyBullets.push(bullet);
game.addChild(bullet);
self.lastFired = LK.ticks;
}
}
};
return self;
});
var Item = Container.expand(function (type) {
var self = Container.call(this);
self.type = type;
var itemGraphics = self.attachAsset(type, {
anchorX: 0.5,
anchorY: 0.5
});
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.weapon = null;
self.speed = 4;
return self;
});
var Weapon = Container.expand(function (type) {
var self = Container.call(this);
self.type = type || 'pistol';
self.damage = 25;
self.fireRate = 15;
self.maxAmmo = 12;
self.reloadTime = 60;
if (self.type === 'rifle') {
self.damage = 35;
self.fireRate = 8;
self.maxAmmo = 30;
self.reloadTime = 90;
} else if (self.type === 'shotgun') {
self.damage = 60;
self.fireRate = 25;
self.maxAmmo = 8;
self.reloadTime = 120;
}
self.ammo = self.maxAmmo;
self.lastFired = 0;
self.reloading = false;
self.reloadStart = 0;
var weaponGraphics = self.attachAsset(self.type, {
anchorX: 0.5,
anchorY: 0.5
});
self.canFire = function () {
return !self.reloading && self.ammo > 0 && LK.ticks - self.lastFired >= self.fireRate;
};
self.fire = function () {
if (self.canFire()) {
self.ammo--;
self.lastFired = LK.ticks;
LK.getSound('shoot').play();
return true;
}
return false;
};
self.reload = function () {
if (!self.reloading && self.ammo < self.maxAmmo) {
self.reloading = true;
self.reloadStart = LK.ticks;
LK.getSound('reload').play();
}
};
self.update = function () {
if (self.reloading && LK.ticks - self.reloadStart >= self.reloadTime) {
self.ammo = self.maxAmmo;
self.reloading = false;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2d5a3d
});
/****
* Game Code
****/
// Game variables
var player;
var enemies = [];
var playerBullets = [];
var enemyBullets = [];
var items = [];
var dragNode = null;
var shootTarget = null;
var zoneRadius = 1200;
var zoneCenter = {
x: 1024,
y: 1366
};
var zoneShrinkRate = 0.5;
var waveNumber = 1;
var enemiesKilled = 0;
var nextWaveTimer = 0;
// Create UI elements
var healthBar = LK.getAsset('healthPack', {
anchorX: 0,
anchorY: 0,
scaleX: 6,
scaleY: 1
});
LK.gui.topLeft.addChild(healthBar);
healthBar.x = 120;
healthBar.y = 20;
var healthText = new Text2('100/100', {
size: 40,
fill: 0xFFFFFF
});
healthText.anchor.set(0, 0);
LK.gui.topLeft.addChild(healthText);
healthText.x = 120;
healthText.y = 60;
var ammoText = new Text2('12/12', {
size: 40,
fill: 0xFFFFFF
});
ammoText.anchor.set(0, 0);
LK.gui.topLeft.addChild(ammoText);
ammoText.x = 120;
ammoText.y = 100;
var scoreText = new Text2('Kills: 0', {
size: 50,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
var waveText = new Text2('Wave: 1', {
size: 45,
fill: 0xFFFFFF
});
waveText.anchor.set(1, 0);
LK.gui.topRight.addChild(waveText);
waveText.x = -20;
waveText.y = 20;
// Initialize player
player = game.addChild(new Player());
player.x = 1024;
player.y = 1366;
// Give player starting weapon
var startWeapon = new Weapon('pistol');
startWeapon.x = player.x;
startWeapon.y = player.y - 50;
player.weapon = startWeapon;
game.addChild(startWeapon);
// Spawn initial enemies
function spawnWave() {
var enemiesToSpawn = Math.min(3 + waveNumber, 8);
for (var i = 0; i < enemiesToSpawn; i++) {
var enemy = new Enemy();
var angle = Math.random() * Math.PI * 2;
var distance = 400 + Math.random() * 400;
enemy.x = player.x + Math.cos(angle) * distance;
enemy.y = player.y + Math.sin(angle) * distance;
// Keep enemies within bounds
enemy.x = Math.max(100, Math.min(1948, enemy.x));
enemy.y = Math.max(100, Math.min(2632, enemy.y));
enemies.push(enemy);
game.addChild(enemy);
}
}
// Spawn initial items
function spawnItems() {
// Spawn weapons
for (var i = 0; i < 3; i++) {
var weaponTypes = ['pistol', 'rifle', 'shotgun'];
var weaponType = weaponTypes[Math.floor(Math.random() * weaponTypes.length)];
var weapon = new Item(weaponType);
weapon.x = Math.random() * 1800 + 124;
weapon.y = Math.random() * 2400 + 166;
items.push(weapon);
game.addChild(weapon);
}
// Spawn health packs
for (var i = 0; i < 4; i++) {
var health = new Item('healthPack');
health.x = Math.random() * 1800 + 124;
health.y = Math.random() * 2400 + 166;
items.push(health);
game.addChild(health);
}
// Spawn ammo boxes
for (var i = 0; i < 3; i++) {
var ammo = new Item('ammoBox');
ammo.x = Math.random() * 1800 + 124;
ammo.y = Math.random() * 2400 + 166;
items.push(ammo);
game.addChild(ammo);
}
}
spawnWave();
spawnItems();
// Event handlers
function handleMove(x, y, obj) {
if (dragNode) {
dragNode.x = x;
dragNode.y = y;
// Move weapon with player
if (player.weapon) {
player.weapon.x = player.x;
player.weapon.y = player.y;
}
}
}
game.move = handleMove;
game.down = function (x, y, obj) {
var distanceToPlayer = Math.sqrt((x - player.x) * (x - player.x) + (y - player.y) * (y - player.y));
if (distanceToPlayer < 100) {
dragNode = player;
handleMove(x, y, obj);
} else {
// Shoot towards tap location
shootTarget = {
x: x,
y: y
};
}
};
game.up = function (x, y, obj) {
if (shootTarget && player.weapon && player.weapon.fire()) {
var dx = shootTarget.x - player.x;
var dy = shootTarget.y - player.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var bullet = new Bullet(player.weapon.damage, 10, false);
bullet.x = player.x;
bullet.y = player.y;
bullet.direction.x = dx / distance;
bullet.direction.y = dy / distance;
playerBullets.push(bullet);
game.addChild(bullet);
// Auto reload if empty
if (player.weapon.ammo === 0) {
player.weapon.reload();
}
}
dragNode = null;
shootTarget = null;
};
// Main game loop
game.update = function () {
// Update player weapon
if (player.weapon) {
player.weapon.update();
}
// Update enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
enemy.update();
// Check if enemy is outside zone
var distanceFromCenter = Math.sqrt((enemy.x - zoneCenter.x) * (enemy.x - zoneCenter.x) + (enemy.y - zoneCenter.y) * (enemy.y - zoneCenter.y));
if (distanceFromCenter > zoneRadius) {
enemy.health -= 2;
LK.effects.flashObject(enemy, 0xff0000, 100);
}
}
// Update player bullets
for (var i = playerBullets.length - 1; i >= 0; i--) {
var bullet = playerBullets[i];
bullet.update();
// Check bounds
if (bullet.x < 0 || bullet.x > 2048 || bullet.y < 0 || bullet.y > 2732) {
bullet.destroy();
playerBullets.splice(i, 1);
continue;
}
// Check enemy collisions
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (bullet.intersects(enemy)) {
enemy.health -= bullet.damage;
LK.effects.flashObject(enemy, 0xff0000, 200);
LK.getSound('hit').play();
bullet.destroy();
playerBullets.splice(i, 1);
if (enemy.health <= 0) {
enemy.destroy();
enemies.splice(j, 1);
enemiesKilled++;
LK.setScore(enemiesKilled);
scoreText.setText('Kills: ' + enemiesKilled);
}
break;
}
}
}
// Update enemy bullets
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var bullet = enemyBullets[i];
bullet.update();
// Check bounds
if (bullet.x < 0 || bullet.x > 2048 || bullet.y < 0 || bullet.y > 2732) {
bullet.destroy();
enemyBullets.splice(i, 1);
continue;
}
// Check player collision
if (bullet.intersects(player)) {
player.health -= bullet.damage;
LK.effects.flashObject(player, 0xff0000, 300);
LK.getSound('hit').play();
bullet.destroy();
enemyBullets.splice(i, 1);
if (player.health <= 0) {
LK.showGameOver();
return;
}
}
}
// Check item pickups
for (var i = items.length - 1; i >= 0; i--) {
var item = items[i];
var distance = Math.sqrt((player.x - item.x) * (player.x - item.x) + (player.y - item.y) * (player.y - item.y));
if (distance < 60) {
if (item.type === 'healthPack') {
player.health = Math.min(player.maxHealth, player.health + 30);
LK.getSound('pickup').play();
} else if (item.type === 'ammoBox' && player.weapon) {
player.weapon.ammo = player.weapon.maxAmmo;
LK.getSound('pickup').play();
} else if (item.type === 'pistol' || item.type === 'rifle' || item.type === 'shotgun') {
if (player.weapon) {
player.weapon.destroy();
}
player.weapon = new Weapon(item.type);
player.weapon.x = player.x;
player.weapon.y = player.y;
game.addChild(player.weapon);
LK.getSound('pickup').play();
}
item.destroy();
items.splice(i, 1);
}
}
// Check zone damage for player
var playerDistanceFromCenter = Math.sqrt((player.x - zoneCenter.x) * (player.x - zoneCenter.x) + (player.y - zoneCenter.y) * (player.y - zoneCenter.y));
if (playerDistanceFromCenter > zoneRadius) {
player.health -= 1;
LK.effects.flashScreen(0xff0000, 100);
}
// Shrink zone
if (LK.ticks % 180 === 0) {
zoneRadius = Math.max(200, zoneRadius - zoneShrinkRate);
}
// Spawn new wave when all enemies are dead
if (enemies.length === 0) {
nextWaveTimer++;
if (nextWaveTimer >= 120) {
waveNumber++;
spawnWave();
spawnItems();
nextWaveTimer = 0;
waveText.setText('Wave: ' + waveNumber);
}
}
// Update UI
healthText.setText(Math.max(0, player.health) + '/' + player.maxHealth);
if (player.weapon) {
ammoText.setText(player.weapon.ammo + '/' + player.weapon.maxAmmo + (player.weapon.reloading ? ' (Reloading...)' : ''));
}
// Update health bar scale
var healthPercent = Math.max(0, player.health) / player.maxHealth;
healthBar.scaleX = 6 * healthPercent;
};