/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Bullet var Bullet = Container.expand(function () { var self = Container.call(this); var bulletGfx = self.attachAsset('lcd_bullet', { anchorX: 0.5, anchorY: 0.5 }); self.width = bulletGfx.width; self.height = bulletGfx.height; self.speed = 20; // px per frame self.update = function () { self.y -= self.speed; }; return self; }); // Cluster Rocket var ClusterRocket = Container.expand(function () { var self = Container.call(this); var rocketGfx = self.attachAsset('cluster_rocket', { anchorX: 0.5, anchorY: 0.5 }); self.width = rocketGfx.width; self.height = rocketGfx.height; self.speed = 12; self.hasExploded = false; self.update = function () { self.x -= self.speed; // Explode when reaching center of screen if (self.x <= GAME_W / 2 && !self.hasExploded) { self.explode(); } }; self.explode = function () { self.hasExploded = true; // Create fire fragments var fragmentCount = 8 + Math.floor(Math.random() * 4); for (var i = 0; i < fragmentCount; i++) { var fragment = new FireFragment(); fragment.x = self.x; fragment.y = self.y; var angle = Math.PI * 2 * i / fragmentCount + (Math.random() - 0.5) * 0.5; var speed = 8 + Math.random() * 6; fragment.velocityX = Math.cos(angle) * speed; fragment.velocityY = Math.sin(angle) * speed; fragment.rotationSpeed = (Math.random() - 0.5) * 0.4; fireFragments.push(fragment); game.addChild(fragment); } // Flash screen for explosion effect LK.effects.flashScreen(0xFFFF00, 200); }; return self; }); // Enemy var Enemy = Container.expand(function () { var self = Container.call(this); var enemyGfx = self.attachAsset('lcd_enemy', { anchorX: 0.5, anchorY: 0.5 }); self.width = enemyGfx.width; self.height = enemyGfx.height; self.speed = 7 + Math.random() * 3; // px per frame self.direction = 0; // 0: straight, -1: up, 1: down self.amplitude = 0; // for sine movement self.phase = Math.random() * Math.PI * 2; self.update = function () { self.x -= self.speed; if (self.amplitude) { self.y += Math.sin(LK.ticks / 12 + self.phase) * self.amplitude; } }; return self; }); // Enemy Fragment var EnemyFragment = Container.expand(function () { var self = Container.call(this); var fragmentGfx = self.attachAsset('lcd_enemy', { anchorX: 0.5, anchorY: 0.5 }); self.width = fragmentGfx.width; self.height = fragmentGfx.height; self.velocityX = 0; self.velocityY = 0; self.rotationSpeed = 0; self.gravity = 0.5; self.update = function () { self.x += self.velocityX; self.y += self.velocityY; self.velocityY += self.gravity; self.rotation += self.rotationSpeed; self.alpha -= 0.02; }; return self; }); // Fire Fragment var FireFragment = Container.expand(function () { var self = Container.call(this); var fragmentGfx = self.attachAsset('fire_fragment', { anchorX: 0.5, anchorY: 0.5 }); self.width = fragmentGfx.width; self.height = fragmentGfx.height; self.velocityX = 0; self.velocityY = 0; self.rotationSpeed = 0; self.lifetime = 180; // frames self.maxLifetime = 180; self.update = function () { self.x += self.velocityX; self.y += self.velocityY; self.rotation += self.rotationSpeed; self.lifetime--; // Fade out over time self.alpha = self.lifetime / self.maxLifetime; // Change color from yellow to red over time var t = 1 - self.lifetime / self.maxLifetime; var red = Math.floor(255); var green = Math.floor(255 * (1 - t)); var blue = 0; self.tint = red << 16 | green << 8 | blue; }; return self; }); // Player Ship var Ship = Container.expand(function () { var self = Container.call(this); var shipGfx = self.attachAsset('lcd_ship', { anchorX: 0.5, anchorY: 0.5 }); self.width = shipGfx.width; self.height = shipGfx.height; self.canShoot = true; self.shootCooldown = 18; // frames between shots // Ship flash effect on hit self.flash = function () { tween(self, { alpha: 0.2 }, { duration: 80, easing: tween.linear, onFinish: function onFinish() { tween(self, { alpha: 1 }, { duration: 120, easing: tween.linear }); } }); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Ship: white box, Enemy: white ellipse, Bullet: white box, Background: black, Accent: #A3FFB2 (LCD green). // LCD-style monochrome: use only black, white, and one accent color (e.g. greenish for LCD). // --- LCD color accent for UI --- var LCD_ACCENT = 0xA3FFB2; // --- Game constants --- var GAME_W = 2048, GAME_H = 2732; var SHIP_Y = GAME_H - 220; var ENEMY_SPAWN_Y_MIN = 220, ENEMY_SPAWN_Y_MAX = GAME_H - 600; var ENEMY_SPAWN_X = GAME_W + 120; var ENEMY_SPAWN_INTERVAL = 48; // frames var MAX_LIVES = 3; // --- Game state --- var ship; var bullets = []; var enemies = []; var fragments = []; var clusterRockets = []; var fireFragments = []; var lives = MAX_LIVES; var score = 0; var canMove = true; var lastTouchX = null; // --- UI --- var scoreTxt = new Text2('0', { size: 120, fill: 0xA3FFB2 }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); var livesContainer = new Container(); LK.gui.topRight.addChild(livesContainer); // --- Helper: update lives UI --- function updateLivesUI() { livesContainer.removeChildren(); for (var i = 0; i < lives; i++) { var life = LK.getAsset('lcd_life', { anchorX: 0.5, anchorY: 0.5 }); life.x = -i * 60 - 60; life.y = 60; livesContainer.addChild(life); } } updateLivesUI(); // --- Helper: reset game state --- function resetGame() { // Remove all bullets/enemies/fragments for (var i = 0; i < bullets.length; i++) bullets[i].destroy(); for (var i = 0; i < enemies.length; i++) enemies[i].destroy(); for (var i = 0; i < fragments.length; i++) fragments[i].destroy(); for (var i = 0; i < clusterRockets.length; i++) clusterRockets[i].destroy(); for (var i = 0; i < fireFragments.length; i++) fireFragments[i].destroy(); bullets = []; enemies = []; fragments = []; clusterRockets = []; fireFragments = []; lives = MAX_LIVES; score = 0; scoreTxt.setText(score); updateLivesUI(); canMove = true; // Place ship if (ship) ship.destroy(); ship = new Ship(); ship.x = 320; ship.y = SHIP_Y; game.addChild(ship); } resetGame(); // --- Touch controls: drag ship horizontally --- game.down = function (x, y, obj) { if (!canMove) return; // Only allow drag if touch is in lower 1/3 of screen if (y > GAME_H * 0.6) { lastTouchX = x; } }; game.move = function (x, y, obj) { if (!canMove) return; if (lastTouchX !== null) { // Clamp ship to screen var newX = Math.max(ship.width / 2, Math.min(GAME_W - ship.width / 2, x)); // Stop any existing tween on ship position tween.stop(ship, { x: true }); // Smoothly tween ship to new position tween(ship, { x: newX }, { duration: 800, easing: tween.easeOut }); } }; game.up = function (x, y, obj) { lastTouchX = null; }; // --- Ship auto-fire --- var shootTimer = 0; function tryShoot() { if (!canMove) return; if (shootTimer > 0) { shootTimer--; return; } // Fire bullet var bullet = new Bullet(); bullet.x = ship.x; bullet.y = ship.y - ship.height / 2 - bullet.height / 2 - 10; bullets.push(bullet); game.addChild(bullet); shootTimer = ship.shootCooldown; } // --- Enemy spawn --- var enemySpawnTimer = 0; function spawnEnemy() { var enemy = new Enemy(); enemy.x = ENEMY_SPAWN_X; // Random Y within play area enemy.y = ENEMY_SPAWN_Y_MIN + Math.random() * (ENEMY_SPAWN_Y_MAX - ENEMY_SPAWN_Y_MIN); // Some enemies move in sine wave if (Math.random() < 0.4) { enemy.amplitude = 6 + Math.random() * 18; } enemies.push(enemy); game.addChild(enemy); } // --- Cluster rocket spawn --- var rocketSpawnTimer = 0; function spawnClusterRocket() { var rocket = new ClusterRocket(); rocket.x = ENEMY_SPAWN_X; rocket.y = ENEMY_SPAWN_Y_MIN + Math.random() * (ENEMY_SPAWN_Y_MAX - ENEMY_SPAWN_Y_MIN); clusterRockets.push(rocket); game.addChild(rocket); } // --- Main update loop --- game.update = function () { // --- Ship auto-fire --- tryShoot(); // --- Bullets update --- for (var i = bullets.length - 1; i >= 0; i--) { var b = bullets[i]; b.update(); // Remove if off screen if (b.y < -b.height) { b.destroy(); bullets.splice(i, 1); continue; } // Check collision with enemies for (var j = enemies.length - 1; j >= 0; j--) { var e = enemies[j]; if (b.intersects(e)) { // Create enemy fragments var fragmentCount = 4 + Math.floor(Math.random() * 3); for (var f = 0; f < fragmentCount; f++) { var fragment = new EnemyFragment(); fragment.x = e.x + (Math.random() - 0.5) * e.width; fragment.y = e.y + (Math.random() - 0.5) * e.height; fragment.scaleX = 0.3 + Math.random() * 0.4; fragment.scaleY = 0.3 + Math.random() * 0.4; fragment.velocityX = (Math.random() - 0.5) * 15; fragment.velocityY = (Math.random() - 0.5) * 10 - 5; fragment.rotationSpeed = (Math.random() - 0.5) * 0.3; fragment.alpha = 0.8; fragments.push(fragment); game.addChild(fragment); } // Flash screen briefly for explosion effect LK.effects.flashScreen(0xFFFFFF, 100); // Play hit sound LK.getSound('123bullethitenemy').play(); // Destroy enemy and bullet e.destroy(); b.destroy(); bullets.splice(i, 1); enemies.splice(j, 1); // Score score += 1; scoreTxt.setText(score); // Small flash effect on ship LK.effects.flashObject(ship, LCD_ACCENT, 120); break; } } } // --- Fragments update --- for (var i = fragments.length - 1; i >= 0; i--) { var f = fragments[i]; f.update(); // Remove if off screen or fully transparent if (f.y > GAME_H + 100 || f.x < -100 || f.x > GAME_W + 100 || f.alpha <= 0) { f.destroy(); fragments.splice(i, 1); } } // --- Enemies update --- for (var i = enemies.length - 1; i >= 0; i--) { var e = enemies[i]; e.update(); // Remove if off screen if (e.x < -e.width) { e.destroy(); enemies.splice(i, 1); continue; } // Check collision with ship if (e.intersects(ship)) { // Ship hit! e.destroy(); enemies.splice(i, 1); lives--; updateLivesUI(); ship.flash(); canMove = false; // Flash screen LK.effects.flashScreen(0xffffff, 200); // After short delay, allow movement again or game over LK.setTimeout(function () { if (lives <= 0) { // Game over LK.showGameOver(); } else { canMove = true; } }, 600); break; } } // --- Cluster rockets update --- for (var i = clusterRockets.length - 1; i >= 0; i--) { var r = clusterRockets[i]; r.update(); // Remove if off screen or exploded if (r.x < -r.width || r.hasExploded) { r.destroy(); clusterRockets.splice(i, 1); continue; } // Check collision with ship if (r.intersects(ship)) { r.explode(); lives--; updateLivesUI(); ship.flash(); canMove = false; // Flash screen LK.effects.flashScreen(0xFFFF00, 300); // After short delay, allow movement again or game over LK.setTimeout(function () { if (lives <= 0) { // Game over LK.showGameOver(); } else { canMove = true; } }, 600); break; } } // --- Fire fragments update --- for (var i = fireFragments.length - 1; i >= 0; i--) { var f = fireFragments[i]; f.update(); // Remove if lifetime expired or off screen if (f.lifetime <= 0 || f.y > GAME_H + 100 || f.x < -100 || f.x > GAME_W + 100) { f.destroy(); fireFragments.splice(i, 1); continue; } // Check collision with ship if (f.intersects(ship)) { f.destroy(); fireFragments.splice(i, 1); lives--; updateLivesUI(); ship.flash(); canMove = false; // Flash screen LK.effects.flashScreen(0xFF4500, 200); // After short delay, allow movement again or game over LK.setTimeout(function () { if (lives <= 0) { // Game over LK.showGameOver(); } else { canMove = true; } }, 600); break; } } // --- Enemy spawn --- enemySpawnTimer--; if (enemySpawnTimer <= 0) { spawnEnemy(); // Faster spawn as score increases var minInterval = 18; var interval = Math.max(minInterval, ENEMY_SPAWN_INTERVAL - Math.floor(score / 8) * 4); enemySpawnTimer = interval + Math.floor(Math.random() * 12); } // --- Cluster rocket spawn --- rocketSpawnTimer--; if (rocketSpawnTimer <= 0) { spawnClusterRocket(); // Spawn rockets less frequently than enemies rocketSpawnTimer = 300 + Math.floor(Math.random() * 200); } }; // --- Center score text --- scoreTxt.setText(score); scoreTxt.anchor.set(0.5, 0); scoreTxt.x = 0; // LK.gui.top is centered horizontally // --- LCD-style background (monochrome rectangle) --- function addBackground() { // Use the background asset at its native resolution, then scale up to fit the game area to avoid blur var bg = LK.getAsset('background', { anchorX: 0.5, anchorY: 0.5, x: GAME_W / 2, y: GAME_H / 2 }); // Calculate scale factors to fit the game area var scaleX = GAME_W / bg.width; var scaleY = GAME_H / bg.height; bg.scaleX = scaleX; bg.scaleY = scaleY; game.addChildAt(bg, 0); // Ensure background is at the bottom layer // LCD accent border (use a shape asset for a crisp border) var border = LK.getAsset('lcd_life', { width: GAME_W - 120, height: GAME_H - 120, color: LCD_ACCENT, shape: 'box', anchorX: 0.5, anchorY: 0.5 }); border.alpha = 0.08; border.x = GAME_W / 2; border.y = GAME_H / 2; game.addChildAt(border, 1); } addBackground(); // --- Play background music --- LK.playMusic('1alarmofwar'); // --- On game over, reset state --- LK.on('gameover', function () { LK.stopMusic(); resetGame(); }); // --- On you win (not used, but for completeness) --- LK.on('youwin', function () { LK.stopMusic(); resetGame(); });
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Bullet
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletGfx = self.attachAsset('lcd_bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = bulletGfx.width;
self.height = bulletGfx.height;
self.speed = 20; // px per frame
self.update = function () {
self.y -= self.speed;
};
return self;
});
// Cluster Rocket
var ClusterRocket = Container.expand(function () {
var self = Container.call(this);
var rocketGfx = self.attachAsset('cluster_rocket', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = rocketGfx.width;
self.height = rocketGfx.height;
self.speed = 12;
self.hasExploded = false;
self.update = function () {
self.x -= self.speed;
// Explode when reaching center of screen
if (self.x <= GAME_W / 2 && !self.hasExploded) {
self.explode();
}
};
self.explode = function () {
self.hasExploded = true;
// Create fire fragments
var fragmentCount = 8 + Math.floor(Math.random() * 4);
for (var i = 0; i < fragmentCount; i++) {
var fragment = new FireFragment();
fragment.x = self.x;
fragment.y = self.y;
var angle = Math.PI * 2 * i / fragmentCount + (Math.random() - 0.5) * 0.5;
var speed = 8 + Math.random() * 6;
fragment.velocityX = Math.cos(angle) * speed;
fragment.velocityY = Math.sin(angle) * speed;
fragment.rotationSpeed = (Math.random() - 0.5) * 0.4;
fireFragments.push(fragment);
game.addChild(fragment);
}
// Flash screen for explosion effect
LK.effects.flashScreen(0xFFFF00, 200);
};
return self;
});
// Enemy
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGfx = self.attachAsset('lcd_enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = enemyGfx.width;
self.height = enemyGfx.height;
self.speed = 7 + Math.random() * 3; // px per frame
self.direction = 0; // 0: straight, -1: up, 1: down
self.amplitude = 0; // for sine movement
self.phase = Math.random() * Math.PI * 2;
self.update = function () {
self.x -= self.speed;
if (self.amplitude) {
self.y += Math.sin(LK.ticks / 12 + self.phase) * self.amplitude;
}
};
return self;
});
// Enemy Fragment
var EnemyFragment = Container.expand(function () {
var self = Container.call(this);
var fragmentGfx = self.attachAsset('lcd_enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = fragmentGfx.width;
self.height = fragmentGfx.height;
self.velocityX = 0;
self.velocityY = 0;
self.rotationSpeed = 0;
self.gravity = 0.5;
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
self.velocityY += self.gravity;
self.rotation += self.rotationSpeed;
self.alpha -= 0.02;
};
return self;
});
// Fire Fragment
var FireFragment = Container.expand(function () {
var self = Container.call(this);
var fragmentGfx = self.attachAsset('fire_fragment', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = fragmentGfx.width;
self.height = fragmentGfx.height;
self.velocityX = 0;
self.velocityY = 0;
self.rotationSpeed = 0;
self.lifetime = 180; // frames
self.maxLifetime = 180;
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
self.rotation += self.rotationSpeed;
self.lifetime--;
// Fade out over time
self.alpha = self.lifetime / self.maxLifetime;
// Change color from yellow to red over time
var t = 1 - self.lifetime / self.maxLifetime;
var red = Math.floor(255);
var green = Math.floor(255 * (1 - t));
var blue = 0;
self.tint = red << 16 | green << 8 | blue;
};
return self;
});
// Player Ship
var Ship = Container.expand(function () {
var self = Container.call(this);
var shipGfx = self.attachAsset('lcd_ship', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = shipGfx.width;
self.height = shipGfx.height;
self.canShoot = true;
self.shootCooldown = 18; // frames between shots
// Ship flash effect on hit
self.flash = function () {
tween(self, {
alpha: 0.2
}, {
duration: 80,
easing: tween.linear,
onFinish: function onFinish() {
tween(self, {
alpha: 1
}, {
duration: 120,
easing: tween.linear
});
}
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Ship: white box, Enemy: white ellipse, Bullet: white box, Background: black, Accent: #A3FFB2 (LCD green).
// LCD-style monochrome: use only black, white, and one accent color (e.g. greenish for LCD).
// --- LCD color accent for UI ---
var LCD_ACCENT = 0xA3FFB2;
// --- Game constants ---
var GAME_W = 2048,
GAME_H = 2732;
var SHIP_Y = GAME_H - 220;
var ENEMY_SPAWN_Y_MIN = 220,
ENEMY_SPAWN_Y_MAX = GAME_H - 600;
var ENEMY_SPAWN_X = GAME_W + 120;
var ENEMY_SPAWN_INTERVAL = 48; // frames
var MAX_LIVES = 3;
// --- Game state ---
var ship;
var bullets = [];
var enemies = [];
var fragments = [];
var clusterRockets = [];
var fireFragments = [];
var lives = MAX_LIVES;
var score = 0;
var canMove = true;
var lastTouchX = null;
// --- UI ---
var scoreTxt = new Text2('0', {
size: 120,
fill: 0xA3FFB2
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var livesContainer = new Container();
LK.gui.topRight.addChild(livesContainer);
// --- Helper: update lives UI ---
function updateLivesUI() {
livesContainer.removeChildren();
for (var i = 0; i < lives; i++) {
var life = LK.getAsset('lcd_life', {
anchorX: 0.5,
anchorY: 0.5
});
life.x = -i * 60 - 60;
life.y = 60;
livesContainer.addChild(life);
}
}
updateLivesUI();
// --- Helper: reset game state ---
function resetGame() {
// Remove all bullets/enemies/fragments
for (var i = 0; i < bullets.length; i++) bullets[i].destroy();
for (var i = 0; i < enemies.length; i++) enemies[i].destroy();
for (var i = 0; i < fragments.length; i++) fragments[i].destroy();
for (var i = 0; i < clusterRockets.length; i++) clusterRockets[i].destroy();
for (var i = 0; i < fireFragments.length; i++) fireFragments[i].destroy();
bullets = [];
enemies = [];
fragments = [];
clusterRockets = [];
fireFragments = [];
lives = MAX_LIVES;
score = 0;
scoreTxt.setText(score);
updateLivesUI();
canMove = true;
// Place ship
if (ship) ship.destroy();
ship = new Ship();
ship.x = 320;
ship.y = SHIP_Y;
game.addChild(ship);
}
resetGame();
// --- Touch controls: drag ship horizontally ---
game.down = function (x, y, obj) {
if (!canMove) return;
// Only allow drag if touch is in lower 1/3 of screen
if (y > GAME_H * 0.6) {
lastTouchX = x;
}
};
game.move = function (x, y, obj) {
if (!canMove) return;
if (lastTouchX !== null) {
// Clamp ship to screen
var newX = Math.max(ship.width / 2, Math.min(GAME_W - ship.width / 2, x));
// Stop any existing tween on ship position
tween.stop(ship, {
x: true
});
// Smoothly tween ship to new position
tween(ship, {
x: newX
}, {
duration: 800,
easing: tween.easeOut
});
}
};
game.up = function (x, y, obj) {
lastTouchX = null;
};
// --- Ship auto-fire ---
var shootTimer = 0;
function tryShoot() {
if (!canMove) return;
if (shootTimer > 0) {
shootTimer--;
return;
}
// Fire bullet
var bullet = new Bullet();
bullet.x = ship.x;
bullet.y = ship.y - ship.height / 2 - bullet.height / 2 - 10;
bullets.push(bullet);
game.addChild(bullet);
shootTimer = ship.shootCooldown;
}
// --- Enemy spawn ---
var enemySpawnTimer = 0;
function spawnEnemy() {
var enemy = new Enemy();
enemy.x = ENEMY_SPAWN_X;
// Random Y within play area
enemy.y = ENEMY_SPAWN_Y_MIN + Math.random() * (ENEMY_SPAWN_Y_MAX - ENEMY_SPAWN_Y_MIN);
// Some enemies move in sine wave
if (Math.random() < 0.4) {
enemy.amplitude = 6 + Math.random() * 18;
}
enemies.push(enemy);
game.addChild(enemy);
}
// --- Cluster rocket spawn ---
var rocketSpawnTimer = 0;
function spawnClusterRocket() {
var rocket = new ClusterRocket();
rocket.x = ENEMY_SPAWN_X;
rocket.y = ENEMY_SPAWN_Y_MIN + Math.random() * (ENEMY_SPAWN_Y_MAX - ENEMY_SPAWN_Y_MIN);
clusterRockets.push(rocket);
game.addChild(rocket);
}
// --- Main update loop ---
game.update = function () {
// --- Ship auto-fire ---
tryShoot();
// --- Bullets update ---
for (var i = bullets.length - 1; i >= 0; i--) {
var b = bullets[i];
b.update();
// Remove if off screen
if (b.y < -b.height) {
b.destroy();
bullets.splice(i, 1);
continue;
}
// Check collision with enemies
for (var j = enemies.length - 1; j >= 0; j--) {
var e = enemies[j];
if (b.intersects(e)) {
// Create enemy fragments
var fragmentCount = 4 + Math.floor(Math.random() * 3);
for (var f = 0; f < fragmentCount; f++) {
var fragment = new EnemyFragment();
fragment.x = e.x + (Math.random() - 0.5) * e.width;
fragment.y = e.y + (Math.random() - 0.5) * e.height;
fragment.scaleX = 0.3 + Math.random() * 0.4;
fragment.scaleY = 0.3 + Math.random() * 0.4;
fragment.velocityX = (Math.random() - 0.5) * 15;
fragment.velocityY = (Math.random() - 0.5) * 10 - 5;
fragment.rotationSpeed = (Math.random() - 0.5) * 0.3;
fragment.alpha = 0.8;
fragments.push(fragment);
game.addChild(fragment);
}
// Flash screen briefly for explosion effect
LK.effects.flashScreen(0xFFFFFF, 100);
// Play hit sound
LK.getSound('123bullethitenemy').play();
// Destroy enemy and bullet
e.destroy();
b.destroy();
bullets.splice(i, 1);
enemies.splice(j, 1);
// Score
score += 1;
scoreTxt.setText(score);
// Small flash effect on ship
LK.effects.flashObject(ship, LCD_ACCENT, 120);
break;
}
}
}
// --- Fragments update ---
for (var i = fragments.length - 1; i >= 0; i--) {
var f = fragments[i];
f.update();
// Remove if off screen or fully transparent
if (f.y > GAME_H + 100 || f.x < -100 || f.x > GAME_W + 100 || f.alpha <= 0) {
f.destroy();
fragments.splice(i, 1);
}
}
// --- Enemies update ---
for (var i = enemies.length - 1; i >= 0; i--) {
var e = enemies[i];
e.update();
// Remove if off screen
if (e.x < -e.width) {
e.destroy();
enemies.splice(i, 1);
continue;
}
// Check collision with ship
if (e.intersects(ship)) {
// Ship hit!
e.destroy();
enemies.splice(i, 1);
lives--;
updateLivesUI();
ship.flash();
canMove = false;
// Flash screen
LK.effects.flashScreen(0xffffff, 200);
// After short delay, allow movement again or game over
LK.setTimeout(function () {
if (lives <= 0) {
// Game over
LK.showGameOver();
} else {
canMove = true;
}
}, 600);
break;
}
}
// --- Cluster rockets update ---
for (var i = clusterRockets.length - 1; i >= 0; i--) {
var r = clusterRockets[i];
r.update();
// Remove if off screen or exploded
if (r.x < -r.width || r.hasExploded) {
r.destroy();
clusterRockets.splice(i, 1);
continue;
}
// Check collision with ship
if (r.intersects(ship)) {
r.explode();
lives--;
updateLivesUI();
ship.flash();
canMove = false;
// Flash screen
LK.effects.flashScreen(0xFFFF00, 300);
// After short delay, allow movement again or game over
LK.setTimeout(function () {
if (lives <= 0) {
// Game over
LK.showGameOver();
} else {
canMove = true;
}
}, 600);
break;
}
}
// --- Fire fragments update ---
for (var i = fireFragments.length - 1; i >= 0; i--) {
var f = fireFragments[i];
f.update();
// Remove if lifetime expired or off screen
if (f.lifetime <= 0 || f.y > GAME_H + 100 || f.x < -100 || f.x > GAME_W + 100) {
f.destroy();
fireFragments.splice(i, 1);
continue;
}
// Check collision with ship
if (f.intersects(ship)) {
f.destroy();
fireFragments.splice(i, 1);
lives--;
updateLivesUI();
ship.flash();
canMove = false;
// Flash screen
LK.effects.flashScreen(0xFF4500, 200);
// After short delay, allow movement again or game over
LK.setTimeout(function () {
if (lives <= 0) {
// Game over
LK.showGameOver();
} else {
canMove = true;
}
}, 600);
break;
}
}
// --- Enemy spawn ---
enemySpawnTimer--;
if (enemySpawnTimer <= 0) {
spawnEnemy();
// Faster spawn as score increases
var minInterval = 18;
var interval = Math.max(minInterval, ENEMY_SPAWN_INTERVAL - Math.floor(score / 8) * 4);
enemySpawnTimer = interval + Math.floor(Math.random() * 12);
}
// --- Cluster rocket spawn ---
rocketSpawnTimer--;
if (rocketSpawnTimer <= 0) {
spawnClusterRocket();
// Spawn rockets less frequently than enemies
rocketSpawnTimer = 300 + Math.floor(Math.random() * 200);
}
};
// --- Center score text ---
scoreTxt.setText(score);
scoreTxt.anchor.set(0.5, 0);
scoreTxt.x = 0; // LK.gui.top is centered horizontally
// --- LCD-style background (monochrome rectangle) ---
function addBackground() {
// Use the background asset at its native resolution, then scale up to fit the game area to avoid blur
var bg = LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5,
x: GAME_W / 2,
y: GAME_H / 2
});
// Calculate scale factors to fit the game area
var scaleX = GAME_W / bg.width;
var scaleY = GAME_H / bg.height;
bg.scaleX = scaleX;
bg.scaleY = scaleY;
game.addChildAt(bg, 0); // Ensure background is at the bottom layer
// LCD accent border (use a shape asset for a crisp border)
var border = LK.getAsset('lcd_life', {
width: GAME_W - 120,
height: GAME_H - 120,
color: LCD_ACCENT,
shape: 'box',
anchorX: 0.5,
anchorY: 0.5
});
border.alpha = 0.08;
border.x = GAME_W / 2;
border.y = GAME_H / 2;
game.addChildAt(border, 1);
}
addBackground();
// --- Play background music ---
LK.playMusic('1alarmofwar');
// --- On game over, reset state ---
LK.on('gameover', function () {
LK.stopMusic();
resetGame();
});
// --- On you win (not used, but for completeness) ---
LK.on('youwin', function () {
LK.stopMusic();
resetGame();
});
tank with vertical cannon. In-Game asset. 2d. High contrast. No shadows
horizontal sharp ufo battle plane. In-Game asset. 2d. High contrast. No shadows
elips vertical fire light. In-Game asset. 2d. High contrast. No shadows
anime image style battlefield plains. on this distance as lost angeles burning city at night In-Game asset. 2d. High contrast. No shadows
cluster rocket. In-Game asset. 2d. High contrast. No shadows