User prompt
now make enemys look like pepole
User prompt
re make enemys
User prompt
add enemys
User prompt
i can not see the enemys
User prompt
now polesh game
User prompt
now make it so you can see enemys
User prompt
now make more enemys
User prompt
make kill anamashon
User prompt
now make it so you can see inventory
User prompt
add inventory
User prompt
remove wave bar
User prompt
now perfect game
User prompt
now make the bullets look real
User prompt
now make the guns look real
User prompt
make the gum sprite real
User prompt
add gun sprits
User prompt
add skin coler and faces to pepole
User prompt
make the pepole realistc
User prompt
and make the gun slowly speed up
User prompt
now make enemy gun slow
User prompt
and slowly speed up
User prompt
make enemys slow
User prompt
make it so you can do damege and kill
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Bullet class var Bullet = Container.expand(function () { var self = Container.call(this); self.radius = 20; self.speed = 30; self.dir = -Math.PI / 2; self.damage = 1; self.fromPlayer = true; self.bulletAsset = 'bullet_basic'; self.sprite = null; self.init = function (asset, speed, dir, damage, fromPlayer) { self.bulletAsset = asset; self.speed = speed; self.dir = dir; self.damage = damage; self.fromPlayer = fromPlayer; if (self.sprite) self.removeChild(self.sprite); self.sprite = self.attachAsset(asset, { anchorX: 0.5, anchorY: 0.5 }); self.radius = self.sprite.width / 2; }; self.update = function () { self.x += Math.cos(self.dir) * self.speed; self.y += Math.sin(self.dir) * self.speed; }; return self; }); // Enemy class var Enemy = Container.expand(function () { var self = Container.call(this); // Head var head = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5, width: 44, height: 44, y: -36 }); // Body var body = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.0, width: 22, height: 48, y: -14, color: 0xc0392b, shape: 'box' }); // Left arm var larm = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.0, width: 10, height: 32, x: -18, y: -8, color: 0xe67e22, shape: 'box' }); // Right arm var rarm = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.0, width: 10, height: 32, x: 18, y: -8, color: 0xe67e22, shape: 'box' }); // Left leg var lleg = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.0, width: 10, height: 32, x: -8, y: 36, color: 0x7f8c8d, shape: 'box' }); // Right leg var rleg = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.0, width: 10, height: 32, x: 8, y: 36, color: 0x7f8c8d, shape: 'box' }); self.radius = 44; // head radius self.hp = 2; self.speed = 6 + Math.random() * 4; self.dir = Math.PI / 2 + (Math.random() - 0.5) * 0.5; // Downwards, slight random angle self.update = function () { self.x += Math.cos(self.dir) * self.speed; self.y += Math.sin(self.dir) * self.speed; }; return self; }); // GunDrop class var GunDrop = Container.expand(function () { var self = Container.call(this); self.gun = null; var dropSprite = self.attachAsset('gun_drop', { anchorX: 0.5, anchorY: 0.5 }); self.radius = dropSprite.width / 2; self.setGun = function (gun) { self.gun = gun; dropSprite.tint = gun.color; }; self.update = function () { self.y += 8; }; return self; }); // Player class var Player = Container.expand(function () { var self = Container.call(this); // Head var head = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5, width: 54, height: 54, y: -44 }); // Body var body = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.0, width: 28, height: 64, y: -17, color: 0x2980b9, shape: 'box' }); // Left arm var larm = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.0, width: 12, height: 40, x: -24, y: -8, color: 0x27ae60, shape: 'box' }); // Right arm var rarm = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.0, width: 12, height: 40, x: 24, y: -8, color: 0x27ae60, shape: 'box' }); // Left leg var lleg = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.0, width: 12, height: 40, x: -10, y: 48, color: 0xf1c40f, shape: 'box' }); // Right leg var rleg = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.0, width: 12, height: 40, x: 10, y: 48, color: 0xf1c40f, shape: 'box' }); self.radius = 54; // head radius self.invulnTicks = 0; self.flashTween = null; self.setInvulnerable = function (ticks) { self.invulnTicks = ticks; if (self.flashTween) tween.stop(head, { alpha: true }); head.alpha = 0.5; self.flashTween = tween(head, { alpha: 1 }, { duration: 200, easing: tween.linear, onFinish: function onFinish() { tween(head, { alpha: 0.5 }, { duration: 200, easing: tween.linear, onFinish: function onFinish() { if (self.invulnTicks > 0) self.setInvulnerable(self.invulnTicks - 1);else head.alpha = 1; } }); } }); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x181c20 }); /**** * Game Code ****/ // Game state // Guns (shapes for now, will be replaced by images automatically) // Sounds // Gun definitions var GUNS = [{ id: 'basic', name: 'Basic Gun', bulletAsset: 'bullet_basic', fireRate: 18, // ticks between shots bulletSpeed: 32, spread: 0, bulletsPerShot: 1, damage: 1, color: 0xf1c40f }, { id: 'spread', name: 'Spread Shot', bulletAsset: 'bullet_spread', fireRate: 28, bulletSpeed: 26, spread: 0.25, bulletsPerShot: 3, damage: 1, color: 0x8e44ad }, { id: 'rapid', name: 'Rapid Fire', bulletAsset: 'bullet_rapid', fireRate: 7, bulletSpeed: 24, spread: 0.08, bulletsPerShot: 1, damage: 1, color: 0x16a085 }, { id: 'big', name: 'Big Blaster', bulletAsset: 'bullet_big', fireRate: 30, bulletSpeed: 20, spread: 0, bulletsPerShot: 1, damage: 3, color: 0xff9800 }]; // Helper: get random gun (not in excludeIds) function getRandomGun(excludeIds) { var pool = []; for (var i = 0; i < GUNS.length; ++i) { if (!excludeIds || excludeIds.indexOf(GUNS[i].id) === -1) pool.push(GUNS[i]); } if (pool.length === 0) pool = GUNS; return pool[Math.floor(Math.random() * pool.length)]; } var player = null; var enemies = []; var bullets = []; var gunDrops = []; var score = 0; var scoreTxt = null; var gunTxt = null; var wave = 1; var ticksToNextWave = 0; var playerGuns = []; var currentGunIndex = 0; var fireCooldown = 0; var dragging = false; var dragOffsetX = 0; var dragOffsetY = 0; var lastTouchX = 0; var lastTouchY = 0; var gameArea = { x: 0, y: 0, w: 2048, h: 2732 - 200 }; // leave some space at bottom for gun UI // Setup UI scoreTxt = new Text2('0', { size: 120, fill: '#fff' }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); gunTxt = new Text2('', { size: 70, fill: '#fff' }); gunTxt.anchor.set(0.5, 0); LK.gui.bottom.addChild(gunTxt); // Initialize player player = new Player(); player.x = 2048 / 2; player.y = 2732 - 350; game.addChild(player); // Give player a starting gun playerGuns = [GUNS[0]]; currentGunIndex = 0; updateGunUI(); // Spawn first wave spawnWave(wave); // Touch controls game.down = function (x, y, obj) { // Only start drag if touch is on player var dx = x - player.x; var dy = y - player.y; if (dx * dx + dy * dy < player.radius * player.radius * 1.5) { dragging = true; dragOffsetX = player.x - x; dragOffsetY = player.y - y; lastTouchX = x; lastTouchY = y; } }; game.move = function (x, y, obj) { if (dragging) { // Move player directly to the touch/mouse position, clamped to game area var nx = x; var ny = y; if (nx < gameArea.x + player.radius) nx = gameArea.x + player.radius; if (nx > gameArea.x + gameArea.w - player.radius) nx = gameArea.x + gameArea.w - player.radius; if (ny < gameArea.y + player.radius) ny = gameArea.y + player.radius; if (ny > gameArea.y + gameArea.h - player.radius) ny = gameArea.y + gameArea.h - player.radius; player.x = nx; player.y = ny; lastTouchX = x; lastTouchY = y; } }; game.up = function (x, y, obj) { dragging = false; }; // Tap bottom of screen to switch gun game.on('down', function (x, y, obj) { if (y > 2732 - 200) { // Switch gun if (playerGuns.length > 1) { currentGunIndex = (currentGunIndex + 1) % playerGuns.length; updateGunUI(); LK.getSound('gunchange').play(); } } }); // Main update loop game.update = function () { // Player invulnerability if (player.invulnTicks > 0) player.invulnTicks--; // Firing fireCooldown--; if (dragging && fireCooldown <= 0) { var gun = playerGuns[currentGunIndex]; fireGun(gun); fireCooldown = gun.fireRate; } // Update bullets for (var i = bullets.length - 1; i >= 0; --i) { var b = bullets[i]; b.update(); // Remove if out of bounds if (b.x < -100 || b.x > 2148 || b.y < -100 || b.y > 2832) { b.destroy(); bullets.splice(i, 1); continue; } // Collisions if (b.fromPlayer) { // Hit enemy for (var j = enemies.length - 1; j >= 0; --j) { var e = enemies[j]; var dx = b.x - e.x; var dy = b.y - e.y; var dist = dx * dx + dy * dy; if (dist < (b.radius + e.radius) * (b.radius + e.radius)) { // Bullet hits enemy: deal damage e.hp -= b.damage; LK.getSound('enemyhit').play(); b.destroy(); bullets.splice(i, 1); if (e.hp <= 0) { // Enemy dies spawnGunDrop(e.x, e.y); e.destroy(); enemies.splice(j, 1); score += 10; scoreTxt.setText(score); } break; } } } else { // Enemy bullet hits player var dx = b.x - player.x; var dy = b.y - player.y; var dist = dx * dx + dy * dy; if (dist < (b.radius + player.radius) * (b.radius + player.radius)) { if (player.invulnTicks <= 0) { LK.effects.flashScreen(0xff0000, 600); player.setInvulnerable(40); b.destroy(); bullets.splice(i, 1); // Game over LK.showGameOver(); return; } } } } // Update enemies for (var i = enemies.length - 1; i >= 0; --i) { var e = enemies[i]; e.update(); // Remove if out of bounds if (e.x < -120 || e.x > 2168 || e.y > 2832) { e.destroy(); enemies.splice(i, 1); continue; } // Enemy collides with player var dx = e.x - player.x; var dy = e.y - player.y; var dist = dx * dx + dy * dy; if (dist < (e.radius + player.radius) * (e.radius + player.radius)) { if (player.invulnTicks <= 0) { LK.effects.flashScreen(0xff0000, 600); player.setInvulnerable(40); // Game over LK.showGameOver(); return; } } // Enemy fires at player if (Math.random() < 0.008 + wave * 0.001) { var dir = Math.atan2(player.y - e.y, player.x - e.x); var eb = new Bullet(); eb.init('bullet_basic', 18 + Math.random() * 6, dir, 1, false); eb.x = e.x; eb.y = e.y; bullets.push(eb); game.addChild(eb); } } // Update gun drops for (var i = gunDrops.length - 1; i >= 0; --i) { var g = gunDrops[i]; g.update(); // Remove if out of bounds if (g.y > 2832) { g.destroy(); gunDrops.splice(i, 1); continue; } // Pickup var dx = g.x - player.x; var dy = g.y - player.y; var dist = dx * dx + dy * dy; if (dist < (g.radius + player.radius) * (g.radius + player.radius)) { // Add gun if not already owned if (!hasGun(g.gun.id)) { playerGuns.push(g.gun); currentGunIndex = playerGuns.length - 1; updateGunUI(); LK.getSound('pickup').play(); } g.destroy(); gunDrops.splice(i, 1); } } // Next wave if (enemies.length === 0 && gunDrops.length === 0 && ticksToNextWave <= 0) { ticksToNextWave = 60; } if (ticksToNextWave > 0) { ticksToNextWave--; if (ticksToNextWave === 0) { wave++; spawnWave(wave); } } }; // Helper: fire gun function fireGun(gun) { for (var i = 0; i < gun.bulletsPerShot; ++i) { var b = new Bullet(); var spread = gun.spread * (Math.random() - 0.5); var dir = -Math.PI / 2 + spread + (gun.bulletsPerShot > 1 ? (i - (gun.bulletsPerShot - 1) / 2) * gun.spread : 0); b.init(gun.bulletAsset, gun.bulletSpeed, dir, gun.damage, true); b.x = player.x; b.y = player.y - player.radius; bullets.push(b); game.addChild(b); } LK.getSound('shoot').play(); } // Helper: spawn wave function spawnWave(w) { var n = 3 + Math.floor(w * 1.5); for (var i = 0; i < n; ++i) { var e = new Enemy(); e.x = 200 + Math.random() * (2048 - 400); e.y = -100 - Math.random() * 200; e.hp = 2 + Math.floor(w / 2); e.speed = 7 + Math.random() * 3 + w * 0.2; enemies.push(e); game.addChild(e); } } // Helper: spawn gun drop function spawnGunDrop(x, y) { // 50% chance to drop a gun, only if player doesn't have all guns if (playerGuns.length >= GUNS.length) return; if (Math.random() < 0.5) { var exclude = []; for (var i = 0; i < playerGuns.length; ++i) exclude.push(playerGuns[i].id); var gun = getRandomGun(exclude); var g = new GunDrop(); g.x = x; g.y = y; g.setGun(gun); gunDrops.push(g); game.addChild(g); } } // Helper: update gun UI function updateGunUI() { var gun = playerGuns[currentGunIndex]; gunTxt.setText("Gun: " + gun.name + " (Tap here to switch)"); gunTxt.setStyle({ fill: "#" + gun.color.toString(16) }); } // Helper: has gun function hasGun(id) { for (var i = 0; i < playerGuns.length; ++i) if (playerGuns[i].id === id) return true; return false; }
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Bullet class
var Bullet = Container.expand(function () {
var self = Container.call(this);
self.radius = 20;
self.speed = 30;
self.dir = -Math.PI / 2;
self.damage = 1;
self.fromPlayer = true;
self.bulletAsset = 'bullet_basic';
self.sprite = null;
self.init = function (asset, speed, dir, damage, fromPlayer) {
self.bulletAsset = asset;
self.speed = speed;
self.dir = dir;
self.damage = damage;
self.fromPlayer = fromPlayer;
if (self.sprite) self.removeChild(self.sprite);
self.sprite = self.attachAsset(asset, {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = self.sprite.width / 2;
};
self.update = function () {
self.x += Math.cos(self.dir) * self.speed;
self.y += Math.sin(self.dir) * self.speed;
};
return self;
});
// Enemy class
var Enemy = Container.expand(function () {
var self = Container.call(this);
// Head
var head = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5,
width: 44,
height: 44,
y: -36
});
// Body
var body = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.0,
width: 22,
height: 48,
y: -14,
color: 0xc0392b,
shape: 'box'
});
// Left arm
var larm = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.0,
width: 10,
height: 32,
x: -18,
y: -8,
color: 0xe67e22,
shape: 'box'
});
// Right arm
var rarm = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.0,
width: 10,
height: 32,
x: 18,
y: -8,
color: 0xe67e22,
shape: 'box'
});
// Left leg
var lleg = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.0,
width: 10,
height: 32,
x: -8,
y: 36,
color: 0x7f8c8d,
shape: 'box'
});
// Right leg
var rleg = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.0,
width: 10,
height: 32,
x: 8,
y: 36,
color: 0x7f8c8d,
shape: 'box'
});
self.radius = 44; // head radius
self.hp = 2;
self.speed = 6 + Math.random() * 4;
self.dir = Math.PI / 2 + (Math.random() - 0.5) * 0.5; // Downwards, slight random angle
self.update = function () {
self.x += Math.cos(self.dir) * self.speed;
self.y += Math.sin(self.dir) * self.speed;
};
return self;
});
// GunDrop class
var GunDrop = Container.expand(function () {
var self = Container.call(this);
self.gun = null;
var dropSprite = self.attachAsset('gun_drop', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = dropSprite.width / 2;
self.setGun = function (gun) {
self.gun = gun;
dropSprite.tint = gun.color;
};
self.update = function () {
self.y += 8;
};
return self;
});
// Player class
var Player = Container.expand(function () {
var self = Container.call(this);
// Head
var head = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5,
width: 54,
height: 54,
y: -44
});
// Body
var body = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.0,
width: 28,
height: 64,
y: -17,
color: 0x2980b9,
shape: 'box'
});
// Left arm
var larm = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.0,
width: 12,
height: 40,
x: -24,
y: -8,
color: 0x27ae60,
shape: 'box'
});
// Right arm
var rarm = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.0,
width: 12,
height: 40,
x: 24,
y: -8,
color: 0x27ae60,
shape: 'box'
});
// Left leg
var lleg = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.0,
width: 12,
height: 40,
x: -10,
y: 48,
color: 0xf1c40f,
shape: 'box'
});
// Right leg
var rleg = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.0,
width: 12,
height: 40,
x: 10,
y: 48,
color: 0xf1c40f,
shape: 'box'
});
self.radius = 54; // head radius
self.invulnTicks = 0;
self.flashTween = null;
self.setInvulnerable = function (ticks) {
self.invulnTicks = ticks;
if (self.flashTween) tween.stop(head, {
alpha: true
});
head.alpha = 0.5;
self.flashTween = tween(head, {
alpha: 1
}, {
duration: 200,
easing: tween.linear,
onFinish: function onFinish() {
tween(head, {
alpha: 0.5
}, {
duration: 200,
easing: tween.linear,
onFinish: function onFinish() {
if (self.invulnTicks > 0) self.setInvulnerable(self.invulnTicks - 1);else head.alpha = 1;
}
});
}
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x181c20
});
/****
* Game Code
****/
// Game state
// Guns (shapes for now, will be replaced by images automatically)
// Sounds
// Gun definitions
var GUNS = [{
id: 'basic',
name: 'Basic Gun',
bulletAsset: 'bullet_basic',
fireRate: 18,
// ticks between shots
bulletSpeed: 32,
spread: 0,
bulletsPerShot: 1,
damage: 1,
color: 0xf1c40f
}, {
id: 'spread',
name: 'Spread Shot',
bulletAsset: 'bullet_spread',
fireRate: 28,
bulletSpeed: 26,
spread: 0.25,
bulletsPerShot: 3,
damage: 1,
color: 0x8e44ad
}, {
id: 'rapid',
name: 'Rapid Fire',
bulletAsset: 'bullet_rapid',
fireRate: 7,
bulletSpeed: 24,
spread: 0.08,
bulletsPerShot: 1,
damage: 1,
color: 0x16a085
}, {
id: 'big',
name: 'Big Blaster',
bulletAsset: 'bullet_big',
fireRate: 30,
bulletSpeed: 20,
spread: 0,
bulletsPerShot: 1,
damage: 3,
color: 0xff9800
}];
// Helper: get random gun (not in excludeIds)
function getRandomGun(excludeIds) {
var pool = [];
for (var i = 0; i < GUNS.length; ++i) {
if (!excludeIds || excludeIds.indexOf(GUNS[i].id) === -1) pool.push(GUNS[i]);
}
if (pool.length === 0) pool = GUNS;
return pool[Math.floor(Math.random() * pool.length)];
}
var player = null;
var enemies = [];
var bullets = [];
var gunDrops = [];
var score = 0;
var scoreTxt = null;
var gunTxt = null;
var wave = 1;
var ticksToNextWave = 0;
var playerGuns = [];
var currentGunIndex = 0;
var fireCooldown = 0;
var dragging = false;
var dragOffsetX = 0;
var dragOffsetY = 0;
var lastTouchX = 0;
var lastTouchY = 0;
var gameArea = {
x: 0,
y: 0,
w: 2048,
h: 2732 - 200
}; // leave some space at bottom for gun UI
// Setup UI
scoreTxt = new Text2('0', {
size: 120,
fill: '#fff'
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
gunTxt = new Text2('', {
size: 70,
fill: '#fff'
});
gunTxt.anchor.set(0.5, 0);
LK.gui.bottom.addChild(gunTxt);
// Initialize player
player = new Player();
player.x = 2048 / 2;
player.y = 2732 - 350;
game.addChild(player);
// Give player a starting gun
playerGuns = [GUNS[0]];
currentGunIndex = 0;
updateGunUI();
// Spawn first wave
spawnWave(wave);
// Touch controls
game.down = function (x, y, obj) {
// Only start drag if touch is on player
var dx = x - player.x;
var dy = y - player.y;
if (dx * dx + dy * dy < player.radius * player.radius * 1.5) {
dragging = true;
dragOffsetX = player.x - x;
dragOffsetY = player.y - y;
lastTouchX = x;
lastTouchY = y;
}
};
game.move = function (x, y, obj) {
if (dragging) {
// Move player directly to the touch/mouse position, clamped to game area
var nx = x;
var ny = y;
if (nx < gameArea.x + player.radius) nx = gameArea.x + player.radius;
if (nx > gameArea.x + gameArea.w - player.radius) nx = gameArea.x + gameArea.w - player.radius;
if (ny < gameArea.y + player.radius) ny = gameArea.y + player.radius;
if (ny > gameArea.y + gameArea.h - player.radius) ny = gameArea.y + gameArea.h - player.radius;
player.x = nx;
player.y = ny;
lastTouchX = x;
lastTouchY = y;
}
};
game.up = function (x, y, obj) {
dragging = false;
};
// Tap bottom of screen to switch gun
game.on('down', function (x, y, obj) {
if (y > 2732 - 200) {
// Switch gun
if (playerGuns.length > 1) {
currentGunIndex = (currentGunIndex + 1) % playerGuns.length;
updateGunUI();
LK.getSound('gunchange').play();
}
}
});
// Main update loop
game.update = function () {
// Player invulnerability
if (player.invulnTicks > 0) player.invulnTicks--;
// Firing
fireCooldown--;
if (dragging && fireCooldown <= 0) {
var gun = playerGuns[currentGunIndex];
fireGun(gun);
fireCooldown = gun.fireRate;
}
// Update bullets
for (var i = bullets.length - 1; i >= 0; --i) {
var b = bullets[i];
b.update();
// Remove if out of bounds
if (b.x < -100 || b.x > 2148 || b.y < -100 || b.y > 2832) {
b.destroy();
bullets.splice(i, 1);
continue;
}
// Collisions
if (b.fromPlayer) {
// Hit enemy
for (var j = enemies.length - 1; j >= 0; --j) {
var e = enemies[j];
var dx = b.x - e.x;
var dy = b.y - e.y;
var dist = dx * dx + dy * dy;
if (dist < (b.radius + e.radius) * (b.radius + e.radius)) {
// Bullet hits enemy: deal damage
e.hp -= b.damage;
LK.getSound('enemyhit').play();
b.destroy();
bullets.splice(i, 1);
if (e.hp <= 0) {
// Enemy dies
spawnGunDrop(e.x, e.y);
e.destroy();
enemies.splice(j, 1);
score += 10;
scoreTxt.setText(score);
}
break;
}
}
} else {
// Enemy bullet hits player
var dx = b.x - player.x;
var dy = b.y - player.y;
var dist = dx * dx + dy * dy;
if (dist < (b.radius + player.radius) * (b.radius + player.radius)) {
if (player.invulnTicks <= 0) {
LK.effects.flashScreen(0xff0000, 600);
player.setInvulnerable(40);
b.destroy();
bullets.splice(i, 1);
// Game over
LK.showGameOver();
return;
}
}
}
}
// Update enemies
for (var i = enemies.length - 1; i >= 0; --i) {
var e = enemies[i];
e.update();
// Remove if out of bounds
if (e.x < -120 || e.x > 2168 || e.y > 2832) {
e.destroy();
enemies.splice(i, 1);
continue;
}
// Enemy collides with player
var dx = e.x - player.x;
var dy = e.y - player.y;
var dist = dx * dx + dy * dy;
if (dist < (e.radius + player.radius) * (e.radius + player.radius)) {
if (player.invulnTicks <= 0) {
LK.effects.flashScreen(0xff0000, 600);
player.setInvulnerable(40);
// Game over
LK.showGameOver();
return;
}
}
// Enemy fires at player
if (Math.random() < 0.008 + wave * 0.001) {
var dir = Math.atan2(player.y - e.y, player.x - e.x);
var eb = new Bullet();
eb.init('bullet_basic', 18 + Math.random() * 6, dir, 1, false);
eb.x = e.x;
eb.y = e.y;
bullets.push(eb);
game.addChild(eb);
}
}
// Update gun drops
for (var i = gunDrops.length - 1; i >= 0; --i) {
var g = gunDrops[i];
g.update();
// Remove if out of bounds
if (g.y > 2832) {
g.destroy();
gunDrops.splice(i, 1);
continue;
}
// Pickup
var dx = g.x - player.x;
var dy = g.y - player.y;
var dist = dx * dx + dy * dy;
if (dist < (g.radius + player.radius) * (g.radius + player.radius)) {
// Add gun if not already owned
if (!hasGun(g.gun.id)) {
playerGuns.push(g.gun);
currentGunIndex = playerGuns.length - 1;
updateGunUI();
LK.getSound('pickup').play();
}
g.destroy();
gunDrops.splice(i, 1);
}
}
// Next wave
if (enemies.length === 0 && gunDrops.length === 0 && ticksToNextWave <= 0) {
ticksToNextWave = 60;
}
if (ticksToNextWave > 0) {
ticksToNextWave--;
if (ticksToNextWave === 0) {
wave++;
spawnWave(wave);
}
}
};
// Helper: fire gun
function fireGun(gun) {
for (var i = 0; i < gun.bulletsPerShot; ++i) {
var b = new Bullet();
var spread = gun.spread * (Math.random() - 0.5);
var dir = -Math.PI / 2 + spread + (gun.bulletsPerShot > 1 ? (i - (gun.bulletsPerShot - 1) / 2) * gun.spread : 0);
b.init(gun.bulletAsset, gun.bulletSpeed, dir, gun.damage, true);
b.x = player.x;
b.y = player.y - player.radius;
bullets.push(b);
game.addChild(b);
}
LK.getSound('shoot').play();
}
// Helper: spawn wave
function spawnWave(w) {
var n = 3 + Math.floor(w * 1.5);
for (var i = 0; i < n; ++i) {
var e = new Enemy();
e.x = 200 + Math.random() * (2048 - 400);
e.y = -100 - Math.random() * 200;
e.hp = 2 + Math.floor(w / 2);
e.speed = 7 + Math.random() * 3 + w * 0.2;
enemies.push(e);
game.addChild(e);
}
}
// Helper: spawn gun drop
function spawnGunDrop(x, y) {
// 50% chance to drop a gun, only if player doesn't have all guns
if (playerGuns.length >= GUNS.length) return;
if (Math.random() < 0.5) {
var exclude = [];
for (var i = 0; i < playerGuns.length; ++i) exclude.push(playerGuns[i].id);
var gun = getRandomGun(exclude);
var g = new GunDrop();
g.x = x;
g.y = y;
g.setGun(gun);
gunDrops.push(g);
game.addChild(g);
}
}
// Helper: update gun UI
function updateGunUI() {
var gun = playerGuns[currentGunIndex];
gunTxt.setText("Gun: " + gun.name + " (Tap here to switch)");
gunTxt.setStyle({
fill: "#" + gun.color.toString(16)
});
}
// Helper: has gun
function hasGun(id) {
for (var i = 0; i < playerGuns.length; ++i) if (playerGuns[i].id === id) return true;
return false;
}