/****
* 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
});
self.radius = bulletSprite.width / 2;
self.vx = 0;
self.vy = 0;
self.speed = 38;
self.update = function () {
self.x += self.vx * self.speed;
self.y += self.vy * self.speed;
};
return self;
});
// EnemyBullet class
var EnemyBullet = Container.expand(function () {
var self = Container.call(this);
var bulletSprite = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = bulletSprite.width / 2;
self.vx = 0;
self.vy = 0;
self.speed = 8; // Slower enemy bullet speed
self.update = function () {
self.x += self.vx * self.speed;
self.y += self.vy * self.speed;
};
return self;
});
// Helper to spawn an enemy bullet
var GunZombie = Container.expand(function () {
var self = Container.call(this);
self.zombieSprite = self.attachAsset('gunzombie', {
// Use new gunzombie sprite
anchorX: 0.5,
anchorY: 0.5
});
self.radius = self.zombieSprite.width / 2;
self.speed = 1.2 + Math.random() * 0.7;
self.vx = 0;
self.vy = 0;
self.target = null;
self.hp = 2; // Give GunZombie 2 HP
self.fireCooldown = 120 + Math.floor(Math.random() * 60); // Slower: 2x slower than before
self.fireTimer = Math.floor(Math.random() * 60); // randomize first shot
self.update = function () {
// Move like a normal zombie
if (!self.target) return;
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 0) {
self.vx = dx / dist * self.speed;
self.vy = dy / dist * self.speed;
self.x += self.vx;
self.y += self.vy;
// Rotate zombie sprite to face movement direction
if (typeof self.zombieSprite !== "undefined") {
self.zombieSprite.rotation = Math.atan2(self.vy, self.vx);
} else if (self.children && self.children.length > 0 && typeof self.children[0].rotation !== "undefined") {
self.children[0].rotation = Math.atan2(self.vy, self.vx);
}
}
// Shooting logic
self.fireTimer++;
if (self.fireTimer >= self.fireCooldown) {
self.fireTimer = 0;
// Only shoot if player is within 1200px
if (dist < 1200) {
spawnEnemyBullet(self.x, self.y, dx, dy);
}
}
};
return self;
});
// Heart class for health powerup
var Heart = Container.expand(function () {
var self = Container.call(this);
var heartSprite = self.attachAsset('heart', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = heartSprite.width / 2;
self.update = function () {
// Could animate or float, but static for now
};
return self;
});
// Player class
var Player = Container.expand(function () {
var self = Container.call(this);
var playerSprite = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = playerSprite.width / 2;
self.speed = 16; // Max speed per frame
self.vx = 0;
self.vy = 0;
self.hp = 5;
self.invincible = false;
// For hit flash
self.flash = function () {
if (self.invincible) return;
self.invincible = true;
tween(playerSprite, {
tint: 0xff4444
}, {
duration: 100,
onFinish: function onFinish() {
tween(playerSprite, {
tint: 0x3498db
}, {
duration: 200,
onFinish: function onFinish() {
self.invincible = false;
}
});
}
});
};
// Ensure playerSprite follows self.rotation
self.update = function () {
playerSprite.rotation = self.rotation || 0;
};
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
});
self.radius = zombieSprite.width / 2;
self.speed = 1.2 + Math.random() * 0.7; // Slower zombies
self.vx = 0;
self.vy = 0;
self.target = null; // Player
self.update = function () {
if (!self.target) return;
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 0) {
self.vx = dx / dist * self.speed;
self.vy = dy / dist * self.speed;
self.x += self.vx;
self.y += self.vy;
// Rotate zombie sprite to face movement direction
zombieSprite.rotation = Math.atan2(self.vy, self.vx);
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x222222
});
/****
* Game Code
****/
// Helper to spawn an enemy bullet
// Joystick knob
// Joystick base
// Bullet
// Zombie
// Character (player)
// Game variables
function spawnEnemyBullet(x, y, dx, dy) {
var len = Math.sqrt(dx * dx + dy * dy);
if (len < 0.1) return;
var b = new EnemyBullet();
b.x = x;
b.y = y;
b.vx = dx / len;
b.vy = dy / len;
b.rotation = Math.atan2(dy, dx);
enemyBullets.push(b);
game.addChild(b);
}
var player;
var zombies = [];
var bullets = [];
var enemyBullets = []; // NEW: enemy bullets array
var score = 0;
var scoreTxt;
var hpTxt;
var spawnTimer = 0;
var spawnInterval = 90; // Frames between zombie spawns
var lastFireTick = 0;
var fireCooldown = 12; // Frames between shots
// Create player
player = new Player();
player.x = 2048 / 2;
player.y = 2732 * 0.7;
game.addChild(player);
// Set initial target move position to player start
game._targetMovePos = {
x: player.x,
y: player.y
};
// Score text
scoreTxt = new Text2('0', {
size: 110,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// HP text
hpTxt = new Text2('❤❤❤', {
size: 90,
fill: 0xFF4444
});
hpTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(hpTxt);
// Helper: update HP display
function updateHpTxt() {
var s = '';
for (var i = 0; i < player.hp; ++i) s += '❤';
hpTxt.setText(s);
}
// Helper: update score display
function updateScoreTxt() {
scoreTxt.setText(score);
}
// Helper: spawn a zombie at a random edge
function spawnZombie() {
// Only spawn GunZombie (with 2 HP) or normal Zombie
var z;
if (score > 0 && score % 5 === 0) {
z = new GunZombie();
} else if (Math.random() < 0.15) {
z = new GunZombie();
} else {
z = new Zombie();
}
// Pick a random edge: 0=top, 1=bottom, 2=left, 3=right
var edge = Math.floor(Math.random() * 4);
var margin = 80;
if (edge === 0) {
// Top
z.x = margin + Math.random() * (2048 - 2 * margin);
z.y = -z.radius - 10;
} else if (edge === 1) {
// Bottom
z.x = margin + Math.random() * (2048 - 2 * margin);
z.y = 2732 + z.radius + 10;
} else if (edge === 2) {
// Left
z.x = -z.radius - 10;
z.y = margin + Math.random() * (2732 - 2 * margin);
} else {
// Right
z.x = 2048 + z.radius + 10;
z.y = margin + Math.random() * (2732 - 2 * margin);
}
z.target = player;
zombies.push(z);
game.addChild(z);
}
// Helper: fire a bullet towards a direction
function fireBullet(dirX, dirY) {
var len = Math.sqrt(dirX * dirX + dirY * dirY);
if (len < 0.1) return;
var b = new Bullet();
b.x = player.x;
b.y = player.y;
b.vx = dirX / len;
b.vy = dirY / len;
b.rotation = Math.atan2(dirY, dirX);
bullets.push(b);
game.addChild(b);
// Rotate player to face the direction of the fired bullet
player.rotation = Math.atan2(dirY, dirX);
}
// Game event handling
game.down = function (x, y, obj) {
var now = LK.ticks;
if (now - lastFireTick >= fireCooldown) {
fireBullet(x - player.x, y - player.y);
lastFireTick = now;
}
// Always rotate player to face the direction of the click/touch
var dx = x - player.x;
var dy = y - player.y;
if (Math.abs(dx) > 0.01 || Math.abs(dy) > 0.01) {
player.rotation = Math.atan2(dy, dx);
}
};
game.move = function (x, y, obj) {
// Always update target move position to follow pointer
if (typeof game._targetMovePos === "undefined") {
game._targetMovePos = {
x: player.x,
y: player.y
};
}
game._targetMovePos.x = x;
game._targetMovePos.y = y;
};
game.up = function (x, y, obj) {
// No joystick logic needed
};
// Main game update
game.update = function () {
// Player movement follows last pointer position
if (typeof game._targetMovePos === "undefined") {
game._targetMovePos = {
x: player.x,
y: player.y
};
}
var tx = game._targetMovePos.x;
var ty = game._targetMovePos.y;
var dx = tx - player.x;
var dy = ty - player.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 2) {
var moveDist = Math.min(player.speed, dist);
player.x += dx / dist * moveDist;
player.y += dy / dist * moveDist;
// Clamp to arena
var r = player.radius + 10;
if (player.x < r) player.x = r;
if (player.x > 2048 - r) player.x = 2048 - r;
if (player.y < r) player.y = r;
if (player.y > 2732 - r) player.y = 2732 - r;
}
// Always rotate player to face pointer direction
if (dist > 2) {
player.rotation = Math.atan2(dy, dx);
}
// Spawn zombies
spawnTimer++;
if (spawnTimer >= spawnInterval) {
spawnZombie();
spawnTimer = 0;
// Gradually increase spawn rate
if (spawnInterval > 30) spawnInterval -= 1;
}
// Update zombies
for (var i = zombies.length - 1; i >= 0; --i) {
var z = zombies[i];
z.update();
// Remove if off screen (failsafe)
if (z.x < -200 || z.x > 2248 || z.y < -200 || z.y > 2932) {
z.destroy();
zombies.splice(i, 1);
}
}
// Update bullets
for (var i = bullets.length - 1; i >= 0; --i) {
var b = bullets[i];
b.update();
// Remove if off screen
if (b.x < -100 || b.x > 2148 || b.y < -100 || b.y > 2832) {
b.destroy();
bullets.splice(i, 1);
continue;
}
}
// Update enemy bullets
for (var i = enemyBullets.length - 1; i >= 0; --i) {
var eb = enemyBullets[i];
eb.update();
// Remove if off screen
if (eb.x < -100 || eb.x > 2148 || eb.y < -100 || eb.y > 2832) {
eb.destroy();
enemyBullets.splice(i, 1);
continue;
}
// Check collision with player
var dx = eb.x - player.x;
var dy = eb.y - player.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < eb.radius + player.radius - 10) {
if (!player.invincible) {
player.hp -= 1;
updateHpTxt();
player.flash();
if (player.hp <= 0) {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
} else if (player.hp === 1 && typeof heartSpawned === "undefined") {
// Spawn hearts at random locations when HP drops to 1
heartSpawned = true;
if (typeof hearts === "undefined") hearts = [];
for (var h = 0; h < 3; ++h) {
var heart = new Heart();
// Avoid spawning too close to player or outside arena
var safe = false;
var hx, hy;
while (!safe) {
hx = 150 + Math.random() * (2048 - 300);
hy = 150 + Math.random() * (2732 - 300);
var pdx = hx - player.x;
var pdy = hy - player.y;
if (Math.sqrt(pdx * pdx + pdy * pdy) > 400) safe = true;
}
heart.x = hx;
heart.y = hy;
hearts.push(heart);
game.addChild(heart);
}
}
}
eb.destroy();
enemyBullets.splice(i, 1);
continue;
}
}
// Bullet-zombie collisions
for (var i = bullets.length - 1; i >= 0; --i) {
var b = bullets[i];
for (var j = zombies.length - 1; j >= 0; --j) {
var z = zombies[j];
var dx = b.x - z.x;
var dy = b.y - z.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < b.radius + z.radius - 10) {
// Hit!
var isGunZombie = typeof z.hp === "number" && z.hp > 0;
if (isGunZombie) {
z.hp -= 1;
b.destroy();
bullets.splice(i, 1);
if (z.hp <= 0) {
z.destroy();
zombies.splice(j, 1);
score += 1;
updateScoreTxt();
}
} else {
z.destroy();
zombies.splice(j, 1);
b.destroy();
bullets.splice(i, 1);
score += 1;
updateScoreTxt();
}
break;
}
}
}
// Zombie-player collisions
for (var i = zombies.length - 1; i >= 0; --i) {
var z = zombies[i];
var dx = z.x - player.x;
var dy = z.y - player.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < z.radius + player.radius - 10) {
if (!player.invincible) {
player.hp -= 1;
updateHpTxt();
player.flash();
if (player.hp <= 0) {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
}
// Push zombie away
var pushDist = z.radius + player.radius - dist + 10;
if (pushDist > 0) {
var px = dx / dist * pushDist;
var py = dy / dist * pushDist;
z.x += px;
z.y += py;
}
}
}
// Heart pickup logic
if (typeof hearts !== "undefined" && hearts.length > 0) {
for (var i = hearts.length - 1; i >= 0; --i) {
var heart = hearts[i];
var dx = heart.x - player.x;
var dy = heart.y - player.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < heart.radius + player.radius - 10) {
// Picked up heart: restore HP to full
player.hp = 5;
updateHpTxt();
// Remove all hearts
for (var j = hearts.length - 1; j >= 0; --j) {
hearts[j].destroy();
}
hearts = [];
heartSpawned = undefined;
break;
}
}
}
};
// Initial UI update
updateScoreTxt();
updateHpTxt();
// Timer to spawn a heart at the center area every 5 seconds
if (typeof centerHeartTimer === "undefined") {
centerHeartTimer = LK.setInterval(function () {
if (typeof hearts === "undefined") hearts = [];
// Spawn a heart at a random position near the center (±200px)
var heart = new Heart();
var centerX = 2048 / 2;
var centerY = 2732 / 2;
var hx = centerX - 200 + Math.random() * 400;
var hy = centerY - 200 + Math.random() * 400;
heart.x = hx;
heart.y = hy;
hearts.push(heart);
game.addChild(heart);
}, 5000);
} /****
* 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
});
self.radius = bulletSprite.width / 2;
self.vx = 0;
self.vy = 0;
self.speed = 38;
self.update = function () {
self.x += self.vx * self.speed;
self.y += self.vy * self.speed;
};
return self;
});
// EnemyBullet class
var EnemyBullet = Container.expand(function () {
var self = Container.call(this);
var bulletSprite = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = bulletSprite.width / 2;
self.vx = 0;
self.vy = 0;
self.speed = 8; // Slower enemy bullet speed
self.update = function () {
self.x += self.vx * self.speed;
self.y += self.vy * self.speed;
};
return self;
});
// Helper to spawn an enemy bullet
var GunZombie = Container.expand(function () {
var self = Container.call(this);
self.zombieSprite = self.attachAsset('gunzombie', {
// Use new gunzombie sprite
anchorX: 0.5,
anchorY: 0.5
});
self.radius = self.zombieSprite.width / 2;
self.speed = 1.2 + Math.random() * 0.7;
self.vx = 0;
self.vy = 0;
self.target = null;
self.hp = 2; // Give GunZombie 2 HP
self.fireCooldown = 120 + Math.floor(Math.random() * 60); // Slower: 2x slower than before
self.fireTimer = Math.floor(Math.random() * 60); // randomize first shot
self.update = function () {
// Move like a normal zombie
if (!self.target) return;
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 0) {
self.vx = dx / dist * self.speed;
self.vy = dy / dist * self.speed;
self.x += self.vx;
self.y += self.vy;
// Rotate zombie sprite to face movement direction
if (typeof self.zombieSprite !== "undefined") {
self.zombieSprite.rotation = Math.atan2(self.vy, self.vx);
} else if (self.children && self.children.length > 0 && typeof self.children[0].rotation !== "undefined") {
self.children[0].rotation = Math.atan2(self.vy, self.vx);
}
}
// Shooting logic
self.fireTimer++;
if (self.fireTimer >= self.fireCooldown) {
self.fireTimer = 0;
// Only shoot if player is within 1200px
if (dist < 1200) {
spawnEnemyBullet(self.x, self.y, dx, dy);
}
}
};
return self;
});
// Heart class for health powerup
var Heart = Container.expand(function () {
var self = Container.call(this);
var heartSprite = self.attachAsset('heart', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = heartSprite.width / 2;
self.update = function () {
// Could animate or float, but static for now
};
return self;
});
// Player class
var Player = Container.expand(function () {
var self = Container.call(this);
var playerSprite = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = playerSprite.width / 2;
self.speed = 16; // Max speed per frame
self.vx = 0;
self.vy = 0;
self.hp = 5;
self.invincible = false;
// For hit flash
self.flash = function () {
if (self.invincible) return;
self.invincible = true;
tween(playerSprite, {
tint: 0xff4444
}, {
duration: 100,
onFinish: function onFinish() {
tween(playerSprite, {
tint: 0x3498db
}, {
duration: 200,
onFinish: function onFinish() {
self.invincible = false;
}
});
}
});
};
// Ensure playerSprite follows self.rotation
self.update = function () {
playerSprite.rotation = self.rotation || 0;
};
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
});
self.radius = zombieSprite.width / 2;
self.speed = 1.2 + Math.random() * 0.7; // Slower zombies
self.vx = 0;
self.vy = 0;
self.target = null; // Player
self.update = function () {
if (!self.target) return;
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 0) {
self.vx = dx / dist * self.speed;
self.vy = dy / dist * self.speed;
self.x += self.vx;
self.y += self.vy;
// Rotate zombie sprite to face movement direction
zombieSprite.rotation = Math.atan2(self.vy, self.vx);
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x222222
});
/****
* Game Code
****/
// Helper to spawn an enemy bullet
// Joystick knob
// Joystick base
// Bullet
// Zombie
// Character (player)
// Game variables
function spawnEnemyBullet(x, y, dx, dy) {
var len = Math.sqrt(dx * dx + dy * dy);
if (len < 0.1) return;
var b = new EnemyBullet();
b.x = x;
b.y = y;
b.vx = dx / len;
b.vy = dy / len;
b.rotation = Math.atan2(dy, dx);
enemyBullets.push(b);
game.addChild(b);
}
var player;
var zombies = [];
var bullets = [];
var enemyBullets = []; // NEW: enemy bullets array
var score = 0;
var scoreTxt;
var hpTxt;
var spawnTimer = 0;
var spawnInterval = 90; // Frames between zombie spawns
var lastFireTick = 0;
var fireCooldown = 12; // Frames between shots
// Create player
player = new Player();
player.x = 2048 / 2;
player.y = 2732 * 0.7;
game.addChild(player);
// Set initial target move position to player start
game._targetMovePos = {
x: player.x,
y: player.y
};
// Score text
scoreTxt = new Text2('0', {
size: 110,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// HP text
hpTxt = new Text2('❤❤❤', {
size: 90,
fill: 0xFF4444
});
hpTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(hpTxt);
// Helper: update HP display
function updateHpTxt() {
var s = '';
for (var i = 0; i < player.hp; ++i) s += '❤';
hpTxt.setText(s);
}
// Helper: update score display
function updateScoreTxt() {
scoreTxt.setText(score);
}
// Helper: spawn a zombie at a random edge
function spawnZombie() {
// Only spawn GunZombie (with 2 HP) or normal Zombie
var z;
if (score > 0 && score % 5 === 0) {
z = new GunZombie();
} else if (Math.random() < 0.15) {
z = new GunZombie();
} else {
z = new Zombie();
}
// Pick a random edge: 0=top, 1=bottom, 2=left, 3=right
var edge = Math.floor(Math.random() * 4);
var margin = 80;
if (edge === 0) {
// Top
z.x = margin + Math.random() * (2048 - 2 * margin);
z.y = -z.radius - 10;
} else if (edge === 1) {
// Bottom
z.x = margin + Math.random() * (2048 - 2 * margin);
z.y = 2732 + z.radius + 10;
} else if (edge === 2) {
// Left
z.x = -z.radius - 10;
z.y = margin + Math.random() * (2732 - 2 * margin);
} else {
// Right
z.x = 2048 + z.radius + 10;
z.y = margin + Math.random() * (2732 - 2 * margin);
}
z.target = player;
zombies.push(z);
game.addChild(z);
}
// Helper: fire a bullet towards a direction
function fireBullet(dirX, dirY) {
var len = Math.sqrt(dirX * dirX + dirY * dirY);
if (len < 0.1) return;
var b = new Bullet();
b.x = player.x;
b.y = player.y;
b.vx = dirX / len;
b.vy = dirY / len;
b.rotation = Math.atan2(dirY, dirX);
bullets.push(b);
game.addChild(b);
// Rotate player to face the direction of the fired bullet
player.rotation = Math.atan2(dirY, dirX);
}
// Game event handling
game.down = function (x, y, obj) {
var now = LK.ticks;
if (now - lastFireTick >= fireCooldown) {
fireBullet(x - player.x, y - player.y);
lastFireTick = now;
}
// Always rotate player to face the direction of the click/touch
var dx = x - player.x;
var dy = y - player.y;
if (Math.abs(dx) > 0.01 || Math.abs(dy) > 0.01) {
player.rotation = Math.atan2(dy, dx);
}
};
game.move = function (x, y, obj) {
// Always update target move position to follow pointer
if (typeof game._targetMovePos === "undefined") {
game._targetMovePos = {
x: player.x,
y: player.y
};
}
game._targetMovePos.x = x;
game._targetMovePos.y = y;
};
game.up = function (x, y, obj) {
// No joystick logic needed
};
// Main game update
game.update = function () {
// Player movement follows last pointer position
if (typeof game._targetMovePos === "undefined") {
game._targetMovePos = {
x: player.x,
y: player.y
};
}
var tx = game._targetMovePos.x;
var ty = game._targetMovePos.y;
var dx = tx - player.x;
var dy = ty - player.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 2) {
var moveDist = Math.min(player.speed, dist);
player.x += dx / dist * moveDist;
player.y += dy / dist * moveDist;
// Clamp to arena
var r = player.radius + 10;
if (player.x < r) player.x = r;
if (player.x > 2048 - r) player.x = 2048 - r;
if (player.y < r) player.y = r;
if (player.y > 2732 - r) player.y = 2732 - r;
}
// Always rotate player to face pointer direction
if (dist > 2) {
player.rotation = Math.atan2(dy, dx);
}
// Spawn zombies
spawnTimer++;
if (spawnTimer >= spawnInterval) {
spawnZombie();
spawnTimer = 0;
// Gradually increase spawn rate
if (spawnInterval > 30) spawnInterval -= 1;
}
// Update zombies
for (var i = zombies.length - 1; i >= 0; --i) {
var z = zombies[i];
z.update();
// Remove if off screen (failsafe)
if (z.x < -200 || z.x > 2248 || z.y < -200 || z.y > 2932) {
z.destroy();
zombies.splice(i, 1);
}
}
// Update bullets
for (var i = bullets.length - 1; i >= 0; --i) {
var b = bullets[i];
b.update();
// Remove if off screen
if (b.x < -100 || b.x > 2148 || b.y < -100 || b.y > 2832) {
b.destroy();
bullets.splice(i, 1);
continue;
}
}
// Update enemy bullets
for (var i = enemyBullets.length - 1; i >= 0; --i) {
var eb = enemyBullets[i];
eb.update();
// Remove if off screen
if (eb.x < -100 || eb.x > 2148 || eb.y < -100 || eb.y > 2832) {
eb.destroy();
enemyBullets.splice(i, 1);
continue;
}
// Check collision with player
var dx = eb.x - player.x;
var dy = eb.y - player.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < eb.radius + player.radius - 10) {
if (!player.invincible) {
player.hp -= 1;
updateHpTxt();
player.flash();
if (player.hp <= 0) {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
} else if (player.hp === 1 && typeof heartSpawned === "undefined") {
// Spawn hearts at random locations when HP drops to 1
heartSpawned = true;
if (typeof hearts === "undefined") hearts = [];
for (var h = 0; h < 3; ++h) {
var heart = new Heart();
// Avoid spawning too close to player or outside arena
var safe = false;
var hx, hy;
while (!safe) {
hx = 150 + Math.random() * (2048 - 300);
hy = 150 + Math.random() * (2732 - 300);
var pdx = hx - player.x;
var pdy = hy - player.y;
if (Math.sqrt(pdx * pdx + pdy * pdy) > 400) safe = true;
}
heart.x = hx;
heart.y = hy;
hearts.push(heart);
game.addChild(heart);
}
}
}
eb.destroy();
enemyBullets.splice(i, 1);
continue;
}
}
// Bullet-zombie collisions
for (var i = bullets.length - 1; i >= 0; --i) {
var b = bullets[i];
for (var j = zombies.length - 1; j >= 0; --j) {
var z = zombies[j];
var dx = b.x - z.x;
var dy = b.y - z.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < b.radius + z.radius - 10) {
// Hit!
var isGunZombie = typeof z.hp === "number" && z.hp > 0;
if (isGunZombie) {
z.hp -= 1;
b.destroy();
bullets.splice(i, 1);
if (z.hp <= 0) {
z.destroy();
zombies.splice(j, 1);
score += 1;
updateScoreTxt();
}
} else {
z.destroy();
zombies.splice(j, 1);
b.destroy();
bullets.splice(i, 1);
score += 1;
updateScoreTxt();
}
break;
}
}
}
// Zombie-player collisions
for (var i = zombies.length - 1; i >= 0; --i) {
var z = zombies[i];
var dx = z.x - player.x;
var dy = z.y - player.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < z.radius + player.radius - 10) {
if (!player.invincible) {
player.hp -= 1;
updateHpTxt();
player.flash();
if (player.hp <= 0) {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
}
// Push zombie away
var pushDist = z.radius + player.radius - dist + 10;
if (pushDist > 0) {
var px = dx / dist * pushDist;
var py = dy / dist * pushDist;
z.x += px;
z.y += py;
}
}
}
// Heart pickup logic
if (typeof hearts !== "undefined" && hearts.length > 0) {
for (var i = hearts.length - 1; i >= 0; --i) {
var heart = hearts[i];
var dx = heart.x - player.x;
var dy = heart.y - player.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < heart.radius + player.radius - 10) {
// Picked up heart: restore HP to full
player.hp = 5;
updateHpTxt();
// Remove all hearts
for (var j = hearts.length - 1; j >= 0; --j) {
hearts[j].destroy();
}
hearts = [];
heartSpawned = undefined;
break;
}
}
}
};
// Initial UI update
updateScoreTxt();
updateHpTxt();
// Timer to spawn a heart at the center area every 5 seconds
if (typeof centerHeartTimer === "undefined") {
centerHeartTimer = LK.setInterval(function () {
if (typeof hearts === "undefined") hearts = [];
// Spawn a heart at a random position near the center (±200px)
var heart = new Heart();
var centerX = 2048 / 2;
var centerY = 2732 / 2;
var hx = centerX - 200 + Math.random() * 400;
var hy = centerY - 200 + Math.random() * 400;
heart.x = hx;
heart.y = hy;
hearts.push(heart);
game.addChild(heart);
}, 5000);
}
terraria oyunundaki gibi bir zombi. In-Game asset. 2d. High contrast. No shadows
pixel fireball. In-Game asset. 2d. High contrast. No shadows
aduket pozu vermiş pixel bir adam avucunun içi boş olsun. In-Game asset. 2d. High contrast. No shadows
elinde silah tutan bir zombi çiz pixel tarzı ile. In-Game asset. 2d. High contrast. No shadows
pixel heart. In-Game asset. 2d. High contrast. No shadows