/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Bullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 15; self.damage = 25; self.targetX = 0; self.targetY = 0; self.directionX = 0; self.directionY = 0; self.setTarget = function (x, y) { self.targetX = x; self.targetY = y; var dx = x - self.x; var dy = y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); self.directionX = dx / distance; self.directionY = dy / distance; }; self.update = function () { self.x += self.directionX * self.speed; self.y += self.directionY * self.speed; }; return self; }); var Cover = Container.expand(function () { var self = Container.call(this); var coverGraphics = self.attachAsset('cover', { anchorX: 0.5, anchorY: 0.5 }); return self; }); var Enemy = Container.expand(function () { var self = Container.call(this); var enemyGraphics = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); self.health = 20; self.speed = 2; self.damage = 15; self.lastAttack = 0; self.attackCooldown = 120; // 2 seconds at 60fps self.targetX = Math.random() * 2048; self.targetY = Math.random() * 2732; self.changeTargetTime = LK.ticks + Math.random() * 180; // Change direction every 1-3 seconds self.takeDamage = function (damage) { self.health -= damage; if (self.health <= 0) { return true; // enemy died } return false; }; self.update = function () { // Change movement target periodically if (LK.ticks > self.changeTargetTime) { self.targetX = Math.random() * 2048; self.targetY = Math.random() * 2732; self.changeTargetTime = LK.ticks + Math.random() * 180; } // Move towards target var dx = self.targetX - self.x; var dy = self.targetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 10) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; } // Attack player if close enough var playerDistance = Math.sqrt((player.x - self.x) * (player.x - self.x) + (player.y - self.y) * (player.y - self.y)); if (playerDistance < 200 && LK.ticks - self.lastAttack > self.attackCooldown) { self.lastAttack = LK.ticks; var playerDied = player.takeDamage(self.damage); if (playerDied) { gameOver = true; } LK.getSound('playerHit').play(); LK.effects.flashObject(player, 0xff0000, 500); } }; return self; }); var Player = Container.expand(function () { var self = Container.call(this); var playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); self.health = 100; self.maxHealth = 100; self.ammo = 30; self.maxAmmo = 30; self.lastShot = 0; self.shootCooldown = 200; // milliseconds self.ammoRegenTime = 0; self.ammoRegenDelay = 2000; // 2 seconds self.takeDamage = function (damage) { self.health -= damage; if (self.health <= 0) { self.health = 0; return true; // player died } return false; }; self.canShoot = function () { return self.ammo > 0 && LK.ticks - self.lastShot > self.shootCooldown / 16.67; }; self.shoot = function () { if (self.canShoot()) { self.ammo--; self.lastShot = LK.ticks; self.ammoRegenTime = LK.ticks + self.ammoRegenDelay / 16.67; return true; } return false; }; self.update = function () { // Regenerate ammo after delay if (self.ammo < self.maxAmmo && LK.ticks > self.ammoRegenTime) { if (LK.ticks % 30 === 0) { // Regenerate every half second self.ammo++; } } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x2d4a2b }); /**** * Game Code ****/ var player; var enemies = []; var bullets = []; var covers = []; var dragNode = null; var gameOver = false; var currentWave = 1; var enemiesKilled = 0; var waveEnemiesCount = 3; var waveInProgress = false; // UI Elements var healthBarBg = LK.getAsset('healthBar', { x: 100, y: 100, scaleX: 1, scaleY: 1, alpha: 0.3 }); var healthBarFill = LK.getAsset('healthBar', { x: 100, y: 100, scaleX: 1, scaleY: 1 }); var ammoBarBg = LK.getAsset('ammoBar', { x: 100, y: 150, scaleX: 1, scaleY: 1, alpha: 0.3 }); var ammoBarFill = LK.getAsset('ammoBar', { x: 100, y: 150, scaleX: 1, scaleY: 1 }); game.addChild(healthBarBg); game.addChild(healthBarFill); game.addChild(ammoBarBg); game.addChild(ammoBarFill); var waveText = new Text2('Wave: 1', { size: 80, fill: 0xFFFFFF }); waveText.anchor.set(0.5, 0); LK.gui.top.addChild(waveText); var scoreText = new Text2('Score: 0', { size: 60, fill: 0xFFFFFF }); scoreText.anchor.set(1, 0); LK.gui.topRight.addChild(scoreText); // Add mobile control hints var controlHint = new Text2('Drag player to move • Tap to shoot', { size: 40, fill: 0xCCCCCC }); controlHint.anchor.set(0.5, 1); LK.gui.bottom.addChild(controlHint); // Position control hint slightly above bottom controlHint.y = -50; // Initialize player player = game.addChild(new Player()); player.x = 1024; player.y = 2000; // Create cover objects for (var i = 0; i < 12; i++) { var cover = game.addChild(new Cover()); // Create 3 rows of 4 covers with more spacing and random positioning var row = Math.floor(i / 4); var col = i % 4; cover.x = 300 + col * 500 + Math.random() * 150 - 75; // More spacing between columns with random offset cover.y = 700 + row * 650 + Math.random() * 250 - 125; // More spacing between rows with random offset covers.push(cover); } function spawnWave() { waveInProgress = true; var enemiesToSpawn = waveEnemiesCount * 2 + (currentWave - 1) * 2; for (var i = 0; i < enemiesToSpawn; i++) { var enemy = game.addChild(new Enemy()); enemy.x = Math.random() * 2048; enemy.y = Math.random() * 800; // Spawn in upper part of screen enemy.health += (currentWave - 1) * 5; // Increase health each wave enemy.speed += (currentWave - 1) * 0.5; // Increase speed each wave enemies.push(enemy); } waveText.setText('Wave: ' + currentWave); } function updateUI() { // Update health bar var healthPercent = player.health / player.maxHealth; healthBarFill.scaleX = healthPercent; // Update ammo bar var ammoPercent = player.ammo / player.maxAmmo; ammoBarFill.scaleX = ammoPercent; // Update score scoreText.setText('Score: ' + LK.getScore()); } function handleMove(x, y, obj) { // Update mouse position for keyboard shooting mousePosition.x = x; mousePosition.y = y; if (dragNode && !gameOver) { // Store original position var originalX = dragNode.x; var originalY = dragNode.y; // Try to move to new position dragNode.x = x; dragNode.y = y; // Check collision with cover objects var collisionDetected = false; for (var i = 0; i < covers.length; i++) { if (dragNode.intersects(covers[i])) { collisionDetected = true; break; } } // Keep player within screen bounds if (dragNode.x < 87.5 || dragNode.x > 1960.5 || dragNode.y < 87.5 || dragNode.y > 2644.5) { collisionDetected = true; } // If collision detected, revert to original position if (collisionDetected) { dragNode.x = originalX; dragNode.y = originalY; } } } game.move = handleMove; // Keyboard state tracking var keysPressed = {}; var mousePosition = { x: 1024, y: 1366 }; // Add keyboard event listeners LK.on('keydown', function (event) { keysPressed[event.key.toLowerCase()] = true; }); LK.on('keyup', function (event) { keysPressed[event.key.toLowerCase()] = false; }); // Track mouse position for shooting LK.on('mousemove', function (event) { mousePosition.x = event.x; mousePosition.y = event.y; }); game.down = function (x, y, obj) { if (gameOver) return; // Update mouse position for shooting mousePosition.x = x; mousePosition.y = y; // Check if clicking on player for dragging var playerDistance = Math.sqrt((player.x - x) * (player.x - x) + (player.y - y) * (player.y - y)); if (playerDistance < 50) { dragNode = player; handleMove(x, y, obj); } else { // Shoot at clicked location if (player.shoot()) { var bullet = game.addChild(new Bullet()); bullet.x = player.x; bullet.y = player.y; bullet.setTarget(x, y); bullets.push(bullet); LK.getSound('shoot').play(); } } }; game.up = function (x, y, obj) { dragNode = null; }; // Start first wave spawnWave(); game.update = function () { if (gameOver) return; // Handle keyboard movement (WASD) var moveSpeed = 8; var originalX = player.x; var originalY = player.y; var moved = false; if (keysPressed['w'] || keysPressed['arrowup']) { player.y -= moveSpeed; moved = true; } if (keysPressed['s'] || keysPressed['arrowdown']) { player.y += moveSpeed; moved = true; } if (keysPressed['a'] || keysPressed['arrowleft']) { player.x -= moveSpeed; moved = true; } if (keysPressed['d'] || keysPressed['arrowright']) { player.x += moveSpeed; moved = true; } // Check collision with cover objects if player moved if (moved) { var collisionDetected = false; for (var i = 0; i < covers.length; i++) { if (player.intersects(covers[i])) { collisionDetected = true; break; } } // Keep player within screen bounds if (player.x < 87.5 || player.x > 1960.5 || player.y < 87.5 || player.y > 2644.5) { collisionDetected = true; } // If collision detected, revert to original position if (collisionDetected) { player.x = originalX; player.y = originalY; } } // Handle keyboard shooting (spacebar) if (keysPressed[' '] && player.canShoot()) { if (player.shoot()) { var bullet = game.addChild(new Bullet()); bullet.x = player.x; bullet.y = player.y; bullet.setTarget(mousePosition.x, mousePosition.y); bullets.push(bullet); LK.getSound('shoot').play(); } } // Update bullets for (var i = bullets.length - 1; i >= 0; i--) { var bullet = bullets[i]; // Check if bullet is off screen if (bullet.x < -50 || bullet.x > 2098 || bullet.y < -50 || bullet.y > 2782) { bullet.destroy(); bullets.splice(i, 1); continue; } // Check bullet-enemy collisions var bulletHit = false; for (var j = enemies.length - 1; j >= 0; j--) { var enemy = enemies[j]; if (bullet.intersects(enemy)) { var enemyDied = enemy.takeDamage(bullet.damage); if (enemyDied) { LK.setScore(LK.getScore() + 10); enemiesKilled++; LK.effects.flashObject(enemy, 0xffffff, 300); enemy.destroy(); enemies.splice(j, 1); } LK.getSound('enemyHit').play(); bullet.destroy(); bullets.splice(i, 1); bulletHit = true; break; } } if (bulletHit) continue; // Check bullet-cover collisions for (var k = covers.length - 1; k >= 0; k--) { var cover = covers[k]; if (bullet.intersects(cover)) { bullet.destroy(); bullets.splice(i, 1); bulletHit = true; break; } } if (bulletHit) continue; } // Check if wave is complete if (waveInProgress && enemies.length === 0) { waveInProgress = false; currentWave++; // Restore some health and ammo between waves player.health = Math.min(player.maxHealth, player.health + 20); player.ammo = Math.min(player.maxAmmo, player.ammo + 10); // Start next wave after delay LK.setTimeout(function () { if (!gameOver) { spawnWave(); } }, 2000); } // Check for game over conditions if (player.health <= 0) { gameOver = true; LK.showGameOver(); } // Check for win condition (survive 10 waves) if (currentWave > 10 && enemies.length === 0) { LK.showYouWin(); } updateUI(); };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 15;
self.damage = 25;
self.targetX = 0;
self.targetY = 0;
self.directionX = 0;
self.directionY = 0;
self.setTarget = function (x, y) {
self.targetX = x;
self.targetY = y;
var dx = x - self.x;
var dy = y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
self.directionX = dx / distance;
self.directionY = dy / distance;
};
self.update = function () {
self.x += self.directionX * self.speed;
self.y += self.directionY * self.speed;
};
return self;
});
var Cover = Container.expand(function () {
var self = Container.call(this);
var coverGraphics = self.attachAsset('cover', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 20;
self.speed = 2;
self.damage = 15;
self.lastAttack = 0;
self.attackCooldown = 120; // 2 seconds at 60fps
self.targetX = Math.random() * 2048;
self.targetY = Math.random() * 2732;
self.changeTargetTime = LK.ticks + Math.random() * 180; // Change direction every 1-3 seconds
self.takeDamage = function (damage) {
self.health -= damage;
if (self.health <= 0) {
return true; // enemy died
}
return false;
};
self.update = function () {
// Change movement target periodically
if (LK.ticks > self.changeTargetTime) {
self.targetX = Math.random() * 2048;
self.targetY = Math.random() * 2732;
self.changeTargetTime = LK.ticks + Math.random() * 180;
}
// Move towards target
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 10) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
// Attack player if close enough
var playerDistance = Math.sqrt((player.x - self.x) * (player.x - self.x) + (player.y - self.y) * (player.y - self.y));
if (playerDistance < 200 && LK.ticks - self.lastAttack > self.attackCooldown) {
self.lastAttack = LK.ticks;
var playerDied = player.takeDamage(self.damage);
if (playerDied) {
gameOver = true;
}
LK.getSound('playerHit').play();
LK.effects.flashObject(player, 0xff0000, 500);
}
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 100;
self.maxHealth = 100;
self.ammo = 30;
self.maxAmmo = 30;
self.lastShot = 0;
self.shootCooldown = 200; // milliseconds
self.ammoRegenTime = 0;
self.ammoRegenDelay = 2000; // 2 seconds
self.takeDamage = function (damage) {
self.health -= damage;
if (self.health <= 0) {
self.health = 0;
return true; // player died
}
return false;
};
self.canShoot = function () {
return self.ammo > 0 && LK.ticks - self.lastShot > self.shootCooldown / 16.67;
};
self.shoot = function () {
if (self.canShoot()) {
self.ammo--;
self.lastShot = LK.ticks;
self.ammoRegenTime = LK.ticks + self.ammoRegenDelay / 16.67;
return true;
}
return false;
};
self.update = function () {
// Regenerate ammo after delay
if (self.ammo < self.maxAmmo && LK.ticks > self.ammoRegenTime) {
if (LK.ticks % 30 === 0) {
// Regenerate every half second
self.ammo++;
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2d4a2b
});
/****
* Game Code
****/
var player;
var enemies = [];
var bullets = [];
var covers = [];
var dragNode = null;
var gameOver = false;
var currentWave = 1;
var enemiesKilled = 0;
var waveEnemiesCount = 3;
var waveInProgress = false;
// UI Elements
var healthBarBg = LK.getAsset('healthBar', {
x: 100,
y: 100,
scaleX: 1,
scaleY: 1,
alpha: 0.3
});
var healthBarFill = LK.getAsset('healthBar', {
x: 100,
y: 100,
scaleX: 1,
scaleY: 1
});
var ammoBarBg = LK.getAsset('ammoBar', {
x: 100,
y: 150,
scaleX: 1,
scaleY: 1,
alpha: 0.3
});
var ammoBarFill = LK.getAsset('ammoBar', {
x: 100,
y: 150,
scaleX: 1,
scaleY: 1
});
game.addChild(healthBarBg);
game.addChild(healthBarFill);
game.addChild(ammoBarBg);
game.addChild(ammoBarFill);
var waveText = new Text2('Wave: 1', {
size: 80,
fill: 0xFFFFFF
});
waveText.anchor.set(0.5, 0);
LK.gui.top.addChild(waveText);
var scoreText = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreText.anchor.set(1, 0);
LK.gui.topRight.addChild(scoreText);
// Add mobile control hints
var controlHint = new Text2('Drag player to move • Tap to shoot', {
size: 40,
fill: 0xCCCCCC
});
controlHint.anchor.set(0.5, 1);
LK.gui.bottom.addChild(controlHint);
// Position control hint slightly above bottom
controlHint.y = -50;
// Initialize player
player = game.addChild(new Player());
player.x = 1024;
player.y = 2000;
// Create cover objects
for (var i = 0; i < 12; i++) {
var cover = game.addChild(new Cover());
// Create 3 rows of 4 covers with more spacing and random positioning
var row = Math.floor(i / 4);
var col = i % 4;
cover.x = 300 + col * 500 + Math.random() * 150 - 75; // More spacing between columns with random offset
cover.y = 700 + row * 650 + Math.random() * 250 - 125; // More spacing between rows with random offset
covers.push(cover);
}
function spawnWave() {
waveInProgress = true;
var enemiesToSpawn = waveEnemiesCount * 2 + (currentWave - 1) * 2;
for (var i = 0; i < enemiesToSpawn; i++) {
var enemy = game.addChild(new Enemy());
enemy.x = Math.random() * 2048;
enemy.y = Math.random() * 800; // Spawn in upper part of screen
enemy.health += (currentWave - 1) * 5; // Increase health each wave
enemy.speed += (currentWave - 1) * 0.5; // Increase speed each wave
enemies.push(enemy);
}
waveText.setText('Wave: ' + currentWave);
}
function updateUI() {
// Update health bar
var healthPercent = player.health / player.maxHealth;
healthBarFill.scaleX = healthPercent;
// Update ammo bar
var ammoPercent = player.ammo / player.maxAmmo;
ammoBarFill.scaleX = ammoPercent;
// Update score
scoreText.setText('Score: ' + LK.getScore());
}
function handleMove(x, y, obj) {
// Update mouse position for keyboard shooting
mousePosition.x = x;
mousePosition.y = y;
if (dragNode && !gameOver) {
// Store original position
var originalX = dragNode.x;
var originalY = dragNode.y;
// Try to move to new position
dragNode.x = x;
dragNode.y = y;
// Check collision with cover objects
var collisionDetected = false;
for (var i = 0; i < covers.length; i++) {
if (dragNode.intersects(covers[i])) {
collisionDetected = true;
break;
}
}
// Keep player within screen bounds
if (dragNode.x < 87.5 || dragNode.x > 1960.5 || dragNode.y < 87.5 || dragNode.y > 2644.5) {
collisionDetected = true;
}
// If collision detected, revert to original position
if (collisionDetected) {
dragNode.x = originalX;
dragNode.y = originalY;
}
}
}
game.move = handleMove;
// Keyboard state tracking
var keysPressed = {};
var mousePosition = {
x: 1024,
y: 1366
};
// Add keyboard event listeners
LK.on('keydown', function (event) {
keysPressed[event.key.toLowerCase()] = true;
});
LK.on('keyup', function (event) {
keysPressed[event.key.toLowerCase()] = false;
});
// Track mouse position for shooting
LK.on('mousemove', function (event) {
mousePosition.x = event.x;
mousePosition.y = event.y;
});
game.down = function (x, y, obj) {
if (gameOver) return;
// Update mouse position for shooting
mousePosition.x = x;
mousePosition.y = y;
// Check if clicking on player for dragging
var playerDistance = Math.sqrt((player.x - x) * (player.x - x) + (player.y - y) * (player.y - y));
if (playerDistance < 50) {
dragNode = player;
handleMove(x, y, obj);
} else {
// Shoot at clicked location
if (player.shoot()) {
var bullet = game.addChild(new Bullet());
bullet.x = player.x;
bullet.y = player.y;
bullet.setTarget(x, y);
bullets.push(bullet);
LK.getSound('shoot').play();
}
}
};
game.up = function (x, y, obj) {
dragNode = null;
};
// Start first wave
spawnWave();
game.update = function () {
if (gameOver) return;
// Handle keyboard movement (WASD)
var moveSpeed = 8;
var originalX = player.x;
var originalY = player.y;
var moved = false;
if (keysPressed['w'] || keysPressed['arrowup']) {
player.y -= moveSpeed;
moved = true;
}
if (keysPressed['s'] || keysPressed['arrowdown']) {
player.y += moveSpeed;
moved = true;
}
if (keysPressed['a'] || keysPressed['arrowleft']) {
player.x -= moveSpeed;
moved = true;
}
if (keysPressed['d'] || keysPressed['arrowright']) {
player.x += moveSpeed;
moved = true;
}
// Check collision with cover objects if player moved
if (moved) {
var collisionDetected = false;
for (var i = 0; i < covers.length; i++) {
if (player.intersects(covers[i])) {
collisionDetected = true;
break;
}
}
// Keep player within screen bounds
if (player.x < 87.5 || player.x > 1960.5 || player.y < 87.5 || player.y > 2644.5) {
collisionDetected = true;
}
// If collision detected, revert to original position
if (collisionDetected) {
player.x = originalX;
player.y = originalY;
}
}
// Handle keyboard shooting (spacebar)
if (keysPressed[' '] && player.canShoot()) {
if (player.shoot()) {
var bullet = game.addChild(new Bullet());
bullet.x = player.x;
bullet.y = player.y;
bullet.setTarget(mousePosition.x, mousePosition.y);
bullets.push(bullet);
LK.getSound('shoot').play();
}
}
// Update bullets
for (var i = bullets.length - 1; i >= 0; i--) {
var bullet = bullets[i];
// Check if bullet is off screen
if (bullet.x < -50 || bullet.x > 2098 || bullet.y < -50 || bullet.y > 2782) {
bullet.destroy();
bullets.splice(i, 1);
continue;
}
// Check bullet-enemy collisions
var bulletHit = false;
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (bullet.intersects(enemy)) {
var enemyDied = enemy.takeDamage(bullet.damage);
if (enemyDied) {
LK.setScore(LK.getScore() + 10);
enemiesKilled++;
LK.effects.flashObject(enemy, 0xffffff, 300);
enemy.destroy();
enemies.splice(j, 1);
}
LK.getSound('enemyHit').play();
bullet.destroy();
bullets.splice(i, 1);
bulletHit = true;
break;
}
}
if (bulletHit) continue;
// Check bullet-cover collisions
for (var k = covers.length - 1; k >= 0; k--) {
var cover = covers[k];
if (bullet.intersects(cover)) {
bullet.destroy();
bullets.splice(i, 1);
bulletHit = true;
break;
}
}
if (bulletHit) continue;
}
// Check if wave is complete
if (waveInProgress && enemies.length === 0) {
waveInProgress = false;
currentWave++;
// Restore some health and ammo between waves
player.health = Math.min(player.maxHealth, player.health + 20);
player.ammo = Math.min(player.maxAmmo, player.ammo + 10);
// Start next wave after delay
LK.setTimeout(function () {
if (!gameOver) {
spawnWave();
}
}, 2000);
}
// Check for game over conditions
if (player.health <= 0) {
gameOver = true;
LK.showGameOver();
}
// Check for win condition (survive 10 waves)
if (currentWave > 10 && enemies.length === 0) {
LK.showYouWin();
}
updateUI();
};