/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Boss = Container.expand(function () {
var self = Container.call(this);
// Boss main body (larger than regular enemy)
var bossBody = self.attachAsset('enemyShipBody', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 4,
scaleY: 4
});
// Boss wings (scaled up)
var bossWings = self.attachAsset('enemyShipWings', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -60,
scaleX: 5,
scaleY: 3
});
// Boss core (scaled up)
var bossCore = self.attachAsset('enemyShipCore', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 0,
scaleX: 3,
scaleY: 3
});
// Boss thruster (scaled up)
var bossThruster = self.attachAsset('enemyShipThruster', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 120,
scaleX: 4,
scaleY: 4
});
self.health = 50;
self.maxHealth = 50;
self.speed = 1;
self.shootTimer = 0;
self.shootInterval = 30;
self.moveTimer = 0;
self.moveDirection = 1;
self.lastHealth = self.health;
self.update = function () {
// Boss movement pattern - side to side
self.moveTimer++;
if (self.moveTimer % 120 == 0) {
self.moveDirection *= -1;
}
self.x += self.moveDirection * 2;
// Keep boss on screen
if (self.x <= 200) {
self.x = 200;
self.moveDirection = 1;
}
if (self.x >= 1848) {
self.x = 1848;
self.moveDirection = -1;
}
// Boss shooting - multiple bullets
self.shootTimer++;
if (self.shootTimer >= self.shootInterval) {
self.shootTimer = 0;
// Fire 5 bullets in spread pattern
for (var bulletIndex = 0; bulletIndex < 5; bulletIndex++) {
var bullet = new EnemyBullet();
bullet.x = self.x + (bulletIndex - 2) * 50;
bullet.y = self.y + 80;
bullet.lastY = bullet.y;
bullet.speed = 6;
enemyBullets.push(bullet);
game.addChild(bullet);
}
}
};
return self;
});
var EnemyBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('enemyBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.update = function () {
self.y += self.speed;
};
return self;
});
var EnemyShip = Container.expand(function () {
var self = Container.call(this);
// Main body
var shipBody = self.attachAsset('enemyShipBody', {
anchorX: 0.5,
anchorY: 0.5
});
// Wings
var wings = self.attachAsset('enemyShipWings', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -15
});
// Core/cockpit
var core = self.attachAsset('enemyShipCore', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 0
});
// Thruster
var thruster = self.attachAsset('enemyShipThruster', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 30
});
self.speed = 3;
self.health = 1;
self.shootTimer = 0;
self.shootInterval = 60 + Math.random() * 120; // Random shooting interval
self.update = function () {
self.y += self.speed;
// Enemy shooting logic
self.shootTimer++;
if (self.shootTimer >= self.shootInterval) {
self.shootTimer = 0;
self.shootInterval = 60 + Math.random() * 120; // Reset with new random interval
// Create enemy bullet
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y + 40;
bullet.lastY = bullet.y;
enemyBullets.push(bullet);
game.addChild(bullet);
}
};
return self;
});
var PlayerBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('playerBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -12;
self.update = function () {
self.y += self.speed;
};
return self;
});
var PlayerShip = Container.expand(function () {
var self = Container.call(this);
// Main body
var shipBody = self.attachAsset('playerShipBody', {
anchorX: 0.5,
anchorY: 0.5
});
// Wings
var leftWing = self.attachAsset('playerShipWings', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 20
});
// Cockpit
var cockpit = self.attachAsset('playerShipCockpit', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -15
});
// Engine thrusters
var leftEngine = self.attachAsset('playerShipEngines', {
anchorX: 0.5,
anchorY: 0.5,
x: -25,
y: 35
});
var rightEngine = self.attachAsset('playerShipEngines', {
anchorX: 0.5,
anchorY: 0.5,
x: 25,
y: 35
});
// Shield visual effect (initially hidden)
var shieldGraphics = self.attachAsset('shieldEffect', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 0,
alpha: 0
});
self.shieldGraphics = shieldGraphics;
self.shootTimer = 0;
self.shootInterval = 15; // Shoot every 15 ticks (4 times per second)
self.update = function () {
// Auto-shooting logic
self.shootTimer++;
var currentShootInterval = playerUpgrades.rapidFire ? Math.floor(self.shootInterval / 2) : self.shootInterval;
if (self.shootTimer >= currentShootInterval) {
self.shootTimer = 0;
if (playerUpgrades.tripleShot) {
// Triple shot
for (var shotIndex = 0; shotIndex < 3; shotIndex++) {
var bullet = new PlayerBullet();
bullet.x = self.x + (shotIndex - 1) * 30; // Spread shots
bullet.y = self.y - 50;
bullet.lastY = bullet.y;
playerBullets.push(bullet);
game.addChild(bullet);
}
} else {
// Single shot
var bullet = new PlayerBullet();
bullet.x = self.x;
bullet.y = self.y - 50;
bullet.lastY = bullet.y;
playerBullets.push(bullet);
game.addChild(bullet);
}
LK.getSound('shoot').play();
}
};
return self;
});
var Upgrade = Container.expand(function (type) {
var self = Container.call(this);
self.type = type;
self.speed = 4;
var upgradeGraphics = self.attachAsset('upgrade' + type, {
anchorX: 0.5,
anchorY: 0.5
});
// Pulsing animation
tween(upgradeGraphics, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(upgradeGraphics, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Restart the pulsing animation
if (self.parent) {
tween(upgradeGraphics, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: arguments.callee.caller
});
}
}
});
}
});
self.update = function () {
self.y += self.speed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000011
});
/****
* Game Code
****/
// Game variables
var playerBullets = [];
var enemyBullets = [];
var enemies = [];
var bosses = [];
var upgrades = [];
var enemySpawnTimer = 0;
var enemySpawnInterval = 120; // Start with 2 seconds between spawns
var upgradeSpawnTimer = 0;
var upgradeSpawnInterval = 600; // 10 seconds between upgrades
var dragNode = null;
var difficultyTimer = 0;
// Upgrade system
var playerUpgrades = {
rapidFire: false,
rapidFireTimer: 0,
shield: false,
shieldTimer: 0,
tripleShot: false,
tripleShotTimer: 0
};
// Player stats
var playerStats = {
damage: 1,
speed: 1
};
// Create player ship
var player = game.addChild(new PlayerShip());
player.x = 1024; // Center horizontally
player.y = 2400; // Near bottom of screen
// Create game title
var titleTxt = new Text2('SPACE INVADERS 2.0', {
size: 80,
fill: 0x00ff00
});
titleTxt.anchor.set(0.5, 0);
titleTxt.x = 0;
titleTxt.y = 20;
LK.gui.top.addChild(titleTxt);
// Create score display
var scoreTxt = new Text2('0', {
size: 120,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
scoreTxt.y = 120;
LK.gui.top.addChild(scoreTxt);
scoreTxt.setText(LK.getScore());
// Create boss health bar (initially hidden)
var bossHealthBarBg = LK.getAsset('bossHealthBarBg', {
anchorX: 0.5,
anchorY: 0,
alpha: 0
});
var bossHealthBarFill = LK.getAsset('bossHealthBarFill', {
anchorX: 0,
anchorY: 0,
alpha: 0
});
bossHealthBarBg.x = 0;
bossHealthBarBg.y = 220;
bossHealthBarFill.x = -200;
bossHealthBarFill.y = 0;
LK.gui.top.addChild(bossHealthBarBg);
bossHealthBarBg.addChild(bossHealthBarFill);
// Boss health bar text
var bossHealthTxt = new Text2('BOSS', {
size: 40,
fill: 0xff0000
});
bossHealthTxt.anchor.set(0.5, 0);
bossHealthTxt.x = 0;
bossHealthTxt.y = 250;
bossHealthTxt.alpha = 0;
LK.gui.top.addChild(bossHealthTxt);
// Stick control variables
var stickActive = false;
var stickStartX = 0;
var stickStartY = 0;
var stickCurrentX = 0;
var stickCurrentY = 0;
var maxStickDistance = 150;
// Touch controls for stick movement
function handleMove(x, y, obj) {
if (stickActive) {
stickCurrentX = x;
stickCurrentY = y;
// Calculate distance from start point
var deltaX = stickCurrentX - stickStartX;
var deltaY = stickCurrentY - stickStartY;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
// Limit stick movement to max distance
if (distance > maxStickDistance) {
var angle = Math.atan2(deltaY, deltaX);
deltaX = Math.cos(angle) * maxStickDistance;
deltaY = Math.sin(angle) * maxStickDistance;
stickCurrentX = stickStartX + deltaX;
stickCurrentY = stickStartY + deltaY;
}
}
}
game.move = handleMove;
game.down = function (x, y, obj) {
stickActive = true;
stickStartX = x;
stickStartY = y;
stickCurrentX = x;
stickCurrentY = y;
};
game.up = function (x, y, obj) {
stickActive = false;
};
game.update = function () {
// Move player based on stick input
if (stickActive) {
var deltaX = stickCurrentX - stickStartX;
var deltaY = stickCurrentY - stickStartY;
// Normalize movement based on stick distance
var moveSpeed = 16 * playerStats.speed;
var normalizedX = deltaX / maxStickDistance;
var normalizedY = deltaY / maxStickDistance;
// Apply movement
player.x += normalizedX * moveSpeed;
player.y += normalizedY * moveSpeed;
// Keep player within screen bounds
player.x = Math.max(40, Math.min(2008, player.x));
player.y = Math.max(100, Math.min(2632, player.y));
}
// Update difficulty over time
difficultyTimer++;
if (difficultyTimer % 600 == 0) {
// Every 10 seconds
enemySpawnInterval = Math.max(30, enemySpawnInterval - 10); // Faster spawning, minimum 0.5 seconds
}
// Update upgrade timers
if (playerUpgrades.rapidFire) {
playerUpgrades.rapidFireTimer--;
if (playerUpgrades.rapidFireTimer <= 0) {
playerUpgrades.rapidFire = false;
// Flash effect when upgrade expires
LK.effects.flashObject(player, 0x00ff00, 300);
}
}
if (playerUpgrades.shield) {
playerUpgrades.shieldTimer--;
if (playerUpgrades.shieldTimer <= 0) {
playerUpgrades.shield = false;
player.alpha = 1.0; // Reset transparency
// Hide shield visual effect
tween.stop(player.shieldGraphics);
tween(player.shieldGraphics, {
alpha: 0
}, {
duration: 300,
easing: tween.easeOut
});
}
}
if (playerUpgrades.tripleShot) {
playerUpgrades.tripleShotTimer--;
if (playerUpgrades.tripleShotTimer <= 0) {
playerUpgrades.tripleShot = false;
// Flash effect when upgrade expires
LK.effects.flashObject(player, 0xff0080, 300);
}
}
// Spawn upgrades
upgradeSpawnTimer++;
if (upgradeSpawnTimer >= upgradeSpawnInterval) {
upgradeSpawnTimer = 0;
var upgradeTypes = ['RapidFire', 'Shield', 'TripleShot'];
var randomType = upgradeTypes[Math.floor(Math.random() * upgradeTypes.length)];
var upgrade = new Upgrade(randomType);
upgrade.x = 100 + Math.random() * 1848;
upgrade.y = -50;
upgrade.lastY = upgrade.y;
upgrades.push(upgrade);
game.addChild(upgrade);
}
// Spawn enemies (but not during boss battles)
enemySpawnTimer++;
if (enemySpawnTimer >= enemySpawnInterval && bosses.length === 0) {
enemySpawnTimer = 0;
var enemy = new EnemyShip();
enemy.x = 100 + Math.random() * 1848; // Random x position within screen
enemy.y = -50; // Start above screen
enemy.lastY = enemy.y;
enemy.speed = 2 + Math.random() * 3 + LK.getScore() / 50; // Increase speed with score
enemies.push(enemy);
game.addChild(enemy);
}
// Update and check player bullets
for (var i = playerBullets.length - 1; i >= 0; i--) {
var bullet = playerBullets[i];
if (bullet.lastY === undefined) {
bullet.lastY = bullet.y;
}
// Remove bullets that go off screen
if (bullet.lastY >= -25 && bullet.y < -25) {
bullet.destroy();
playerBullets.splice(i, 1);
continue;
}
// Check collision with enemies
var hitEnemy = false;
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (bullet.intersects(enemy)) {
// Deal damage based on upgrade level
enemy.health -= playerStats.damage;
bullet.destroy();
playerBullets.splice(i, 1);
hitEnemy = true;
if (enemy.health <= 0) {
// Enemy destroyed
LK.setScore(LK.getScore() + 10);
scoreTxt.setText(LK.getScore());
// Visual effect
LK.effects.flashObject(enemy, 0xffffff, 200);
// Clean up
enemy.destroy();
enemies.splice(j, 1);
LK.getSound('enemyDestroy').play();
} else {
// Enemy damaged but not destroyed
LK.effects.flashObject(enemy, 0xff0000, 100);
}
break;
}
}
if (!hitEnemy) {
bullet.lastY = bullet.y;
}
}
// Update and check enemy bullets
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var bullet = enemyBullets[i];
if (bullet.lastY === undefined) {
bullet.lastY = bullet.y;
}
// Remove bullets that go off screen
if (bullet.lastY <= 2757 && bullet.y > 2757) {
bullet.destroy();
enemyBullets.splice(i, 1);
continue;
}
// Check collision with player
if (bullet.intersects(player)) {
if (!playerUpgrades.shield) {
LK.showGameOver();
return;
} else {
// Shield absorbs the hit
LK.effects.flashObject(player, 0x0080ff, 200);
}
bullet.destroy();
enemyBullets.splice(i, 1);
continue;
}
bullet.lastY = bullet.y;
}
// Update and check upgrades
for (var i = upgrades.length - 1; i >= 0; i--) {
var upgrade = upgrades[i];
if (upgrade.lastY === undefined) {
upgrade.lastY = upgrade.y;
}
// Remove upgrades that go off screen
if (upgrade.lastY <= 2757 && upgrade.y > 2757) {
upgrade.destroy();
upgrades.splice(i, 1);
continue;
}
// Check collision with player
if (upgrade.intersects(player)) {
LK.getSound('upgradePickup').play();
if (upgrade.type === 'RapidFire') {
playerUpgrades.rapidFire = true;
playerUpgrades.rapidFireTimer = 600; // 10 seconds
LK.effects.flashObject(player, 0x00ff00, 500);
} else if (upgrade.type === 'Shield') {
playerUpgrades.shield = true;
playerUpgrades.shieldTimer = 600; // 10 seconds
player.alpha = 0.7; // Make player semi-transparent to show shield
// Show shield visual effect
player.shieldGraphics.alpha = 0.6;
// Start pulsing animation for shield
tween(player.shieldGraphics, {
alpha: 0.3
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (playerUpgrades.shield) {
tween(player.shieldGraphics, {
alpha: 0.6
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: arguments.callee.caller
});
}
}
});
LK.effects.flashObject(player, 0x0080ff, 500);
} else if (upgrade.type === 'TripleShot') {
playerUpgrades.tripleShot = true;
playerUpgrades.tripleShotTimer = 600; // 10 seconds
LK.effects.flashObject(player, 0xff0080, 500);
}
upgrade.destroy();
upgrades.splice(i, 1);
continue;
}
upgrade.lastY = upgrade.y;
}
// Boss spawn logic - spawn immediately at 500 points and stay until killed
var currentScore = LK.getScore();
var shouldSpawnBoss = false;
if (currentScore >= 500 && bosses.length === 0) {
shouldSpawnBoss = true;
}
if (shouldSpawnBoss) {
var boss = new Boss();
boss.x = 1024;
boss.y = 200;
boss.lastY = boss.y;
boss.lastHealth = boss.health;
bosses.push(boss);
game.addChild(boss);
LK.effects.flashScreen(0xff0000, 500);
// Show boss health bar
bossHealthBarBg.alpha = 1;
bossHealthBarFill.alpha = 1;
bossHealthTxt.alpha = 1;
}
// Update and check bosses
for (var i = bosses.length - 1; i >= 0; i--) {
var boss = bosses[i];
if (boss.lastY === undefined) {
boss.lastY = boss.y;
}
if (boss.lastHealth === undefined) {
boss.lastHealth = boss.health;
}
// Check collision with player bullets
for (var j = playerBullets.length - 1; j >= 0; j--) {
var bullet = playerBullets[j];
if (bullet.intersects(boss)) {
boss.health -= playerStats.damage;
LK.effects.flashObject(boss, 0xffffff, 100);
bullet.destroy();
playerBullets.splice(j, 1);
// Update boss health bar
var healthPercentage = boss.health / boss.maxHealth;
bossHealthBarFill.scaleX = healthPercentage;
if (boss.health <= 0) {
// Boss defeated
LK.setScore(LK.getScore() + 500);
scoreTxt.setText(LK.getScore());
LK.effects.flashObject(boss, 0xffffff, 1000);
boss.destroy();
bosses.splice(i, 1);
LK.getSound('enemyDestroy').play();
// Hide boss health bar
bossHealthBarBg.alpha = 0;
bossHealthBarFill.alpha = 0;
bossHealthTxt.alpha = 0;
break;
}
}
}
// Check collision with player
if (boss.intersects(player)) {
if (!playerUpgrades.shield) {
LK.showGameOver();
return;
} else {
LK.setScore(LK.getScore() + 10);
scoreTxt.setText(LK.getScore());
LK.effects.flashObject(player, 0x0080ff, 200);
}
}
boss.lastY = boss.y;
boss.lastHealth = boss.health;
}
// Update and check enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (enemy.lastY === undefined) {
enemy.lastY = enemy.y;
}
// Remove enemies that go off screen
if (enemy.lastY <= 2757 && enemy.y > 2757) {
enemy.destroy();
enemies.splice(i, 1);
continue;
}
// Check collision with player
if (enemy.intersects(player)) {
if (!playerUpgrades.shield) {
LK.showGameOver();
return;
} else {
// Shield absorbs the hit and destroys the enemy
LK.setScore(LK.getScore() + 5); // Bonus points for shield collision
scoreTxt.setText(LK.getScore());
LK.effects.flashObject(player, 0x0080ff, 200);
}
enemy.destroy();
enemies.splice(i, 1);
continue;
}
enemy.lastY = enemy.y;
}
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Boss = Container.expand(function () {
var self = Container.call(this);
// Boss main body (larger than regular enemy)
var bossBody = self.attachAsset('enemyShipBody', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 4,
scaleY: 4
});
// Boss wings (scaled up)
var bossWings = self.attachAsset('enemyShipWings', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -60,
scaleX: 5,
scaleY: 3
});
// Boss core (scaled up)
var bossCore = self.attachAsset('enemyShipCore', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 0,
scaleX: 3,
scaleY: 3
});
// Boss thruster (scaled up)
var bossThruster = self.attachAsset('enemyShipThruster', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 120,
scaleX: 4,
scaleY: 4
});
self.health = 50;
self.maxHealth = 50;
self.speed = 1;
self.shootTimer = 0;
self.shootInterval = 30;
self.moveTimer = 0;
self.moveDirection = 1;
self.lastHealth = self.health;
self.update = function () {
// Boss movement pattern - side to side
self.moveTimer++;
if (self.moveTimer % 120 == 0) {
self.moveDirection *= -1;
}
self.x += self.moveDirection * 2;
// Keep boss on screen
if (self.x <= 200) {
self.x = 200;
self.moveDirection = 1;
}
if (self.x >= 1848) {
self.x = 1848;
self.moveDirection = -1;
}
// Boss shooting - multiple bullets
self.shootTimer++;
if (self.shootTimer >= self.shootInterval) {
self.shootTimer = 0;
// Fire 5 bullets in spread pattern
for (var bulletIndex = 0; bulletIndex < 5; bulletIndex++) {
var bullet = new EnemyBullet();
bullet.x = self.x + (bulletIndex - 2) * 50;
bullet.y = self.y + 80;
bullet.lastY = bullet.y;
bullet.speed = 6;
enemyBullets.push(bullet);
game.addChild(bullet);
}
}
};
return self;
});
var EnemyBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('enemyBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.update = function () {
self.y += self.speed;
};
return self;
});
var EnemyShip = Container.expand(function () {
var self = Container.call(this);
// Main body
var shipBody = self.attachAsset('enemyShipBody', {
anchorX: 0.5,
anchorY: 0.5
});
// Wings
var wings = self.attachAsset('enemyShipWings', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -15
});
// Core/cockpit
var core = self.attachAsset('enemyShipCore', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 0
});
// Thruster
var thruster = self.attachAsset('enemyShipThruster', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 30
});
self.speed = 3;
self.health = 1;
self.shootTimer = 0;
self.shootInterval = 60 + Math.random() * 120; // Random shooting interval
self.update = function () {
self.y += self.speed;
// Enemy shooting logic
self.shootTimer++;
if (self.shootTimer >= self.shootInterval) {
self.shootTimer = 0;
self.shootInterval = 60 + Math.random() * 120; // Reset with new random interval
// Create enemy bullet
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y + 40;
bullet.lastY = bullet.y;
enemyBullets.push(bullet);
game.addChild(bullet);
}
};
return self;
});
var PlayerBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('playerBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -12;
self.update = function () {
self.y += self.speed;
};
return self;
});
var PlayerShip = Container.expand(function () {
var self = Container.call(this);
// Main body
var shipBody = self.attachAsset('playerShipBody', {
anchorX: 0.5,
anchorY: 0.5
});
// Wings
var leftWing = self.attachAsset('playerShipWings', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 20
});
// Cockpit
var cockpit = self.attachAsset('playerShipCockpit', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -15
});
// Engine thrusters
var leftEngine = self.attachAsset('playerShipEngines', {
anchorX: 0.5,
anchorY: 0.5,
x: -25,
y: 35
});
var rightEngine = self.attachAsset('playerShipEngines', {
anchorX: 0.5,
anchorY: 0.5,
x: 25,
y: 35
});
// Shield visual effect (initially hidden)
var shieldGraphics = self.attachAsset('shieldEffect', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 0,
alpha: 0
});
self.shieldGraphics = shieldGraphics;
self.shootTimer = 0;
self.shootInterval = 15; // Shoot every 15 ticks (4 times per second)
self.update = function () {
// Auto-shooting logic
self.shootTimer++;
var currentShootInterval = playerUpgrades.rapidFire ? Math.floor(self.shootInterval / 2) : self.shootInterval;
if (self.shootTimer >= currentShootInterval) {
self.shootTimer = 0;
if (playerUpgrades.tripleShot) {
// Triple shot
for (var shotIndex = 0; shotIndex < 3; shotIndex++) {
var bullet = new PlayerBullet();
bullet.x = self.x + (shotIndex - 1) * 30; // Spread shots
bullet.y = self.y - 50;
bullet.lastY = bullet.y;
playerBullets.push(bullet);
game.addChild(bullet);
}
} else {
// Single shot
var bullet = new PlayerBullet();
bullet.x = self.x;
bullet.y = self.y - 50;
bullet.lastY = bullet.y;
playerBullets.push(bullet);
game.addChild(bullet);
}
LK.getSound('shoot').play();
}
};
return self;
});
var Upgrade = Container.expand(function (type) {
var self = Container.call(this);
self.type = type;
self.speed = 4;
var upgradeGraphics = self.attachAsset('upgrade' + type, {
anchorX: 0.5,
anchorY: 0.5
});
// Pulsing animation
tween(upgradeGraphics, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(upgradeGraphics, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Restart the pulsing animation
if (self.parent) {
tween(upgradeGraphics, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: arguments.callee.caller
});
}
}
});
}
});
self.update = function () {
self.y += self.speed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000011
});
/****
* Game Code
****/
// Game variables
var playerBullets = [];
var enemyBullets = [];
var enemies = [];
var bosses = [];
var upgrades = [];
var enemySpawnTimer = 0;
var enemySpawnInterval = 120; // Start with 2 seconds between spawns
var upgradeSpawnTimer = 0;
var upgradeSpawnInterval = 600; // 10 seconds between upgrades
var dragNode = null;
var difficultyTimer = 0;
// Upgrade system
var playerUpgrades = {
rapidFire: false,
rapidFireTimer: 0,
shield: false,
shieldTimer: 0,
tripleShot: false,
tripleShotTimer: 0
};
// Player stats
var playerStats = {
damage: 1,
speed: 1
};
// Create player ship
var player = game.addChild(new PlayerShip());
player.x = 1024; // Center horizontally
player.y = 2400; // Near bottom of screen
// Create game title
var titleTxt = new Text2('SPACE INVADERS 2.0', {
size: 80,
fill: 0x00ff00
});
titleTxt.anchor.set(0.5, 0);
titleTxt.x = 0;
titleTxt.y = 20;
LK.gui.top.addChild(titleTxt);
// Create score display
var scoreTxt = new Text2('0', {
size: 120,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
scoreTxt.y = 120;
LK.gui.top.addChild(scoreTxt);
scoreTxt.setText(LK.getScore());
// Create boss health bar (initially hidden)
var bossHealthBarBg = LK.getAsset('bossHealthBarBg', {
anchorX: 0.5,
anchorY: 0,
alpha: 0
});
var bossHealthBarFill = LK.getAsset('bossHealthBarFill', {
anchorX: 0,
anchorY: 0,
alpha: 0
});
bossHealthBarBg.x = 0;
bossHealthBarBg.y = 220;
bossHealthBarFill.x = -200;
bossHealthBarFill.y = 0;
LK.gui.top.addChild(bossHealthBarBg);
bossHealthBarBg.addChild(bossHealthBarFill);
// Boss health bar text
var bossHealthTxt = new Text2('BOSS', {
size: 40,
fill: 0xff0000
});
bossHealthTxt.anchor.set(0.5, 0);
bossHealthTxt.x = 0;
bossHealthTxt.y = 250;
bossHealthTxt.alpha = 0;
LK.gui.top.addChild(bossHealthTxt);
// Stick control variables
var stickActive = false;
var stickStartX = 0;
var stickStartY = 0;
var stickCurrentX = 0;
var stickCurrentY = 0;
var maxStickDistance = 150;
// Touch controls for stick movement
function handleMove(x, y, obj) {
if (stickActive) {
stickCurrentX = x;
stickCurrentY = y;
// Calculate distance from start point
var deltaX = stickCurrentX - stickStartX;
var deltaY = stickCurrentY - stickStartY;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
// Limit stick movement to max distance
if (distance > maxStickDistance) {
var angle = Math.atan2(deltaY, deltaX);
deltaX = Math.cos(angle) * maxStickDistance;
deltaY = Math.sin(angle) * maxStickDistance;
stickCurrentX = stickStartX + deltaX;
stickCurrentY = stickStartY + deltaY;
}
}
}
game.move = handleMove;
game.down = function (x, y, obj) {
stickActive = true;
stickStartX = x;
stickStartY = y;
stickCurrentX = x;
stickCurrentY = y;
};
game.up = function (x, y, obj) {
stickActive = false;
};
game.update = function () {
// Move player based on stick input
if (stickActive) {
var deltaX = stickCurrentX - stickStartX;
var deltaY = stickCurrentY - stickStartY;
// Normalize movement based on stick distance
var moveSpeed = 16 * playerStats.speed;
var normalizedX = deltaX / maxStickDistance;
var normalizedY = deltaY / maxStickDistance;
// Apply movement
player.x += normalizedX * moveSpeed;
player.y += normalizedY * moveSpeed;
// Keep player within screen bounds
player.x = Math.max(40, Math.min(2008, player.x));
player.y = Math.max(100, Math.min(2632, player.y));
}
// Update difficulty over time
difficultyTimer++;
if (difficultyTimer % 600 == 0) {
// Every 10 seconds
enemySpawnInterval = Math.max(30, enemySpawnInterval - 10); // Faster spawning, minimum 0.5 seconds
}
// Update upgrade timers
if (playerUpgrades.rapidFire) {
playerUpgrades.rapidFireTimer--;
if (playerUpgrades.rapidFireTimer <= 0) {
playerUpgrades.rapidFire = false;
// Flash effect when upgrade expires
LK.effects.flashObject(player, 0x00ff00, 300);
}
}
if (playerUpgrades.shield) {
playerUpgrades.shieldTimer--;
if (playerUpgrades.shieldTimer <= 0) {
playerUpgrades.shield = false;
player.alpha = 1.0; // Reset transparency
// Hide shield visual effect
tween.stop(player.shieldGraphics);
tween(player.shieldGraphics, {
alpha: 0
}, {
duration: 300,
easing: tween.easeOut
});
}
}
if (playerUpgrades.tripleShot) {
playerUpgrades.tripleShotTimer--;
if (playerUpgrades.tripleShotTimer <= 0) {
playerUpgrades.tripleShot = false;
// Flash effect when upgrade expires
LK.effects.flashObject(player, 0xff0080, 300);
}
}
// Spawn upgrades
upgradeSpawnTimer++;
if (upgradeSpawnTimer >= upgradeSpawnInterval) {
upgradeSpawnTimer = 0;
var upgradeTypes = ['RapidFire', 'Shield', 'TripleShot'];
var randomType = upgradeTypes[Math.floor(Math.random() * upgradeTypes.length)];
var upgrade = new Upgrade(randomType);
upgrade.x = 100 + Math.random() * 1848;
upgrade.y = -50;
upgrade.lastY = upgrade.y;
upgrades.push(upgrade);
game.addChild(upgrade);
}
// Spawn enemies (but not during boss battles)
enemySpawnTimer++;
if (enemySpawnTimer >= enemySpawnInterval && bosses.length === 0) {
enemySpawnTimer = 0;
var enemy = new EnemyShip();
enemy.x = 100 + Math.random() * 1848; // Random x position within screen
enemy.y = -50; // Start above screen
enemy.lastY = enemy.y;
enemy.speed = 2 + Math.random() * 3 + LK.getScore() / 50; // Increase speed with score
enemies.push(enemy);
game.addChild(enemy);
}
// Update and check player bullets
for (var i = playerBullets.length - 1; i >= 0; i--) {
var bullet = playerBullets[i];
if (bullet.lastY === undefined) {
bullet.lastY = bullet.y;
}
// Remove bullets that go off screen
if (bullet.lastY >= -25 && bullet.y < -25) {
bullet.destroy();
playerBullets.splice(i, 1);
continue;
}
// Check collision with enemies
var hitEnemy = false;
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (bullet.intersects(enemy)) {
// Deal damage based on upgrade level
enemy.health -= playerStats.damage;
bullet.destroy();
playerBullets.splice(i, 1);
hitEnemy = true;
if (enemy.health <= 0) {
// Enemy destroyed
LK.setScore(LK.getScore() + 10);
scoreTxt.setText(LK.getScore());
// Visual effect
LK.effects.flashObject(enemy, 0xffffff, 200);
// Clean up
enemy.destroy();
enemies.splice(j, 1);
LK.getSound('enemyDestroy').play();
} else {
// Enemy damaged but not destroyed
LK.effects.flashObject(enemy, 0xff0000, 100);
}
break;
}
}
if (!hitEnemy) {
bullet.lastY = bullet.y;
}
}
// Update and check enemy bullets
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var bullet = enemyBullets[i];
if (bullet.lastY === undefined) {
bullet.lastY = bullet.y;
}
// Remove bullets that go off screen
if (bullet.lastY <= 2757 && bullet.y > 2757) {
bullet.destroy();
enemyBullets.splice(i, 1);
continue;
}
// Check collision with player
if (bullet.intersects(player)) {
if (!playerUpgrades.shield) {
LK.showGameOver();
return;
} else {
// Shield absorbs the hit
LK.effects.flashObject(player, 0x0080ff, 200);
}
bullet.destroy();
enemyBullets.splice(i, 1);
continue;
}
bullet.lastY = bullet.y;
}
// Update and check upgrades
for (var i = upgrades.length - 1; i >= 0; i--) {
var upgrade = upgrades[i];
if (upgrade.lastY === undefined) {
upgrade.lastY = upgrade.y;
}
// Remove upgrades that go off screen
if (upgrade.lastY <= 2757 && upgrade.y > 2757) {
upgrade.destroy();
upgrades.splice(i, 1);
continue;
}
// Check collision with player
if (upgrade.intersects(player)) {
LK.getSound('upgradePickup').play();
if (upgrade.type === 'RapidFire') {
playerUpgrades.rapidFire = true;
playerUpgrades.rapidFireTimer = 600; // 10 seconds
LK.effects.flashObject(player, 0x00ff00, 500);
} else if (upgrade.type === 'Shield') {
playerUpgrades.shield = true;
playerUpgrades.shieldTimer = 600; // 10 seconds
player.alpha = 0.7; // Make player semi-transparent to show shield
// Show shield visual effect
player.shieldGraphics.alpha = 0.6;
// Start pulsing animation for shield
tween(player.shieldGraphics, {
alpha: 0.3
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (playerUpgrades.shield) {
tween(player.shieldGraphics, {
alpha: 0.6
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: arguments.callee.caller
});
}
}
});
LK.effects.flashObject(player, 0x0080ff, 500);
} else if (upgrade.type === 'TripleShot') {
playerUpgrades.tripleShot = true;
playerUpgrades.tripleShotTimer = 600; // 10 seconds
LK.effects.flashObject(player, 0xff0080, 500);
}
upgrade.destroy();
upgrades.splice(i, 1);
continue;
}
upgrade.lastY = upgrade.y;
}
// Boss spawn logic - spawn immediately at 500 points and stay until killed
var currentScore = LK.getScore();
var shouldSpawnBoss = false;
if (currentScore >= 500 && bosses.length === 0) {
shouldSpawnBoss = true;
}
if (shouldSpawnBoss) {
var boss = new Boss();
boss.x = 1024;
boss.y = 200;
boss.lastY = boss.y;
boss.lastHealth = boss.health;
bosses.push(boss);
game.addChild(boss);
LK.effects.flashScreen(0xff0000, 500);
// Show boss health bar
bossHealthBarBg.alpha = 1;
bossHealthBarFill.alpha = 1;
bossHealthTxt.alpha = 1;
}
// Update and check bosses
for (var i = bosses.length - 1; i >= 0; i--) {
var boss = bosses[i];
if (boss.lastY === undefined) {
boss.lastY = boss.y;
}
if (boss.lastHealth === undefined) {
boss.lastHealth = boss.health;
}
// Check collision with player bullets
for (var j = playerBullets.length - 1; j >= 0; j--) {
var bullet = playerBullets[j];
if (bullet.intersects(boss)) {
boss.health -= playerStats.damage;
LK.effects.flashObject(boss, 0xffffff, 100);
bullet.destroy();
playerBullets.splice(j, 1);
// Update boss health bar
var healthPercentage = boss.health / boss.maxHealth;
bossHealthBarFill.scaleX = healthPercentage;
if (boss.health <= 0) {
// Boss defeated
LK.setScore(LK.getScore() + 500);
scoreTxt.setText(LK.getScore());
LK.effects.flashObject(boss, 0xffffff, 1000);
boss.destroy();
bosses.splice(i, 1);
LK.getSound('enemyDestroy').play();
// Hide boss health bar
bossHealthBarBg.alpha = 0;
bossHealthBarFill.alpha = 0;
bossHealthTxt.alpha = 0;
break;
}
}
}
// Check collision with player
if (boss.intersects(player)) {
if (!playerUpgrades.shield) {
LK.showGameOver();
return;
} else {
LK.setScore(LK.getScore() + 10);
scoreTxt.setText(LK.getScore());
LK.effects.flashObject(player, 0x0080ff, 200);
}
}
boss.lastY = boss.y;
boss.lastHealth = boss.health;
}
// Update and check enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (enemy.lastY === undefined) {
enemy.lastY = enemy.y;
}
// Remove enemies that go off screen
if (enemy.lastY <= 2757 && enemy.y > 2757) {
enemy.destroy();
enemies.splice(i, 1);
continue;
}
// Check collision with player
if (enemy.intersects(player)) {
if (!playerUpgrades.shield) {
LK.showGameOver();
return;
} else {
// Shield absorbs the hit and destroys the enemy
LK.setScore(LK.getScore() + 5); // Bonus points for shield collision
scoreTxt.setText(LK.getScore());
LK.effects.flashObject(player, 0x0080ff, 200);
}
enemy.destroy();
enemies.splice(i, 1);
continue;
}
enemy.lastY = enemy.y;
}
};