/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Energy Core (collectible) var Core = Container.expand(function () { var self = Container.call(this); var coreSprite = self.attachAsset('core', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 6; self.update = function () { self.y += self.speed; }; return self; }); // Enemy Robot var Enemy = Container.expand(function () { var self = Container.call(this); var enemySprite = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 4 + Math.random() * 2; self.shootCooldown = 60 + Math.floor(Math.random() * 60); // frames self.update = function () { self.y += self.speed; self.shootCooldown--; }; return self; }); // Enemy Bullet var EnemyBullet = Container.expand(function () { var self = Container.call(this); var bulletSprite = self.attachAsset('enemyBullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 13; self.update = function () { self.y += self.speed; }; return self; }); // Player Mech var Mech = Container.expand(function () { var self = Container.call(this); var mechSprite = self.attachAsset('mech', { anchorX: 0.5, anchorY: 0.5 }); self.hp = 3; self.invincible = false; // For drag self.down = function (x, y, obj) {}; self.up = function (x, y, obj) {}; // Flash when hit self.flash = function () { if (self.invincible) return; self.invincible = true; tween(mechSprite, { alpha: 0.3 }, { duration: 100, easing: tween.linear, onFinish: function onFinish() { tween(mechSprite, { alpha: 1 }, { duration: 200, easing: tween.linear, onFinish: function onFinish() { self.invincible = false; } }); } }); }; return self; }); // Player Bullet var MechBullet = Container.expand(function () { var self = Container.call(this); var bulletSprite = self.attachAsset('mechBullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = -22; self.update = function () { self.y += self.speed; }; return self; }); // Repair Node (objective) var RepairNode = Container.expand(function () { var self = Container.call(this); var repairSprite = self.attachAsset('repair', { anchorX: 0.5, anchorY: 0.5 }); self.repairing = false; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x181c2c }); /**** * Game Code ****/ // Music // Sound effects // Bullet (enemy) // Bullet (player) // Repair node (for "repair" objective) // Energy core collectible // Enemy robot // Mech (player) // Play background music LK.playMusic('mechaverse_bgm'); // Game state variables var mech; var enemies = []; var mechBullets = []; var enemyBullets = []; var cores = []; var repairNodes = []; var dragNode = null; var lastMechX = 0, lastMechY = 0; var score = 0; var coresCollected = 0; var repairsDone = 0; var hp = 3; var gameOver = false; var canShoot = true; var shootCooldown = 0; var level = 1; var levelProgress = 0; var levelTarget = 5; // Number of cores to collect or repairs to do per level // GUI var scoreTxt = new Text2('Cores: 0', { size: 90, fill: "#fff" }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); var hpTxt = new Text2('HP: 3', { size: 90, fill: 0xFF6B6B }); hpTxt.anchor.set(1, 0); LK.gui.topRight.addChild(hpTxt); var levelTxt = new Text2('Level 1', { size: 70, fill: 0xFFE066 }); levelTxt.anchor.set(0, 0); LK.gui.topLeft.addChild(levelTxt); // Place player mech at bottom center mech = new Mech(); mech.x = 2048 / 2; mech.y = 2732 - 350; game.addChild(mech); // Place first repair node (for variety, alternate between core and repair objectives) function spawnRepairNode() { var node = new RepairNode(); node.x = 2048 / 2; node.y = 600 + Math.random() * 600; repairNodes.push(node); game.addChild(node); } // Spawn an energy core at a random x function spawnCore() { var core = new Core(); core.x = 200 + Math.random() * (2048 - 400); core.y = -100; cores.push(core); game.addChild(core); } // Spawn an enemy at a random x function spawnEnemy() { var enemy = new Enemy(); enemy.x = 200 + Math.random() * (2048 - 400); enemy.y = -120; enemies.push(enemy); game.addChild(enemy); } // Fire a bullet from the mech function fireMechBullet() { if (!canShoot) return; var bullet = new MechBullet(); bullet.x = mech.x; bullet.y = mech.y - 120; mechBullets.push(bullet); game.addChild(bullet); canShoot = false; shootCooldown = 12; LK.getSound('shoot').play(); } // Touch/drag controls function handleMove(x, y, obj) { if (dragNode) { // Clamp to game area, avoid top 100px (menu) var nx = Math.max(100, Math.min(2048 - 100, x)); var ny = Math.max(300, Math.min(2732 - 100, y)); dragNode.x = nx; dragNode.y = ny; } } game.move = handleMove; game.down = function (x, y, obj) { // Only allow drag if touch is not in top left 100x100 if (x < 100 && y < 100) return; dragNode = mech; handleMove(x, y, obj); }; game.up = function (x, y, obj) { dragNode = null; }; // Tap to shoot (anywhere except top left) game.tap = function (x, y, obj) { if (x < 100 && y < 100) return; fireMechBullet(); }; // For compatibility, also allow shooting on down if not dragging game.down = function (x, y, obj) { if (x < 100 && y < 100) return; dragNode = mech; handleMove(x, y, obj); fireMechBullet(); }; // Main game update loop game.update = function () { if (gameOver) return; // Cooldown for shooting if (!canShoot) { shootCooldown--; if (shootCooldown <= 0) { canShoot = true; } } // Spawn logic: enemies, cores, repair nodes if (level % 2 === 1) { // Odd levels: collect cores if (LK.ticks % Math.max(60, 120 - level * 10) === 0) { spawnCore(); } if (LK.ticks % Math.max(90, 180 - level * 12) === 0) { spawnEnemy(); } } else { // Even levels: repair nodes if (repairNodes.length === 0) { spawnRepairNode(); } if (LK.ticks % Math.max(90, 180 - level * 12) === 0) { spawnEnemy(); } } // Update enemies for (var i = enemies.length - 1; i >= 0; i--) { var enemy = enemies[i]; enemy.update(); // Enemy shoots if (enemy.shootCooldown <= 0 && enemy.y > 0) { var eb = new EnemyBullet(); eb.x = enemy.x; eb.y = enemy.y + 80; enemyBullets.push(eb); game.addChild(eb); enemy.shootCooldown = 60 + Math.floor(Math.random() * 60); } // Remove if off screen if (enemy.y > 2732 + 100) { enemy.destroy(); enemies.splice(i, 1); continue; } // Collision: enemy with mech if (!mech.invincible && enemy.intersects(mech)) { LK.getSound('hit').play(); mech.flash(); hp--; hpTxt.setText('HP: ' + hp); enemy.destroy(); enemies.splice(i, 1); if (hp <= 0) { LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); gameOver = true; return; } } } // Update mech bullets for (var i = mechBullets.length - 1; i >= 0; i--) { var b = mechBullets[i]; b.update(); // Remove if off screen if (b.y < -60) { b.destroy(); mechBullets.splice(i, 1); continue; } // Collision: bullet with enemy for (var j = enemies.length - 1; j >= 0; j--) { var enemy = enemies[j]; if (b.intersects(enemy)) { LK.getSound('hit').play(); enemy.destroy(); enemies.splice(j, 1); b.destroy(); mechBullets.splice(i, 1); break; } } } // Update enemy bullets for (var i = enemyBullets.length - 1; i >= 0; i--) { var eb = enemyBullets[i]; eb.update(); if (eb.y > 2732 + 60) { eb.destroy(); enemyBullets.splice(i, 1); continue; } // Collision: enemy bullet with mech if (!mech.invincible && eb.intersects(mech)) { LK.getSound('hit').play(); mech.flash(); hp--; hpTxt.setText('HP: ' + hp); eb.destroy(); enemyBullets.splice(i, 1); if (hp <= 0) { LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); gameOver = true; return; } } } // Update cores for (var i = cores.length - 1; i >= 0; i--) { var core = cores[i]; core.update(); if (core.y > 2732 + 60) { core.destroy(); cores.splice(i, 1); continue; } // Collect core if (core.intersects(mech)) { LK.getSound('core').play(); score++; coresCollected++; scoreTxt.setText('Cores: ' + coresCollected); core.destroy(); cores.splice(i, 1); // Level up if enough cores if (coresCollected >= levelTarget) { level++; levelTxt.setText('Level ' + level); coresCollected = 0; repairsDone = 0; scoreTxt.setText(level % 2 === 1 ? 'Cores: 0' : 'Repairs: 0'); // Show win screen if level 5 reached if (level > 5) { LK.showYouWin(); gameOver = true; return; } } } } // Update repair nodes for (var i = repairNodes.length - 1; i >= 0; i--) { var node = repairNodes[i]; // "Repair" by holding mech over node for 1 second if (node.intersects(mech)) { if (!node.repairing) { node.repairing = true; tween(node, { scaleX: 1.3, scaleY: 1.3 }, { duration: 1000, easing: tween.easeInOut, onFinish: function onFinish() { LK.getSound('repair').play(); repairsDone++; scoreTxt.setText('Repairs: ' + repairsDone); node.destroy(); repairNodes.splice(i, 1); // Level up if enough repairs if (repairsDone >= levelTarget) { level++; levelTxt.setText('Level ' + level); coresCollected = 0; repairsDone = 0; scoreTxt.setText(level % 2 === 1 ? 'Cores: 0' : 'Repairs: 0'); if (level > 5) { LK.showYouWin(); gameOver = true; return; } } } }); } } else { if (node.repairing) { node.repairing = false; tween.stop(node, { scaleX: true, scaleY: true }); node.scaleX = 1; node.scaleY = 1; } } } }; // Fade in music at start LK.playMusic('mechaverse_bgm', { fade: { start: 0, end: 0.7, duration: 1200 } });
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Energy Core (collectible)
var Core = Container.expand(function () {
var self = Container.call(this);
var coreSprite = self.attachAsset('core', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 6;
self.update = function () {
self.y += self.speed;
};
return self;
});
// Enemy Robot
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemySprite = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 4 + Math.random() * 2;
self.shootCooldown = 60 + Math.floor(Math.random() * 60); // frames
self.update = function () {
self.y += self.speed;
self.shootCooldown--;
};
return self;
});
// Enemy Bullet
var EnemyBullet = Container.expand(function () {
var self = Container.call(this);
var bulletSprite = self.attachAsset('enemyBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 13;
self.update = function () {
self.y += self.speed;
};
return self;
});
// Player Mech
var Mech = Container.expand(function () {
var self = Container.call(this);
var mechSprite = self.attachAsset('mech', {
anchorX: 0.5,
anchorY: 0.5
});
self.hp = 3;
self.invincible = false;
// For drag
self.down = function (x, y, obj) {};
self.up = function (x, y, obj) {};
// Flash when hit
self.flash = function () {
if (self.invincible) return;
self.invincible = true;
tween(mechSprite, {
alpha: 0.3
}, {
duration: 100,
easing: tween.linear,
onFinish: function onFinish() {
tween(mechSprite, {
alpha: 1
}, {
duration: 200,
easing: tween.linear,
onFinish: function onFinish() {
self.invincible = false;
}
});
}
});
};
return self;
});
// Player Bullet
var MechBullet = Container.expand(function () {
var self = Container.call(this);
var bulletSprite = self.attachAsset('mechBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -22;
self.update = function () {
self.y += self.speed;
};
return self;
});
// Repair Node (objective)
var RepairNode = Container.expand(function () {
var self = Container.call(this);
var repairSprite = self.attachAsset('repair', {
anchorX: 0.5,
anchorY: 0.5
});
self.repairing = false;
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x181c2c
});
/****
* Game Code
****/
// Music
// Sound effects
// Bullet (enemy)
// Bullet (player)
// Repair node (for "repair" objective)
// Energy core collectible
// Enemy robot
// Mech (player)
// Play background music
LK.playMusic('mechaverse_bgm');
// Game state variables
var mech;
var enemies = [];
var mechBullets = [];
var enemyBullets = [];
var cores = [];
var repairNodes = [];
var dragNode = null;
var lastMechX = 0,
lastMechY = 0;
var score = 0;
var coresCollected = 0;
var repairsDone = 0;
var hp = 3;
var gameOver = false;
var canShoot = true;
var shootCooldown = 0;
var level = 1;
var levelProgress = 0;
var levelTarget = 5; // Number of cores to collect or repairs to do per level
// GUI
var scoreTxt = new Text2('Cores: 0', {
size: 90,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var hpTxt = new Text2('HP: 3', {
size: 90,
fill: 0xFF6B6B
});
hpTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(hpTxt);
var levelTxt = new Text2('Level 1', {
size: 70,
fill: 0xFFE066
});
levelTxt.anchor.set(0, 0);
LK.gui.topLeft.addChild(levelTxt);
// Place player mech at bottom center
mech = new Mech();
mech.x = 2048 / 2;
mech.y = 2732 - 350;
game.addChild(mech);
// Place first repair node (for variety, alternate between core and repair objectives)
function spawnRepairNode() {
var node = new RepairNode();
node.x = 2048 / 2;
node.y = 600 + Math.random() * 600;
repairNodes.push(node);
game.addChild(node);
}
// Spawn an energy core at a random x
function spawnCore() {
var core = new Core();
core.x = 200 + Math.random() * (2048 - 400);
core.y = -100;
cores.push(core);
game.addChild(core);
}
// Spawn an enemy at a random x
function spawnEnemy() {
var enemy = new Enemy();
enemy.x = 200 + Math.random() * (2048 - 400);
enemy.y = -120;
enemies.push(enemy);
game.addChild(enemy);
}
// Fire a bullet from the mech
function fireMechBullet() {
if (!canShoot) return;
var bullet = new MechBullet();
bullet.x = mech.x;
bullet.y = mech.y - 120;
mechBullets.push(bullet);
game.addChild(bullet);
canShoot = false;
shootCooldown = 12;
LK.getSound('shoot').play();
}
// Touch/drag controls
function handleMove(x, y, obj) {
if (dragNode) {
// Clamp to game area, avoid top 100px (menu)
var nx = Math.max(100, Math.min(2048 - 100, x));
var ny = Math.max(300, Math.min(2732 - 100, y));
dragNode.x = nx;
dragNode.y = ny;
}
}
game.move = handleMove;
game.down = function (x, y, obj) {
// Only allow drag if touch is not in top left 100x100
if (x < 100 && y < 100) return;
dragNode = mech;
handleMove(x, y, obj);
};
game.up = function (x, y, obj) {
dragNode = null;
};
// Tap to shoot (anywhere except top left)
game.tap = function (x, y, obj) {
if (x < 100 && y < 100) return;
fireMechBullet();
};
// For compatibility, also allow shooting on down if not dragging
game.down = function (x, y, obj) {
if (x < 100 && y < 100) return;
dragNode = mech;
handleMove(x, y, obj);
fireMechBullet();
};
// Main game update loop
game.update = function () {
if (gameOver) return;
// Cooldown for shooting
if (!canShoot) {
shootCooldown--;
if (shootCooldown <= 0) {
canShoot = true;
}
}
// Spawn logic: enemies, cores, repair nodes
if (level % 2 === 1) {
// Odd levels: collect cores
if (LK.ticks % Math.max(60, 120 - level * 10) === 0) {
spawnCore();
}
if (LK.ticks % Math.max(90, 180 - level * 12) === 0) {
spawnEnemy();
}
} else {
// Even levels: repair nodes
if (repairNodes.length === 0) {
spawnRepairNode();
}
if (LK.ticks % Math.max(90, 180 - level * 12) === 0) {
spawnEnemy();
}
}
// Update enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
enemy.update();
// Enemy shoots
if (enemy.shootCooldown <= 0 && enemy.y > 0) {
var eb = new EnemyBullet();
eb.x = enemy.x;
eb.y = enemy.y + 80;
enemyBullets.push(eb);
game.addChild(eb);
enemy.shootCooldown = 60 + Math.floor(Math.random() * 60);
}
// Remove if off screen
if (enemy.y > 2732 + 100) {
enemy.destroy();
enemies.splice(i, 1);
continue;
}
// Collision: enemy with mech
if (!mech.invincible && enemy.intersects(mech)) {
LK.getSound('hit').play();
mech.flash();
hp--;
hpTxt.setText('HP: ' + hp);
enemy.destroy();
enemies.splice(i, 1);
if (hp <= 0) {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
gameOver = true;
return;
}
}
}
// Update mech bullets
for (var i = mechBullets.length - 1; i >= 0; i--) {
var b = mechBullets[i];
b.update();
// Remove if off screen
if (b.y < -60) {
b.destroy();
mechBullets.splice(i, 1);
continue;
}
// Collision: bullet with enemy
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (b.intersects(enemy)) {
LK.getSound('hit').play();
enemy.destroy();
enemies.splice(j, 1);
b.destroy();
mechBullets.splice(i, 1);
break;
}
}
}
// Update enemy bullets
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var eb = enemyBullets[i];
eb.update();
if (eb.y > 2732 + 60) {
eb.destroy();
enemyBullets.splice(i, 1);
continue;
}
// Collision: enemy bullet with mech
if (!mech.invincible && eb.intersects(mech)) {
LK.getSound('hit').play();
mech.flash();
hp--;
hpTxt.setText('HP: ' + hp);
eb.destroy();
enemyBullets.splice(i, 1);
if (hp <= 0) {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
gameOver = true;
return;
}
}
}
// Update cores
for (var i = cores.length - 1; i >= 0; i--) {
var core = cores[i];
core.update();
if (core.y > 2732 + 60) {
core.destroy();
cores.splice(i, 1);
continue;
}
// Collect core
if (core.intersects(mech)) {
LK.getSound('core').play();
score++;
coresCollected++;
scoreTxt.setText('Cores: ' + coresCollected);
core.destroy();
cores.splice(i, 1);
// Level up if enough cores
if (coresCollected >= levelTarget) {
level++;
levelTxt.setText('Level ' + level);
coresCollected = 0;
repairsDone = 0;
scoreTxt.setText(level % 2 === 1 ? 'Cores: 0' : 'Repairs: 0');
// Show win screen if level 5 reached
if (level > 5) {
LK.showYouWin();
gameOver = true;
return;
}
}
}
}
// Update repair nodes
for (var i = repairNodes.length - 1; i >= 0; i--) {
var node = repairNodes[i];
// "Repair" by holding mech over node for 1 second
if (node.intersects(mech)) {
if (!node.repairing) {
node.repairing = true;
tween(node, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
LK.getSound('repair').play();
repairsDone++;
scoreTxt.setText('Repairs: ' + repairsDone);
node.destroy();
repairNodes.splice(i, 1);
// Level up if enough repairs
if (repairsDone >= levelTarget) {
level++;
levelTxt.setText('Level ' + level);
coresCollected = 0;
repairsDone = 0;
scoreTxt.setText(level % 2 === 1 ? 'Cores: 0' : 'Repairs: 0');
if (level > 5) {
LK.showYouWin();
gameOver = true;
return;
}
}
}
});
}
} else {
if (node.repairing) {
node.repairing = false;
tween.stop(node, {
scaleX: true,
scaleY: true
});
node.scaleX = 1;
node.scaleY = 1;
}
}
}
};
// Fade in music at start
LK.playMusic('mechaverse_bgm', {
fade: {
start: 0,
end: 0.7,
duration: 1200
}
});