User prompt
start thiss ↪💡 Consider importing and using the following plugins: @upit/tween.v1, @upit/storage.v1
Code edit (1 edits merged)
Please save this source code
User prompt
Cosmic Ascent: Rogue Squadron
Initial prompt
Create a vertically-scrolling space shooter with roguelike elements where players pilot a customizable ship through waves of alien enemies, collecting power-ups and defeating massive bosses.
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Boss = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('boss', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 1;
self.health = 50;
self.maxHealth = 50;
self.shootTimer = 0;
self.shootInterval = 30;
self.moveTimer = 0;
self.moveDirection = 1;
self.update = function () {
// Boss movement pattern
self.x += self.moveDirection * 2;
if (self.x <= graphics.width / 2 || self.x >= 2048 - graphics.width / 2) {
self.moveDirection *= -1;
}
// Boss shooting pattern
self.shootTimer++;
if (self.shootTimer >= self.shootInterval) {
self.shootTimer = 0;
// Triple shot
for (var i = -1; i <= 1; i++) {
var bullet = new EnemyBullet();
bullet.x = self.x + i * 50;
bullet.y = self.y + graphics.height / 2;
enemyBullets.push(bullet);
game.addChild(bullet);
}
}
};
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xffffff, 300);
if (self.health <= 0) {
self.destroy();
return true;
}
return false;
};
return self;
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('enemy1', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 3;
self.health = 1;
self.maxHealth = 1;
self.shootTimer = 0;
self.shootInterval = 120;
self.movePattern = 'straight';
self.moveTimer = 0;
self.update = function () {
// Movement patterns
if (self.movePattern === 'straight') {
self.y += self.speed;
} else if (self.movePattern === 'zigzag') {
self.y += self.speed;
self.x += Math.sin(self.moveTimer * 0.1) * 2;
}
self.moveTimer++;
// Shooting
self.shootTimer++;
if (self.shootTimer >= self.shootInterval) {
self.shootTimer = 0;
if (self.y > 0 && self.y < 2732) {
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y + graphics.height / 2;
enemyBullets.push(bullet);
game.addChild(bullet);
}
}
};
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xffffff, 200);
if (self.health <= 0) {
self.destroy();
return true;
}
return false;
};
return self;
});
var EnemyBullet = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('enemyBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.damage = 1;
self.update = function () {
self.y += self.speed;
};
return self;
});
var FastEnemy = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('enemy2', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 5;
self.health = 2;
self.maxHealth = 2;
self.shootInterval = 80;
self.movePattern = 'zigzag';
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 3;
self.maxHealth = 3;
self.shootTimer = 0;
self.shootInterval = 10;
self.rapidFire = false;
self.rapidFireTimer = 0;
self.multiShot = false;
self.multiShotTimer = 0;
self.invulnerable = false;
self.invulnerableTimer = 0;
self.update = function () {
// Shield regeneration
if (self.hasRegen && LK.ticks % 300 === 0 && self.health < self.maxHealth) {
self.health++;
}
// Power-up timers
if (self.rapidFire) {
self.rapidFireTimer--;
if (self.rapidFireTimer <= 0) {
self.rapidFire = false;
self.shootInterval = 10;
}
}
if (self.multiShot) {
self.multiShotTimer--;
if (self.multiShotTimer <= 0) {
self.multiShot = false;
}
}
if (self.invulnerable) {
self.invulnerableTimer--;
graphics.alpha = 0.5 + Math.sin(LK.ticks * 0.5) * 0.3;
if (self.invulnerableTimer <= 0) {
self.invulnerable = false;
graphics.alpha = 1;
}
}
// Auto-shooting
self.shootTimer++;
if (self.shootTimer >= self.shootInterval) {
self.shootTimer = 0;
self.shoot();
}
};
self.shoot = function () {
LK.getSound('shoot').play();
// Use weapon spread configuration
var shots = self.weaponSpread || (self.multiShot ? 3 : 1);
if (shots > 1) {
// Multiple shots
for (var i = 0; i < shots; i++) {
var bullet = new PlayerBullet();
var spread = (i - (shots - 1) / 2) * 30;
bullet.x = self.x + spread;
bullet.y = self.y - graphics.height / 2;
bullet.damage = self.weaponDamage || 1;
playerBullets.push(bullet);
game.addChild(bullet);
}
} else {
// Single shot
var bullet = new PlayerBullet();
bullet.x = self.x;
bullet.y = self.y - graphics.height / 2;
bullet.damage = self.weaponDamage || 1;
playerBullets.push(bullet);
game.addChild(bullet);
}
};
self.takeDamage = function () {
if (self.invulnerable) return false;
self.health--;
self.invulnerable = true;
self.invulnerableTimer = 120;
LK.effects.flashObject(self, 0xff0000, 500);
if (self.health <= 0) {
return true;
}
return false;
};
self.applyPowerUp = function (powerUpType) {
LK.getSound('powerup').play();
if (powerUpType === 'rapidfire') {
self.rapidFire = true;
self.rapidFireTimer = 600; // 10 seconds at 60fps
self.shootInterval = 5;
} else if (powerUpType === 'multishot') {
self.multiShot = true;
self.multiShotTimer = 600;
} else if (powerUpType === 'shield') {
if (self.health < self.maxHealth) {
self.health++;
}
}
};
return self;
});
var PlayerBullet = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('playerBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 15;
self.damage = 1;
self.update = function () {
self.y -= self.speed;
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 4;
self.type = 'rapidfire'; // rapidfire, shield, multishot
self.moveTimer = 0;
self.update = function () {
self.y += self.speed;
self.moveTimer++;
graphics.rotation += 0.1;
// Pulsing effect
var scale = 1 + Math.sin(self.moveTimer * 0.2) * 0.2;
graphics.scaleX = scale;
graphics.scaleY = scale;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x001122
});
/****
* Game Code
****/
// Game state variables
var gameState = 'customizing'; // customizing, playing, gameover
var currentWave = 1;
var enemiesInWave = 0;
var enemiesKilled = 0;
var waveTimer = 0;
var nextWaveDelay = 180; // 3 seconds
var bossWave = false;
var currentBoss = null;
// Game arrays
var playerBullets = [];
var enemyBullets = [];
var enemies = [];
var powerUps = [];
// Spawn timers
var enemySpawnTimer = 0;
var powerUpSpawnTimer = 0;
// Player stats
var playerLives = storage.playerLives || 3;
var totalScore = storage.totalScore || 0;
var highScore = storage.highScore || 0;
// Roguelike progression - unlocked components
var unlockedWeapons = storage.unlockedWeapons || ['basic'];
var unlockedEngines = storage.unlockedEngines || ['standard'];
var unlockedShields = storage.unlockedShields || ['light'];
var runsCompleted = storage.runsCompleted || 0;
// Current ship configuration
var selectedWeapon = 'basic';
var selectedEngine = 'standard';
var selectedShield = 'light';
// Ship component definitions
var weaponTypes = {
basic: {
name: 'Basic Laser',
damage: 1,
fireRate: 10,
spread: 0
},
rapid: {
name: 'Rapid Fire',
damage: 1,
fireRate: 5,
spread: 0
},
spread: {
name: 'Spread Shot',
damage: 1,
fireRate: 15,
spread: 3
},
heavy: {
name: 'Heavy Cannon',
damage: 3,
fireRate: 20,
spread: 0
}
};
var engineTypes = {
standard: {
name: 'Standard Engine',
speed: 1.0
},
fast: {
name: 'Speed Boost',
speed: 1.5
},
agile: {
name: 'Agile Thrusters',
speed: 1.2
}
};
var shieldTypes = {
light: {
name: 'Light Shield',
health: 3
},
heavy: {
name: 'Heavy Shield',
health: 5
},
regen: {
name: 'Regen Shield',
health: 4,
regen: true
}
};
// Create player (initially hidden during customization)
var player = game.addChild(new Player());
player.x = 2048 / 2;
player.y = 2732 - 200;
player.visible = false;
// UI Elements
var scoreText = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreText.anchor.set(0, 0);
scoreText.x = 150;
scoreText.y = 50;
LK.gui.topLeft.addChild(scoreText);
var waveText = new Text2('Wave: 1', {
size: 60,
fill: 0xFFFFFF
});
waveText.anchor.set(0.5, 0);
LK.gui.top.addChild(waveText);
var healthText = new Text2('Lives: 3', {
size: 60,
fill: 0xFFFFFF
});
healthText.anchor.set(1, 0);
healthText.x = -50;
healthText.y = 50;
LK.gui.topRight.addChild(healthText);
// Customization UI
var customizationUI = new Container();
game.addChild(customizationUI);
var titleText = new Text2('SHIP CUSTOMIZATION', {
size: 80,
fill: 0x00AAFF
});
titleText.anchor.set(0.5, 0);
titleText.x = 2048 / 2;
titleText.y = 200;
customizationUI.addChild(titleText);
var weaponLabel = new Text2('WEAPON: ' + weaponTypes[selectedWeapon].name, {
size: 50,
fill: 0xFFFFFF
});
weaponLabel.anchor.set(0.5, 0);
weaponLabel.x = 2048 / 2;
weaponLabel.y = 400;
customizationUI.addChild(weaponLabel);
var engineLabel = new Text2('ENGINE: ' + engineTypes[selectedEngine].name, {
size: 50,
fill: 0xFFFFFF
});
engineLabel.anchor.set(0.5, 0);
engineLabel.x = 2048 / 2;
engineLabel.y = 500;
customizationUI.addChild(engineLabel);
var shieldLabel = new Text2('SHIELD: ' + shieldTypes[selectedShield].name, {
size: 50,
fill: 0xFFFFFF
});
shieldLabel.anchor.set(0.5, 0);
shieldLabel.x = 2048 / 2;
shieldLabel.y = 600;
customizationUI.addChild(shieldLabel);
var startButton = new Text2('START MISSION', {
size: 60,
fill: 0x00FF00
});
startButton.anchor.set(0.5, 0);
startButton.x = 2048 / 2;
startButton.y = 800;
customizationUI.addChild(startButton);
var runsText = new Text2('Runs Completed: ' + runsCompleted, {
size: 40,
fill: 0xAAAA00
});
runsText.anchor.set(0.5, 0);
runsText.x = 2048 / 2;
runsText.y = 1000;
customizationUI.addChild(runsText);
// Touch controls
var dragActive = false;
game.down = function (x, y, obj) {
if (gameState === 'customizing') {
// Check if clicking on weapon selection
if (y >= 380 && y <= 430) {
cycleWeapon();
}
// Check if clicking on engine selection
else if (y >= 480 && y <= 530) {
cycleEngine();
}
// Check if clicking on shield selection
else if (y >= 580 && y <= 630) {
cycleShield();
}
// Check if clicking start button
else if (y >= 780 && y <= 840) {
startGame();
}
} else if (gameState === 'playing') {
dragActive = true;
player.x = x;
player.y = y;
}
};
game.move = function (x, y, obj) {
if (dragActive && gameState === 'playing') {
player.x = Math.max(40, Math.min(2048 - 40, x));
player.y = Math.max(100, Math.min(2732 - 100, y));
}
};
game.up = function (x, y, obj) {
dragActive = false;
};
// Customization functions
function cycleWeapon() {
var availableWeapons = unlockedWeapons.slice();
var currentIndex = availableWeapons.indexOf(selectedWeapon);
selectedWeapon = availableWeapons[(currentIndex + 1) % availableWeapons.length];
weaponLabel.setText('WEAPON: ' + weaponTypes[selectedWeapon].name);
}
function cycleEngine() {
var availableEngines = unlockedEngines.slice();
var currentIndex = availableEngines.indexOf(selectedEngine);
selectedEngine = availableEngines[(currentIndex + 1) % availableEngines.length];
engineLabel.setText('ENGINE: ' + engineTypes[selectedEngine].name);
}
function cycleShield() {
var availableShields = unlockedShields.slice();
var currentIndex = availableShields.indexOf(selectedShield);
selectedShield = availableShields[(currentIndex + 1) % availableShields.length];
shieldLabel.setText('SHIELD: ' + shieldTypes[selectedShield].name);
}
function startGame() {
gameState = 'playing';
customizationUI.visible = false;
player.visible = true;
// Apply ship configuration
configurePlayer();
// Start first wave
startWave();
}
function configurePlayer() {
var weapon = weaponTypes[selectedWeapon];
var engine = engineTypes[selectedEngine];
var shield = shieldTypes[selectedShield];
// Configure player stats based on selections
player.shootInterval = weapon.fireRate;
player.weaponDamage = weapon.damage;
player.weaponSpread = weapon.spread;
player.moveSpeed = engine.speed;
player.health = shield.health;
player.maxHealth = shield.health;
player.hasRegen = shield.regen || false;
// Update UI
healthText.setText('Lives: ' + player.health);
}
// Wave generation
function startWave() {
enemiesInWave = currentWave * 3 + Math.floor(currentWave / 2);
enemiesKilled = 0;
waveTimer = 0;
// Boss every 5th wave
if (currentWave % 5 === 0) {
bossWave = true;
spawnBoss();
} else {
bossWave = false;
}
waveText.setText('Wave: ' + currentWave);
}
function spawnBoss() {
currentBoss = new Boss();
currentBoss.x = 2048 / 2;
currentBoss.y = 200;
enemies.push(currentBoss);
game.addChild(currentBoss);
}
function spawnEnemy() {
var enemy;
// 30% chance for fast enemy after wave 3
if (currentWave > 3 && Math.random() < 0.3) {
enemy = new FastEnemy();
} else {
enemy = new Enemy();
}
enemy.x = Math.random() * (2048 - 100) + 50;
enemy.y = -50;
enemies.push(enemy);
game.addChild(enemy);
}
function spawnPowerUp() {
var powerUp = new PowerUp();
powerUp.x = Math.random() * (2048 - 80) + 40;
powerUp.y = -40;
var types = ['rapidfire', 'multishot', 'shield'];
powerUp.type = types[Math.floor(Math.random() * types.length)];
powerUps.push(powerUp);
game.addChild(powerUp);
}
// Component unlock system
function unlockComponents() {
var score = LK.getScore();
var wave = currentWave;
// Unlock weapons based on score
if (score >= 1000 && unlockedWeapons.indexOf('rapid') === -1) {
unlockedWeapons.push('rapid');
storage.unlockedWeapons = unlockedWeapons;
}
if (score >= 2500 && unlockedWeapons.indexOf('spread') === -1) {
unlockedWeapons.push('spread');
storage.unlockedWeapons = unlockedWeapons;
}
if (score >= 5000 && unlockedWeapons.indexOf('heavy') === -1) {
unlockedWeapons.push('heavy');
storage.unlockedWeapons = unlockedWeapons;
}
// Unlock engines based on waves survived
if (wave >= 5 && unlockedEngines.indexOf('fast') === -1) {
unlockedEngines.push('fast');
storage.unlockedEngines = unlockedEngines;
}
if (wave >= 10 && unlockedEngines.indexOf('agile') === -1) {
unlockedEngines.push('agile');
storage.unlockedEngines = unlockedEngines;
}
// Unlock shields based on runs completed
if (runsCompleted >= 3 && unlockedShields.indexOf('heavy') === -1) {
unlockedShields.push('heavy');
storage.unlockedShields = unlockedShields;
}
if (runsCompleted >= 7 && unlockedShields.indexOf('regen') === -1) {
unlockedShields.push('regen');
storage.unlockedShields = unlockedShields;
}
}
// Don't start wave automatically - wait for customization
//startWave();
// Main game update loop
game.update = function () {
if (gameState === 'customizing') {
// Animate customization UI elements
titleText.alpha = 0.8 + Math.sin(LK.ticks * 0.05) * 0.2;
return;
}
if (gameState !== 'playing') return;
// Update wave timer
waveTimer++;
// Spawn enemies during wave
if (!bossWave && enemiesKilled < enemiesInWave) {
enemySpawnTimer++;
var spawnRate = Math.max(30, 120 - currentWave * 5);
if (enemySpawnTimer >= spawnRate) {
enemySpawnTimer = 0;
spawnEnemy();
}
}
// Spawn power-ups occasionally
powerUpSpawnTimer++;
if (powerUpSpawnTimer >= 900) {
// Every 15 seconds
powerUpSpawnTimer = 0;
if (Math.random() < 0.7) {
spawnPowerUp();
}
}
// 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 off-screen bullets
if (bullet.lastY >= -30 && bullet.y < -30) {
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)) {
if (enemy.takeDamage(bullet.damage)) {
// Enemy destroyed
LK.getSound('enemyHit').play();
LK.setScore(LK.getScore() + (enemy === currentBoss ? 500 : 100));
enemies.splice(j, 1);
enemiesKilled++;
if (enemy === currentBoss) {
currentBoss = null;
bossWave = false;
}
}
bullet.destroy();
playerBullets.splice(i, 1);
hitEnemy = true;
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 off-screen bullets
if (bullet.lastY <= 2760 && bullet.y > 2760) {
bullet.destroy();
enemyBullets.splice(i, 1);
continue;
}
// Check collision with player
if (bullet.intersects(player)) {
if (player.takeDamage()) {
// Player died
LK.getSound('explosion').play();
gameState = 'gameover';
// Update storage and unlock new components
storage.totalScore = totalScore + LK.getScore();
storage.runsCompleted = runsCompleted + 1;
unlockComponents();
if (LK.getScore() > highScore) {
storage.highScore = LK.getScore();
}
LK.showGameOver();
return;
}
bullet.destroy();
enemyBullets.splice(i, 1);
} else {
bullet.lastY = bullet.y;
}
}
// 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 off-screen enemies (except boss)
if (enemy !== currentBoss && enemy.lastY <= 2760 && enemy.y > 2760) {
enemy.destroy();
enemies.splice(i, 1);
continue;
}
// Check collision with player
if (enemy.intersects(player)) {
if (player.takeDamage()) {
// Player died
LK.getSound('explosion').play();
gameState = 'gameover';
// Update storage
storage.totalScore = totalScore + LK.getScore();
if (LK.getScore() > highScore) {
storage.highScore = LK.getScore();
}
LK.showGameOver();
return;
}
}
enemy.lastY = enemy.y;
}
// Update and check power-ups
for (var i = powerUps.length - 1; i >= 0; i--) {
var powerUp = powerUps[i];
if (powerUp.lastY === undefined) powerUp.lastY = powerUp.y;
// Remove off-screen power-ups
if (powerUp.lastY <= 2760 && powerUp.y > 2760) {
powerUp.destroy();
powerUps.splice(i, 1);
continue;
}
// Check collision with player
if (powerUp.intersects(player)) {
player.applyPowerUp(powerUp.type);
powerUp.destroy();
powerUps.splice(i, 1);
} else {
powerUp.lastY = powerUp.y;
}
}
// Check wave completion
if (bossWave && currentBoss === null || !bossWave && enemiesKilled >= enemiesInWave && enemies.length === 0) {
if (waveTimer >= nextWaveDelay) {
currentWave++;
startWave();
}
}
// Update UI
scoreText.setText('Score: ' + LK.getScore());
healthText.setText('Lives: ' + player.health);
// Victory condition (survive 20 waves)
if (currentWave > 20) {
storage.totalScore = totalScore + LK.getScore();
if (LK.getScore() > highScore) {
storage.highScore = LK.getScore();
}
LK.showYouWin();
}
};
// Start background music
LK.playMusic('bgmusic'); ===================================================================
--- original.js
+++ change.js
@@ -139,8 +139,12 @@
self.multiShotTimer = 0;
self.invulnerable = false;
self.invulnerableTimer = 0;
self.update = function () {
+ // Shield regeneration
+ if (self.hasRegen && LK.ticks % 300 === 0 && self.health < self.maxHealth) {
+ self.health++;
+ }
// Power-up timers
if (self.rapidFire) {
self.rapidFireTimer--;
if (self.rapidFireTimer <= 0) {
@@ -170,22 +174,27 @@
}
};
self.shoot = function () {
LK.getSound('shoot').play();
- if (self.multiShot) {
- // Triple shot
- for (var i = -1; i <= 1; i++) {
+ // Use weapon spread configuration
+ var shots = self.weaponSpread || (self.multiShot ? 3 : 1);
+ if (shots > 1) {
+ // Multiple shots
+ for (var i = 0; i < shots; i++) {
var bullet = new PlayerBullet();
- bullet.x = self.x + i * 30;
+ var spread = (i - (shots - 1) / 2) * 30;
+ bullet.x = self.x + spread;
bullet.y = self.y - graphics.height / 2;
+ bullet.damage = self.weaponDamage || 1;
playerBullets.push(bullet);
game.addChild(bullet);
}
} else {
// Single shot
var bullet = new PlayerBullet();
bullet.x = self.x;
bullet.y = self.y - graphics.height / 2;
+ bullet.damage = self.weaponDamage || 1;
playerBullets.push(bullet);
game.addChild(bullet);
}
};
@@ -261,9 +270,9 @@
/****
* Game Code
****/
// Game state variables
-var gameState = 'playing'; // playing, gameover
+var gameState = 'customizing'; // customizing, playing, gameover
var currentWave = 1;
var enemiesInWave = 0;
var enemiesKilled = 0;
var waveTimer = 0;
@@ -281,12 +290,78 @@
// Player stats
var playerLives = storage.playerLives || 3;
var totalScore = storage.totalScore || 0;
var highScore = storage.highScore || 0;
-// Create player
+// Roguelike progression - unlocked components
+var unlockedWeapons = storage.unlockedWeapons || ['basic'];
+var unlockedEngines = storage.unlockedEngines || ['standard'];
+var unlockedShields = storage.unlockedShields || ['light'];
+var runsCompleted = storage.runsCompleted || 0;
+// Current ship configuration
+var selectedWeapon = 'basic';
+var selectedEngine = 'standard';
+var selectedShield = 'light';
+// Ship component definitions
+var weaponTypes = {
+ basic: {
+ name: 'Basic Laser',
+ damage: 1,
+ fireRate: 10,
+ spread: 0
+ },
+ rapid: {
+ name: 'Rapid Fire',
+ damage: 1,
+ fireRate: 5,
+ spread: 0
+ },
+ spread: {
+ name: 'Spread Shot',
+ damage: 1,
+ fireRate: 15,
+ spread: 3
+ },
+ heavy: {
+ name: 'Heavy Cannon',
+ damage: 3,
+ fireRate: 20,
+ spread: 0
+ }
+};
+var engineTypes = {
+ standard: {
+ name: 'Standard Engine',
+ speed: 1.0
+ },
+ fast: {
+ name: 'Speed Boost',
+ speed: 1.5
+ },
+ agile: {
+ name: 'Agile Thrusters',
+ speed: 1.2
+ }
+};
+var shieldTypes = {
+ light: {
+ name: 'Light Shield',
+ health: 3
+ },
+ heavy: {
+ name: 'Heavy Shield',
+ health: 5
+ },
+ regen: {
+ name: 'Regen Shield',
+ health: 4,
+ regen: true
+ }
+};
+// Create player (initially hidden during customization)
var player = game.addChild(new Player());
player.x = 2048 / 2;
player.y = 2732 - 200;
+player.visible = false;
// UI Elements
var scoreText = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
@@ -308,14 +383,84 @@
healthText.anchor.set(1, 0);
healthText.x = -50;
healthText.y = 50;
LK.gui.topRight.addChild(healthText);
+// Customization UI
+var customizationUI = new Container();
+game.addChild(customizationUI);
+var titleText = new Text2('SHIP CUSTOMIZATION', {
+ size: 80,
+ fill: 0x00AAFF
+});
+titleText.anchor.set(0.5, 0);
+titleText.x = 2048 / 2;
+titleText.y = 200;
+customizationUI.addChild(titleText);
+var weaponLabel = new Text2('WEAPON: ' + weaponTypes[selectedWeapon].name, {
+ size: 50,
+ fill: 0xFFFFFF
+});
+weaponLabel.anchor.set(0.5, 0);
+weaponLabel.x = 2048 / 2;
+weaponLabel.y = 400;
+customizationUI.addChild(weaponLabel);
+var engineLabel = new Text2('ENGINE: ' + engineTypes[selectedEngine].name, {
+ size: 50,
+ fill: 0xFFFFFF
+});
+engineLabel.anchor.set(0.5, 0);
+engineLabel.x = 2048 / 2;
+engineLabel.y = 500;
+customizationUI.addChild(engineLabel);
+var shieldLabel = new Text2('SHIELD: ' + shieldTypes[selectedShield].name, {
+ size: 50,
+ fill: 0xFFFFFF
+});
+shieldLabel.anchor.set(0.5, 0);
+shieldLabel.x = 2048 / 2;
+shieldLabel.y = 600;
+customizationUI.addChild(shieldLabel);
+var startButton = new Text2('START MISSION', {
+ size: 60,
+ fill: 0x00FF00
+});
+startButton.anchor.set(0.5, 0);
+startButton.x = 2048 / 2;
+startButton.y = 800;
+customizationUI.addChild(startButton);
+var runsText = new Text2('Runs Completed: ' + runsCompleted, {
+ size: 40,
+ fill: 0xAAAA00
+});
+runsText.anchor.set(0.5, 0);
+runsText.x = 2048 / 2;
+runsText.y = 1000;
+customizationUI.addChild(runsText);
// Touch controls
var dragActive = false;
game.down = function (x, y, obj) {
- dragActive = true;
- player.x = x;
- player.y = y;
+ if (gameState === 'customizing') {
+ // Check if clicking on weapon selection
+ if (y >= 380 && y <= 430) {
+ cycleWeapon();
+ }
+ // Check if clicking on engine selection
+ else if (y >= 480 && y <= 530) {
+ cycleEngine();
+ }
+ // Check if clicking on shield selection
+ else if (y >= 580 && y <= 630) {
+ cycleShield();
+ }
+ // Check if clicking start button
+ else if (y >= 780 && y <= 840) {
+ startGame();
+ }
+ } else if (gameState === 'playing') {
+ dragActive = true;
+ player.x = x;
+ player.y = y;
+ }
};
game.move = function (x, y, obj) {
if (dragActive && gameState === 'playing') {
player.x = Math.max(40, Math.min(2048 - 40, x));
@@ -324,8 +469,51 @@
};
game.up = function (x, y, obj) {
dragActive = false;
};
+// Customization functions
+function cycleWeapon() {
+ var availableWeapons = unlockedWeapons.slice();
+ var currentIndex = availableWeapons.indexOf(selectedWeapon);
+ selectedWeapon = availableWeapons[(currentIndex + 1) % availableWeapons.length];
+ weaponLabel.setText('WEAPON: ' + weaponTypes[selectedWeapon].name);
+}
+function cycleEngine() {
+ var availableEngines = unlockedEngines.slice();
+ var currentIndex = availableEngines.indexOf(selectedEngine);
+ selectedEngine = availableEngines[(currentIndex + 1) % availableEngines.length];
+ engineLabel.setText('ENGINE: ' + engineTypes[selectedEngine].name);
+}
+function cycleShield() {
+ var availableShields = unlockedShields.slice();
+ var currentIndex = availableShields.indexOf(selectedShield);
+ selectedShield = availableShields[(currentIndex + 1) % availableShields.length];
+ shieldLabel.setText('SHIELD: ' + shieldTypes[selectedShield].name);
+}
+function startGame() {
+ gameState = 'playing';
+ customizationUI.visible = false;
+ player.visible = true;
+ // Apply ship configuration
+ configurePlayer();
+ // Start first wave
+ startWave();
+}
+function configurePlayer() {
+ var weapon = weaponTypes[selectedWeapon];
+ var engine = engineTypes[selectedEngine];
+ var shield = shieldTypes[selectedShield];
+ // Configure player stats based on selections
+ player.shootInterval = weapon.fireRate;
+ player.weaponDamage = weapon.damage;
+ player.weaponSpread = weapon.spread;
+ player.moveSpeed = engine.speed;
+ player.health = shield.health;
+ player.maxHealth = shield.health;
+ player.hasRegen = shield.regen || false;
+ // Update UI
+ healthText.setText('Lives: ' + player.health);
+}
// Wave generation
function startWave() {
enemiesInWave = currentWave * 3 + Math.floor(currentWave / 2);
enemiesKilled = 0;
@@ -367,12 +555,53 @@
powerUp.type = types[Math.floor(Math.random() * types.length)];
powerUps.push(powerUp);
game.addChild(powerUp);
}
-// Start first wave
-startWave();
+// Component unlock system
+function unlockComponents() {
+ var score = LK.getScore();
+ var wave = currentWave;
+ // Unlock weapons based on score
+ if (score >= 1000 && unlockedWeapons.indexOf('rapid') === -1) {
+ unlockedWeapons.push('rapid');
+ storage.unlockedWeapons = unlockedWeapons;
+ }
+ if (score >= 2500 && unlockedWeapons.indexOf('spread') === -1) {
+ unlockedWeapons.push('spread');
+ storage.unlockedWeapons = unlockedWeapons;
+ }
+ if (score >= 5000 && unlockedWeapons.indexOf('heavy') === -1) {
+ unlockedWeapons.push('heavy');
+ storage.unlockedWeapons = unlockedWeapons;
+ }
+ // Unlock engines based on waves survived
+ if (wave >= 5 && unlockedEngines.indexOf('fast') === -1) {
+ unlockedEngines.push('fast');
+ storage.unlockedEngines = unlockedEngines;
+ }
+ if (wave >= 10 && unlockedEngines.indexOf('agile') === -1) {
+ unlockedEngines.push('agile');
+ storage.unlockedEngines = unlockedEngines;
+ }
+ // Unlock shields based on runs completed
+ if (runsCompleted >= 3 && unlockedShields.indexOf('heavy') === -1) {
+ unlockedShields.push('heavy');
+ storage.unlockedShields = unlockedShields;
+ }
+ if (runsCompleted >= 7 && unlockedShields.indexOf('regen') === -1) {
+ unlockedShields.push('regen');
+ storage.unlockedShields = unlockedShields;
+ }
+}
+// Don't start wave automatically - wait for customization
+//startWave();
// Main game update loop
game.update = function () {
+ if (gameState === 'customizing') {
+ // Animate customization UI elements
+ titleText.alpha = 0.8 + Math.sin(LK.ticks * 0.05) * 0.2;
+ return;
+ }
if (gameState !== 'playing') return;
// Update wave timer
waveTimer++;
// Spawn enemies during wave
@@ -444,10 +673,12 @@
if (player.takeDamage()) {
// Player died
LK.getSound('explosion').play();
gameState = 'gameover';
- // Update storage
+ // Update storage and unlock new components
storage.totalScore = totalScore + LK.getScore();
+ storage.runsCompleted = runsCompleted + 1;
+ unlockComponents();
if (LK.getScore() > highScore) {
storage.highScore = LK.getScore();
}
LK.showGameOver();