/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Background class for trees var Background = Container.expand(function () { var self = Container.call(this); // Place fewer trees at new positions var treePositions = [ // Top left { x: 300, y: 300 }, // Top right { x: 2048 - 300, y: 320 }, // Bottom left { x: 350, y: 2732 - 320 }, // Bottom right { x: 2048 - 350, y: 2732 - 300 }, // Center left { x: 500, y: 1366 }, // Center right { x: 2048 - 500, y: 1366 }, // Center { x: 1024, y: 900 }, { x: 1024, y: 2000 }]; for (var i = 0; i < treePositions.length; ++i) { var pos = treePositions[i]; var tree = self.attachAsset('Tree', { anchorX: 0.5, anchorY: 1, x: pos.x, y: pos.y + 110, scaleX: 1 + Math.random() * 0.2, scaleY: 1 + Math.random() * 0.2 }); } return self; }); // Bullet class var Bullet = Container.expand(function () { var self = Container.call(this); var sprite = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5 }); self.radius = 20; self.speed = 48; self.dx = 0; self.dy = 0; self.owner = null; // 'player' or 'enemy' self.damage = 1; self.lifetime = 60; // frames self.age = 0; self.update = function () { self.x += self.dx; self.y += self.dy; self.age++; }; return self; }); // Cover class var Cover = Container.expand(function () { var self = Container.call(this); var sprite = self.attachAsset('cover', { anchorX: 0.5, anchorY: 0.5 }); self.radius = 100; return self; }); // Enemy class var Enemy = Container.expand(function () { var self = Container.call(this); var sprite = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); // Add gun sprite to enemy hand (pistol texture) var gun = self.attachAsset('pistol', { anchorX: 0.1, anchorY: 0.5, scaleX: 1.0, scaleY: 1.0 }); gun.y = 20; // offset to hand gun.x = 40; // offset to right hand self.radius = 60; self.speed = 5 + Math.random() * 2; self.maxHealth = 3; self.health = self.maxHealth; self.shootCooldown = 40 + Math.floor(Math.random() * 20); self.lastShotTick = -100; self.target = null; self.alive = true; self.aimError = 0.2 + Math.random() * 0.2; // radians self.takeDamage = function (amount) { if (!self.alive) return; self.health -= amount; LK.getSound('hit').play(); if (self.health <= 0) { self.health = 0; self.die(); } }; self.die = function () { self.alive = false; LK.getSound('enemy_down').play(); tween(self, { alpha: 0 }, { duration: 400, onFinish: function onFinish() { self.visible = false; } }); }; self.update = function () { if (!self.alive) return; // Move towards player if not too close if (self.target && self.target.alive) { var dx = self.target.x - self.x; var dy = self.target.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 300) { var moveX = dx / dist * self.speed; var moveY = dy / dist * self.speed; // Check for cover collision var blocked = false; for (var i = 0; i < covers.length; ++i) { if (self.intersects(covers[i])) { blocked = true; break; } } if (!blocked) { self.x += moveX; self.y += moveY; } } } // Rotate gun towards player if alive if (self.target && self.target.alive) { var dxg = self.target.x - self.x; var dyg = self.target.y - self.y; gun.rotation = Math.atan2(dyg, dxg); } }; return self; }); // Health pickup class var HealthPickup = Container.expand(function () { var self = Container.call(this); var sprite = self.attachAsset('health', { anchorX: 0.5, anchorY: 0.5 }); self.radius = 30; self.healAmount = 2; return self; }); // Player class var Player = Container.expand(function () { var self = Container.call(this); var sprite = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); // Add gun sprite (pistol texture) var gun = self.attachAsset('pistol', { anchorX: 0.1, // grip of gun at hand anchorY: 0.5, scaleX: 1.0, scaleY: 1.0 }); gun.y = 20; // offset to hand gun.x = 40; // offset to right hand self.radius = 60; self.speed = 9; self.maxHealth = 100; self.health = self.maxHealth; self.ammo = 6; self.maxAmmo = 6; self.reloadTime = 60; // frames self.reloadCounter = 0; self.isReloading = false; self.lastShotTick = -100; self.shootCooldown = 6; // frames (0.1 seconds at 60FPS) self.alive = true; self.takeDamage = function (amount) { if (!self.alive) return; self.health -= amount; LK.getSound('hit').play(); if (self.health <= 0) { self.health = 0; self.die(); } }; self.die = function () { self.alive = false; LK.getSound('player_down').play(); tween(self, { alpha: 0 }, { duration: 400, onFinish: function onFinish() { self.visible = false; } }); }; self.heal = function (amount) { self.health += amount; if (self.health > self.maxHealth) self.health = self.maxHealth; }; self.reload = function () { if (self.isReloading || self.ammo === self.maxAmmo) return; self.isReloading = true; self.reloadCounter = self.reloadTime; }; self.update = function () { if (!self.alive) return; if (self.isReloading) { self.reloadCounter--; if (self.reloadCounter <= 0) { self.ammo = self.maxAmmo; self.isReloading = false; } } // Rotate gun towards last aim/touch position var dx = 0, dy = 0; if (typeof lastTouchX !== "undefined" && typeof lastTouchY !== "undefined") { dx = lastTouchX - self.x; dy = lastTouchY - self.y; } gun.rotation = Math.atan2(dy, dx); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x181c24 }); /**** * Game Code ****/ // Game state variables // Player character: blue box // Enemy: red box // Bullet: yellow ellipse // Cover: dark gray box // Health pickup: green ellipse // Sound for shooting // Sound for pickup // Sound for hit // Sound for enemy down // Sound for player down var player; var enemies = []; var bullets = []; var covers = []; var healthPickups = []; var round = 1; var maxRounds = 20; // 10 more rounds var enemyCount = 2; var bulletDamage = 1; // Bullet damage, increases each round var enemyStrengthMultiplier = 1; // Multiplier for enemy health and damage var dragging = false; var dragOffsetX = 0; var dragOffsetY = 0; var aimX = 0; var aimY = 0; var lastTouchX = 0; var lastTouchY = 0; var gameState = 'playing'; // 'playing', 'win', 'lose' var roundResetTimer = 0; // UI var scoreTxt = new Text2('Round 1', { size: 90, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); var healthTxt = new Text2('♥♥♥♥♥', { size: 80, fill: 0x3BE14D }); healthTxt.anchor.set(0, 0); LK.gui.topRight.addChild(healthTxt); var ammoTxt = new Text2('Ammo: 6/6', { size: 80, fill: 0xFFE14D }); ammoTxt.anchor.set(1, 0); LK.gui.topLeft.addChild(ammoTxt); // Helper: clamp function clamp(val, min, max) { if (val < min) return min; if (val > max) return max; return val; } // Helper: reset round function resetRound() { // Remove all objects for (var i = 0; i < enemies.length; ++i) enemies[i].destroy(); for (var i = 0; i < bullets.length; ++i) bullets[i].destroy(); for (var i = 0; i < healthPickups.length; ++i) healthPickups[i].destroy(); enemies = []; bullets = []; healthPickups = []; // Reset player player.x = 2048 / 2; player.y = 2732 - 350; player.health = player.maxHealth; player.ammo = player.maxAmmo; player.isReloading = false; player.reloadCounter = 0; player.alive = true; player.alpha = 1; player.visible = true; // Set enemy strength multiplier for rounds 11-20 enemyStrengthMultiplier = round > 10 ? 5 : 1; // Spawn enemies for (var i = 0; i < enemyCount; ++i) { var e = new Enemy(); // If round > 10, swap to enemy2 texture if (round > 10 && e.children && e.children.length > 0) { // Remove old enemy sprite e.removeChildAt(0); // Add enemy2 sprite var enemy2Sprite = e.attachAsset('enemy2', { anchorX: 0.5, anchorY: 0.5 }); // Re-add gun to hand (as second child) var gun = e.attachAsset('pistol', { anchorX: 0.1, anchorY: 0.5, scaleX: 1.0, scaleY: 1.0 }); gun.y = 20; gun.x = 40; } // Place enemies at top of map, spread out e.x = 400 + i * 400 + Math.random() * 100; e.y = 400 + Math.random() * 100; e.target = player; // Apply 5x health for rounds 11-20 e.maxHealth = Math.floor(e.maxHealth * enemyStrengthMultiplier) + (round - 1); e.health = e.maxHealth; // Increase enemy damage by +1 per round e.baseDamage = 1 + (round - 1); // Optionally, you could also increase enemy damage or speed here if desired enemies.push(e); game.addChild(e); } // Spawn health pickups at random locations every round var healthPickupCount = 1 + Math.floor(Math.random() * 2); // 1 or 2 per round for (var h = 0; h < healthPickupCount; ++h) { var hp = new HealthPickup(); // Avoid spawning too close to player start or out of bounds var safeMargin = 150; var px, py; var tries = 0; do { px = safeMargin + Math.random() * (2048 - 2 * safeMargin); py = safeMargin + Math.random() * (2732 - 2 * safeMargin); tries++; // Avoid center spawn (player start) } while (Math.abs(px - 2048 / 2) < 200 && Math.abs(py - (2732 - 350)) < 200 && tries < 10); hp.x = px; hp.y = py; healthPickups.push(hp); game.addChild(hp); } // Update UI scoreTxt.setText('Round ' + round); updateHealthUI(); updateAmmoUI(); gameState = 'playing'; } // Helper: update health UI function updateHealthUI() { var s = ''; for (var i = 0; i < player.health; ++i) s += '♥'; for (var i = player.health; i < player.maxHealth; ++i) s += '♡'; healthTxt.setText(s); } // Helper: update ammo UI function updateAmmoUI() { if (player.isReloading) { ammoTxt.setText('Reloading...'); } else { ammoTxt.setText('Ammo: ' + player.ammo + '/' + player.maxAmmo); } } // Helper: spawn covers function spawnCovers() { for (var i = 0; i < covers.length; ++i) covers[i].destroy(); covers = []; // Place 3 covers var c1 = new Cover(); c1.x = 2048 / 2; c1.y = 1200; covers.push(c1); game.addChild(c1); var c2 = new Cover(); c2.x = 600; c2.y = 1800; covers.push(c2); game.addChild(c2); var c3 = new Cover(); c3.x = 2048 - 600; c3.y = 1800; covers.push(c3); game.addChild(c3); } // Helper: check line of sight (simple, ignores covers for MVP) function hasLineOfSight(ax, ay, bx, by) { // For MVP, always true return true; } // Helper: shoot bullet function shootBullet(from, toX, toY, owner) { var b = new Bullet(); b.x = from.x; b.y = from.y; var dx = toX - from.x; var dy = toY - from.y; var dist = Math.sqrt(dx * dx + dy * dy); b.dx = dx / dist * b.speed; b.dy = dy / dist * b.speed; b.owner = owner; b.rotation = Math.atan2(dy, dx); // Set bullet damage based on round if (owner === 'enemy' && from.baseDamage !== undefined) { b.damage = from.baseDamage; } else { b.damage = bulletDamage; } bullets.push(b); game.addChild(b); LK.getSound('shoot').play(); } // Helper: check collision (circle) function circlesCollide(a, b) { var dx = a.x - b.x; var dy = a.y - b.y; var dist = Math.sqrt(dx * dx + dy * dy); return dist < a.radius + b.radius - 10; } // Add background texture behind all gameplay elements var backgroundTexture = LK.getAsset('Background', { anchorX: 0, anchorY: 0, x: 0, y: 0, scaleX: 2048 / 1000, scaleY: 2732 / 1024 }); game.addChild(backgroundTexture); // Add background with trees above the background texture var background = new Background(); game.addChild(background); // Initialize player player = new Player(); player.x = 2048 / 2; player.y = 2732 - 350; game.addChild(player); // Initialize covers spawnCovers(); // Start first round resetRound(); // Touch controls: drag to move, tap to shoot game.down = function (x, y, obj) { if (gameState !== 'playing') return; // If touch is on player, start dragging var dx = x - player.x; var dy = y - player.y; if (dx * dx + dy * dy < player.radius * player.radius) { dragging = true; dragOffsetX = player.x - x; dragOffsetY = player.y - y; } else { // Else, shoot if possible if (!player.isReloading && player.ammo > 0 && player.alive) { var now = LK.ticks; if (now - player.lastShotTick >= player.shootCooldown) { shootBullet(player, x, y, 'player'); player.ammo--; player.lastShotTick = now; updateAmmoUI(); if (player.ammo === 0) { player.reload(); updateAmmoUI(); } } } } lastTouchX = x; lastTouchY = y; }; game.move = function (x, y, obj) { if (gameState !== 'playing') return; if (dragging && player.alive) { // Move player, clamp to map var nx = clamp(x + dragOffsetX, player.radius, 2048 - player.radius); var ny = clamp(y + dragOffsetY, player.radius, 2732 - player.radius); // Prevent moving into covers var blocked = false; for (var i = 0; i < covers.length; ++i) { if (Math.abs(nx - covers[i].x) < player.radius + covers[i].radius - 30 && Math.abs(ny - covers[i].y) < player.radius + covers[i].radius - 30) { blocked = true; break; } } if (!blocked) { player.x = nx; player.y = ny; } } lastTouchX = x; lastTouchY = y; }; game.up = function (x, y, obj) { dragging = false; }; // Main update loop game.update = function () { if (gameState === 'win' || gameState === 'lose') { roundResetTimer--; if (roundResetTimer <= 0) { if (gameState === 'win') { round++; bulletDamage += 0.5; // Increase bullet damage each round player.maxHealth += 1; // Increase player's maxHealth each round if (round > maxRounds) { LK.showYouWin(); return; } enemyCount = Math.min(6, 2 + Math.floor(round / 2)); } resetRound(); } return; } // Update player player.update(); // Update enemies for (var i = enemies.length - 1; i >= 0; --i) { var e = enemies[i]; e.update(); // Enemy shoot at player if in range and cooldown ready if (e.alive && player.alive) { var dx = player.x - e.x; var dy = player.y - e.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < 1200 && hasLineOfSight(e.x, e.y, player.x, player.y)) { var now = LK.ticks; if (now - e.lastShotTick >= e.shootCooldown) { // Add aim error var angle = Math.atan2(dy, dx) + (Math.random() - 0.5) * e.aimError; var tx = e.x + Math.cos(angle) * 2000; var ty = e.y + Math.sin(angle) * 2000; shootBullet(e, tx, ty, 'enemy'); e.lastShotTick = now; } } } } // Update bullets for (var i = bullets.length - 1; i >= 0; --i) { var b = bullets[i]; b.update(); // Remove if out of bounds or too old if (b.x < -100 || b.x > 2148 || b.y < -100 || b.y > 2832 || b.age > b.lifetime) { b.destroy(); bullets.splice(i, 1); continue; } // Check collision with covers var hitCover = false; for (var j = 0; j < covers.length; ++j) { if (circlesCollide(b, covers[j])) { hitCover = true; break; } } if (hitCover) { b.destroy(); bullets.splice(i, 1); continue; } // Check collision with enemies if (b.owner === 'player') { for (var j = 0; j < enemies.length; ++j) { var e = enemies[j]; if (e.alive && circlesCollide(b, e)) { e.takeDamage(b.damage); b.destroy(); bullets.splice(i, 1); break; } } } // Check collision with player if (b.owner === 'enemy' && player.alive && circlesCollide(b, player)) { player.takeDamage(b.damage); updateHealthUI(); b.destroy(); bullets.splice(i, 1); if (!player.alive) { gameState = 'lose'; roundResetTimer = 90; LK.effects.flashScreen(0xff0000, 800); LK.showGameOver(); } break; } } // Remove dead enemies for (var i = enemies.length - 1; i >= 0; --i) { if (!enemies[i].alive && enemies[i].alpha <= 0.01) { enemies[i].destroy(); enemies.splice(i, 1); } } // Update health pickups for (var i = healthPickups.length - 1; i >= 0; --i) { var hp = healthPickups[i]; if (player.alive && circlesCollide(player, hp)) { player.heal(hp.healAmount); updateHealthUI(); LK.getSound('pickup').play(); hp.destroy(); healthPickups.splice(i, 1); } } // Win condition: all enemies dead var allDead = true; for (var i = 0; i < enemies.length; ++i) { if (enemies[i].alive) { allDead = false; break; } } if (allDead && gameState === 'playing') { gameState = 'win'; roundResetTimer = 60; LK.effects.flashScreen(0x3be14d, 600); } // Update UI updateAmmoUI(); }; /* End of game code */
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Background class for trees
var Background = Container.expand(function () {
var self = Container.call(this);
// Place fewer trees at new positions
var treePositions = [
// Top left
{
x: 300,
y: 300
},
// Top right
{
x: 2048 - 300,
y: 320
},
// Bottom left
{
x: 350,
y: 2732 - 320
},
// Bottom right
{
x: 2048 - 350,
y: 2732 - 300
},
// Center left
{
x: 500,
y: 1366
},
// Center right
{
x: 2048 - 500,
y: 1366
},
// Center
{
x: 1024,
y: 900
}, {
x: 1024,
y: 2000
}];
for (var i = 0; i < treePositions.length; ++i) {
var pos = treePositions[i];
var tree = self.attachAsset('Tree', {
anchorX: 0.5,
anchorY: 1,
x: pos.x,
y: pos.y + 110,
scaleX: 1 + Math.random() * 0.2,
scaleY: 1 + Math.random() * 0.2
});
}
return self;
});
// Bullet class
var Bullet = Container.expand(function () {
var self = Container.call(this);
var sprite = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = 20;
self.speed = 48;
self.dx = 0;
self.dy = 0;
self.owner = null; // 'player' or 'enemy'
self.damage = 1;
self.lifetime = 60; // frames
self.age = 0;
self.update = function () {
self.x += self.dx;
self.y += self.dy;
self.age++;
};
return self;
});
// Cover class
var Cover = Container.expand(function () {
var self = Container.call(this);
var sprite = self.attachAsset('cover', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = 100;
return self;
});
// Enemy class
var Enemy = Container.expand(function () {
var self = Container.call(this);
var sprite = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
// Add gun sprite to enemy hand (pistol texture)
var gun = self.attachAsset('pistol', {
anchorX: 0.1,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 1.0
});
gun.y = 20; // offset to hand
gun.x = 40; // offset to right hand
self.radius = 60;
self.speed = 5 + Math.random() * 2;
self.maxHealth = 3;
self.health = self.maxHealth;
self.shootCooldown = 40 + Math.floor(Math.random() * 20);
self.lastShotTick = -100;
self.target = null;
self.alive = true;
self.aimError = 0.2 + Math.random() * 0.2; // radians
self.takeDamage = function (amount) {
if (!self.alive) return;
self.health -= amount;
LK.getSound('hit').play();
if (self.health <= 0) {
self.health = 0;
self.die();
}
};
self.die = function () {
self.alive = false;
LK.getSound('enemy_down').play();
tween(self, {
alpha: 0
}, {
duration: 400,
onFinish: function onFinish() {
self.visible = false;
}
});
};
self.update = function () {
if (!self.alive) return;
// Move towards player if not too close
if (self.target && self.target.alive) {
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 300) {
var moveX = dx / dist * self.speed;
var moveY = dy / dist * self.speed;
// Check for cover collision
var blocked = false;
for (var i = 0; i < covers.length; ++i) {
if (self.intersects(covers[i])) {
blocked = true;
break;
}
}
if (!blocked) {
self.x += moveX;
self.y += moveY;
}
}
}
// Rotate gun towards player if alive
if (self.target && self.target.alive) {
var dxg = self.target.x - self.x;
var dyg = self.target.y - self.y;
gun.rotation = Math.atan2(dyg, dxg);
}
};
return self;
});
// Health pickup class
var HealthPickup = Container.expand(function () {
var self = Container.call(this);
var sprite = self.attachAsset('health', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = 30;
self.healAmount = 2;
return self;
});
// Player class
var Player = Container.expand(function () {
var self = Container.call(this);
var sprite = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
// Add gun sprite (pistol texture)
var gun = self.attachAsset('pistol', {
anchorX: 0.1,
// grip of gun at hand
anchorY: 0.5,
scaleX: 1.0,
scaleY: 1.0
});
gun.y = 20; // offset to hand
gun.x = 40; // offset to right hand
self.radius = 60;
self.speed = 9;
self.maxHealth = 100;
self.health = self.maxHealth;
self.ammo = 6;
self.maxAmmo = 6;
self.reloadTime = 60; // frames
self.reloadCounter = 0;
self.isReloading = false;
self.lastShotTick = -100;
self.shootCooldown = 6; // frames (0.1 seconds at 60FPS)
self.alive = true;
self.takeDamage = function (amount) {
if (!self.alive) return;
self.health -= amount;
LK.getSound('hit').play();
if (self.health <= 0) {
self.health = 0;
self.die();
}
};
self.die = function () {
self.alive = false;
LK.getSound('player_down').play();
tween(self, {
alpha: 0
}, {
duration: 400,
onFinish: function onFinish() {
self.visible = false;
}
});
};
self.heal = function (amount) {
self.health += amount;
if (self.health > self.maxHealth) self.health = self.maxHealth;
};
self.reload = function () {
if (self.isReloading || self.ammo === self.maxAmmo) return;
self.isReloading = true;
self.reloadCounter = self.reloadTime;
};
self.update = function () {
if (!self.alive) return;
if (self.isReloading) {
self.reloadCounter--;
if (self.reloadCounter <= 0) {
self.ammo = self.maxAmmo;
self.isReloading = false;
}
}
// Rotate gun towards last aim/touch position
var dx = 0,
dy = 0;
if (typeof lastTouchX !== "undefined" && typeof lastTouchY !== "undefined") {
dx = lastTouchX - self.x;
dy = lastTouchY - self.y;
}
gun.rotation = Math.atan2(dy, dx);
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x181c24
});
/****
* Game Code
****/
// Game state variables
// Player character: blue box
// Enemy: red box
// Bullet: yellow ellipse
// Cover: dark gray box
// Health pickup: green ellipse
// Sound for shooting
// Sound for pickup
// Sound for hit
// Sound for enemy down
// Sound for player down
var player;
var enemies = [];
var bullets = [];
var covers = [];
var healthPickups = [];
var round = 1;
var maxRounds = 20; // 10 more rounds
var enemyCount = 2;
var bulletDamage = 1; // Bullet damage, increases each round
var enemyStrengthMultiplier = 1; // Multiplier for enemy health and damage
var dragging = false;
var dragOffsetX = 0;
var dragOffsetY = 0;
var aimX = 0;
var aimY = 0;
var lastTouchX = 0;
var lastTouchY = 0;
var gameState = 'playing'; // 'playing', 'win', 'lose'
var roundResetTimer = 0;
// UI
var scoreTxt = new Text2('Round 1', {
size: 90,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var healthTxt = new Text2('♥♥♥♥♥', {
size: 80,
fill: 0x3BE14D
});
healthTxt.anchor.set(0, 0);
LK.gui.topRight.addChild(healthTxt);
var ammoTxt = new Text2('Ammo: 6/6', {
size: 80,
fill: 0xFFE14D
});
ammoTxt.anchor.set(1, 0);
LK.gui.topLeft.addChild(ammoTxt);
// Helper: clamp
function clamp(val, min, max) {
if (val < min) return min;
if (val > max) return max;
return val;
}
// Helper: reset round
function resetRound() {
// Remove all objects
for (var i = 0; i < enemies.length; ++i) enemies[i].destroy();
for (var i = 0; i < bullets.length; ++i) bullets[i].destroy();
for (var i = 0; i < healthPickups.length; ++i) healthPickups[i].destroy();
enemies = [];
bullets = [];
healthPickups = [];
// Reset player
player.x = 2048 / 2;
player.y = 2732 - 350;
player.health = player.maxHealth;
player.ammo = player.maxAmmo;
player.isReloading = false;
player.reloadCounter = 0;
player.alive = true;
player.alpha = 1;
player.visible = true;
// Set enemy strength multiplier for rounds 11-20
enemyStrengthMultiplier = round > 10 ? 5 : 1;
// Spawn enemies
for (var i = 0; i < enemyCount; ++i) {
var e = new Enemy();
// If round > 10, swap to enemy2 texture
if (round > 10 && e.children && e.children.length > 0) {
// Remove old enemy sprite
e.removeChildAt(0);
// Add enemy2 sprite
var enemy2Sprite = e.attachAsset('enemy2', {
anchorX: 0.5,
anchorY: 0.5
});
// Re-add gun to hand (as second child)
var gun = e.attachAsset('pistol', {
anchorX: 0.1,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 1.0
});
gun.y = 20;
gun.x = 40;
}
// Place enemies at top of map, spread out
e.x = 400 + i * 400 + Math.random() * 100;
e.y = 400 + Math.random() * 100;
e.target = player;
// Apply 5x health for rounds 11-20
e.maxHealth = Math.floor(e.maxHealth * enemyStrengthMultiplier) + (round - 1);
e.health = e.maxHealth;
// Increase enemy damage by +1 per round
e.baseDamage = 1 + (round - 1);
// Optionally, you could also increase enemy damage or speed here if desired
enemies.push(e);
game.addChild(e);
}
// Spawn health pickups at random locations every round
var healthPickupCount = 1 + Math.floor(Math.random() * 2); // 1 or 2 per round
for (var h = 0; h < healthPickupCount; ++h) {
var hp = new HealthPickup();
// Avoid spawning too close to player start or out of bounds
var safeMargin = 150;
var px, py;
var tries = 0;
do {
px = safeMargin + Math.random() * (2048 - 2 * safeMargin);
py = safeMargin + Math.random() * (2732 - 2 * safeMargin);
tries++;
// Avoid center spawn (player start)
} while (Math.abs(px - 2048 / 2) < 200 && Math.abs(py - (2732 - 350)) < 200 && tries < 10);
hp.x = px;
hp.y = py;
healthPickups.push(hp);
game.addChild(hp);
}
// Update UI
scoreTxt.setText('Round ' + round);
updateHealthUI();
updateAmmoUI();
gameState = 'playing';
}
// Helper: update health UI
function updateHealthUI() {
var s = '';
for (var i = 0; i < player.health; ++i) s += '♥';
for (var i = player.health; i < player.maxHealth; ++i) s += '♡';
healthTxt.setText(s);
}
// Helper: update ammo UI
function updateAmmoUI() {
if (player.isReloading) {
ammoTxt.setText('Reloading...');
} else {
ammoTxt.setText('Ammo: ' + player.ammo + '/' + player.maxAmmo);
}
}
// Helper: spawn covers
function spawnCovers() {
for (var i = 0; i < covers.length; ++i) covers[i].destroy();
covers = [];
// Place 3 covers
var c1 = new Cover();
c1.x = 2048 / 2;
c1.y = 1200;
covers.push(c1);
game.addChild(c1);
var c2 = new Cover();
c2.x = 600;
c2.y = 1800;
covers.push(c2);
game.addChild(c2);
var c3 = new Cover();
c3.x = 2048 - 600;
c3.y = 1800;
covers.push(c3);
game.addChild(c3);
}
// Helper: check line of sight (simple, ignores covers for MVP)
function hasLineOfSight(ax, ay, bx, by) {
// For MVP, always true
return true;
}
// Helper: shoot bullet
function shootBullet(from, toX, toY, owner) {
var b = new Bullet();
b.x = from.x;
b.y = from.y;
var dx = toX - from.x;
var dy = toY - from.y;
var dist = Math.sqrt(dx * dx + dy * dy);
b.dx = dx / dist * b.speed;
b.dy = dy / dist * b.speed;
b.owner = owner;
b.rotation = Math.atan2(dy, dx);
// Set bullet damage based on round
if (owner === 'enemy' && from.baseDamage !== undefined) {
b.damage = from.baseDamage;
} else {
b.damage = bulletDamage;
}
bullets.push(b);
game.addChild(b);
LK.getSound('shoot').play();
}
// Helper: check collision (circle)
function circlesCollide(a, b) {
var dx = a.x - b.x;
var dy = a.y - b.y;
var dist = Math.sqrt(dx * dx + dy * dy);
return dist < a.radius + b.radius - 10;
}
// Add background texture behind all gameplay elements
var backgroundTexture = LK.getAsset('Background', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
scaleX: 2048 / 1000,
scaleY: 2732 / 1024
});
game.addChild(backgroundTexture);
// Add background with trees above the background texture
var background = new Background();
game.addChild(background);
// Initialize player
player = new Player();
player.x = 2048 / 2;
player.y = 2732 - 350;
game.addChild(player);
// Initialize covers
spawnCovers();
// Start first round
resetRound();
// Touch controls: drag to move, tap to shoot
game.down = function (x, y, obj) {
if (gameState !== 'playing') return;
// If touch is on player, start dragging
var dx = x - player.x;
var dy = y - player.y;
if (dx * dx + dy * dy < player.radius * player.radius) {
dragging = true;
dragOffsetX = player.x - x;
dragOffsetY = player.y - y;
} else {
// Else, shoot if possible
if (!player.isReloading && player.ammo > 0 && player.alive) {
var now = LK.ticks;
if (now - player.lastShotTick >= player.shootCooldown) {
shootBullet(player, x, y, 'player');
player.ammo--;
player.lastShotTick = now;
updateAmmoUI();
if (player.ammo === 0) {
player.reload();
updateAmmoUI();
}
}
}
}
lastTouchX = x;
lastTouchY = y;
};
game.move = function (x, y, obj) {
if (gameState !== 'playing') return;
if (dragging && player.alive) {
// Move player, clamp to map
var nx = clamp(x + dragOffsetX, player.radius, 2048 - player.radius);
var ny = clamp(y + dragOffsetY, player.radius, 2732 - player.radius);
// Prevent moving into covers
var blocked = false;
for (var i = 0; i < covers.length; ++i) {
if (Math.abs(nx - covers[i].x) < player.radius + covers[i].radius - 30 && Math.abs(ny - covers[i].y) < player.radius + covers[i].radius - 30) {
blocked = true;
break;
}
}
if (!blocked) {
player.x = nx;
player.y = ny;
}
}
lastTouchX = x;
lastTouchY = y;
};
game.up = function (x, y, obj) {
dragging = false;
};
// Main update loop
game.update = function () {
if (gameState === 'win' || gameState === 'lose') {
roundResetTimer--;
if (roundResetTimer <= 0) {
if (gameState === 'win') {
round++;
bulletDamage += 0.5; // Increase bullet damage each round
player.maxHealth += 1; // Increase player's maxHealth each round
if (round > maxRounds) {
LK.showYouWin();
return;
}
enemyCount = Math.min(6, 2 + Math.floor(round / 2));
}
resetRound();
}
return;
}
// Update player
player.update();
// Update enemies
for (var i = enemies.length - 1; i >= 0; --i) {
var e = enemies[i];
e.update();
// Enemy shoot at player if in range and cooldown ready
if (e.alive && player.alive) {
var dx = player.x - e.x;
var dy = player.y - e.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < 1200 && hasLineOfSight(e.x, e.y, player.x, player.y)) {
var now = LK.ticks;
if (now - e.lastShotTick >= e.shootCooldown) {
// Add aim error
var angle = Math.atan2(dy, dx) + (Math.random() - 0.5) * e.aimError;
var tx = e.x + Math.cos(angle) * 2000;
var ty = e.y + Math.sin(angle) * 2000;
shootBullet(e, tx, ty, 'enemy');
e.lastShotTick = now;
}
}
}
}
// Update bullets
for (var i = bullets.length - 1; i >= 0; --i) {
var b = bullets[i];
b.update();
// Remove if out of bounds or too old
if (b.x < -100 || b.x > 2148 || b.y < -100 || b.y > 2832 || b.age > b.lifetime) {
b.destroy();
bullets.splice(i, 1);
continue;
}
// Check collision with covers
var hitCover = false;
for (var j = 0; j < covers.length; ++j) {
if (circlesCollide(b, covers[j])) {
hitCover = true;
break;
}
}
if (hitCover) {
b.destroy();
bullets.splice(i, 1);
continue;
}
// Check collision with enemies
if (b.owner === 'player') {
for (var j = 0; j < enemies.length; ++j) {
var e = enemies[j];
if (e.alive && circlesCollide(b, e)) {
e.takeDamage(b.damage);
b.destroy();
bullets.splice(i, 1);
break;
}
}
}
// Check collision with player
if (b.owner === 'enemy' && player.alive && circlesCollide(b, player)) {
player.takeDamage(b.damage);
updateHealthUI();
b.destroy();
bullets.splice(i, 1);
if (!player.alive) {
gameState = 'lose';
roundResetTimer = 90;
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
}
break;
}
}
// Remove dead enemies
for (var i = enemies.length - 1; i >= 0; --i) {
if (!enemies[i].alive && enemies[i].alpha <= 0.01) {
enemies[i].destroy();
enemies.splice(i, 1);
}
}
// Update health pickups
for (var i = healthPickups.length - 1; i >= 0; --i) {
var hp = healthPickups[i];
if (player.alive && circlesCollide(player, hp)) {
player.heal(hp.healAmount);
updateHealthUI();
LK.getSound('pickup').play();
hp.destroy();
healthPickups.splice(i, 1);
}
}
// Win condition: all enemies dead
var allDead = true;
for (var i = 0; i < enemies.length; ++i) {
if (enemies[i].alive) {
allDead = false;
break;
}
}
if (allDead && gameState === 'playing') {
gameState = 'win';
roundResetTimer = 60;
LK.effects.flashScreen(0x3be14d, 600);
}
// Update UI
updateAmmoUI();
};
/* End of game code */
a man's head's behind. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
DEMON. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
deagle with a supressor . No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
3d wood container. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
top-down grass . No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
change color with neon green
change skin color to Dark Blue
bullet. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat