/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Bullet class
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletSprite = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
// Velocity components
self.vx = 0;
self.vy = -22;
// Set direction and speed
self.setDirection = function (dx, dy, speed) {
var len = Math.sqrt(dx * dx + dy * dy);
if (len === 0) {
self.vx = 0;
self.vy = -Math.abs(speed);
} else {
self.vx = dx / len * speed;
self.vy = dy / len * speed;
}
// Rotate bullet to face direction
self.rotation = Math.atan2(self.vy, self.vx) + Math.PI / 2;
};
// Default: straight up
self.setDirection(0, -1, 22);
self.update = function () {
self.x += self.vx;
self.y += self.vy;
};
return self;
});
// Powerup class
var Powerup = Container.expand(function () {
var self = Container.call(this);
var powerupSprite = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 7;
self.update = function () {
self.y += self.speed;
};
return self;
});
// Survivor class
var Survivor = Container.expand(function () {
var self = Container.call(this);
var survivorSprite = self.attachAsset('survivor', {
anchorX: 0.5,
anchorY: 0.5
});
// For powerup effect
self.isPowered = false;
self.powerTimer = 0;
// For future: add more survivor logic here
return self;
});
// Zombie class
var Zombie = Container.expand(function () {
var self = Container.call(this);
var zombieSprite = self.attachAsset('zombie', {
anchorX: 0.5,
anchorY: 0.5
});
// Movement speed (pixels per frame) -- REDUCED for slower zombies
self.speed = 1.2 + Math.random() * 0.7;
// Sway amplitude and frequency for zigzag (not used anymore, but kept for possible future use)
self.swayAmp = 60 + Math.random() * 80;
self.swayFreq = 0.005 + Math.random() * 0.003;
self.baseX = 0;
self.t = 0;
// For tracking last position for offscreen detection
self.lastY = undefined;
// For tracking intersection with bullets
self.lastIntersecting = false;
// For tracking intersection with survivor
self.lastTouchSurvivor = false;
// For powerup drop
self.hasDroppedPowerup = false;
// New: spawnType and movement toward play area
self.spawnType = "top"; // "top", "left", "right"
self.targetX = 2048 / 2;
self.targetY = 2732 - 400; // play area center-ish
self.initSpawn = function (type, x, y, targetX, targetY) {
self.spawnType = type;
self.x = x;
self.y = y;
self.targetX = targetX;
self.targetY = targetY;
self.baseX = x;
// Calculate direction vector for left/right spawn
if (type === "left" || type === "right") {
var dx = targetX - x;
var dy = targetY - y;
var len = Math.sqrt(dx * dx + dy * dy);
self.dirX = dx / len;
self.dirY = dy / len;
}
};
self.update = function () {
self.t += 1;
// Always move directly toward survivor
if (typeof survivor !== "undefined") {
var dx = survivor.x - self.x;
var dy = survivor.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 0) {
self.x += dx / dist * self.speed;
self.y += dy / dist * self.speed;
}
// Rotate zombie to face survivor
self.rotation = Math.atan2(dy, dx);
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x181818
});
/****
* Game Code
****/
// Music (not played in MVP as per instructions, but asset is here for future)
// Sound for zombie hit
// Sound for powerup
// Sound for shooting
// Powerup asset: a magenta ellipse
// Bullet asset: a yellow box
// Zombie asset: a green ellipse
// Survivor (player) asset: a blue box
// Survivor instance
var survivor = new Survivor();
game.addChild(survivor);
// Place survivor in the middle of the screen
survivor.x = 2048 / 2;
survivor.y = 2732 / 2;
// Arrays for game objects
var zombies = [];
var bullets = [];
var powerups = [];
// Score display
var scoreTxt = new Text2('0', {
size: 120,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Health bar variables and UI
var survivorMaxHealth = 5;
var survivorHealth = survivorMaxHealth;
var healthBarWidth = 400;
var healthBarHeight = 36;
var healthBarBg = LK.getAsset('healthbar_bg', {
width: healthBarWidth,
height: healthBarHeight,
color: 0x333333,
shape: 'box',
anchorX: 0.5,
anchorY: 0
});
var healthBarFg = LK.getAsset('healthbar_fg', {
width: healthBarWidth,
height: healthBarHeight,
color: 0x4de14d,
shape: 'box',
anchorX: 0.5,
anchorY: 0
});
healthBarBg.y = 120;
healthBarFg.y = 120;
healthBarBg.x = 2048 / 2;
healthBarFg.x = 2048 / 2;
LK.gui.top.addChild(healthBarBg);
LK.gui.top.addChild(healthBarFg);
// Powerup timer display
var powerupTxt = new Text2('', {
size: 70,
fill: 0xFF3FD6
});
powerupTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(powerupTxt);
powerupTxt.y = 170;
// Game state
var dragNode = null;
var canShoot = true;
var shootCooldown = 0;
var shootInterval = 12; // frames between shots
var zombieSpawnTimer = 0;
var zombieSpawnInterval = 60; // frames between spawns, will decrease
var zombieSpeedIncrease = 0;
var powerupActive = false;
var powerupTimer = 0;
var powerupDuration = 360; // frames (6 seconds)
var lastGameOver = false;
// Helper: spawn a zombie
function spawnZombie() {
var z = new Zombie();
// Randomly choose spawn edge: 0=top, 1=left, 2=right
var edge = Math.floor(Math.random() * 3);
var margin = 120;
var spawnType, zx, zy, tx, ty;
tx = 2048 / 2;
ty = 2732 - 400;
if (edge === 0) {
// Top
spawnType = "top";
zx = margin + Math.random() * (2048 - 2 * margin);
zy = -100;
} else if (edge === 1) {
// Left
spawnType = "left";
zx = -100;
zy = 300 + Math.random() * (2732 - 800);
} else {
// Right
spawnType = "right";
zx = 2048 + 100;
zy = 300 + Math.random() * (2732 - 800);
}
z.initSpawn(spawnType, zx, zy, tx, ty);
// Increase speed as game progresses
z.speed += zombieSpeedIncrease;
zombies.push(z);
game.addChild(z);
}
// Helper: spawn a powerup at (x, y)
function spawnPowerup(x, y) {
var p = new Powerup();
p.x = x;
p.y = y;
powerups.push(p);
game.addChild(p);
}
// Helper: shoot a bullet
function shootBullet(targetX, targetY) {
if (!canShoot) return;
canShoot = false;
shootCooldown = 0;
var b = new Bullet();
b.x = survivor.x;
b.y = survivor.y - 80;
// If no target provided, shoot straight up
if (typeof targetX === "number" && typeof targetY === "number") {
var dx = targetX - survivor.x;
var dy = targetY - (survivor.y - 80);
b.setDirection(dx, dy, 22);
} else {
b.setDirection(0, -1, 22);
}
bullets.push(b);
game.addChild(b);
LK.getSound('shoot').play();
}
// Dragging logic
// (player movement removed)
function handleMove(x, y, obj) {
// Always rotate survivor to face the pointer (x, y)
var dx = x - survivor.x;
var dy = y - survivor.y;
// If pointer is on the left half and in the vertical middle, rotate survivor 180 degrees
if (x < 2048 / 2 && y > 2732 / 4 && y < 2732 * 3 / 4) {
survivor.rotation = Math.atan2(dy, dx) + Math.PI;
} else {
survivor.rotation = Math.atan2(dy, dx);
}
}
game.move = handleMove;
// Tap to shoot logic
game.tap = function (x, y, obj) {
// Allow tap to shoot anywhere, even if dragging
shootBullet(x, y);
};
// For touch devices, simulate tap on quick down/up
var lastDownTime = 0;
game.down = function (x, y, obj) {
lastDownTime = Date.now();
};
game.up = function (x, y, obj) {
// If quick tap, treat as tap to shoot
if (Date.now() - lastDownTime < 250) {
shootBullet(x, y);
}
};
// Main update loop
game.update = function () {
// Handle survivor powerup timer
if (powerupActive) {
powerupTimer--;
if (powerupTimer <= 0) {
powerupActive = false;
survivor.isPowered = false;
powerupTxt.setText('');
// Visual: scale back to normal
tween(survivor, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.easeOut
});
} else {
powerupTxt.setText('POWER! ' + Math.ceil(powerupTimer / 60));
}
}
// Shooting cooldown
if (!canShoot) {
shootCooldown++;
if (shootCooldown >= (powerupActive ? 4 : shootInterval)) {
canShoot = true;
}
}
// Spawn zombies
zombieSpawnTimer++;
if (zombieSpawnTimer >= zombieSpawnInterval) {
spawnZombie();
zombieSpawnTimer = 0;
// Increase difficulty over time
if (zombieSpawnInterval > 24) zombieSpawnInterval -= 1;
zombieSpeedIncrease += 0.01;
}
// Update bullets
for (var i = bullets.length - 1; i >= 0; i--) {
var b = bullets[i];
b.update();
// Remove if offscreen
if (b.y < -100) {
b.destroy();
bullets.splice(i, 1);
continue;
}
// Check collision with zombies
for (var j = zombies.length - 1; j >= 0; j--) {
var z = zombies[j];
if (b.intersects(z)) {
// Hit!
LK.getSound('zombiehit').play();
// Score
LK.setScore(LK.getScore() + 1);
scoreTxt.setText(LK.getScore());
// Powerup drop chance
if (!z.hasDroppedPowerup && Math.random() < 0.08) {
spawnPowerup(z.x, z.y);
z.hasDroppedPowerup = true;
}
// Visual: flash zombie
LK.effects.flashObject(z, 0xffffff, 200);
// Remove both
z.destroy();
zombies.splice(j, 1);
b.destroy();
bullets.splice(i, 1);
break;
}
}
}
// Update zombies
for (var i = zombies.length - 1; i >= 0; i--) {
var z = zombies[i];
z.update();
// Remove if offscreen (bottom)
if (z.y > 2732 + 100) {
z.destroy();
zombies.splice(i, 1);
continue;
}
// Check collision with survivor
if (z.intersects(survivor)) {
// Only damage once per collision
if (!z.lastTouchSurvivor) {
survivorHealth--;
// Animate health bar
var healthFrac = Math.max(0, survivorHealth) / survivorMaxHealth;
healthBarFg.width = healthBarWidth * healthFrac;
LK.effects.flashObject(survivor, 0xff0000, 200);
if (survivorHealth <= 0 && !lastGameOver) {
LK.effects.flashScreen(0xff0000, 1000);
lastGameOver = true;
LK.showGameOver();
return;
}
}
z.lastTouchSurvivor = true;
} else {
z.lastTouchSurvivor = false;
}
}
// Update powerups
for (var i = powerups.length - 1; i >= 0; i--) {
var p = powerups[i];
p.update();
// Remove if offscreen
if (p.y > 2732 + 100) {
p.destroy();
powerups.splice(i, 1);
continue;
}
// Check collision with survivor
if (p.intersects(survivor)) {
LK.getSound('powerup').play();
// Activate powerup: rapid fire
powerupActive = true;
powerupTimer = powerupDuration;
survivor.isPowered = true;
// Visual: scale up
tween(survivor, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 200,
easing: tween.easeOut
});
powerupTxt.setText('POWER! ' + Math.ceil(powerupTimer / 60));
p.destroy();
powerups.splice(i, 1);
continue;
}
}
};
// Reset game state on restart
LK.on('gameStart', function () {
// Remove all zombies, bullets, powerups
for (var i = 0; i < zombies.length; i++) zombies[i].destroy();
for (var i = 0; i < bullets.length; i++) bullets[i].destroy();
for (var i = 0; i < powerups.length; i++) powerups[i].destroy();
zombies = [];
bullets = [];
powerups = [];
// Reset survivor
survivor.x = 2048 / 2;
survivor.y = 2732 / 2;
survivor.isPowered = false;
survivor.scaleX = 1;
survivor.scaleY = 1;
survivorHealth = survivorMaxHealth;
healthBarFg.width = healthBarWidth;
// Reset timers and state
canShoot = true;
shootCooldown = 0;
zombieSpawnTimer = 0;
zombieSpawnInterval = 60;
zombieSpeedIncrease = 0;
powerupActive = false;
powerupTimer = 0;
powerupTxt.setText('');
lastGameOver = false;
LK.setScore(0);
scoreTxt.setText('0');
}); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Bullet class
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletSprite = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
// Velocity components
self.vx = 0;
self.vy = -22;
// Set direction and speed
self.setDirection = function (dx, dy, speed) {
var len = Math.sqrt(dx * dx + dy * dy);
if (len === 0) {
self.vx = 0;
self.vy = -Math.abs(speed);
} else {
self.vx = dx / len * speed;
self.vy = dy / len * speed;
}
// Rotate bullet to face direction
self.rotation = Math.atan2(self.vy, self.vx) + Math.PI / 2;
};
// Default: straight up
self.setDirection(0, -1, 22);
self.update = function () {
self.x += self.vx;
self.y += self.vy;
};
return self;
});
// Powerup class
var Powerup = Container.expand(function () {
var self = Container.call(this);
var powerupSprite = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 7;
self.update = function () {
self.y += self.speed;
};
return self;
});
// Survivor class
var Survivor = Container.expand(function () {
var self = Container.call(this);
var survivorSprite = self.attachAsset('survivor', {
anchorX: 0.5,
anchorY: 0.5
});
// For powerup effect
self.isPowered = false;
self.powerTimer = 0;
// For future: add more survivor logic here
return self;
});
// Zombie class
var Zombie = Container.expand(function () {
var self = Container.call(this);
var zombieSprite = self.attachAsset('zombie', {
anchorX: 0.5,
anchorY: 0.5
});
// Movement speed (pixels per frame) -- REDUCED for slower zombies
self.speed = 1.2 + Math.random() * 0.7;
// Sway amplitude and frequency for zigzag (not used anymore, but kept for possible future use)
self.swayAmp = 60 + Math.random() * 80;
self.swayFreq = 0.005 + Math.random() * 0.003;
self.baseX = 0;
self.t = 0;
// For tracking last position for offscreen detection
self.lastY = undefined;
// For tracking intersection with bullets
self.lastIntersecting = false;
// For tracking intersection with survivor
self.lastTouchSurvivor = false;
// For powerup drop
self.hasDroppedPowerup = false;
// New: spawnType and movement toward play area
self.spawnType = "top"; // "top", "left", "right"
self.targetX = 2048 / 2;
self.targetY = 2732 - 400; // play area center-ish
self.initSpawn = function (type, x, y, targetX, targetY) {
self.spawnType = type;
self.x = x;
self.y = y;
self.targetX = targetX;
self.targetY = targetY;
self.baseX = x;
// Calculate direction vector for left/right spawn
if (type === "left" || type === "right") {
var dx = targetX - x;
var dy = targetY - y;
var len = Math.sqrt(dx * dx + dy * dy);
self.dirX = dx / len;
self.dirY = dy / len;
}
};
self.update = function () {
self.t += 1;
// Always move directly toward survivor
if (typeof survivor !== "undefined") {
var dx = survivor.x - self.x;
var dy = survivor.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 0) {
self.x += dx / dist * self.speed;
self.y += dy / dist * self.speed;
}
// Rotate zombie to face survivor
self.rotation = Math.atan2(dy, dx);
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x181818
});
/****
* Game Code
****/
// Music (not played in MVP as per instructions, but asset is here for future)
// Sound for zombie hit
// Sound for powerup
// Sound for shooting
// Powerup asset: a magenta ellipse
// Bullet asset: a yellow box
// Zombie asset: a green ellipse
// Survivor (player) asset: a blue box
// Survivor instance
var survivor = new Survivor();
game.addChild(survivor);
// Place survivor in the middle of the screen
survivor.x = 2048 / 2;
survivor.y = 2732 / 2;
// Arrays for game objects
var zombies = [];
var bullets = [];
var powerups = [];
// Score display
var scoreTxt = new Text2('0', {
size: 120,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Health bar variables and UI
var survivorMaxHealth = 5;
var survivorHealth = survivorMaxHealth;
var healthBarWidth = 400;
var healthBarHeight = 36;
var healthBarBg = LK.getAsset('healthbar_bg', {
width: healthBarWidth,
height: healthBarHeight,
color: 0x333333,
shape: 'box',
anchorX: 0.5,
anchorY: 0
});
var healthBarFg = LK.getAsset('healthbar_fg', {
width: healthBarWidth,
height: healthBarHeight,
color: 0x4de14d,
shape: 'box',
anchorX: 0.5,
anchorY: 0
});
healthBarBg.y = 120;
healthBarFg.y = 120;
healthBarBg.x = 2048 / 2;
healthBarFg.x = 2048 / 2;
LK.gui.top.addChild(healthBarBg);
LK.gui.top.addChild(healthBarFg);
// Powerup timer display
var powerupTxt = new Text2('', {
size: 70,
fill: 0xFF3FD6
});
powerupTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(powerupTxt);
powerupTxt.y = 170;
// Game state
var dragNode = null;
var canShoot = true;
var shootCooldown = 0;
var shootInterval = 12; // frames between shots
var zombieSpawnTimer = 0;
var zombieSpawnInterval = 60; // frames between spawns, will decrease
var zombieSpeedIncrease = 0;
var powerupActive = false;
var powerupTimer = 0;
var powerupDuration = 360; // frames (6 seconds)
var lastGameOver = false;
// Helper: spawn a zombie
function spawnZombie() {
var z = new Zombie();
// Randomly choose spawn edge: 0=top, 1=left, 2=right
var edge = Math.floor(Math.random() * 3);
var margin = 120;
var spawnType, zx, zy, tx, ty;
tx = 2048 / 2;
ty = 2732 - 400;
if (edge === 0) {
// Top
spawnType = "top";
zx = margin + Math.random() * (2048 - 2 * margin);
zy = -100;
} else if (edge === 1) {
// Left
spawnType = "left";
zx = -100;
zy = 300 + Math.random() * (2732 - 800);
} else {
// Right
spawnType = "right";
zx = 2048 + 100;
zy = 300 + Math.random() * (2732 - 800);
}
z.initSpawn(spawnType, zx, zy, tx, ty);
// Increase speed as game progresses
z.speed += zombieSpeedIncrease;
zombies.push(z);
game.addChild(z);
}
// Helper: spawn a powerup at (x, y)
function spawnPowerup(x, y) {
var p = new Powerup();
p.x = x;
p.y = y;
powerups.push(p);
game.addChild(p);
}
// Helper: shoot a bullet
function shootBullet(targetX, targetY) {
if (!canShoot) return;
canShoot = false;
shootCooldown = 0;
var b = new Bullet();
b.x = survivor.x;
b.y = survivor.y - 80;
// If no target provided, shoot straight up
if (typeof targetX === "number" && typeof targetY === "number") {
var dx = targetX - survivor.x;
var dy = targetY - (survivor.y - 80);
b.setDirection(dx, dy, 22);
} else {
b.setDirection(0, -1, 22);
}
bullets.push(b);
game.addChild(b);
LK.getSound('shoot').play();
}
// Dragging logic
// (player movement removed)
function handleMove(x, y, obj) {
// Always rotate survivor to face the pointer (x, y)
var dx = x - survivor.x;
var dy = y - survivor.y;
// If pointer is on the left half and in the vertical middle, rotate survivor 180 degrees
if (x < 2048 / 2 && y > 2732 / 4 && y < 2732 * 3 / 4) {
survivor.rotation = Math.atan2(dy, dx) + Math.PI;
} else {
survivor.rotation = Math.atan2(dy, dx);
}
}
game.move = handleMove;
// Tap to shoot logic
game.tap = function (x, y, obj) {
// Allow tap to shoot anywhere, even if dragging
shootBullet(x, y);
};
// For touch devices, simulate tap on quick down/up
var lastDownTime = 0;
game.down = function (x, y, obj) {
lastDownTime = Date.now();
};
game.up = function (x, y, obj) {
// If quick tap, treat as tap to shoot
if (Date.now() - lastDownTime < 250) {
shootBullet(x, y);
}
};
// Main update loop
game.update = function () {
// Handle survivor powerup timer
if (powerupActive) {
powerupTimer--;
if (powerupTimer <= 0) {
powerupActive = false;
survivor.isPowered = false;
powerupTxt.setText('');
// Visual: scale back to normal
tween(survivor, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.easeOut
});
} else {
powerupTxt.setText('POWER! ' + Math.ceil(powerupTimer / 60));
}
}
// Shooting cooldown
if (!canShoot) {
shootCooldown++;
if (shootCooldown >= (powerupActive ? 4 : shootInterval)) {
canShoot = true;
}
}
// Spawn zombies
zombieSpawnTimer++;
if (zombieSpawnTimer >= zombieSpawnInterval) {
spawnZombie();
zombieSpawnTimer = 0;
// Increase difficulty over time
if (zombieSpawnInterval > 24) zombieSpawnInterval -= 1;
zombieSpeedIncrease += 0.01;
}
// Update bullets
for (var i = bullets.length - 1; i >= 0; i--) {
var b = bullets[i];
b.update();
// Remove if offscreen
if (b.y < -100) {
b.destroy();
bullets.splice(i, 1);
continue;
}
// Check collision with zombies
for (var j = zombies.length - 1; j >= 0; j--) {
var z = zombies[j];
if (b.intersects(z)) {
// Hit!
LK.getSound('zombiehit').play();
// Score
LK.setScore(LK.getScore() + 1);
scoreTxt.setText(LK.getScore());
// Powerup drop chance
if (!z.hasDroppedPowerup && Math.random() < 0.08) {
spawnPowerup(z.x, z.y);
z.hasDroppedPowerup = true;
}
// Visual: flash zombie
LK.effects.flashObject(z, 0xffffff, 200);
// Remove both
z.destroy();
zombies.splice(j, 1);
b.destroy();
bullets.splice(i, 1);
break;
}
}
}
// Update zombies
for (var i = zombies.length - 1; i >= 0; i--) {
var z = zombies[i];
z.update();
// Remove if offscreen (bottom)
if (z.y > 2732 + 100) {
z.destroy();
zombies.splice(i, 1);
continue;
}
// Check collision with survivor
if (z.intersects(survivor)) {
// Only damage once per collision
if (!z.lastTouchSurvivor) {
survivorHealth--;
// Animate health bar
var healthFrac = Math.max(0, survivorHealth) / survivorMaxHealth;
healthBarFg.width = healthBarWidth * healthFrac;
LK.effects.flashObject(survivor, 0xff0000, 200);
if (survivorHealth <= 0 && !lastGameOver) {
LK.effects.flashScreen(0xff0000, 1000);
lastGameOver = true;
LK.showGameOver();
return;
}
}
z.lastTouchSurvivor = true;
} else {
z.lastTouchSurvivor = false;
}
}
// Update powerups
for (var i = powerups.length - 1; i >= 0; i--) {
var p = powerups[i];
p.update();
// Remove if offscreen
if (p.y > 2732 + 100) {
p.destroy();
powerups.splice(i, 1);
continue;
}
// Check collision with survivor
if (p.intersects(survivor)) {
LK.getSound('powerup').play();
// Activate powerup: rapid fire
powerupActive = true;
powerupTimer = powerupDuration;
survivor.isPowered = true;
// Visual: scale up
tween(survivor, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 200,
easing: tween.easeOut
});
powerupTxt.setText('POWER! ' + Math.ceil(powerupTimer / 60));
p.destroy();
powerups.splice(i, 1);
continue;
}
}
};
// Reset game state on restart
LK.on('gameStart', function () {
// Remove all zombies, bullets, powerups
for (var i = 0; i < zombies.length; i++) zombies[i].destroy();
for (var i = 0; i < bullets.length; i++) bullets[i].destroy();
for (var i = 0; i < powerups.length; i++) powerups[i].destroy();
zombies = [];
bullets = [];
powerups = [];
// Reset survivor
survivor.x = 2048 / 2;
survivor.y = 2732 / 2;
survivor.isPowered = false;
survivor.scaleX = 1;
survivor.scaleY = 1;
survivorHealth = survivorMaxHealth;
healthBarFg.width = healthBarWidth;
// Reset timers and state
canShoot = true;
shootCooldown = 0;
zombieSpawnTimer = 0;
zombieSpawnInterval = 60;
zombieSpeedIncrease = 0;
powerupActive = false;
powerupTimer = 0;
powerupTxt.setText('');
lastGameOver = false;
LK.setScore(0);
scoreTxt.setText('0');
});