/**** * 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, flipX: 1 // Flip the spaceship horizontally }); 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); // Add space background var spaceBackground = LK.getAsset('spaceBackground', { anchorX: 0.5, anchorY: 0.5 }); spaceBackground.x = GAME_WIDTH / 2; spaceBackground.y = GAME_HEIGHT / 2; game.addChild(spaceBackground); // Create player if not already created if (!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
@@ -401,13 +401,15 @@
});
spaceBackground.x = GAME_WIDTH / 2;
spaceBackground.y = GAME_HEIGHT / 2;
game.addChild(spaceBackground);
- // Create player
- player = new PlayerShip();
- player.x = GAME_WIDTH / 2;
- player.y = GAME_HEIGHT - 200;
- game.addChild(player);
+ // Create player if not already created
+ if (!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);