/**** * 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 = 32; // px per frame self.update = function () { self.y -= self.speed; }; 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; }); // 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 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 for (var i = 0; i < bullets.length; i++) bullets[i].destroy(); for (var i = 0; i < enemies.length; i++) enemies[i].destroy(); bullets = []; enemies = []; 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)); ship.x = newX; } }; 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); } // --- 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)) { // Destroy both b.destroy(); bullets.splice(i, 1); e.destroy(); enemies.splice(j, 1); // Score score += 1; scoreTxt.setText(score); // Small flash effect on enemy LK.effects.flashObject(ship, LCD_ACCENT, 120); break; } } } // --- 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; } } // --- 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); } }; // --- 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 = 32; // px per frame
self.update = function () {
self.y -= self.speed;
};
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;
});
// 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 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
for (var i = 0; i < bullets.length; i++) bullets[i].destroy();
for (var i = 0; i < enemies.length; i++) enemies[i].destroy();
bullets = [];
enemies = [];
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));
ship.x = newX;
}
};
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);
}
// --- 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)) {
// Destroy both
b.destroy();
bullets.splice(i, 1);
e.destroy();
enemies.splice(j, 1);
// Score
score += 1;
scoreTxt.setText(score);
// Small flash effect on enemy
LK.effects.flashObject(ship, LCD_ACCENT, 120);
break;
}
}
}
// --- 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;
}
}
// --- 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);
}
};
// --- 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