/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
highScore: 0,
level: 1
});
/****
* Classes
****/
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = enemyGraphics.width;
self.height = enemyGraphics.height;
self.hp = 1;
self.scoreValue = 100;
self.canShoot = true;
self.movingRight = true;
self.moveSpeed = 2;
self.dropDistance = 40;
self.shoot = function () {
if (!self.canShoot || Math.random() > 0.01) {
return;
} // Random chance to shoot
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y + self.height / 2;
game.addChild(bullet);
enemyBullets.push(bullet);
// Cooldown between shots
self.canShoot = false;
LK.setTimeout(function () {
self.canShoot = true;
}, 2000);
};
self.takeDamage = function () {
self.hp--;
if (self.hp <= 0) {
// Update score
LK.setScore(LK.getScore() + self.scoreValue);
scoreTxt.setText(LK.getScore());
// Chance to drop power-up
if (Math.random() < 0.1) {
// 10% chance
var powerUp = new PowerUp();
powerUp.x = self.x;
powerUp.y = self.y;
game.addChild(powerUp);
powerUps.push(powerUp);
}
// Play sound
LK.getSound('enemyDestroyed').play();
// Visual effect
LK.effects.flashObject(self, 0xffff00, 300);
// Remove enemy
self.destroy();
var index = enemies.indexOf(self);
if (index > -1) {
enemies.splice(index, 1);
}
// Check if level complete
if (enemies.length === 0) {
levelComplete();
}
} else {
// Visual effect for damage
LK.effects.flashObject(self, 0xffff00, 200);
}
};
return self;
});
var Boss = Enemy.expand(function () {
var self = Enemy.call(this);
// Replace graphics with boss graphics
self.removeChildAt(0);
var bossGraphics = self.attachAsset('boss', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = bossGraphics.width;
self.height = bossGraphics.height;
self.hp = 20;
self.scoreValue = 2000;
self.moveSpeed = 3;
self.attackPattern = 0;
self.attackTimer = null;
self.startAttackPattern = function () {
self.attackTimer = LK.setInterval(function () {
self.performAttack();
}, 2000);
};
self.performAttack = function () {
self.attackPattern = (self.attackPattern + 1) % 3;
switch (self.attackPattern) {
case 0:
// Single strong shot
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y + self.height / 2;
bullet.speed = 8;
bullet.scale.set(2, 2);
game.addChild(bullet);
enemyBullets.push(bullet);
break;
case 1:
// Multiple shots in a spread
for (var i = -2; i <= 2; i++) {
var bullet = new EnemyBullet();
bullet.x = self.x + i * 40;
bullet.y = self.y + self.height / 2;
game.addChild(bullet);
enemyBullets.push(bullet);
}
break;
case 2:
// Wave pattern of bullets
var interval = LK.setInterval(function () {
var bullet = new EnemyBullet();
bullet.x = self.x + (Math.random() * 200 - 100);
bullet.y = self.y + self.height / 2;
game.addChild(bullet);
enemyBullets.push(bullet);
}, 200);
LK.setTimeout(function () {
LK.clearInterval(interval);
}, 1000);
break;
}
};
var parentTakeDamage = self.takeDamage;
self.takeDamage = function () {
parentTakeDamage.call(self);
// When boss is destroyed, clear the attack timer
if (self.hp <= 0 && self.attackTimer) {
LK.clearInterval(self.attackTimer);
}
};
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 = 6;
self.update = function () {
self.y += self.speed;
// Destroy if out of bounds
if (self.y > 2732 + 50) {
self.destroy();
var index = enemyBullets.indexOf(self);
if (index > -1) {
enemyBullets.splice(index, 1);
}
}
};
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 = -15; // Negative because moving upward
self.update = function () {
self.y += self.speed;
// Destroy if out of bounds
if (self.y < -50) {
self.destroy();
var index = bullets.indexOf(self);
if (index > -1) {
bullets.splice(index, 1);
}
}
};
return self;
});
var PlayerShip = Container.expand(function () {
var self = Container.call(this);
var shipGraphics = self.attachAsset('playerShip', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = shipGraphics.width;
self.height = shipGraphics.height;
self.lives = 3;
self.speed = 15;
self.canShoot = true;
self.shootCooldown = 300; // milliseconds
self.invulnerable = false;
self.powerUpActive = false;
self.startShootCooldown = function () {
self.canShoot = false;
LK.setTimeout(function () {
self.canShoot = true;
}, self.shootCooldown);
};
self.shoot = function () {
if (!self.canShoot) {
return;
}
var bullet = new PlayerBullet();
bullet.x = self.x;
bullet.y = self.y - self.height / 2;
game.addChild(bullet);
bullets.push(bullet);
LK.getSound('shoot').play();
self.startShootCooldown();
// Create double bullet when power-up is active
if (self.powerUpActive) {
var bulletLeft = new PlayerBullet();
bulletLeft.x = self.x - 20;
bulletLeft.y = self.y - self.height / 2;
var bulletRight = new PlayerBullet();
bulletRight.x = self.x + 20;
bulletRight.y = self.y - self.height / 2;
game.addChild(bulletLeft);
game.addChild(bulletRight);
bullets.push(bulletLeft);
bullets.push(bulletRight);
}
};
self.hit = function () {
if (self.invulnerable) {
return;
}
self.lives--;
LK.getSound('playerHit').play();
// Flash player ship to indicate damage
LK.effects.flashObject(self, 0xff0000, 1000);
// Make player temporarily invulnerable
self.invulnerable = true;
LK.setTimeout(function () {
self.invulnerable = false;
}, 2000);
// Check for game over
if (self.lives <= 0) {
LK.showGameOver();
}
};
self.activatePowerUp = function (type) {
LK.getSound('powerUpCollected').play();
switch (type) {
case 'rapidFire':
var oldCooldown = self.shootCooldown;
self.shootCooldown = 150;
LK.setTimeout(function () {
self.shootCooldown = oldCooldown;
}, 5000);
break;
case 'doubleBullet':
self.powerUpActive = true;
LK.setTimeout(function () {
self.powerUpActive = false;
}, 8000);
break;
case 'shield':
// Create shield
createShield();
break;
}
};
self.update = function () {
// Movement logic handled in game.update
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
var powerUpGraphics = self.attachAsset('powerUp', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 3;
self.type = ['rapidFire', 'doubleBullet', 'shield'][Math.floor(Math.random() * 3)];
// Set color based on power-up type
switch (self.type) {
case 'rapidFire':
powerUpGraphics.tint = 0xff0000; // Red
break;
case 'doubleBullet':
powerUpGraphics.tint = 0x00ff00; // Green
break;
case 'shield':
powerUpGraphics.tint = 0x0000ff; // Blue
break;
}
self.update = function () {
self.y += self.speed;
// Destroy if out of bounds
if (self.y > 2732 + 50) {
self.destroy();
var index = powerUps.indexOf(self);
if (index > -1) {
powerUps.splice(index, 1);
}
}
};
return self;
});
var Shield = Container.expand(function () {
var self = Container.call(this);
var shieldGraphics = self.attachAsset('shield', {
anchorX: 0.5,
anchorY: 0.5
});
self.hp = 3;
self.takeDamage = function () {
self.hp--;
// Visual feedback
LK.effects.flashObject(self, 0x2980b9, 200);
// Adjust opacity based on remaining HP
self.alpha = self.hp / 3;
if (self.hp <= 0) {
self.destroy();
var index = shields.indexOf(self);
if (index > -1) {
shields.splice(index, 1);
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Game constants
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
var GAME_MARGIN = 100;
var ENEMY_ROWS = 5;
var ENEMY_COLUMNS = 8;
var ENEMY_SPACING_X = 150;
var ENEMY_SPACING_Y = 120;
var ENEMY_START_Y = 300;
var GROUP_MOVE_AMOUNT = 15;
var GROUP_DROP_AMOUNT = 40;
var MOVE_INTERVAL = 800; // ms
// Game variables
var level = storage.level || 1;
var player;
var bullets = [];
var enemies = [];
var enemyBullets = [];
var shields = [];
var powerUps = [];
var enemyMoveTimer;
var movingRight = true;
var bossActive = false;
var touchX = null;
// Create UI elements
var scoreTxt = new Text2('0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0, 0);
LK.gui.topRight.addChild(scoreTxt);
scoreTxt.x = -250; // Offset from the right edge
var levelTxt = new Text2('LEVEL ' + level, {
size: 60,
fill: 0xFFFFFF
});
levelTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(levelTxt);
var livesTxt = new Text2('LIVES: 3', {
size: 60,
fill: 0xFFFFFF
});
livesTxt.anchor.set(0, 0);
LK.gui.topLeft.addChild(livesTxt);
livesTxt.x = 120; // Ensure we don't place this in the top-left 100x100 area
// Game functions
function initializeGame() {
// Reset game state
clearArrays();
// Set difficulty based on level
var enemyHp = Math.min(Math.floor(level / 3) + 1, 3);
var enemySpeed = Math.min(2 + level * 0.5, 8);
var moveInterval = Math.max(MOVE_INTERVAL - level * 50, 300);
// Create player
player = new PlayerShip();
player.x = GAME_WIDTH / 2;
player.y = GAME_HEIGHT - 200;
game.addChild(player);
// Create enemies
createEnemies(enemyHp);
// Start enemy movement
startEnemyMovement(moveInterval);
// Reset score if starting a new game
if (level === 1) {
LK.setScore(0);
}
// Update UI
scoreTxt.setText(LK.getScore());
levelTxt.setText('LEVEL ' + level);
// Play music
LK.playMusic('gameMusic', {
fade: {
start: 0,
end: 0.8,
duration: 1000
}
});
}
function clearArrays() {
// Clear existing game objects
for (var i = bullets.length - 1; i >= 0; i--) {
bullets[i].destroy();
}
for (var i = enemies.length - 1; i >= 0; i--) {
enemies[i].destroy();
}
for (var i = enemyBullets.length - 1; i >= 0; i--) {
enemyBullets[i].destroy();
}
for (var i = shields.length - 1; i >= 0; i--) {
shields[i].destroy();
}
for (var i = powerUps.length - 1; i >= 0; i--) {
powerUps[i].destroy();
}
bullets = [];
enemies = [];
enemyBullets = [];
shields = [];
powerUps = [];
// Clear any existing timers
if (enemyMoveTimer) {
LK.clearInterval(enemyMoveTimer);
}
}
function createEnemies(hp) {
bossActive = false;
// Boss level every 5 levels
if (level % 5 === 0) {
createBoss();
return;
}
// Create grid of enemies
var startX = (GAME_WIDTH - (ENEMY_COLUMNS - 1) * ENEMY_SPACING_X) / 2;
for (var row = 0; row < ENEMY_ROWS; row++) {
for (var col = 0; col < ENEMY_COLUMNS; col++) {
var enemy = new Enemy();
// Different types/strength based on row
if (row === 0) {
enemy.hp = hp + 1;
enemy.scoreValue = 300;
enemy.tint = 0xff0000; // Red top row
} else if (row === 1 || row === 2) {
enemy.hp = hp;
enemy.scoreValue = 200;
enemy.tint = 0x00ff00; // Green middle rows
} else {
enemy.hp = Math.max(1, hp - 1);
enemy.scoreValue = 100;
enemy.tint = 0x0000ff; // Blue bottom rows
}
enemy.x = startX + col * ENEMY_SPACING_X;
enemy.y = ENEMY_START_Y + row * ENEMY_SPACING_Y;
game.addChild(enemy);
enemies.push(enemy);
}
}
}
function createBoss() {
bossActive = true;
var boss = new Boss();
boss.x = GAME_WIDTH / 2;
boss.y = 300;
boss.hp = 15 + level / 5 * 5; // Increases with level
game.addChild(boss);
enemies.push(boss);
boss.startAttackPattern();
}
function startEnemyMovement(interval) {
enemyMoveTimer = LK.setInterval(function () {
moveEnemyGroup();
}, interval);
}
function moveEnemyGroup() {
if (enemies.length === 0) {
return;
}
var reachedEdge = false;
var moveAmount = bossActive ? GROUP_MOVE_AMOUNT * 1.5 : GROUP_MOVE_AMOUNT;
// Check if any enemy would go beyond screen edge
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
if (movingRight && enemy.x + enemy.width / 2 + moveAmount > GAME_WIDTH - GAME_MARGIN || !movingRight && enemy.x - enemy.width / 2 - moveAmount < GAME_MARGIN) {
reachedEdge = true;
break;
}
}
// Move group horizontally or drop and change direction
if (reachedEdge) {
movingRight = !movingRight;
// Move all enemies down
for (var i = 0; i < enemies.length; i++) {
enemies[i].y += GROUP_DROP_AMOUNT;
}
// Check if enemies reached player's area
checkEnemiesBottom();
} else {
// Move enemies sideways
for (var i = 0; i < enemies.length; i++) {
enemies[i].x += movingRight ? moveAmount : -moveAmount;
}
}
// Try to make some enemies shoot
for (var i = 0; i < enemies.length; i++) {
enemies[i].shoot();
}
}
function checkEnemiesBottom() {
for (var i = 0; i < enemies.length; i++) {
if (enemies[i].y + enemies[i].height / 2 > player.y - 100) {
// Game over if enemies get too close to bottom
LK.showGameOver();
return;
}
}
}
function createShield() {
var shield = new Shield();
shield.x = player.x;
shield.y = player.y - 80;
game.addChild(shield);
shields.push(shield);
}
function levelComplete() {
LK.getSound('levelComplete').play();
// Save high score if it's better than previous
if (LK.getScore() > storage.highScore) {
storage.highScore = LK.getScore();
}
// Increment level
level++;
storage.level = level;
// Show level transition
var levelCompleteTxt = new Text2('LEVEL COMPLETE!', {
size: 120,
fill: 0xFFFFFF
});
levelCompleteTxt.anchor.set(0.5, 0.5);
levelCompleteTxt.x = GAME_WIDTH / 2;
levelCompleteTxt.y = GAME_HEIGHT / 2;
game.addChild(levelCompleteTxt);
// Fade out current level
tween(levelCompleteTxt, {
alpha: 0
}, {
duration: 2000,
onFinish: function onFinish() {
levelCompleteTxt.destroy();
// Start next level
initializeGame();
}
});
}
function checkCollisions() {
// Player bullets vs enemies
for (var i = bullets.length - 1; i >= 0; i--) {
var bullet = bullets[i];
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (bullet.intersects(enemy)) {
// Handle hit
enemy.takeDamage();
// Remove bullet
bullet.destroy();
bullets.splice(i, 1);
break;
}
}
}
// Enemy bullets vs player
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var bullet = enemyBullets[i];
// Check for shield hits first
var hitShield = false;
for (var j = shields.length - 1; j >= 0; j--) {
var shield = shields[j];
if (bullet.intersects(shield)) {
shield.takeDamage();
// Remove bullet
bullet.destroy();
enemyBullets.splice(i, 1);
hitShield = true;
break;
}
}
if (hitShield) {
continue;
}
// Check for player hit
if (bullet.intersects(player)) {
player.hit();
// Remove bullet
bullet.destroy();
enemyBullets.splice(i, 1);
}
}
// Player vs power-ups
for (var i = powerUps.length - 1; i >= 0; i--) {
var powerUp = powerUps[i];
if (powerUp.intersects(player)) {
player.activatePowerUp(powerUp.type);
// Remove power-up
powerUp.destroy();
powerUps.splice(i, 1);
}
}
// Update lives display
livesTxt.setText('LIVES: ' + player.lives);
}
function movePlayer() {
// If touch input is active, move towards it
if (touchX !== null) {
var moveSpeed = player.speed;
var distanceToTouch = touchX - player.x;
if (Math.abs(distanceToTouch) < moveSpeed) {
player.x = touchX;
} else if (distanceToTouch > 0) {
player.x += moveSpeed;
} else {
player.x -= moveSpeed;
}
}
// Keep player within screen bounds
if (player.x < GAME_MARGIN + player.width / 2) {
player.x = GAME_MARGIN + player.width / 2;
} else if (player.x > GAME_WIDTH - GAME_MARGIN - player.width / 2) {
player.x = GAME_WIDTH - GAME_MARGIN - player.width / 2;
}
}
// Handle touch/mouse input
game.down = function (x, y, obj) {
touchX = x;
// Shoot when tapping
player.shoot();
};
game.move = function (x, y, obj) {
touchX = x;
};
game.up = function (x, y, obj) {
touchX = null;
};
// Game update loop
game.update = function () {
movePlayer();
// Update all game objects
for (var i = 0; i < bullets.length; i++) {
bullets[i].update();
}
for (var i = 0; i < enemyBullets.length; i++) {
enemyBullets[i].update();
}
for (var i = 0; i < powerUps.length; i++) {
powerUps[i].update();
}
// Check for collisions
checkCollisions();
};
// Initialize the game
initializeGame(); ===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,681 @@
-/****
+/****
+* Plugins
+****/
+var tween = LK.import("@upit/tween.v1");
+var storage = LK.import("@upit/storage.v1", {
+ highScore: 0,
+ level: 1
+});
+
+/****
+* Classes
+****/
+var Enemy = Container.expand(function () {
+ var self = Container.call(this);
+ var enemyGraphics = self.attachAsset('enemy', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.width = enemyGraphics.width;
+ self.height = enemyGraphics.height;
+ self.hp = 1;
+ self.scoreValue = 100;
+ self.canShoot = true;
+ self.movingRight = true;
+ self.moveSpeed = 2;
+ self.dropDistance = 40;
+ self.shoot = function () {
+ if (!self.canShoot || Math.random() > 0.01) {
+ return;
+ } // Random chance to shoot
+ var bullet = new EnemyBullet();
+ bullet.x = self.x;
+ bullet.y = self.y + self.height / 2;
+ game.addChild(bullet);
+ enemyBullets.push(bullet);
+ // Cooldown between shots
+ self.canShoot = false;
+ LK.setTimeout(function () {
+ self.canShoot = true;
+ }, 2000);
+ };
+ self.takeDamage = function () {
+ self.hp--;
+ if (self.hp <= 0) {
+ // Update score
+ LK.setScore(LK.getScore() + self.scoreValue);
+ scoreTxt.setText(LK.getScore());
+ // Chance to drop power-up
+ if (Math.random() < 0.1) {
+ // 10% chance
+ var powerUp = new PowerUp();
+ powerUp.x = self.x;
+ powerUp.y = self.y;
+ game.addChild(powerUp);
+ powerUps.push(powerUp);
+ }
+ // Play sound
+ LK.getSound('enemyDestroyed').play();
+ // Visual effect
+ LK.effects.flashObject(self, 0xffff00, 300);
+ // Remove enemy
+ self.destroy();
+ var index = enemies.indexOf(self);
+ if (index > -1) {
+ enemies.splice(index, 1);
+ }
+ // Check if level complete
+ if (enemies.length === 0) {
+ levelComplete();
+ }
+ } else {
+ // Visual effect for damage
+ LK.effects.flashObject(self, 0xffff00, 200);
+ }
+ };
+ return self;
+});
+var Boss = Enemy.expand(function () {
+ var self = Enemy.call(this);
+ // Replace graphics with boss graphics
+ self.removeChildAt(0);
+ var bossGraphics = self.attachAsset('boss', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.width = bossGraphics.width;
+ self.height = bossGraphics.height;
+ self.hp = 20;
+ self.scoreValue = 2000;
+ self.moveSpeed = 3;
+ self.attackPattern = 0;
+ self.attackTimer = null;
+ self.startAttackPattern = function () {
+ self.attackTimer = LK.setInterval(function () {
+ self.performAttack();
+ }, 2000);
+ };
+ self.performAttack = function () {
+ self.attackPattern = (self.attackPattern + 1) % 3;
+ switch (self.attackPattern) {
+ case 0:
+ // Single strong shot
+ var bullet = new EnemyBullet();
+ bullet.x = self.x;
+ bullet.y = self.y + self.height / 2;
+ bullet.speed = 8;
+ bullet.scale.set(2, 2);
+ game.addChild(bullet);
+ enemyBullets.push(bullet);
+ break;
+ case 1:
+ // Multiple shots in a spread
+ for (var i = -2; i <= 2; i++) {
+ var bullet = new EnemyBullet();
+ bullet.x = self.x + i * 40;
+ bullet.y = self.y + self.height / 2;
+ game.addChild(bullet);
+ enemyBullets.push(bullet);
+ }
+ break;
+ case 2:
+ // Wave pattern of bullets
+ var interval = LK.setInterval(function () {
+ var bullet = new EnemyBullet();
+ bullet.x = self.x + (Math.random() * 200 - 100);
+ bullet.y = self.y + self.height / 2;
+ game.addChild(bullet);
+ enemyBullets.push(bullet);
+ }, 200);
+ LK.setTimeout(function () {
+ LK.clearInterval(interval);
+ }, 1000);
+ break;
+ }
+ };
+ var parentTakeDamage = self.takeDamage;
+ self.takeDamage = function () {
+ parentTakeDamage.call(self);
+ // When boss is destroyed, clear the attack timer
+ if (self.hp <= 0 && self.attackTimer) {
+ LK.clearInterval(self.attackTimer);
+ }
+ };
+ 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 = 6;
+ self.update = function () {
+ self.y += self.speed;
+ // Destroy if out of bounds
+ if (self.y > 2732 + 50) {
+ self.destroy();
+ var index = enemyBullets.indexOf(self);
+ if (index > -1) {
+ enemyBullets.splice(index, 1);
+ }
+ }
+ };
+ 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 = -15; // Negative because moving upward
+ self.update = function () {
+ self.y += self.speed;
+ // Destroy if out of bounds
+ if (self.y < -50) {
+ self.destroy();
+ var index = bullets.indexOf(self);
+ if (index > -1) {
+ bullets.splice(index, 1);
+ }
+ }
+ };
+ return self;
+});
+var PlayerShip = Container.expand(function () {
+ var self = Container.call(this);
+ var shipGraphics = self.attachAsset('playerShip', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.width = shipGraphics.width;
+ self.height = shipGraphics.height;
+ self.lives = 3;
+ self.speed = 15;
+ self.canShoot = true;
+ self.shootCooldown = 300; // milliseconds
+ self.invulnerable = false;
+ self.powerUpActive = false;
+ self.startShootCooldown = function () {
+ self.canShoot = false;
+ LK.setTimeout(function () {
+ self.canShoot = true;
+ }, self.shootCooldown);
+ };
+ self.shoot = function () {
+ if (!self.canShoot) {
+ return;
+ }
+ var bullet = new PlayerBullet();
+ bullet.x = self.x;
+ bullet.y = self.y - self.height / 2;
+ game.addChild(bullet);
+ bullets.push(bullet);
+ LK.getSound('shoot').play();
+ self.startShootCooldown();
+ // Create double bullet when power-up is active
+ if (self.powerUpActive) {
+ var bulletLeft = new PlayerBullet();
+ bulletLeft.x = self.x - 20;
+ bulletLeft.y = self.y - self.height / 2;
+ var bulletRight = new PlayerBullet();
+ bulletRight.x = self.x + 20;
+ bulletRight.y = self.y - self.height / 2;
+ game.addChild(bulletLeft);
+ game.addChild(bulletRight);
+ bullets.push(bulletLeft);
+ bullets.push(bulletRight);
+ }
+ };
+ self.hit = function () {
+ if (self.invulnerable) {
+ return;
+ }
+ self.lives--;
+ LK.getSound('playerHit').play();
+ // Flash player ship to indicate damage
+ LK.effects.flashObject(self, 0xff0000, 1000);
+ // Make player temporarily invulnerable
+ self.invulnerable = true;
+ LK.setTimeout(function () {
+ self.invulnerable = false;
+ }, 2000);
+ // Check for game over
+ if (self.lives <= 0) {
+ LK.showGameOver();
+ }
+ };
+ self.activatePowerUp = function (type) {
+ LK.getSound('powerUpCollected').play();
+ switch (type) {
+ case 'rapidFire':
+ var oldCooldown = self.shootCooldown;
+ self.shootCooldown = 150;
+ LK.setTimeout(function () {
+ self.shootCooldown = oldCooldown;
+ }, 5000);
+ break;
+ case 'doubleBullet':
+ self.powerUpActive = true;
+ LK.setTimeout(function () {
+ self.powerUpActive = false;
+ }, 8000);
+ break;
+ case 'shield':
+ // Create shield
+ createShield();
+ break;
+ }
+ };
+ self.update = function () {
+ // Movement logic handled in game.update
+ };
+ return self;
+});
+var PowerUp = Container.expand(function () {
+ var self = Container.call(this);
+ var powerUpGraphics = self.attachAsset('powerUp', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.speed = 3;
+ self.type = ['rapidFire', 'doubleBullet', 'shield'][Math.floor(Math.random() * 3)];
+ // Set color based on power-up type
+ switch (self.type) {
+ case 'rapidFire':
+ powerUpGraphics.tint = 0xff0000; // Red
+ break;
+ case 'doubleBullet':
+ powerUpGraphics.tint = 0x00ff00; // Green
+ break;
+ case 'shield':
+ powerUpGraphics.tint = 0x0000ff; // Blue
+ break;
+ }
+ self.update = function () {
+ self.y += self.speed;
+ // Destroy if out of bounds
+ if (self.y > 2732 + 50) {
+ self.destroy();
+ var index = powerUps.indexOf(self);
+ if (index > -1) {
+ powerUps.splice(index, 1);
+ }
+ }
+ };
+ return self;
+});
+var Shield = Container.expand(function () {
+ var self = Container.call(this);
+ var shieldGraphics = self.attachAsset('shield', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.hp = 3;
+ self.takeDamage = function () {
+ self.hp--;
+ // Visual feedback
+ LK.effects.flashObject(self, 0x2980b9, 200);
+ // Adjust opacity based on remaining HP
+ self.alpha = self.hp / 3;
+ if (self.hp <= 0) {
+ self.destroy();
+ var index = shields.indexOf(self);
+ if (index > -1) {
+ shields.splice(index, 1);
+ }
+ }
+ };
+ return self;
+});
+
+/****
* Initialize Game
-****/
+****/
var game = new LK.Game({
backgroundColor: 0x000000
-});
\ No newline at end of file
+});
+
+/****
+* Game Code
+****/
+// Game constants
+var GAME_WIDTH = 2048;
+var GAME_HEIGHT = 2732;
+var GAME_MARGIN = 100;
+var ENEMY_ROWS = 5;
+var ENEMY_COLUMNS = 8;
+var ENEMY_SPACING_X = 150;
+var ENEMY_SPACING_Y = 120;
+var ENEMY_START_Y = 300;
+var GROUP_MOVE_AMOUNT = 15;
+var GROUP_DROP_AMOUNT = 40;
+var MOVE_INTERVAL = 800; // ms
+// Game variables
+var level = storage.level || 1;
+var player;
+var bullets = [];
+var enemies = [];
+var enemyBullets = [];
+var shields = [];
+var powerUps = [];
+var enemyMoveTimer;
+var movingRight = true;
+var bossActive = false;
+var touchX = null;
+// Create UI elements
+var scoreTxt = new Text2('0', {
+ size: 60,
+ fill: 0xFFFFFF
+});
+scoreTxt.anchor.set(0, 0);
+LK.gui.topRight.addChild(scoreTxt);
+scoreTxt.x = -250; // Offset from the right edge
+var levelTxt = new Text2('LEVEL ' + level, {
+ size: 60,
+ fill: 0xFFFFFF
+});
+levelTxt.anchor.set(0.5, 0);
+LK.gui.top.addChild(levelTxt);
+var livesTxt = new Text2('LIVES: 3', {
+ size: 60,
+ fill: 0xFFFFFF
+});
+livesTxt.anchor.set(0, 0);
+LK.gui.topLeft.addChild(livesTxt);
+livesTxt.x = 120; // Ensure we don't place this in the top-left 100x100 area
+// Game functions
+function initializeGame() {
+ // Reset game state
+ clearArrays();
+ // Set difficulty based on level
+ var enemyHp = Math.min(Math.floor(level / 3) + 1, 3);
+ var enemySpeed = Math.min(2 + level * 0.5, 8);
+ var moveInterval = Math.max(MOVE_INTERVAL - level * 50, 300);
+ // Create player
+ player = new PlayerShip();
+ player.x = GAME_WIDTH / 2;
+ player.y = GAME_HEIGHT - 200;
+ game.addChild(player);
+ // Create enemies
+ createEnemies(enemyHp);
+ // Start enemy movement
+ startEnemyMovement(moveInterval);
+ // Reset score if starting a new game
+ if (level === 1) {
+ LK.setScore(0);
+ }
+ // Update UI
+ scoreTxt.setText(LK.getScore());
+ levelTxt.setText('LEVEL ' + level);
+ // Play music
+ LK.playMusic('gameMusic', {
+ fade: {
+ start: 0,
+ end: 0.8,
+ duration: 1000
+ }
+ });
+}
+function clearArrays() {
+ // Clear existing game objects
+ for (var i = bullets.length - 1; i >= 0; i--) {
+ bullets[i].destroy();
+ }
+ for (var i = enemies.length - 1; i >= 0; i--) {
+ enemies[i].destroy();
+ }
+ for (var i = enemyBullets.length - 1; i >= 0; i--) {
+ enemyBullets[i].destroy();
+ }
+ for (var i = shields.length - 1; i >= 0; i--) {
+ shields[i].destroy();
+ }
+ for (var i = powerUps.length - 1; i >= 0; i--) {
+ powerUps[i].destroy();
+ }
+ bullets = [];
+ enemies = [];
+ enemyBullets = [];
+ shields = [];
+ powerUps = [];
+ // Clear any existing timers
+ if (enemyMoveTimer) {
+ LK.clearInterval(enemyMoveTimer);
+ }
+}
+function createEnemies(hp) {
+ bossActive = false;
+ // Boss level every 5 levels
+ if (level % 5 === 0) {
+ createBoss();
+ return;
+ }
+ // Create grid of enemies
+ var startX = (GAME_WIDTH - (ENEMY_COLUMNS - 1) * ENEMY_SPACING_X) / 2;
+ for (var row = 0; row < ENEMY_ROWS; row++) {
+ for (var col = 0; col < ENEMY_COLUMNS; col++) {
+ var enemy = new Enemy();
+ // Different types/strength based on row
+ if (row === 0) {
+ enemy.hp = hp + 1;
+ enemy.scoreValue = 300;
+ enemy.tint = 0xff0000; // Red top row
+ } else if (row === 1 || row === 2) {
+ enemy.hp = hp;
+ enemy.scoreValue = 200;
+ enemy.tint = 0x00ff00; // Green middle rows
+ } else {
+ enemy.hp = Math.max(1, hp - 1);
+ enemy.scoreValue = 100;
+ enemy.tint = 0x0000ff; // Blue bottom rows
+ }
+ enemy.x = startX + col * ENEMY_SPACING_X;
+ enemy.y = ENEMY_START_Y + row * ENEMY_SPACING_Y;
+ game.addChild(enemy);
+ enemies.push(enemy);
+ }
+ }
+}
+function createBoss() {
+ bossActive = true;
+ var boss = new Boss();
+ boss.x = GAME_WIDTH / 2;
+ boss.y = 300;
+ boss.hp = 15 + level / 5 * 5; // Increases with level
+ game.addChild(boss);
+ enemies.push(boss);
+ boss.startAttackPattern();
+}
+function startEnemyMovement(interval) {
+ enemyMoveTimer = LK.setInterval(function () {
+ moveEnemyGroup();
+ }, interval);
+}
+function moveEnemyGroup() {
+ if (enemies.length === 0) {
+ return;
+ }
+ var reachedEdge = false;
+ var moveAmount = bossActive ? GROUP_MOVE_AMOUNT * 1.5 : GROUP_MOVE_AMOUNT;
+ // Check if any enemy would go beyond screen edge
+ for (var i = 0; i < enemies.length; i++) {
+ var enemy = enemies[i];
+ if (movingRight && enemy.x + enemy.width / 2 + moveAmount > GAME_WIDTH - GAME_MARGIN || !movingRight && enemy.x - enemy.width / 2 - moveAmount < GAME_MARGIN) {
+ reachedEdge = true;
+ break;
+ }
+ }
+ // Move group horizontally or drop and change direction
+ if (reachedEdge) {
+ movingRight = !movingRight;
+ // Move all enemies down
+ for (var i = 0; i < enemies.length; i++) {
+ enemies[i].y += GROUP_DROP_AMOUNT;
+ }
+ // Check if enemies reached player's area
+ checkEnemiesBottom();
+ } else {
+ // Move enemies sideways
+ for (var i = 0; i < enemies.length; i++) {
+ enemies[i].x += movingRight ? moveAmount : -moveAmount;
+ }
+ }
+ // Try to make some enemies shoot
+ for (var i = 0; i < enemies.length; i++) {
+ enemies[i].shoot();
+ }
+}
+function checkEnemiesBottom() {
+ for (var i = 0; i < enemies.length; i++) {
+ if (enemies[i].y + enemies[i].height / 2 > player.y - 100) {
+ // Game over if enemies get too close to bottom
+ LK.showGameOver();
+ return;
+ }
+ }
+}
+function createShield() {
+ var shield = new Shield();
+ shield.x = player.x;
+ shield.y = player.y - 80;
+ game.addChild(shield);
+ shields.push(shield);
+}
+function levelComplete() {
+ LK.getSound('levelComplete').play();
+ // Save high score if it's better than previous
+ if (LK.getScore() > storage.highScore) {
+ storage.highScore = LK.getScore();
+ }
+ // Increment level
+ level++;
+ storage.level = level;
+ // Show level transition
+ var levelCompleteTxt = new Text2('LEVEL COMPLETE!', {
+ size: 120,
+ fill: 0xFFFFFF
+ });
+ levelCompleteTxt.anchor.set(0.5, 0.5);
+ levelCompleteTxt.x = GAME_WIDTH / 2;
+ levelCompleteTxt.y = GAME_HEIGHT / 2;
+ game.addChild(levelCompleteTxt);
+ // Fade out current level
+ tween(levelCompleteTxt, {
+ alpha: 0
+ }, {
+ duration: 2000,
+ onFinish: function onFinish() {
+ levelCompleteTxt.destroy();
+ // Start next level
+ initializeGame();
+ }
+ });
+}
+function checkCollisions() {
+ // Player bullets vs enemies
+ for (var i = bullets.length - 1; i >= 0; i--) {
+ var bullet = bullets[i];
+ for (var j = enemies.length - 1; j >= 0; j--) {
+ var enemy = enemies[j];
+ if (bullet.intersects(enemy)) {
+ // Handle hit
+ enemy.takeDamage();
+ // Remove bullet
+ bullet.destroy();
+ bullets.splice(i, 1);
+ break;
+ }
+ }
+ }
+ // Enemy bullets vs player
+ for (var i = enemyBullets.length - 1; i >= 0; i--) {
+ var bullet = enemyBullets[i];
+ // Check for shield hits first
+ var hitShield = false;
+ for (var j = shields.length - 1; j >= 0; j--) {
+ var shield = shields[j];
+ if (bullet.intersects(shield)) {
+ shield.takeDamage();
+ // Remove bullet
+ bullet.destroy();
+ enemyBullets.splice(i, 1);
+ hitShield = true;
+ break;
+ }
+ }
+ if (hitShield) {
+ continue;
+ }
+ // Check for player hit
+ if (bullet.intersects(player)) {
+ player.hit();
+ // Remove bullet
+ bullet.destroy();
+ enemyBullets.splice(i, 1);
+ }
+ }
+ // Player vs power-ups
+ for (var i = powerUps.length - 1; i >= 0; i--) {
+ var powerUp = powerUps[i];
+ if (powerUp.intersects(player)) {
+ player.activatePowerUp(powerUp.type);
+ // Remove power-up
+ powerUp.destroy();
+ powerUps.splice(i, 1);
+ }
+ }
+ // Update lives display
+ livesTxt.setText('LIVES: ' + player.lives);
+}
+function movePlayer() {
+ // If touch input is active, move towards it
+ if (touchX !== null) {
+ var moveSpeed = player.speed;
+ var distanceToTouch = touchX - player.x;
+ if (Math.abs(distanceToTouch) < moveSpeed) {
+ player.x = touchX;
+ } else if (distanceToTouch > 0) {
+ player.x += moveSpeed;
+ } else {
+ player.x -= moveSpeed;
+ }
+ }
+ // Keep player within screen bounds
+ if (player.x < GAME_MARGIN + player.width / 2) {
+ player.x = GAME_MARGIN + player.width / 2;
+ } else if (player.x > GAME_WIDTH - GAME_MARGIN - player.width / 2) {
+ player.x = GAME_WIDTH - GAME_MARGIN - player.width / 2;
+ }
+}
+// Handle touch/mouse input
+game.down = function (x, y, obj) {
+ touchX = x;
+ // Shoot when tapping
+ player.shoot();
+};
+game.move = function (x, y, obj) {
+ touchX = x;
+};
+game.up = function (x, y, obj) {
+ touchX = null;
+};
+// Game update loop
+game.update = function () {
+ movePlayer();
+ // Update all game objects
+ for (var i = 0; i < bullets.length; i++) {
+ bullets[i].update();
+ }
+ for (var i = 0; i < enemyBullets.length; i++) {
+ enemyBullets[i].update();
+ }
+ for (var i = 0; i < powerUps.length; i++) {
+ powerUps[i].update();
+ }
+ // Check for collisions
+ checkCollisions();
+};
+// Initialize the game
+initializeGame();
\ No newline at end of file