User prompt
Enemy types
User prompt
Please fix the bug: 'TypeError: tween.to is not a function' in or related to this line: 'tween.to(graphics, 0.5, {' Line Number: 181 ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Please fix the bug: 'PowerUpManager is not a constructor' in or related to this line: 'powerUpManager = new PowerUpManager();' Line Number: 305
User prompt
Powerups
User prompt
The game is laggy
User prompt
Please fix the bug: 'ReferenceError: enemy is not defined' in or related to this line: 'if (minX < enemy.width / 2 && enemiesDirection === -1 || maxX > GAME_WIDTH - enemy.width / 2 && enemiesDirection === 1) {' Line Number: 301
Code edit (1 edits merged)
Please save this source code
User prompt
Cosmic Defenders
Initial prompt
Make space invaders
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Enemy = Container.expand(function () { var self = Container.call(this); var enemyGraphics = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); self.active = true; self.width = enemyGraphics.width; self.height = enemyGraphics.height; self.points = 10; self.shotChance = 0.005; // Chance per frame to shoot self.type = "basic"; // Default enemy type self.update = function () { // Enemy logic will be controlled by the formation }; return self; }); var ToughEnemy = Enemy.expand(function () { var self = Enemy.call(this); self.children[0].tint = 0x0000ff; // Blue tough enemy self.type = "tough"; self.points = 25; self.shotChance = 0.005; self.health = 2; // Takes 2 hits to destroy // Override damage method self.damage = function () { self.health--; // Visual feedback for hit LK.effects.flashObject(self, 0xffffff, 100); if (self.health <= 0) { return true; // Enemy is destroyed } // Change appearance after hit self.children[0].alpha = 0.7; return false; // Enemy is still alive }; return self; }); // PowerUpManager has been moved to Classes section var FastEnemy = Enemy.expand(function () { var self = Enemy.call(this); self.children[0].tint = 0xff0000; // Red fast enemy self.type = "fast"; self.points = 15; self.shotChance = 0.008; // Higher chance to shoot self.speedMultiplier = 1.5; // Moves faster than other enemies // Override update to add custom behavior if needed var parentUpdate = self.update; self.update = function () { parentUpdate.call(self); // Additional fast enemy behavior can be added here }; return self; }); var BomberEnemy = Enemy.expand(function () { var self = Enemy.call(this); self.children[0].tint = 0xff00ff; // Purple bomber enemy self.type = "bomber"; self.points = 20; self.shotChance = 0.004; // Lower chance to shoot, but shoots multiple bullets // Bomber enemies will release multiple bullets in a pattern self.fireBurst = function (shootFunction) { if (typeof shootFunction === 'function') { // Fire multiple shots in a spread pattern shootFunction(self); // Schedule additional shots with slight delay LK.setTimeout(function () { shootFunction(self); }, 150); LK.setTimeout(function () { shootFunction(self); }, 300); } }; return self; }); var BasicEnemy = Enemy.expand(function () { var self = Enemy.call(this); self.children[0].tint = 0x00ff00; // Green basic enemy self.type = "basic"; self.points = 10; self.shotChance = 0.005; 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; // Positive because it moves downward self.active = false; self.visible = false; self.width = bulletGraphics.width; self.height = bulletGraphics.height; self.reset = function (x, y) { self.x = x; self.y = y; self.active = true; self.visible = true; }; self.update = function () { self.y += self.speed; // Deactivate when off screen if (self.y > 2732 + self.height) { self.active = false; self.visible = false; } }; 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 it moves upward self.active = false; self.visible = false; self.width = bulletGraphics.width; self.height = bulletGraphics.height; self.reset = function (x, y) { self.x = x; self.y = y; self.active = true; self.visible = true; }; self.update = function () { self.y += self.speed; // Deactivate when off screen if (self.y < -self.height) { self.active = false; self.visible = false; } }; return self; }); var PlayerShip = Container.expand(function () { var self = Container.call(this); var shipGraphics = self.attachAsset('playerShip', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 12; self.width = shipGraphics.width; self.height = shipGraphics.height; self.fireRate = 15; // frames between shots self.lastShot = 0; self.alive = true; self.moveLeft = function () { self.x -= self.speed; if (self.x < self.width / 2) { self.x = self.width / 2; } }; self.moveRight = function () { self.x += self.speed; if (self.x > 2048 - self.width / 2) { self.x = 2048 - self.width / 2; } }; self.canShoot = function () { return self.lastShot <= 0; }; self.resetShotTimer = function () { self.lastShot = self.fireRate; }; self.update = function () { if (self.lastShot > 0) { self.lastShot--; } }; return self; }); var PowerUp = Container.expand(function () { var self = Container.call(this); // Default values self.type = "none"; self.speed = 3; self.active = false; self.visible = false; self.width = 80; self.height = 80; // Create base graphics container that will hold the powerup visual var graphics = new Container(); self.addChild(graphics); // Initialize with specific type self.init = function (type, x, y) { self.type = type; self.x = x; self.y = y; self.active = true; self.visible = true; // Clear previous graphics while (graphics.children.length > 0) { graphics.removeChild(graphics.children[0]); } // Create visuals based on type if (type === "extraLife") { var heart = LK.getAsset('shield', { anchorX: 0.5, anchorY: 0.5, tint: 0xff0000 // Red heart }); graphics.addChild(heart); } else if (type === "weaponUpgrade") { var weapon = LK.getAsset('playerBullet', { anchorX: 0.5, anchorY: 0.5, tint: 0xffff00 // Yellow weapon upgrade }); graphics.addChild(weapon); } else if (type === "shield") { var shield = LK.getAsset('shield', { anchorX: 0.5, anchorY: 0.5, tint: 0x00ffff // Cyan shield }); graphics.addChild(shield); } // Apply a pulsing effect to make powerups stand out self.pulseEffect(); }; // Pulsing animation effect self.pulseEffect = function () { tween(graphics, { scaleX: 1.2, scaleY: 1.2 }, { duration: 500, onFinish: function onComplete() { tween(graphics, { scaleX: 1.0, scaleY: 1.0 }, { duration: 500, onFinish: self.pulseEffect }); } }); }; // Update powerup position - move downward self.update = function () { if (self.active) { self.y += self.speed; // Deactivate when off screen if (self.y > GAME_HEIGHT + self.height) { self.active = false; self.visible = false; } } }; return self; }); var Shield = Container.expand(function () { var self = Container.call(this); var shieldGraphics = self.attachAsset('shield', { anchorX: 0.5, anchorY: 0.5 }); self.health = 3; self.width = shieldGraphics.width; self.height = shieldGraphics.height; self.damage = function () { self.health--; shieldGraphics.alpha = self.health / 3; if (self.health <= 0) { self.active = false; self.visible = false; } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000022 }); /**** * Game Code ****/ // Game constants var PowerUpManager = function PowerUpManager() { var powerups = []; var self = this; var maxPowerups = 10; // Probability settings self.dropChance = 0.2; // 20% chance an enemy drops a powerup // Create initial pool of powerups for (var i = 0; i < maxPowerups; i++) { var powerup = new PowerUp(); powerup.visible = false; powerup.active = false; powerups.push(powerup); game.addChild(powerup); } // Get an inactive powerup from the pool self.getPowerUp = function () { for (var i = 0; i < powerups.length; i++) { if (!powerups[i].active) { return powerups[i]; } } return null; // No powerups available }; // Create a powerup at the given position with random type self.createPowerUp = function (x, y) { if (Math.random() > self.dropChance) return; // Random chance to drop var powerup = self.getPowerUp(); if (!powerup) return; // Determine powerup type randomly var rand = Math.random(); var type; if (rand < 0.3) { type = "extraLife"; } else if (rand < 0.7) { type = "weaponUpgrade"; } else { type = "shield"; } powerup.init(type, x, y); }; // Update all active powerups self.update = function () { for (var i = 0; i < powerups.length; i++) { if (powerups[i].active) { powerups[i].update(); } } }; // Check for collisions with player self.checkCollisions = function (player) { for (var i = 0; i < powerups.length; i++) { var powerup = powerups[i]; if (powerup.active && player.alive && powerup.intersects(player)) { // Apply powerup effect self.applyPowerUp(powerup.type); // Deactivate powerup powerup.active = false; powerup.visible = false; // Visual feedback LK.effects.flashObject(player, 0x00ff00, 300); } } }; // Apply powerup effects self.applyPowerUp = function (type) { if (type === "extraLife") { // Add extra life lives++; livesTxt.setText("Lives: " + lives); } else if (type === "weaponUpgrade") { // Temporary weapon upgrade (faster fire rate) var originalFireRate = player.fireRate; player.fireRate = Math.max(5, player.fireRate - 5); // Reduce fire rate (faster shots) // Reset after 10 seconds LK.setTimeout(function () { player.fireRate = originalFireRate; }, 10000); } else if (type === "shield") { // Create new shield for player var shield = new Shield(); shield.x = player.x; shield.y = SHIELD_Y; shield.active = true; shields.push(shield); game.addChild(shield); } }; // Get all powerups self.getAll = function () { return powerups; }; }; var BulletPool = function BulletPool(bulletType, maxSize) { var pool = []; var self = this; // Pre-create bullets for (var i = 0; i < maxSize; i++) { var bullet = new bulletType(); bullet.visible = false; bullet.active = false; pool.push(bullet); } self.getBullet = function () { for (var i = 0; i < pool.length; i++) { if (!pool[i].active) { pool[i].active = true; pool[i].visible = true; return pool[i]; } } return null; // No bullets available }; self.getAll = function () { return pool; }; }; var GAME_WIDTH = 2048; var GAME_HEIGHT = 2732; var PLAYER_START_Y = GAME_HEIGHT - 200; var SHIELD_Y = PLAYER_START_Y - 150; var ENEMY_START_Y = 300; var ENEMY_ROWS = 5; var ENEMY_COLS = 10; var ENEMY_PADDING = 20; var ENEMIES_MOVE_DOWN_AMOUNT = 30; var WAVE_SPEED_INCREASE = 0.2; // Game state var player; var playerBulletPool; var enemyBulletPool; var powerUpManager; var activePlayerBullets = 0; var activeEnemyBullets = 0; var enemies = []; var shields = []; var score = 0; var lives = 3; var wave = 1; var enemiesDirection = 1; // 1 = right, -1 = left var enemiesSpeed = 1; var enemyMoveTimer = 0; var enemyMoveInterval = 30; // Frames between enemy movement var gameState = "playing"; // playing, gameover var dragActive = false; var dragStartX = 0; var lastFrameTime = Date.now(); var frameTime = 0; // UI elements var scoreTxt; var livesTxt; var waveTxt; // Initialize player player = new PlayerShip(); player.x = GAME_WIDTH / 2; player.y = PLAYER_START_Y; game.addChild(player); // Initialize bullet pools playerBulletPool = new BulletPool(PlayerBullet, 20); enemyBulletPool = new BulletPool(EnemyBullet, 50); // Initialize power-up manager powerUpManager = new PowerUpManager(); // Add all bullets to the game var allPlayerBullets = playerBulletPool.getAll(); var allEnemyBullets = enemyBulletPool.getAll(); for (var i = 0; i < allPlayerBullets.length; i++) { game.addChild(allPlayerBullets[i]); } for (var i = 0; i < allEnemyBullets.length; i++) { game.addChild(allEnemyBullets[i]); } // Initialize shields for (var i = 0; i < 3; i++) { var shield = new Shield(); shield.x = GAME_WIDTH / 4 + GAME_WIDTH / 2 * (i / 2); shield.y = SHIELD_Y; shield.active = true; shields.push(shield); game.addChild(shield); } // Create UI scoreTxt = new Text2('Score: 0', { size: 60, fill: 0xFFFFFF }); scoreTxt.anchor.set(0, 0); scoreTxt.x = 20; scoreTxt.y = 20; LK.gui.addChild(scoreTxt); livesTxt = new Text2('Lives: 3', { size: 60, fill: 0xFFFFFF }); livesTxt.anchor.set(1, 0); livesTxt.x = GAME_WIDTH - 20; livesTxt.y = 20; LK.gui.addChild(livesTxt); waveTxt = new Text2('Wave: 1', { size: 60, fill: 0xFFFFFF }); waveTxt.anchor.set(0.5, 0); waveTxt.x = GAME_WIDTH / 2; waveTxt.y = 20; LK.gui.addChild(waveTxt); // Create enemies function createEnemies() { // Calculate total width of enemy formation var enemyWidth = new Enemy().width; var formationWidth = ENEMY_COLS * (enemyWidth + ENEMY_PADDING) - ENEMY_PADDING; var startX = (GAME_WIDTH - formationWidth) / 2 + enemyWidth / 2; // Enemy type distribution based on wave number // Higher waves have more advanced enemy types for (var row = 0; row < ENEMY_ROWS; row++) { for (var col = 0; col < ENEMY_COLS; col++) { var enemy; var rand = Math.random(); // Different enemy types depending on row and wave number if (row === 0) { // Top row - tougher enemies in higher waves if (wave >= 3 && rand < 0.7) { enemy = new ToughEnemy(); } else if (wave >= 2 && rand < 0.4) { enemy = new FastEnemy(); } else { enemy = new BasicEnemy(); } } else if (row === 1) { // Second row - more bombers in higher waves if (wave >= 3 && rand < 0.5) { enemy = new BomberEnemy(); } else if (wave >= 2 && rand < 0.3) { enemy = new ToughEnemy(); } else { enemy = new FastEnemy(); } } else if (row === 2) { // Third row - mixed enemy types if (rand < 0.4) { enemy = new FastEnemy(); } else if (rand < 0.7) { enemy = new BomberEnemy(); } else { enemy = new BasicEnemy(); } } else { // Lower rows - basic enemies with occasional fast ones if (rand < 0.3 * (wave / 2)) { enemy = new FastEnemy(); } else { enemy = new BasicEnemy(); } } enemy.x = startX + col * (enemy.width + ENEMY_PADDING); enemy.y = ENEMY_START_Y + row * (enemy.height + ENEMY_PADDING); enemy.row = row; enemy.col = col; // Modify points based on row position (higher rows worth more) enemy.points = Math.round(enemy.points * (1 + (ENEMY_ROWS - row) * 0.2)); enemies.push(enemy); game.addChild(enemy); } } } createEnemies(); // Play background music LK.playMusic('bgMusic', { loop: true }); // Game control event handlers game.down = function (x, y, obj) { dragActive = true; dragStartX = x; }; game.up = function (x, y, obj) { dragActive = false; }; game.move = function (x, y, obj) { if (dragActive && gameState === "playing") { // Move player based on drag var deltaX = x - dragStartX; if (Math.abs(deltaX) > 5) { // Threshold to prevent jitter if (deltaX > 0) { player.moveRight(); } else { player.moveLeft(); } dragStartX = x; } } }; // Create player bullet function shootPlayerBullet() { if (player.canShoot() && gameState === "playing") { var bullet = playerBulletPool.getBullet(); if (bullet) { bullet.reset(player.x, player.y - player.height / 2); activePlayerBullets++; player.resetShotTimer(); // Play shoot sound LK.getSound('playerShoot').play(); } } } // Create enemy bullet function shootEnemyBullet(enemy) { var bullet = enemyBulletPool.getBullet(); if (bullet) { bullet.reset(enemy.x, enemy.y + enemy.height / 2); activeEnemyBullets++; } } // Check if formation needs to move down and change direction function checkFormationBounds() { var moveDown = false; var minX = GAME_WIDTH; var maxX = 0; var enemyWidth = 0; // Check if there are any enemies before proceeding if (enemies.length === 0) { return false; } enemies.forEach(function (enemy) { if (enemy.x < minX) minX = enemy.x; if (enemy.x > maxX) maxX = enemy.x; enemyWidth = enemy.width; // Store width from any enemy for boundary checking }); // Using enemyWidth which is now properly set from actual enemies if (minX < enemyWidth / 2 && enemiesDirection === -1 || maxX > GAME_WIDTH - enemyWidth / 2 && enemiesDirection === 1) { moveDown = true; enemiesDirection *= -1; } return moveDown; } // Move enemy formation function moveEnemies() { var moveDown = checkFormationBounds(); enemies.forEach(function (enemy) { if (moveDown) { enemy.y += ENEMIES_MOVE_DOWN_AMOUNT; } enemy.x += enemiesDirection * enemiesSpeed; }); } // Check for collisions function checkCollisions() { var allPlayerBullets = playerBulletPool.getAll(); var allEnemyBullets = enemyBulletPool.getAll(); // Player bullets vs enemies for (var i = 0; i < allPlayerBullets.length; i++) { var bullet = allPlayerBullets[i]; if (!bullet.active) continue; // Check if bullet hits any enemy - using a more efficient method var hitEnemy = false; for (var j = enemies.length - 1; j >= 0; j--) { var enemy = enemies[j]; if (bullet.intersects(enemy)) { var enemyDestroyed = true; var enemyX = enemy.x; var enemyY = enemy.y; var enemyType = enemy.type; // Handle tough enemies differently if (enemy.type === "tough" && typeof enemy.damage === "function") { enemyDestroyed = enemy.damage(); // Returns true if enemy is destroyed } if (enemyDestroyed) { // Enemy hit and destroyed score += enemy.points; scoreTxt.setText("Score: " + score); // Remove enemy game.removeChild(enemy); enemies.splice(j, 1); // Try to spawn a power-up at enemy position powerUpManager.createPowerUp(enemyX, enemyY); // Play explosion sound LK.getSound('enemyExplode').play(); // Flash screen effect LK.effects.flashObject(game, 0xffffff, 100); } // Deactivate bullet regardless of whether enemy was destroyed bullet.active = false; bullet.visible = false; activePlayerBullets--; hitEnemy = true; break; // Bullet can only hit one enemy } } // Check if bullet hits any shield (only if it didn't hit an enemy) if (!hitEnemy && bullet.active) { for (var k = shields.length - 1; k >= 0; k--) { var shield = shields[k]; if (shield.active && bullet.intersects(shield)) { // Shield hit by player bullet shield.damage(); // Deactivate bullet bullet.active = false; bullet.visible = false; activePlayerBullets--; // Remove shield if destroyed if (!shield.active) { game.removeChild(shield); shields.splice(k, 1); } break; } } } } // Enemy bullets vs player and shields for (var i = 0; i < allEnemyBullets.length; i++) { var bullet = allEnemyBullets[i]; if (!bullet.active) continue; // Check player collision if (bullet.intersects(player) && gameState === "playing") { // Player hit lives--; livesTxt.setText("Lives: " + lives); // Deactivate bullet bullet.active = false; bullet.visible = false; activeEnemyBullets--; // Play hit sound LK.getSound('playerHit').play(); // Flash player effect LK.effects.flashObject(player, 0xff0000, 500); if (lives <= 0) { gameState = "gameover"; LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); } continue; } // Check shield collision if (bullet.active) { for (var k = shields.length - 1; k >= 0; k--) { var shield = shields[k]; if (shield.active && bullet.intersects(shield)) { // Shield hit by enemy bullet shield.damage(); // Deactivate bullet bullet.active = false; bullet.visible = false; activeEnemyBullets--; if (!shield.active) { game.removeChild(shield); shields.splice(k, 1); } break; } } } } // Enemies vs bottom of screen // Only check this less frequently (every 10 frames) if (LK.ticks % 10 === 0) { for (var i = 0; i < enemies.length; i++) { if (enemies[i].y + enemies[i].height / 2 > player.y) { // Enemies reached player level - game over gameState = "gameover"; LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); break; } } } } // Start next wave function startNextWave() { wave++; waveTxt.setText("Wave: " + wave); // Display wave number with a nice animation var waveAnnouncement = new Text2('WAVE ' + wave, { size: 120, fill: 0xffff00 }); waveAnnouncement.anchor.set(0.5, 0.5); waveAnnouncement.x = GAME_WIDTH / 2; waveAnnouncement.y = GAME_HEIGHT / 2; waveAnnouncement.alpha = 0; game.addChild(waveAnnouncement); // Animate the wave announcement tween(waveAnnouncement, { alpha: 1 }, { duration: 500, onFinish: function onFinish() { tween(waveAnnouncement, { alpha: 0, scaleX: 1.5, scaleY: 1.5 }, { duration: 800, onFinish: function onFinish() { game.removeChild(waveAnnouncement); } }); } }); // Increase enemy speed with each wave enemiesSpeed += WAVE_SPEED_INCREASE; // Adjust powerup drop chance based on wave difficulty powerUpManager.dropChance = Math.min(0.35, 0.2 + wave * 0.03); // Increase drop chance slightly with waves // Adjust enemy move interval (enemies move faster in higher waves) enemyMoveInterval = Math.max(15, 30 - wave * 2); // Reset all enemy bullets without removing them var allEnemyBullets = enemyBulletPool.getAll(); for (var i = 0; i < allEnemyBullets.length; i++) { if (allEnemyBullets[i].active) { allEnemyBullets[i].active = false; allEnemyBullets[i].visible = false; } } activeEnemyBullets = 0; // Create new enemy formation with more variety in higher waves createEnemies(); } // With object pooling, we no longer need to clean up inactive objects // Main game update loop game.update = function () { // Calculate frame time for consistent speed regardless of framerate var currentTime = Date.now(); frameTime = currentTime - lastFrameTime; lastFrameTime = currentTime; if (gameState === "playing") { // Update player player.update(); // Auto shoot - less frequent check if (LK.ticks % 30 === 0) { shootPlayerBullet(); } // Move enemies enemyMoveTimer++; if (enemyMoveTimer >= enemyMoveInterval) { moveEnemies(); enemyMoveTimer = 0; } // Enemy shooting - only check every 10 frames if (enemies.length > 0 && LK.ticks % 10 === 0) { // Pre-calculate bottom enemies once per update var bottomEnemies = []; var columnsWithEnemies = {}; // Find bottom enemies in each column more efficiently for (var i = 0; i < enemies.length; i++) { var enemy = enemies[i]; var column = enemy.col; if (!columnsWithEnemies[column] || enemies[columnsWithEnemies[column]].row < enemy.row) { columnsWithEnemies[column] = i; } } // Get bottom enemies for (var col in columnsWithEnemies) { bottomEnemies.push(enemies[columnsWithEnemies[col]]); } // Random chance for enemies to shoot if (bottomEnemies.length > 0) { var maxShots = Math.min(3, bottomEnemies.length); var shotCount = 0; for (var i = 0; i < bottomEnemies.length && shotCount < maxShots; i++) { var enemy = bottomEnemies[i]; if (Math.random() < enemy.shotChance * 2) { // Special handling for bomber enemies if (enemy.type === "bomber" && typeof enemy.fireBurst === "function") { enemy.fireBurst(shootEnemyBullet); } else { // Regular enemy shooting shootEnemyBullet(enemy); } shotCount++; } } } } // Update bullets from pools var allPlayerBullets = playerBulletPool.getAll(); var allEnemyBullets = enemyBulletPool.getAll(); // Only update active bullets for (var i = 0; i < allPlayerBullets.length; i++) { if (allPlayerBullets[i].active) { allPlayerBullets[i].update(); } } for (var i = 0; i < allEnemyBullets.length; i++) { if (allEnemyBullets[i].active) { allEnemyBullets[i].update(); } } // Update powerups and check for collisions powerUpManager.update(); powerUpManager.checkCollisions(player); // Check collisions with optimized method checkCollisions(); // Check if wave cleared if (enemies.length === 0) { startNextWave(); } } };
===================================================================
--- original.js
+++ change.js
@@ -17,13 +17,81 @@
self.width = enemyGraphics.width;
self.height = enemyGraphics.height;
self.points = 10;
self.shotChance = 0.005; // Chance per frame to shoot
+ self.type = "basic"; // Default enemy type
self.update = function () {
// Enemy logic will be controlled by the formation
};
return self;
});
+var ToughEnemy = Enemy.expand(function () {
+ var self = Enemy.call(this);
+ self.children[0].tint = 0x0000ff; // Blue tough enemy
+ self.type = "tough";
+ self.points = 25;
+ self.shotChance = 0.005;
+ self.health = 2; // Takes 2 hits to destroy
+ // Override damage method
+ self.damage = function () {
+ self.health--;
+ // Visual feedback for hit
+ LK.effects.flashObject(self, 0xffffff, 100);
+ if (self.health <= 0) {
+ return true; // Enemy is destroyed
+ }
+ // Change appearance after hit
+ self.children[0].alpha = 0.7;
+ return false; // Enemy is still alive
+ };
+ return self;
+});
+// PowerUpManager has been moved to Classes section
+var FastEnemy = Enemy.expand(function () {
+ var self = Enemy.call(this);
+ self.children[0].tint = 0xff0000; // Red fast enemy
+ self.type = "fast";
+ self.points = 15;
+ self.shotChance = 0.008; // Higher chance to shoot
+ self.speedMultiplier = 1.5; // Moves faster than other enemies
+ // Override update to add custom behavior if needed
+ var parentUpdate = self.update;
+ self.update = function () {
+ parentUpdate.call(self);
+ // Additional fast enemy behavior can be added here
+ };
+ return self;
+});
+var BomberEnemy = Enemy.expand(function () {
+ var self = Enemy.call(this);
+ self.children[0].tint = 0xff00ff; // Purple bomber enemy
+ self.type = "bomber";
+ self.points = 20;
+ self.shotChance = 0.004; // Lower chance to shoot, but shoots multiple bullets
+ // Bomber enemies will release multiple bullets in a pattern
+ self.fireBurst = function (shootFunction) {
+ if (typeof shootFunction === 'function') {
+ // Fire multiple shots in a spread pattern
+ shootFunction(self);
+ // Schedule additional shots with slight delay
+ LK.setTimeout(function () {
+ shootFunction(self);
+ }, 150);
+ LK.setTimeout(function () {
+ shootFunction(self);
+ }, 300);
+ }
+ };
+ return self;
+});
+var BasicEnemy = Enemy.expand(function () {
+ var self = Enemy.call(this);
+ self.children[0].tint = 0x00ff00; // Green basic enemy
+ self.type = "basic";
+ self.points = 10;
+ self.shotChance = 0.005;
+ return self;
+});
var EnemyBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('enemyBullet', {
anchorX: 0.5,
@@ -434,22 +502,56 @@
// Calculate total width of enemy formation
var enemyWidth = new Enemy().width;
var formationWidth = ENEMY_COLS * (enemyWidth + ENEMY_PADDING) - ENEMY_PADDING;
var startX = (GAME_WIDTH - formationWidth) / 2 + enemyWidth / 2;
+ // Enemy type distribution based on wave number
+ // Higher waves have more advanced enemy types
for (var row = 0; row < ENEMY_ROWS; row++) {
for (var col = 0; col < ENEMY_COLS; col++) {
- var enemy = new Enemy();
+ var enemy;
+ var rand = Math.random();
+ // Different enemy types depending on row and wave number
+ if (row === 0) {
+ // Top row - tougher enemies in higher waves
+ if (wave >= 3 && rand < 0.7) {
+ enemy = new ToughEnemy();
+ } else if (wave >= 2 && rand < 0.4) {
+ enemy = new FastEnemy();
+ } else {
+ enemy = new BasicEnemy();
+ }
+ } else if (row === 1) {
+ // Second row - more bombers in higher waves
+ if (wave >= 3 && rand < 0.5) {
+ enemy = new BomberEnemy();
+ } else if (wave >= 2 && rand < 0.3) {
+ enemy = new ToughEnemy();
+ } else {
+ enemy = new FastEnemy();
+ }
+ } else if (row === 2) {
+ // Third row - mixed enemy types
+ if (rand < 0.4) {
+ enemy = new FastEnemy();
+ } else if (rand < 0.7) {
+ enemy = new BomberEnemy();
+ } else {
+ enemy = new BasicEnemy();
+ }
+ } else {
+ // Lower rows - basic enemies with occasional fast ones
+ if (rand < 0.3 * (wave / 2)) {
+ enemy = new FastEnemy();
+ } else {
+ enemy = new BasicEnemy();
+ }
+ }
enemy.x = startX + col * (enemy.width + ENEMY_PADDING);
enemy.y = ENEMY_START_Y + row * (enemy.height + ENEMY_PADDING);
enemy.row = row;
enemy.col = col;
- enemy.points = (ENEMY_ROWS - row) * 10; // Higher rows worth more points
- // Different enemy colors based on row
- if (row === 0) {
- enemy.children[0].tint = 0xff0000; // Top row red
- } else if (row === 1 || row === 2) {
- enemy.children[0].tint = 0xff6600; // Middle rows orange
- }
+ // Modify points based on row position (higher rows worth more)
+ enemy.points = Math.round(enemy.points * (1 + (ENEMY_ROWS - row) * 0.2));
enemies.push(enemy);
game.addChild(enemy);
}
}
@@ -547,27 +649,34 @@
var hitEnemy = false;
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (bullet.intersects(enemy)) {
- // Enemy hit
- score += enemy.points;
- scoreTxt.setText("Score: " + score);
- // Create a powerup with a certain chance
+ var enemyDestroyed = true;
var enemyX = enemy.x;
var enemyY = enemy.y;
- // Remove enemy
- game.removeChild(enemy);
- enemies.splice(j, 1);
- // Try to spawn a power-up at enemy position
- powerUpManager.createPowerUp(enemyX, enemyY);
- // Deactivate bullet
+ var enemyType = enemy.type;
+ // Handle tough enemies differently
+ if (enemy.type === "tough" && typeof enemy.damage === "function") {
+ enemyDestroyed = enemy.damage(); // Returns true if enemy is destroyed
+ }
+ if (enemyDestroyed) {
+ // Enemy hit and destroyed
+ score += enemy.points;
+ scoreTxt.setText("Score: " + score);
+ // Remove enemy
+ game.removeChild(enemy);
+ enemies.splice(j, 1);
+ // Try to spawn a power-up at enemy position
+ powerUpManager.createPowerUp(enemyX, enemyY);
+ // Play explosion sound
+ LK.getSound('enemyExplode').play();
+ // Flash screen effect
+ LK.effects.flashObject(game, 0xffffff, 100);
+ }
+ // Deactivate bullet regardless of whether enemy was destroyed
bullet.active = false;
bullet.visible = false;
activePlayerBullets--;
- // Play explosion sound
- LK.getSound('enemyExplode').play();
- // Flash screen effect
- LK.effects.flashObject(enemy, 0xffffff, 300);
hitEnemy = true;
break; // Bullet can only hit one enemy
}
}
@@ -653,12 +762,42 @@
// Start next wave
function startNextWave() {
wave++;
waveTxt.setText("Wave: " + wave);
+ // Display wave number with a nice animation
+ var waveAnnouncement = new Text2('WAVE ' + wave, {
+ size: 120,
+ fill: 0xffff00
+ });
+ waveAnnouncement.anchor.set(0.5, 0.5);
+ waveAnnouncement.x = GAME_WIDTH / 2;
+ waveAnnouncement.y = GAME_HEIGHT / 2;
+ waveAnnouncement.alpha = 0;
+ game.addChild(waveAnnouncement);
+ // Animate the wave announcement
+ tween(waveAnnouncement, {
+ alpha: 1
+ }, {
+ duration: 500,
+ onFinish: function onFinish() {
+ tween(waveAnnouncement, {
+ alpha: 0,
+ scaleX: 1.5,
+ scaleY: 1.5
+ }, {
+ duration: 800,
+ onFinish: function onFinish() {
+ game.removeChild(waveAnnouncement);
+ }
+ });
+ }
+ });
// Increase enemy speed with each wave
enemiesSpeed += WAVE_SPEED_INCREASE;
// Adjust powerup drop chance based on wave difficulty
powerUpManager.dropChance = Math.min(0.35, 0.2 + wave * 0.03); // Increase drop chance slightly with waves
+ // Adjust enemy move interval (enemies move faster in higher waves)
+ enemyMoveInterval = Math.max(15, 30 - wave * 2);
// Reset all enemy bullets without removing them
var allEnemyBullets = enemyBulletPool.getAll();
for (var i = 0; i < allEnemyBullets.length; i++) {
if (allEnemyBullets[i].active) {
@@ -666,9 +805,9 @@
allEnemyBullets[i].visible = false;
}
}
activeEnemyBullets = 0;
- // Create new enemy formation
+ // Create new enemy formation with more variety in higher waves
createEnemies();
}
// With object pooling, we no longer need to clean up inactive objects
// Main game update loop
@@ -708,15 +847,20 @@
bottomEnemies.push(enemies[columnsWithEnemies[col]]);
}
// Random chance for enemies to shoot
if (bottomEnemies.length > 0) {
- // Limit number of shots per frame
var maxShots = Math.min(3, bottomEnemies.length);
var shotCount = 0;
for (var i = 0; i < bottomEnemies.length && shotCount < maxShots; i++) {
- if (Math.random() < bottomEnemies[i].shotChance * 2) {
- // Adjusted for less frequent checks
- shootEnemyBullet(bottomEnemies[i]);
+ var enemy = bottomEnemies[i];
+ if (Math.random() < enemy.shotChance * 2) {
+ // Special handling for bomber enemies
+ if (enemy.type === "bomber" && typeof enemy.fireBurst === "function") {
+ enemy.fireBurst(shootEnemyBullet);
+ } else {
+ // Regular enemy shooting
+ shootEnemyBullet(enemy);
+ }
shotCount++;
}
}
}
@@ -744,6 +888,5 @@
if (enemies.length === 0) {
startNextWave();
}
}
-};
-// PowerUpManager has been moved to Classes section
\ No newline at end of file
+};
\ No newline at end of file
Top down 2d pixilated spaceship. In-Game asset. 2d. High contrast. No shadows
Enemy spaceship top down 2d pixilated and looking downwards. In-Game asset. 2d. High contrast. No shadows
Bullet 2d top down pixilated. In-Game asset. 2d. High contrast. No shadows
Bullet facing down and top Down 2d pixilated. In-Game asset. 2d. High contrast. No shadows
Sheid top down 2d pixilated. In-Game asset. 2d. High contrast. No shadows