/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Bullet class
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletGfx = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -48; // Fast upward
self.update = function () {
self.y += self.speed;
};
return self;
});
// Crosshair class (visual only)
var Crosshair = Container.expand(function () {
var self = Container.call(this);
var crossGfx = self.attachAsset('crosshair', {
anchorX: 0.5,
anchorY: 0.5
});
crossGfx.alpha = 0.4;
return self;
});
// Enemy class
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGfx = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 6 + Math.random() * 6; // Varying speed
self.update = function () {
self.y += self.speed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x181818
});
/****
* Game Code
****/
// Music (optional, will not play by default)
// Sound for enemy escape
// Sound for enemy hit
// Sound for shooting
// Crosshair: Green ellipse, thin
// Bullet: Yellow box, small
// Enemy: Red ellipse, medium size
// Game variables
var bullets = [];
var enemies = [];
var crosshair = null;
var score = 0;
var missed = 0;
var maxMissed = 5;
var spawnInterval = 60; // frames between spawns, will decrease
var lastSpawnTick = 0;
var dragAiming = false;
// Score display
var scoreTxt = new Text2('0', {
size: 120,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Missed display (bottom center)
var missedTxt = new Text2('', {
size: 90,
fill: 0xFF4444
});
missedTxt.anchor.set(0.5, 1);
LK.gui.bottom.addChild(missedTxt);
// Crosshair
crosshair = new Crosshair();
game.addChild(crosshair);
crosshair.x = 2048 / 2;
crosshair.y = 2732 * 0.8;
// Helper: update UI
function updateUI() {
scoreTxt.setText(score);
missedTxt.setText(missed > 0 ? "Missed: " + missed + "/" + maxMissed : "");
}
// Helper: spawn enemy at random x
function spawnEnemy() {
var enemy = new Enemy();
var margin = 120;
enemy.x = margin + Math.random() * (2048 - 2 * margin);
enemy.y = -80;
enemies.push(enemy);
game.addChild(enemy);
}
// Helper: fire bullet from crosshair
function fireBullet(x, y) {
var bullet = new Bullet();
bullet.x = x;
bullet.y = y;
bullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
}
// Touch controls
game.down = function (x, y, obj) {
// Move crosshair to touch, fire
crosshair.x = x;
crosshair.y = y;
fireBullet(x, y);
dragAiming = true;
};
game.move = function (x, y, obj) {
if (dragAiming) {
crosshair.x = x;
crosshair.y = y;
}
};
game.up = function (x, y, obj) {
dragAiming = false;
};
// Main update loop
game.update = function () {
// Spawn enemies
if (LK.ticks - lastSpawnTick >= spawnInterval) {
spawnEnemy();
lastSpawnTick = LK.ticks;
// Increase difficulty
if (spawnInterval > 24) {
spawnInterval -= 1;
}
}
// Update bullets
for (var i = bullets.length - 1; i >= 0; i--) {
var b = bullets[i];
b.update();
// Remove if off screen
if (b.y < -100) {
b.destroy();
bullets.splice(i, 1);
continue;
}
}
// Update enemies
for (var j = enemies.length - 1; j >= 0; j--) {
var e = enemies[j];
e.update();
// Check if enemy reached bottom
if (e.y > 2732 + 100) {
e.destroy();
enemies.splice(j, 1);
missed += 1;
updateUI();
LK.getSound('fail').play();
// Game over if too many missed
if (missed >= maxMissed) {
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
return;
}
continue;
}
// Check collision with bullets
var hit = false;
for (var k = bullets.length - 1; k >= 0; k--) {
var b2 = bullets[k];
if (e.intersects(b2)) {
// Hit!
hit = true;
score += 1;
updateUI();
LK.getSound('hit').play();
// Remove both
e.destroy();
b2.destroy();
enemies.splice(j, 1);
bullets.splice(k, 1);
// Win condition
if (score >= 30) {
LK.effects.flashScreen(0x44ff44, 800);
LK.showYouWin();
return;
}
break;
}
}
if (hit) continue;
}
};
// Initial UI
updateUI(); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Bullet class
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletGfx = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -48; // Fast upward
self.update = function () {
self.y += self.speed;
};
return self;
});
// Crosshair class (visual only)
var Crosshair = Container.expand(function () {
var self = Container.call(this);
var crossGfx = self.attachAsset('crosshair', {
anchorX: 0.5,
anchorY: 0.5
});
crossGfx.alpha = 0.4;
return self;
});
// Enemy class
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGfx = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 6 + Math.random() * 6; // Varying speed
self.update = function () {
self.y += self.speed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x181818
});
/****
* Game Code
****/
// Music (optional, will not play by default)
// Sound for enemy escape
// Sound for enemy hit
// Sound for shooting
// Crosshair: Green ellipse, thin
// Bullet: Yellow box, small
// Enemy: Red ellipse, medium size
// Game variables
var bullets = [];
var enemies = [];
var crosshair = null;
var score = 0;
var missed = 0;
var maxMissed = 5;
var spawnInterval = 60; // frames between spawns, will decrease
var lastSpawnTick = 0;
var dragAiming = false;
// Score display
var scoreTxt = new Text2('0', {
size: 120,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Missed display (bottom center)
var missedTxt = new Text2('', {
size: 90,
fill: 0xFF4444
});
missedTxt.anchor.set(0.5, 1);
LK.gui.bottom.addChild(missedTxt);
// Crosshair
crosshair = new Crosshair();
game.addChild(crosshair);
crosshair.x = 2048 / 2;
crosshair.y = 2732 * 0.8;
// Helper: update UI
function updateUI() {
scoreTxt.setText(score);
missedTxt.setText(missed > 0 ? "Missed: " + missed + "/" + maxMissed : "");
}
// Helper: spawn enemy at random x
function spawnEnemy() {
var enemy = new Enemy();
var margin = 120;
enemy.x = margin + Math.random() * (2048 - 2 * margin);
enemy.y = -80;
enemies.push(enemy);
game.addChild(enemy);
}
// Helper: fire bullet from crosshair
function fireBullet(x, y) {
var bullet = new Bullet();
bullet.x = x;
bullet.y = y;
bullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
}
// Touch controls
game.down = function (x, y, obj) {
// Move crosshair to touch, fire
crosshair.x = x;
crosshair.y = y;
fireBullet(x, y);
dragAiming = true;
};
game.move = function (x, y, obj) {
if (dragAiming) {
crosshair.x = x;
crosshair.y = y;
}
};
game.up = function (x, y, obj) {
dragAiming = false;
};
// Main update loop
game.update = function () {
// Spawn enemies
if (LK.ticks - lastSpawnTick >= spawnInterval) {
spawnEnemy();
lastSpawnTick = LK.ticks;
// Increase difficulty
if (spawnInterval > 24) {
spawnInterval -= 1;
}
}
// Update bullets
for (var i = bullets.length - 1; i >= 0; i--) {
var b = bullets[i];
b.update();
// Remove if off screen
if (b.y < -100) {
b.destroy();
bullets.splice(i, 1);
continue;
}
}
// Update enemies
for (var j = enemies.length - 1; j >= 0; j--) {
var e = enemies[j];
e.update();
// Check if enemy reached bottom
if (e.y > 2732 + 100) {
e.destroy();
enemies.splice(j, 1);
missed += 1;
updateUI();
LK.getSound('fail').play();
// Game over if too many missed
if (missed >= maxMissed) {
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
return;
}
continue;
}
// Check collision with bullets
var hit = false;
for (var k = bullets.length - 1; k >= 0; k--) {
var b2 = bullets[k];
if (e.intersects(b2)) {
// Hit!
hit = true;
score += 1;
updateUI();
LK.getSound('hit').play();
// Remove both
e.destroy();
b2.destroy();
enemies.splice(j, 1);
bullets.splice(k, 1);
// Win condition
if (score >= 30) {
LK.effects.flashScreen(0x44ff44, 800);
LK.showYouWin();
return;
}
break;
}
}
if (hit) continue;
}
};
// Initial UI
updateUI();