User prompt
Let’s make the main ship be controlled by a stick attached to it
User prompt
Remove remove the joystick and make it touch control
User prompt
Increase joystick sensitivity
User prompt
Move the joystick up by eight pixels
User prompt
Make the joystick larger
User prompt
Move the joystick to the right bottom corner
User prompt
Let’s make the ship use a joystick in the bottom left corner of the screen
User prompt
Change the name to space invaders 2.0
User prompt
Let’s make it so that you can see the visible shield around your ship ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Let’s make temporary upgrades for your ship ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Let’s make the ships more realistic, but still 16 bit
Code edit (1 edits merged)
Please save this source code
User prompt
Space Squadron
Initial prompt
It is a game in witch you play as a space ship and have to shoot down other ships
/****
* 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;
}
};