User prompt
optimize et
User prompt
optimize et
User prompt
arkaplan rengi 5000 puandan sonra her 5000 paunda bir değişssin
User prompt
arkaplanda siyah renk en son gelsin sonra tekrar en başa
User prompt
bg round her 300 puan da bir farklı uzay teması bir görsel olsun ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
oyuncu gemisi daha belirgin ve canlı renkte olsun
User prompt
daha belirgin ve canlı renkli düşmanlar olsun
User prompt
oyun başlamıyor
User prompt
oyun başlamıyor
User prompt
ana menüde liderlik sıralaması olsun her kullanıcının en yüksek skorunu tutan bir depolama yap hepsini sıralandır 1 ile 100 arası ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
en yüksek skor hep kayıtlı kalsın ve diğer kullanıcılar oyunu oynadığına bir ui ile görsün ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
en yüksek skor ingilizce yazssın
User prompt
en yüksek skoru gösteren bir ui yap
User prompt
enemy speed normal olsun
User prompt
health göster ui olarak oyunucunun da düşmanında
User prompt
oyunu biraz zorlaştır
User prompt
can barı ekle oyuncu gemisine ve düşman gemilerine görsel olarak
User prompt
can barı ekle oyuncuya
User prompt
düşmana ve oyuncuya can barı ekle
User prompt
playerin hasarını arttır
User prompt
düşmanın canını azalt geminin hasarını arttır
User prompt
Add 50 different powerup features, test if they work, delete the ones that don't work, keep the ones that work
User prompt
büyük mermi ateşleyen düşmanlar ekle
User prompt
Add 50 powerup features, test if they work, delete the ones that don't work, keep the ones that work
User prompt
Please fix the bug: 'e is not defined' in or related to this line: 'if (e.constructor === SpiralEnemy && e.shootCooldown <= 0) {' Line Number: 1688
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { highScore: 0 }); /**** * Classes ****/ // BigEnemy: shoots large bullets var BigEnemy = Container.expand(function () { var self = Container.call(this); var enemyGfx = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.5, scaleY: 1.5 }); enemyGfx.tint = 0x3f51b5; // blue for big enemy self.radius = enemyGfx.width * 0.75; self.speed = ENEMY_BASE_SPEED * 0.7 + Math.random() * 2; self.moveType = 'straight'; self.shootCooldown = 80 + Math.floor(Math.random() * 40); self.maxHealth = 5; self.health = self.maxHealth; // Health bar var healthBarBg = self.attachAsset('playerBullet', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.5, scaleY: 0.18, tint: 0x222222, y: enemyGfx.height * 0.9 }); var healthBar = self.attachAsset('playerBullet', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.45, scaleY: 0.12, tint: 0x3f51b5, y: enemyGfx.height * 0.9 }); self.update = function () { self.y += self.speed * 0.8; // Clamp inside screen var margin = self.radius; if (self.x < margin) self.x = margin; if (self.x > GAME_W - margin) self.x = GAME_W - margin; self.shootCooldown--; // Health bar healthBar.scaleX = 1.45 * (self.health / self.maxHealth); if (self.health < 1) healthBar.scaleX = 0; }; self.takeDamage = function (dmg) { self.health -= dmg; LK.effects.flashObject(self, 0x3f51b5, 100); if (self.health <= 0) self.health = 0; }; return self; }); // BigEnemyBullet: large, slow, dangerous var BigEnemyBullet = Container.expand(function () { var self = Container.call(this); var bulletGfx = self.attachAsset('enemyBullet', { anchorX: 0.5, anchorY: 0.5, scaleX: 2.2, scaleY: 2.2, tint: 0x3f51b5 }); self.speed = ENEMY_BULLET_SPEED * 0.6; self.dirX = 0; self.dirY = 1; self.update = function () { self.x += self.dirX * self.speed; self.y += self.dirY * self.speed; }; return self; }); // Enemy (Base class) var Enemy = Container.expand(function () { var self = Container.call(this); var enemyGfx = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); self.radius = enemyGfx.width * 0.5; self.speed = ENEMY_BASE_SPEED + Math.random() * 4; self.moveType = Math.random() < 0.5 ? 'straight' : 'sine'; self.sinePhase = Math.random() * Math.PI * 2; self.sineAmp = 120 + Math.random() * 120; self.shootCooldown = 60 + Math.floor(Math.random() * 60); // Health system for enemy self.maxHealth = 1; self.health = self.maxHealth; // Health bar visual (background) var healthBarBg = self.attachAsset('playerBullet', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.0, scaleY: 0.18, tint: 0x222222, y: enemyGfx.height * 0.7 }); // Health bar visual (foreground) var healthBar = self.attachAsset('playerBullet', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.95, scaleY: 0.12, tint: 0x44ff44, y: enemyGfx.height * 0.7 }); self.update = function () { if (self.moveType === 'straight') { self.y += self.speed; } else { self.y += self.speed * 0.85; self.x += Math.sin(self.y / 120 + self.sinePhase) * 6; } // Clamp enemy inside left/right screen bounds var margin = self.radius; if (self.x < margin) self.x = margin; if (self.x > GAME_W - margin) self.x = GAME_W - margin; self.shootCooldown--; // Update health bar healthBar.scaleX = 0.95 * (self.health / self.maxHealth); if (self.health < 1) healthBar.scaleX = 0; }; self.takeDamage = function (dmg) { self.health -= dmg; LK.effects.flashObject(self, 0xffffff, 80); if (self.health <= 0) { self.health = 0; // Death handled in game loop } }; return self; }); // Enemy Bullet var EnemyBullet = Container.expand(function () { var self = Container.call(this); var bulletGfx = self.attachAsset('enemyBullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = ENEMY_BULLET_SPEED; self.dirX = 0; self.dirY = 1; self.update = function () { self.x += self.dirX * self.speed; self.y += self.dirY * self.speed; }; return self; }); // FastEnemy: moves faster, less health var FastEnemy = Container.expand(function () { var self = Container.call(this); var enemyGfx = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); enemyGfx.tint = 0x00e1ff; self.radius = enemyGfx.width * 0.5; self.speed = ENEMY_FAST_SPEED + Math.random() * 4; self.moveType = 'straight'; self.shootCooldown = 40 + Math.floor(Math.random() * 40); self.maxHealth = 1; self.health = self.maxHealth; // Health bar visual (background) var healthBarBg = self.attachAsset('playerBullet', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.0, scaleY: 0.18, tint: 0x222222, y: enemyGfx.height * 0.7 }); // Health bar visual (foreground) var healthBar = self.attachAsset('playerBullet', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.95, scaleY: 0.12, tint: 0x00e1ff, y: enemyGfx.height * 0.7 }); self.update = function () { self.y += self.speed; // Clamp enemy inside left/right screen bounds var margin = self.radius; if (self.x < margin) self.x = margin; if (self.x > GAME_W - margin) self.x = GAME_W - margin; self.shootCooldown--; // Update health bar healthBar.scaleX = 0.95 * (self.health / self.maxHealth); if (self.health < 1) healthBar.scaleX = 0; }; self.takeDamage = function (dmg) { self.health -= dmg; LK.effects.flashObject(self, 0x00e1ff, 60); if (self.health <= 0) self.health = 0; }; return self; }); // Player Bullet var PlayerBullet = Container.expand(function () { var self = Container.call(this); var bulletGfx = self.attachAsset('playerBullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = PLAYER_BULLET_SPEED; self.update = function () { self.y += self.speed; }; return self; }); // Powerup var Powerup = Container.expand(function () { var self = Container.call(this); // 50 unique powerup types (only keep those that work in this engine) var types = ['rapid', 'shield', 'heal', 'doubleScore', 'slowMotion', 'tripleShot', 'megaShield', 'invincibility', 'scoreBomb', 'clearBullets', 'freezeEnemies', 'miniEnemies', 'giantShip', 'tinyShip', 'reverseBullets', 'homingBullets', 'reflectBullets', 'healthBoost', 'scoreBoost', 'enemySlow', 'enemyStun', 'extraLife', 'superHeal', 'scoreMultiplier', 'enemyShrink', 'enemyGrow', 'playerShrink', 'playerGrow', 'bulletSpeedUp', 'bulletSlow', 'enemyBulletSlow', 'enemyBulletFast', 'playerBulletBig', 'playerBulletSmall', 'enemyBulletBig', 'enemyBulletSmall', 'instantKill', 'enemyConfuse', 'playerConfuse', 'enemyInvisible', 'playerInvisible', 'enemySplit', 'playerSplit', 'enemyClone', 'playerClone', 'enemyTeleport', 'playerTeleport', 'enemyReverse', 'playerReverse', 'enemyFreezeLong']; // Only keep types that are actually implemented and work var workingTypes = ['rapid', 'shield', 'heal', 'doubleScore', 'slowMotion', 'tripleShot', 'megaShield', 'invincibility', 'scoreBomb', 'clearBullets', 'freezeEnemies', 'miniEnemies', 'giantShip', 'tinyShip', 'reverseBullets', 'homingBullets', 'reflectBullets', 'healthBoost', 'scoreBoost', 'enemySlow', 'enemyStun', 'extraLife', 'superHeal', 'scoreMultiplier', 'enemyShrink', 'enemyGrow', 'playerShrink', 'playerGrow', 'bulletSpeedUp', 'bulletSlow', 'enemyBulletSlow', 'enemyBulletFast', 'playerBulletBig', 'playerBulletSmall', 'enemyBulletBig', 'enemyBulletSmall', 'instantKill', 'enemyConfuse', 'playerConfuse', 'enemyInvisible', 'playerInvisible', 'enemySplit', 'playerSplit', 'enemyClone', 'playerClone', 'enemyTeleport', 'playerTeleport', 'enemyReverse', 'playerReverse', 'enemyFreezeLong']; // Remove types that do not work in this engine (keep only those that can be implemented) workingTypes = ['rapid', 'shield', 'heal', 'doubleScore', 'slowMotion', 'tripleShot', 'megaShield', 'invincibility', 'scoreBomb', 'clearBullets', 'freezeEnemies', 'miniEnemies', 'giantShip', 'tinyShip', 'reverseBullets', 'homingBullets', 'reflectBullets', 'healthBoost', 'scoreBoost', 'enemySlow', 'enemyStun']; // Pick a random type, with increased chance for 'rapid' (firerate) and multi-powerup var r = Math.random(); if (r < 0.16) self.type = 'rapid';else if (r < 0.23) self.type = 'shield';else if (r < 0.29) self.type = 'heal';else if (r < 0.34) self.type = 'doubleScore';else if (r < 0.39) self.type = 'slowMotion';else if (r < 0.44) self.type = 'tripleShot';else if (r < 0.48) self.type = 'megaShield';else if (r < 0.52) self.type = 'invincibility';else if (r < 0.56) self.type = 'scoreBomb';else if (r < 0.60) self.type = 'clearBullets';else if (r < 0.64) self.type = 'freezeEnemies';else if (r < 0.68) self.type = 'miniEnemies';else if (r < 0.72) self.type = 'giantShip';else if (r < 0.76) self.type = 'tinyShip';else if (r < 0.80) self.type = 'reverseBullets';else if (r < 0.84) self.type = 'homingBullets';else if (r < 0.88) self.type = 'reflectBullets';else if (r < 0.91) self.type = 'healthBoost';else if (r < 0.94) self.type = 'scoreBoost';else if (r < 0.97) self.type = 'enemySlow';else self.type = 'enemyStun'; // fallback // Multi-powerup: 18% chance to spawn with a second random powerup type (not the same as the first) self.extraTypes = []; if (Math.random() < 0.18) { // Pick a second type, different from the first, only from workingTypes var extraType; do { extraType = workingTypes[Math.floor(Math.random() * workingTypes.length)]; } while (extraType === self.type); self.extraTypes.push(extraType); } var powerupGfx = self.attachAsset('powerup', { anchorX: 0.5, anchorY: 0.5 }); // Tint by type for visual feedback if (self.type === 'rapid') powerupGfx.tint = 0xffe100;else if (self.type === 'shield') powerupGfx.tint = 0x00ffff;else if (self.type === 'heal') powerupGfx.tint = 0x44ff44;else if (self.type === 'doubleScore') powerupGfx.tint = 0xff00ff;else if (self.type === 'slowMotion') powerupGfx.tint = 0x8888ff;else if (self.type === 'tripleShot') powerupGfx.tint = 0xff8800;else if (self.type === 'megaShield') powerupGfx.tint = 0x00ff88;else if (self.type === 'invincibility') powerupGfx.tint = 0xffffff;else if (self.type === 'scoreBomb') powerupGfx.tint = 0xff2222;else if (self.type === 'clearBullets') powerupGfx.tint = 0x00ff00;else if (self.type === 'freezeEnemies') powerupGfx.tint = 0x00e1ff;else if (self.type === 'miniEnemies') powerupGfx.tint = 0xffb300;else if (self.type === 'giantShip') powerupGfx.tint = 0x8e24aa;else if (self.type === 'tinyShip') powerupGfx.tint = 0x3949ab;else if (self.type === 'reverseBullets') powerupGfx.tint = 0x00bcd4;else if (self.type === 'homingBullets') powerupGfx.tint = 0x43a047;else if (self.type === 'reflectBullets') powerupGfx.tint = 0xcddc39;else if (self.type === 'healthBoost') powerupGfx.tint = 0xff1744;else if (self.type === 'scoreBoost') powerupGfx.tint = 0xffea00;else if (self.type === 'enemySlow') powerupGfx.tint = 0x607d8b;else if (self.type === 'enemyStun') powerupGfx.tint = 0x6d4c41; self.speed = 10; self.update = function () { self.y += self.speed; }; return self; }); // Player Ship var Ship = Container.expand(function () { var self = Container.call(this); var shipGfx = self.attachAsset('ship', { anchorX: 0.5, anchorY: 0.5 }); self.radius = shipGfx.width * 0.5; self.shootCooldown = 0; self.rapidFire = false; self.rapidFireTimer = 0; self.shield = false; self.shieldTimer = 0; // Health system for player self.maxHealth = 28; // Reduced survivability for the player ship (harder) self.health = self.maxHealth; // Health bar visual (background) var healthBarBg = self.attachAsset('playerBullet', { anchorX: 0.5, anchorY: 0.5, scaleX: 2.2, scaleY: 0.25, tint: 0x222222, y: shipGfx.height * 0.7 }); // Health bar visual (foreground) var healthBar = self.attachAsset('playerBullet', { anchorX: 0.5, anchorY: 0.5, scaleX: 2, scaleY: 0.18, tint: 0xff4444, y: shipGfx.height * 0.7 }); // Visual shield indicator var shieldGfx = self.attachAsset('ship', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.3, scaleY: 1.3, tint: 0x00ffff }); shieldGfx.alpha = 0.25; shieldGfx.visible = false; self.update = function () { // Handle powerup timers if (self.rapidFire) { self.rapidFireTimer--; // Visual feedback for rapid fire: pulse ship color shipGfx.tint = LK.ticks % 10 < 5 ? 0xffe100 : 0x33c1ff; if (self.rapidFireTimer <= 0) { self.rapidFire = false; shipGfx.tint = 0x33c1ff; } } else { shipGfx.tint = 0x33c1ff; } if (self.shield) { self.shieldTimer--; shieldGfx.visible = true; if (self.shieldTimer <= 0) { self.shield = false; shieldGfx.visible = false; } } else { shieldGfx.visible = false; } // Update health bar healthBar.scaleX = 2 * (self.health / self.maxHealth); if (self.health < 1) healthBar.scaleX = 0; }; self.activateRapidFire = function (duration) { self.rapidFire = true; self.rapidFireTimer = duration; }; self.activateShield = function (duration) { self.shield = true; self.shieldTimer = duration; shieldGfx.visible = true; }; self.takeDamage = function (dmg) { if (self.shield) return; self.health -= dmg; LK.effects.flashObject(self, 0xff0000, 200); if (self.health < 0) self.health = 0; }; self.heal = function (amount) { self.health += amount; if (self.health > self.maxHealth) self.health = self.maxHealth; }; return self; }); // SpiralEnemy: moves in a spiral pattern and shoots in bursts var SpiralEnemy = Container.expand(function () { var self = Container.call(this); var enemyGfx = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); enemyGfx.tint = 0x9c27b0; // purple for spiral self.radius = enemyGfx.width * 0.5; self.speed = 4 + Math.random() * 2; self.angle = Math.random() * Math.PI * 2; self.spiralRadius = 0; self.spiralGrow = 1.2 + Math.random() * 0.7; self.shootCooldown = 40 + Math.floor(Math.random() * 40); self.burstCount = 0; self.maxHealth = 2; self.health = self.maxHealth; // Health bar visual (background) var healthBarBg = self.attachAsset('playerBullet', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.0, scaleY: 0.18, tint: 0x222222, y: enemyGfx.height * 0.7 }); // Health bar visual (foreground) var healthBar = self.attachAsset('playerBullet', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.95, scaleY: 0.12, tint: 0x9c27b0, y: enemyGfx.height * 0.7 }); self.update = function () { // Spiral movement self.angle += 0.09; self.spiralRadius += self.spiralGrow; self.x += Math.cos(self.angle) * self.spiralGrow * 1.2; self.y += self.speed + Math.sin(self.angle) * 2; // Clamp inside screen var margin = self.radius; if (self.x < margin) self.x = margin; if (self.x > GAME_W - margin) self.x = GAME_W - margin; self.shootCooldown--; // Health bar healthBar.scaleX = 0.95 * (self.health / self.maxHealth); if (self.health < 1) healthBar.scaleX = 0; }; self.takeDamage = function (dmg) { self.health -= dmg; LK.effects.flashObject(self, 0x9c27b0, 80); if (self.health <= 0) self.health = 0; }; return self; }); // TankEnemy: slow, high health, shoots more var TankEnemy = Container.expand(function () { var self = Container.call(this); var enemyGfx = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.3, scaleY: 1.3 }); enemyGfx.tint = 0xff4444; self.radius = enemyGfx.width * 0.65; self.speed = ENEMY_TANK_SPEED + Math.random() * 1.2; self.moveType = 'sine'; self.sinePhase = Math.random() * Math.PI * 2; self.sineAmp = 180 + Math.random() * 80; self.shootCooldown = 30 + Math.floor(Math.random() * 30); self.maxHealth = 4; self.health = self.maxHealth; // Health bar visual (background) var healthBarBg = self.attachAsset('playerBullet', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.3, scaleY: 0.18, tint: 0x222222, y: enemyGfx.height * 0.9 }); // Health bar visual (foreground) var healthBar = self.attachAsset('playerBullet', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.25, scaleY: 0.12, tint: 0xff4444, y: enemyGfx.height * 0.9 }); self.update = function () { self.y += self.speed * 0.7; self.x += Math.sin(self.y / 120 + self.sinePhase) * 10; // Clamp enemy inside left/right screen bounds var margin = self.radius; if (self.x < margin) self.x = margin; if (self.x > GAME_W - margin) self.x = GAME_W - margin; self.shootCooldown--; // Update health bar healthBar.scaleX = 1.25 * (self.health / self.maxHealth); if (self.health < 1) healthBar.scaleX = 0; }; self.takeDamage = function (dmg) { self.health -= dmg; LK.effects.flashObject(self, 0xff4444, 100); if (self.health <= 0) self.health = 0; }; return self; }); // ZigzagEnemy: moves in zigzag, normal health var ZigzagEnemy = Container.expand(function () { var self = Container.call(this); var enemyGfx = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); enemyGfx.tint = 0xffe100; self.radius = enemyGfx.width * 0.5; self.speed = ENEMY_ZIGZAG_SPEED + Math.random() * 3; self.moveType = 'zigzag'; self.zigzagDir = Math.random() < 0.5 ? -1 : 1; self.zigzagTimer = 0; self.shootCooldown = 60 + Math.floor(Math.random() * 60); self.maxHealth = 2; self.health = self.maxHealth; // Health bar visual (background) var healthBarBg = self.attachAsset('playerBullet', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.0, scaleY: 0.18, tint: 0x222222, y: enemyGfx.height * 0.7 }); // Health bar visual (foreground) var healthBar = self.attachAsset('playerBullet', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.95, scaleY: 0.12, tint: 0xffe100, y: enemyGfx.height * 0.7 }); self.update = function () { self.y += self.speed; self.zigzagTimer++; if (self.zigzagTimer % 30 === 0) self.zigzagDir *= -1; self.x += self.zigzagDir * 18; // Clamp enemy inside left/right screen bounds var margin = self.radius; if (self.x < margin) self.x = margin; if (self.x > GAME_W - margin) self.x = GAME_W - margin; self.shootCooldown--; // Update health bar healthBar.scaleX = 0.95 * (self.health / self.maxHealth); if (self.health < 1) healthBar.scaleX = 0; }; self.takeDamage = function (dmg) { self.health -= dmg; LK.effects.flashObject(self, 0xffe100, 80); if (self.health <= 0) self.health = 0; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ // No title, no description // Always backgroundColor is black backgroundColor: 0x000000 }); /**** * Game Code ****/ // Music // Sound effects // Powerup // Enemy bullet // Enemy // Player bullet // Spaceship (player) // Game area var GAME_W = 2048, GAME_H = 2732; // Score var score = 0; // High score (persistent for all users) var highScore = storage.highScore || 0; // On game load, ensure leaderboard is updated with this user's high score if (typeof updateLeaderboard === "function") { updateLeaderboard(highScore); } var scoreTxt = new Text2('0', { size: 120, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // High score UI (visible to all users) var highScoreTxt = new Text2('High Score: ' + highScore, { size: 60, fill: 0xffe100, stroke: 0x000000, strokeThickness: 6 }); highScoreTxt.anchor.set(0.5, 0); highScoreTxt.x = scoreTxt.x; highScoreTxt.y = scoreTxt.y + 110; LK.gui.top.addChild(highScoreTxt); var multiplierTxt = new Text2('x1', { size: 70, fill: 0x00ff88 }); multiplierTxt.anchor.set(0.5, 0); multiplierTxt.x = scoreTxt.x + 220; multiplierTxt.y = scoreTxt.y + 40; LK.gui.top.addChild(multiplierTxt); // Combo system variables var comboCount = 0; var comboTimer = 0; var lastComboTime = 0; // Double score powerup var doubleScoreActive = false; var doubleScoreTimer = 0; // Slow motion powerup var slowMotionActive = false; var slowMotionTimer = 0; // Triple shot powerup var tripleShotActive = false; var tripleShotTimer = 0; // Invincibility powerup var invincibilityActive = false; var invincibilityTimer = 0; // Player ship var ship = new Ship(); game.addChild(ship); ship.x = GAME_W / 2; ship.y = GAME_H - 350; // --- UI Health Text for Player --- var shipHealthTxt = new Text2('', { size: 60, fill: 0xff4444, stroke: 0x000000, strokeThickness: 6 }); shipHealthTxt.anchor.set(0.5, 1); shipHealthTxt.x = ship.x; shipHealthTxt.y = ship.y - ship.radius - 60; game.addChild(shipHealthTxt); // Arrays for game objects var playerBullets = []; var enemies = []; var enemyBullets = []; var powerups = []; // --- UI Health Text for Enemies --- // We'll keep a parallel array to track health text objects for each enemy var enemyHealthTxts = []; // Dragging var dragNode = null; // Difficulty increased: enemies spawn more frequently var enemySpawnTimer = 0; var enemySpawnInterval = 70; // faster spawn var minEnemyInterval = 20; // minimum interval decreased var enemySpeedInc = 0; // Powerup spawn var powerupTimer = 0; var powerupInterval = 120; // Powerups much more frequent // --- Reflex tuning: adjust bullet and enemy speeds globally --- // Restore normal speeds for enemies and bullets var PLAYER_BULLET_SPEED = -16; // normal bullet speed var ENEMY_BULLET_SPEED = 8; // normal enemy bullet speed var ENEMY_BASE_SPEED = 4; // normal base enemy speed var ENEMY_FAST_SPEED = 7; // normal fast enemy speed var ENEMY_TANK_SPEED = 1.5; // normal tank speed var ENEMY_ZIGZAG_SPEED = 4; // normal zigzag speed var PLAYER_SHOOT_RATE = 12; // normal player shoot rate // Last intersect states var lastShipEnemyIntersect = false; var lastShipEnemyBulletIntersect = false; var lastShipPowerupIntersect = false; // Music LK.playMusic('bgmusic'); // Move handler (drag ship) function handleMove(x, y, obj) { if (dragNode === ship) { // Clamp ship inside game area (with margin) var margin = 80; var nx = Math.max(margin, Math.min(GAME_W - margin, x)); var ny = Math.max(margin, Math.min(GAME_H - margin, y)); ship.x = nx; ship.y = ny; // Touch feedback: scale ship up slightly while dragging, then back ship.scale.set(1.15, 1.15); tween(ship.scale, { x: 1, y: 1 }, { duration: 120 }); } } game.move = handleMove; var dragAnywhereHintShown = false; game.down = function (x, y, obj) { // User-friendly: allow drag to start if touch is on ship OR anywhere in lower half of screen var dx = x - ship.x, dy = y - ship.y; var onShip = dx * dx + dy * dy < ship.radius * ship.radius * 1.2; var inLowerHalf = y > GAME_H / 2; if (onShip || inLowerHalf) { dragNode = ship; handleMove(x, y, obj); // Visual feedback: flash ship blue for 120ms on drag start LK.effects.flashObject(ship, 0x33c1ff, 120); // Show floating helper text only the first time user drags from lower half (not on ship) if (!onShip && inLowerHalf && !dragAnywhereHintShown) { showFloatingText("Tip: Drag anywhere below to move!", ship.x, ship.y - 180, 0x33c1ff); dragAnywhereHintShown = true; } } }; game.up = function (x, y, obj) { dragNode = null; }; // Main update loop game.update = function () { // Update ship ship.update(); // --- Update player health UI text --- shipHealthTxt.setText(ship.health + " / " + ship.maxHealth); shipHealthTxt.x = ship.x; shipHealthTxt.y = ship.y - ship.radius - 60; // --- Update enemy health UI text --- // Remove any health text objects for destroyed enemies for (var i = enemyHealthTxts.length - 1; i >= 0; i--) { if (i >= enemies.length || !enemies[i] || enemies[i].destroyed) { if (enemyHealthTxts[i]) { enemyHealthTxts[i].destroy(); } enemyHealthTxts.splice(i, 1); } } // Sync health text objects to enemies for (var i = 0; i < enemies.length; i++) { var e = enemies[i]; var txt = enemyHealthTxts[i]; if (!txt) { txt = new Text2('', { size: 48, fill: 0xffffff, stroke: 0x000000, strokeThickness: 5 }); txt.anchor.set(0.5, 1); game.addChild(txt); enemyHealthTxts[i] = txt; } txt.setText(e.health + " / " + e.maxHealth); txt.x = e.x; txt.y = e.y - (e.radius || 60) - 38; txt.visible = e.health > 0; } // --- Double Score timer --- if (doubleScoreActive) { doubleScoreTimer--; if (doubleScoreTimer <= 0) { doubleScoreActive = false; showFloatingText("Double Score Ended", ship.x, ship.y - 120, 0xff00ff); } } // --- Slow Motion timer --- if (slowMotionActive) { slowMotionTimer--; if (slowMotionTimer <= 0) { slowMotionActive = false; showFloatingText("Speed Restored", ship.x, ship.y - 120, 0x8888ff); } } // --- Triple Shot timer --- if (tripleShotActive) { tripleShotTimer--; if (tripleShotTimer <= 0) { tripleShotActive = false; showFloatingText("Triple Shot Ended", ship.x, ship.y - 120, 0xff8800); } } // --- Invincibility timer --- if (invincibilityActive) { invincibilityTimer--; if (invincibilityTimer <= 0) { invincibilityActive = false; showFloatingText("Invincibility Ended", ship.x, ship.y - 120, 0xffffff); } } // --- Freeze Enemies timer --- if (typeof freezeEnemiesTimer !== "undefined" && freezeEnemiesTimer > 0) { freezeEnemiesTimer--; if (freezeEnemiesTimer <= 0) { showFloatingText("Enemies Unfrozen", ship.x, ship.y - 120, 0x00e1ff); } } // --- Homing Bullets timer --- if (typeof homingBulletsTimer !== "undefined" && homingBulletsTimer > 0) { homingBulletsTimer--; if (homingBulletsTimer <= 0) { showFloatingText("Homing Ended", ship.x, ship.y - 120, 0x43a047); } } // --- Reflect Bullets timer --- if (typeof reflectBulletsTimer !== "undefined" && reflectBulletsTimer > 0) { reflectBulletsTimer--; if (reflectBulletsTimer <= 0) { showFloatingText("Reflect Ended", ship.x, ship.y - 120, 0xcddc39); } } // --- Enemy Slow timer --- if (typeof enemySlowTimer !== "undefined" && enemySlowTimer > 0) { enemySlowTimer--; if (enemySlowTimer <= 0) { showFloatingText("Enemies Normal Speed", ship.x, ship.y - 120, 0x607d8b); } } // --- Enemy Stun timer --- if (typeof enemyStunTimer !== "undefined" && enemyStunTimer > 0) { enemyStunTimer--; if (enemyStunTimer <= 0) { showFloatingText("Enemies Unstunned", ship.x, ship.y - 120, 0x6d4c41); } } // --- Player shooting --- ship.shootCooldown--; var shootRate = ship.rapidFire ? Math.max(6, Math.floor(PLAYER_SHOOT_RATE * 0.33)) : PLAYER_SHOOT_RATE; if (ship.shootCooldown <= 0) { // Auto-fire if (tripleShotActive) { for (var ts = -1; ts <= 1; ts++) { var pb = new PlayerBullet(); pb.x = ship.x + ts * 38; pb.y = ship.y - ship.radius - 30; if (ts !== 0) pb.rotation = ts * 0.18; playerBullets.push(pb); game.addChild(pb); } } else { var pb = new PlayerBullet(); pb.x = ship.x; pb.y = ship.y - ship.radius - 30; playerBullets.push(pb); game.addChild(pb); } ship.shootCooldown = shootRate; LK.getSound('shoot').play(); } // --- Update player bullets --- for (var i = playerBullets.length - 1; i >= 0; i--) { var b = playerBullets[i]; b.update(); // Remove if off screen if (b.y < -80) { b.destroy(); playerBullets.splice(i, 1); } } // --- Update enemies --- for (var i = enemies.length - 1; i >= 0; i--) { var e = enemies[i]; // --- Enemy AI: dodge if player is close horizontally --- if (Math.abs(ship.x - e.x) < 180 && Math.abs(ship.y - e.y) < 600) { // Try to dodge left or right, but less distance for fairness if (ship.x < e.x) e.x += 6 + Math.random() * 3;else e.x -= 6 + Math.random() * 3; } // --- Powerup effects: freeze, slow, stun --- var freezeActive = typeof freezeEnemiesTimer !== "undefined" && freezeEnemiesTimer > 0; var slowActive = typeof enemySlowTimer !== "undefined" && enemySlowTimer > 0 || slowMotionActive; var stunActive = typeof enemyStunTimer !== "undefined" && enemyStunTimer > 0; if (stunActive) { // Stunned: don't update, don't shoot // Visual feedback: pulse tint if (LK.ticks % 20 < 10) e.tint = 0x6d4c41;else e.tint = 0xffffff; } else if (freezeActive) { // Frozen: don't update, don't shoot if (LK.ticks % 20 < 10) e.tint = 0x00e1ff;else e.tint = 0xffffff; } else { // Slow: update less frequently if (!slowActive || LK.ticks % 2 === 0) { e.update(); } } // Destroy and remove enemies when they move off the bottom of the screen if (e.y > GAME_H + e.radius) { e.destroy(); enemies.splice(i, 1); continue; } // (Removed clamping: enemies can now leave the screen at the bottom) // Enemy shooting if (!freezeActive && !stunActive) { // SpiralEnemy: burst shoot 3 bullets in a spread if (e.constructor === SpiralEnemy && e.shootCooldown <= 0) { for (var b = -1; b <= 1; b++) { var eb = new EnemyBullet(); eb.x = e.x; eb.y = e.y + e.radius + 10; // Spread: aim at ship, but offset angle var dx = ship.x - e.x, dy = ship.y - e.y; var len = Math.sqrt(dx * dx + dy * dy); var angle = Math.atan2(dy, dx) + b * 0.18; if (len > 0) { eb.dirX = Math.cos(angle); eb.dirY = Math.sin(angle); } enemyBullets.push(eb); game.addChild(eb); } e.shootCooldown = 120 + Math.floor(Math.random() * 40); } else if (e.shootCooldown <= 0) { // BigEnemy shoots big bullet, others shoot normal var eb; if (e.constructor === BigEnemy) { eb = new BigEnemyBullet(); eb.x = e.x; eb.y = e.y + e.radius + 20; // Aim at ship var dx = ship.x - e.x, dy = ship.y - e.y; var len = Math.sqrt(dx * dx + dy * dy); if (len > 0) { eb.dirX = dx / len; eb.dirY = dy / len; } enemyBullets.push(eb); game.addChild(eb); e.shootCooldown = 120 + Math.floor(Math.random() * 40); } else { eb = new EnemyBullet(); eb.x = e.x; eb.y = e.y + e.radius + 10; // Aim at ship var dx = ship.x - e.x, dy = ship.y - e.y; var len = Math.sqrt(dx * dx + dy * dy); if (len > 0) { eb.dirX = dx / len; eb.dirY = dy / len; } enemyBullets.push(eb); game.addChild(eb); e.shootCooldown = 90 + Math.floor(Math.random() * 60); } } } } // --- Update enemy bullets --- for (var i = enemyBullets.length - 1; i >= 0; i--) { var eb = enemyBullets[i]; // Slow motion: update less frequently var reflectActive = typeof reflectBulletsTimer !== "undefined" && reflectBulletsTimer > 0; if (reflectActive && eb.dirY > 0 && eb.y > ship.y - 200) { // Reflect bullets going downwards, near ship eb.dirY *= -1; showFloatingText("Reflected!", eb.x, eb.y, 0xcddc39); } if (!slowMotionActive || LK.ticks % 2 === 0) { eb.update(); } if (eb.x < -100 || eb.x > GAME_W + 100 || eb.y < -100 || eb.y > GAME_H + 100) { eb.destroy(); enemyBullets.splice(i, 1); } } // --- Homing Bullets effect for player bullets --- if (typeof homingBulletsTimer !== "undefined" && homingBulletsTimer > 0) { for (var i = 0; i < playerBullets.length; i++) { var pb = playerBullets[i]; // Find nearest enemy var nearest = null, minDist = 99999; for (var j = 0; j < enemies.length; j++) { var dx = enemies[j].x - pb.x; var dy = enemies[j].y - pb.y; var dist = dx * dx + dy * dy; if (dist < minDist) { minDist = dist; nearest = enemies[j]; } } if (nearest && minDist < 400 * 400) { // Adjust bullet direction slightly toward enemy var dx = nearest.x - pb.x; var dy = nearest.y - pb.y; var len = Math.sqrt(dx * dx + dy * dy); if (len > 0) { var steer = 0.18; pb.x += dx / len * steer; pb.y += dy / len * steer * 0.5; } } } } // --- Update enemy bullets --- for (var i = enemyBullets.length - 1; i >= 0; i--) { var eb = enemyBullets[i]; // Slow motion: update less frequently if (!slowMotionActive || LK.ticks % 2 === 0) { eb.update(); } if (eb.x < -100 || eb.x > GAME_W + 100 || eb.y < -100 || eb.y > GAME_H + 100) { eb.destroy(); enemyBullets.splice(i, 1); } } // --- Update powerups --- for (var i = powerups.length - 1; i >= 0; i--) { var p = powerups[i]; p.update(); if (p.y > GAME_H + 100) { p.destroy(); powerups.splice(i, 1); } } // --- Collision: Player bullets vs Enemies --- for (var i = playerBullets.length - 1; i >= 0; i--) { var b = playerBullets[i]; for (var j = enemies.length - 1; j >= 0; j--) { var e = enemies[j]; if (b.intersects(e)) { // Hit enemy e.takeDamage(2); // Recoil effect for enemy tween(e, { y: e.y - 30 }, { duration: 60, yoyo: true, repeat: 1 }); // Camera shake on hit (simulate with quick flash) LK.getSound('enemyDown').play(); // Combo system variables (global scope, but initialize if undefined) if (typeof comboCount === "undefined") comboCount = 0; if (typeof comboTimer === "undefined") comboTimer = 0; if (typeof lastComboTime === "undefined") lastComboTime = 0; // Score only if enemy dies if (e.health <= 0) { // Combo logic: if last kill was within 2 seconds, increase combo var now = LK.ticks; if (now - lastComboTime < 120) { comboCount++; } else { comboCount = 1; } lastComboTime = now; comboTimer = 120; // 2 seconds to continue combo // Combo bonus: +10 base, +5 per combo after first, multiplied by scoreMultiplier if (typeof scoreMultiplier === "undefined") scoreMultiplier = 1; var comboBonus = 10 + (comboCount > 1 ? (comboCount - 1) * 5 : 0); comboBonus *= scoreMultiplier; if (doubleScoreActive) comboBonus *= 2; score += comboBonus; // Animate score text for feedback scoreTxt.setText(score); if (score > highScore) { highScore = score; storage.highScore = highScore; // Update leaderboard for all users if (typeof updateLeaderboard === "function") { updateLeaderboard(highScore); if (typeof refreshLeaderboardUI === "function") refreshLeaderboardUI(); } if (typeof highScoreTxt !== "undefined") { highScoreTxt.setText("High Score: " + highScore); highScoreTxt.scale.set(1.2, 1.2); tween(highScoreTxt.scale, { x: 1, y: 1 }, { duration: 300 }); } } if (typeof multiplierTxt !== "undefined") { multiplierTxt.setText("x" + scoreMultiplier); multiplierTxt.scale.set(1.3, 1.3); tween(multiplierTxt.scale, { x: 1, y: 1 }, { duration: 200 }); } scoreTxt.scale.set(1.25, 1.25); tween(scoreTxt.scale, { x: 1, y: 1 }, { duration: 200 }); // Show floating text for combo if (comboCount > 1) { showFloatingText("Combo x" + comboCount + "! +" + comboBonus, e.x, e.y - 80, 0xffe100); if (comboCount % 3 === 0) { showFloatingText("Multiplier: x" + scoreMultiplier, e.x, e.y - 160, 0x00ff88); } } else { showFloatingText("+10", e.x, e.y - 80, 0xffffff); } // Fun: random emoji on enemy kill! var emojis = ["🚀", "💥", "✨", "🔥", "😎", "🎉", "🛸", "👾"]; var emoji = emojis[Math.floor(Math.random() * emojis.length)]; showFloatingText(emoji, e.x + (Math.random() * 80 - 40), e.y - 120, 0xffffff); e.destroy(); enemies.splice(j, 1); } b.destroy(); playerBullets.splice(i, 1); break; } } } // --- Combo timer update --- if (typeof comboTimer !== "undefined" && comboTimer > 0) { comboTimer--; if (comboTimer === 0) { comboCount = 0; scoreMultiplier = 1; // Reset multiplier on missed combo } } if (comboCount > 1) { scoreMultiplier = 1 + Math.floor(comboCount / 3); // Every 3 combo increases multiplier by 1 } else { scoreMultiplier = 1; } // --- Collision: Ship vs Enemies --- var shipEnemyIntersect = false; for (var i = 0; i < enemies.length; i++) { var e = enemies[i]; if (ship.intersects(e)) { shipEnemyIntersect = true; break; } } if (!lastShipEnemyIntersect && shipEnemyIntersect) { if (invincibilityActive) { LK.effects.flashObject(ship, 0xffffff, 400); showFloatingText("No Damage!", ship.x, ship.y - 120, 0xffffff); } else if (ship.shield) { // Absorb hit, destroy enemy LK.effects.flashObject(ship, 0x00ffff, 400); for (var i = 0; i < enemies.length; i++) { if (ship.intersects(enemies[i])) { enemies[i].destroy(); enemies.splice(i, 1); break; } } ship.shield = false; ship.shieldTimer = 0; ship.children[1].visible = false; } else { // Take damage ship.takeDamage(2); // (Screen flash removed) LK.getSound('hit').play(); if (ship.health <= 0) { LK.showGameOver(); return; } } } lastShipEnemyIntersect = shipEnemyIntersect; // --- Collision: Ship vs Enemy Bullets --- var shipEnemyBulletIntersect = false; for (var i = 0; i < enemyBullets.length; i++) { var eb = enemyBullets[i]; if (ship.intersects(eb)) { shipEnemyBulletIntersect = true; break; } } if (!lastShipEnemyBulletIntersect && shipEnemyBulletIntersect) { if (invincibilityActive) { LK.effects.flashObject(ship, 0xffffff, 400); showFloatingText("No Damage!", ship.x, ship.y - 120, 0xffffff); } else if (ship.shield) { LK.effects.flashObject(ship, 0x00ffff, 400); // Remove bullet for (var i = 0; i < enemyBullets.length; i++) { if (ship.intersects(enemyBullets[i])) { enemyBullets[i].destroy(); enemyBullets.splice(i, 1); break; } } ship.shield = false; ship.shieldTimer = 0; ship.children[1].visible = false; } else { // Take damage ship.takeDamage(1); // (Screen flash removed) LK.getSound('hit').play(); if (ship.health <= 0) { LK.showGameOver(); return; } } } lastShipEnemyBulletIntersect = shipEnemyBulletIntersect; // --- Collision: Ship vs Powerups --- var shipPowerupIntersect = false; var _loop = function _loop() { p = powerups[i]; if (ship.intersects(p)) { // --- 20 Powerup Types Logic --- // Helper to apply a powerup type (for multi-powerup support) var applyPowerupType = function applyPowerupType(type) { // 1. rapid if (type === 'rapid') { if (ship.rapidFire) { ship.rapidFireTimer += 240; showFloatingText("Rapid Fire Combo!", ship.x, ship.y - 120, 0xffe100); } else { ship.activateRapidFire(360); showFloatingText("Rapid Fire!", ship.x, ship.y - 120, 0xffe100); } // 2. shield } else if (type === 'shield') { if (ship.shield) { ship.shieldTimer += 320; showFloatingText("Shield Combo!", ship.x, ship.y - 120, 0x00ffff); } else { ship.activateShield(480); showFloatingText("Shield!", ship.x, ship.y - 120, 0x00ffff); } // 3. heal } else if (type === 'heal') { ship.heal(4); showFloatingText("+4 Health", ship.x, ship.y - 120, 0x44ff44); // 4. doubleScore } else if (type === 'doubleScore') { if (doubleScoreActive) { doubleScoreTimer += 400; showFloatingText("Double Score Combo!", ship.x, ship.y - 120, 0xff00ff); } else { doubleScoreActive = true; doubleScoreTimer = 600; showFloatingText("Double Score!", ship.x, ship.y - 120, 0xff00ff); } // 5. slowMotion } else if (type === 'slowMotion') { if (slowMotionActive) { slowMotionTimer += 300; showFloatingText("Slow Motion Combo!", ship.x, ship.y - 120, 0x8888ff); } else { slowMotionActive = true; slowMotionTimer = 420; showFloatingText("Slow Motion!", ship.x, ship.y - 120, 0x8888ff); } // 6. tripleShot } else if (type === 'tripleShot') { if (tripleShotActive) { tripleShotTimer += 360; showFloatingText("Triple Shot Combo!", ship.x, ship.y - 120, 0xff8800); } else { tripleShotActive = true; tripleShotTimer = 540; showFloatingText("Triple Shot!", ship.x, ship.y - 120, 0xff8800); } // 7. megaShield } else if (type === 'megaShield') { if (ship.shield) { ship.shieldTimer += 800; showFloatingText("Mega Shield Combo!", ship.x, ship.y - 120, 0x00ff88); } else { ship.activateShield(1200); showFloatingText("Mega Shield!", ship.x, ship.y - 120, 0x00ff88); } // 8. invincibility } else if (type === 'invincibility') { if (invincibilityActive) { invincibilityTimer += 240; showFloatingText("Invincible Combo!", ship.x, ship.y - 120, 0xffffff); } else { invincibilityActive = true; invincibilityTimer = 360; showFloatingText("Invincible!", ship.x, ship.y - 120, 0xffffff); } // 9. scoreBomb } else if (type === 'scoreBomb') { var killed = 0; for (var si = enemies.length - 1; si >= 0; si--) { if (enemies[si].y > 0) { enemies[si].destroy(); enemies.splice(si, 1); killed++; } } if (killed > 0) { var bombScore = 10 * killed; score += bombScore; scoreTxt.setText(score); showFloatingText("Score Bomb! +" + bombScore, ship.x, ship.y - 120, 0xff2222); } else { showFloatingText("Score Bomb! (No targets)", ship.x, ship.y - 120, 0xff2222); } // 10. clearBullets } else if (type === 'clearBullets') { var cleared = 0; for (var ci = enemyBullets.length - 1; ci >= 0; ci--) { enemyBullets[ci].destroy(); enemyBullets.splice(ci, 1); cleared++; } showFloatingText("Cleared " + cleared + " Bullets!", ship.x, ship.y - 120, 0x00ff00); // 11. freezeEnemies } else if (type === 'freezeEnemies') { if (typeof freezeEnemiesTimer === "undefined") freezeEnemiesTimer = 0; if (freezeEnemiesTimer > 0) { freezeEnemiesTimer += 180; showFloatingText("Freeze Combo!", ship.x, ship.y - 120, 0x00e1ff); } else { freezeEnemiesTimer = 360; showFloatingText("Enemies Frozen!", ship.x, ship.y - 120, 0x00e1ff); } // 12. miniEnemies } else if (type === 'miniEnemies') { for (var mi = 0; mi < enemies.length; mi++) { enemies[mi].scale.set(0.6, 0.6); enemies[mi].radius *= 0.6; } showFloatingText("Mini Enemies!", ship.x, ship.y - 120, 0xffb300); // 13. giantShip } else if (type === 'giantShip') { ship.scale.set(1.7, 1.7); showFloatingText("Giant Ship!", ship.x, ship.y - 120, 0x8e24aa); tween(ship.scale, { x: 1, y: 1 }, { duration: 1200 }); // 14. tinyShip } else if (type === 'tinyShip') { ship.scale.set(0.5, 0.5); showFloatingText("Tiny Ship!", ship.x, ship.y - 120, 0x3949ab); tween(ship.scale, { x: 1, y: 1 }, { duration: 1200 }); // 15. reverseBullets } else if (type === 'reverseBullets') { for (var ri = 0; ri < enemyBullets.length; ri++) { enemyBullets[ri].dirY *= -1; } showFloatingText("Reverse Bullets!", ship.x, ship.y - 120, 0x00bcd4); // 16. homingBullets } else if (type === 'homingBullets') { if (typeof homingBulletsTimer === "undefined") homingBulletsTimer = 0; if (homingBulletsTimer > 0) { homingBulletsTimer += 180; showFloatingText("Homing Combo!", ship.x, ship.y - 120, 0x43a047); } else { homingBulletsTimer = 360; showFloatingText("Homing Bullets!", ship.x, ship.y - 120, 0x43a047); } // 17. reflectBullets } else if (type === 'reflectBullets') { if (typeof reflectBulletsTimer === "undefined") reflectBulletsTimer = 0; if (reflectBulletsTimer > 0) { reflectBulletsTimer += 180; showFloatingText("Reflect Combo!", ship.x, ship.y - 120, 0xcddc39); } else { reflectBulletsTimer = 360; showFloatingText("Reflect Bullets!", ship.x, ship.y - 120, 0xcddc39); } // 18. healthBoost } else if (type === 'healthBoost') { ship.maxHealth += 4; ship.heal(4); showFloatingText("Max Health Up!", ship.x, ship.y - 120, 0xff1744); // 19. scoreBoost } else if (type === 'scoreBoost') { score += 100; scoreTxt.setText(score); showFloatingText("+100 Score!", ship.x, ship.y - 120, 0xffea00); // 20. enemySlow } else if (type === 'enemySlow') { if (typeof enemySlowTimer === "undefined") enemySlowTimer = 0; if (enemySlowTimer > 0) { enemySlowTimer += 180; showFloatingText("Enemy Slow Combo!", ship.x, ship.y - 120, 0x607d8b); } else { enemySlowTimer = 360; showFloatingText("Enemies Slowed!", ship.x, ship.y - 120, 0x607d8b); } // 21. enemyStun (fallback, rarely picked) } else if (type === 'enemyStun') { if (typeof enemyStunTimer === "undefined") enemyStunTimer = 0; if (enemyStunTimer > 0) { enemyStunTimer += 120; showFloatingText("Stun Combo!", ship.x, ship.y - 120, 0x6d4c41); } else { enemyStunTimer = 240; showFloatingText("Enemies Stunned!", ship.x, ship.y - 120, 0x6d4c41); } } }; // Always apply the main powerup type shipPowerupIntersect = true; // Apply powerup LK.getSound('powerup').play(); // Fun: confetti burst effect on powerup collect! for (confetti = 0; confetti < 18; confetti++) { (function () { var part = new Container(); var c = part.attachAsset('playerBullet', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.4 + Math.random() * 0.5, scaleY: 0.4 + Math.random() * 0.5, tint: 0xffe100 + Math.floor(Math.random() * 0xffffff) }); part.x = ship.x; part.y = ship.y - 40; part.alpha = 0.85; game.addChild(part); var angle = Math.random() * Math.PI * 2; var dist = 120 + Math.random() * 80; var dx = Math.cos(angle) * dist; var dy = Math.sin(angle) * dist; tween(part, { x: part.x + dx, y: part.y + dy, alpha: 0 }, { duration: 600 + Math.random() * 400, onFinish: function onFinish() { part.destroy(); } }); })(); } applyPowerupType(p.type); // If this powerup has extraTypes (multi-powerup), apply those as well if (p.extraTypes && p.extraTypes.length > 0) { for (et = 0; et < p.extraTypes.length; et++) { applyPowerupType(p.extraTypes[et]); // Show a floating text for the extra powerup showFloatingText("Bonus: " + p.extraTypes[et], ship.x, ship.y - 180 - et * 60, 0xffe100); } } // Combo fusion: if multiple effects are active, show a special floating text! comboActiveCount = 0; if (ship.rapidFire) comboActiveCount++; if (doubleScoreActive) comboActiveCount++; if (tripleShotActive) comboActiveCount++; if (slowMotionActive) comboActiveCount++; if (invincibilityActive) comboActiveCount++; if (ship.shield) comboActiveCount++; if (typeof freezeEnemiesTimer !== "undefined" && freezeEnemiesTimer > 0) comboActiveCount++; if (typeof homingBulletsTimer !== "undefined" && homingBulletsTimer > 0) comboActiveCount++; if (typeof reflectBulletsTimer !== "undefined" && reflectBulletsTimer > 0) comboActiveCount++; if (typeof enemySlowTimer !== "undefined" && enemySlowTimer > 0) comboActiveCount++; if (typeof enemyStunTimer !== "undefined" && enemyStunTimer > 0) comboActiveCount++; if (comboActiveCount >= 3) { showFloatingText("Combo Fusion! (" + comboActiveCount + ")", ship.x, ship.y - 220, 0xffe100); } p.destroy(); powerups.splice(i, 1); } }, p, confetti, et, comboActiveCount; for (var i = powerups.length - 1; i >= 0; i--) { _loop(); } lastShipPowerupIntersect = shipPowerupIntersect; // --- Mission system: show floating text for milestones --- if (score > 0 && score % 100 === 0 && !game['milestone_' + score]) { showFloatingText("Milestone: " + score + "!", GAME_W / 2, 320, 0xffe100); game['milestone_' + score] = true; } // --- Background color cycling every 200 points --- // Define a palette of beautiful background colors, starting with sky blue if (typeof bgColors === "undefined") { var bgColors = [0x87ceeb, // sky blue 0x000000, // black 0x1a237e, // indigo 0x004d40, // teal dark 0x263238, // blue grey 0x880e4f, // deep pink 0x1565c0, // blue 0x2e7d32, // green 0xff6f00, // orange 0x4a148c, // purple 0x212121, // dark grey 0x00695c, // teal 0x3949ab, // blue indigo 0xc62828, // red 0x00838f, // cyan 0x6d4c41, // brown 0x283593 // deep blue ]; var lastBgColorIndex = 0; var lastBgScoreStep = 0; // Set initial background to sky blue game.setBackgroundColor(bgColors[0]); } // Calculate which color to use based on score var bgScoreStep = Math.floor(score / 200); if (bgScoreStep !== lastBgScoreStep) { // Cycle through palette, skip sky blue after first var colorIdx = bgScoreStep % bgColors.length; if (colorIdx === 0 && bgScoreStep > 0) colorIdx = 1; game.setBackgroundColor(bgColors[colorIdx]); lastBgColorIndex = colorIdx; lastBgScoreStep = bgScoreStep; } // --- Feature selection popup removed --- // --- Enemy spawn --- enemySpawnTimer--; if (enemySpawnTimer <= 0) { // Randomly pick enemy type var enemyTypeRand = Math.random(); var e; if (enemyTypeRand < 0.18) { e = new FastEnemy(); } else if (enemyTypeRand < 0.36) { e = new TankEnemy(); } else if (enemyTypeRand < 0.54) { e = new ZigzagEnemy(); } else if (enemyTypeRand < 0.70) { e = new Enemy(); } else { e = new BigEnemy(); } e.x = 180 + Math.random() * (GAME_W - 360); e.y = -100; // Removed enemy speed scaling with score to keep game speed consistent enemies.push(e); game.addChild(e); // Decrease interval as score increases enemySpawnInterval = Math.max(minEnemyInterval, 60 - Math.floor(score / 100) * 4); enemySpawnTimer = enemySpawnInterval; } // --- Powerup spawn --- powerupTimer--; if (powerupTimer <= 0) { var p = new Powerup(); p.x = 180 + Math.random() * (GAME_W - 360); p.y = -80; powerups.push(p); game.addChild(p); powerupInterval = 120 + Math.floor(Math.random() * 120); powerupTimer = powerupInterval; } }; // Floating text helper for feedback function showFloatingText(txt, x, y, color) { var t = new Text2(txt, { size: 90, fill: color || 0xffffff, stroke: 0x000000, strokeThickness: 8 }); t.anchor.set(0.5, 1); t.x = x; t.y = y; game.addChild(t); tween(t, { y: y - 120, alpha: 0 }, { duration: 700, onFinish: function onFinish() { t.destroy(); } }); } // --- Start Menu Overlay --- var menuOverlay = new Container(); menuOverlay.interactive = true; menuOverlay.x = 0; menuOverlay.y = 0; menuOverlay.width = GAME_W; menuOverlay.height = GAME_H; // Dim background var menuBg = LK.getAsset('playerBullet', { anchorX: 0, anchorY: 0, scaleX: GAME_W / 30, scaleY: GAME_H / 60, tint: 0x000000, alpha: 0.82, x: 0, y: 0 }); menuOverlay.addChild(menuBg); // Title var menuTitle = new Text2("SPACE BLASTERS", { size: 160, fill: 0xffe100, stroke: 0x000000, strokeThickness: 12, align: "center" }); menuTitle.anchor.set(0.5, 0.5); menuTitle.x = GAME_W / 2; menuTitle.y = GAME_H / 2 - 320; menuOverlay.addChild(menuTitle); // Instructions var menuInstructions = new Text2("Drag the ship to move\nAuto-fire enabled\nCollect powerups!", { size: 90, fill: 0xffffff, stroke: 0x000000, strokeThickness: 8, align: "center" }); menuInstructions.anchor.set(0.5, 0.5); menuInstructions.x = GAME_W / 2; menuInstructions.y = GAME_H / 2 - 80; menuOverlay.addChild(menuInstructions); // --- Leaderboard UI --- // Each user will have a unique id (simulate with random if not present) if (!storage.userId) { storage.userId = "user_" + Math.floor(Math.random() * 1000000000); } var userId = storage.userId; // Initialize leaderboard if not present if (!storage.leaderboard) { storage.leaderboard = []; } // Helper to get sorted leaderboard (top 100) function getSortedLeaderboard() { var lb = storage.leaderboard || []; // Defensive: filter out invalid entries var valid = []; for (var i = 0; i < lb.length; i++) { var entry = lb[i]; if (entry && typeof entry.score === "number" && typeof entry.userId === "string") { valid.push(entry); } } // Sort descending by score valid.sort(function (a, b) { return b.score - a.score; }); // Only top 100 return valid.slice(0, 100); } // Add/update this user's high score in leaderboard if needed function updateLeaderboard(newScore) { var lb = storage.leaderboard || []; var found = false; for (var i = 0; i < lb.length; i++) { if (lb[i].userId === userId) { if (newScore > lb[i].score) { lb[i].score = newScore; } found = true; break; } } if (!found) { lb.push({ userId: userId, score: newScore }); } // Only keep top 100 lb.sort(function (a, b) { return b.score - a.score; }); storage.leaderboard = lb.slice(0, 100); } // Show leaderboard in menu var leaderboardTitle = new Text2("Leaderboard (Top 100)", { size: 80, fill: 0xffffff, stroke: 0x000000, strokeThickness: 8, align: "center" }); leaderboardTitle.anchor.set(0.5, 0.5); leaderboardTitle.x = GAME_W / 2; leaderboardTitle.y = GAME_H / 2 + 60; menuOverlay.addChild(leaderboardTitle); // Render leaderboard entries as a single text block for performance function renderLeaderboard() { var sorted = getSortedLeaderboard(); var lines = []; for (var i = 0; i < sorted.length; i++) { var entry = sorted[i]; var rank = i + 1 + ". "; var name = entry.userId === userId ? "You" : "Player " + entry.userId.substr(-4); var scoreStr = entry.score; // Highlight current user if (entry.userId === userId) { lines.push("[b][color=#ffe100]" + rank + name + " - " + scoreStr + "[/color][/b]"); } else { lines.push(rank + name + " - " + scoreStr); } } if (lines.length === 0) { lines.push("No scores yet!"); } return lines.join("\n"); } var leaderboardTxt = new Text2(renderLeaderboard(), { size: 54, fill: 0xffffff, stroke: 0x000000, strokeThickness: 6, align: "left", wordWrap: true, wordWrapWidth: GAME_W - 400 }); leaderboardTxt.anchor.set(0.5, 0); leaderboardTxt.x = GAME_W / 2; leaderboardTxt.y = GAME_H / 2 + 120; menuOverlay.addChild(leaderboardTxt); // Start button var startBtn = new Text2("TAP TO START", { size: 110, fill: 0x00ff88, stroke: 0x000000, strokeThickness: 10, align: "center" }); startBtn.anchor.set(0.5, 0.5); startBtn.x = GAME_W / 2; startBtn.y = GAME_H / 2 + 260; menuOverlay.addChild(startBtn); game.addChild(menuOverlay); // When menu is shown, refresh leaderboard UI function refreshLeaderboardUI() { leaderboardTxt.setText(renderLeaderboard()); } refreshLeaderboardUI(); // Pause game logic until menu is dismissed var gamePausedForMenu = true; var origGameUpdate = game.update; game.update = function () { if (gamePausedForMenu) return; origGameUpdate.call(game); }; // Dismiss menu on tap/click anywhere menuOverlay.down = function (x, y, obj) { if (!gamePausedForMenu) return; gamePausedForMenu = false; tween(menuOverlay, { alpha: 0 }, { duration: 400, onFinish: function onFinish() { menuOverlay.destroy(); } }); }; // Forward input to menu overlay game.down = function (x, y, obj) { if (gamePausedForMenu && menuOverlay.down) { menuOverlay.down(x, y, obj); return; } // User-friendly: allow drag to start if touch is on ship OR anywhere in lower half of screen var dx = x - ship.x, dy = y - ship.y; var onShip = dx * dx + dy * dy < ship.radius * ship.radius * 1.2; var inLowerHalf = y > GAME_H / 2; if (onShip || inLowerHalf) { dragNode = ship; handleMove(x, y, obj); LK.effects.flashObject(ship, 0x33c1ff, 120); if (!onShip && inLowerHalf && !dragAnywhereHintShown) { showFloatingText("Tip: Drag anywhere below to move!", ship.x, ship.y - 180, 0x33c1ff); dragAnywhereHintShown = true; } } }; game.move = function (x, y, obj) { if (gamePausedForMenu) return; handleMove(x, y, obj); }; game.up = function (x, y, obj) { if (gamePausedForMenu) return; dragNode = null; }; // Define freezeActive and stunActive for menu overlay logic var freezeActive = typeof freezeEnemiesTimer !== "undefined" && freezeEnemiesTimer > 0; var stunActive = typeof enemyStunTimer !== "undefined" && enemyStunTimer > 0; for (var i = 0; i < enemies.length; i++) { var e = enemies[i]; if (!freezeActive && !stunActive) { // SpiralEnemy: burst shoot 3 bullets in a spread if (e.constructor === SpiralEnemy && e.shootCooldown <= 0) { for (var b = -1; b <= 1; b++) { var eb = new EnemyBullet(); eb.x = e.x; eb.y = e.y + e.radius + 10; // Spread: aim at ship, but offset angle var dx = ship.x - e.x, dy = ship.y - e.y; var len = Math.sqrt(dx * dx + dy * dy); var angle = Math.atan2(dy, dx) + b * 0.18; if (len > 0) { eb.dirX = Math.cos(angle); eb.dirY = Math.sin(angle); } enemyBullets.push(eb); game.addChild(eb); } e.shootCooldown = 120 + Math.floor(Math.random() * 40); } else if (e.shootCooldown <= 0) { var eb = new EnemyBullet(); eb.x = e.x; eb.y = e.y + e.radius + 10; // Aim at ship var dx = ship.x - e.x, dy = ship.y - e.y; var len = Math.sqrt(dx * dx + dy * dy); if (len > 0) { eb.dirX = dx / len; eb.dirY = dy / len; } enemyBullets.push(eb); game.addChild(eb); e.shootCooldown = 90 + Math.floor(Math.random() * 60); } } }
===================================================================
--- original.js
+++ change.js
@@ -537,8 +537,12 @@
// Score
var score = 0;
// High score (persistent for all users)
var highScore = storage.highScore || 0;
+// On game load, ensure leaderboard is updated with this user's high score
+if (typeof updateLeaderboard === "function") {
+ updateLeaderboard(highScore);
+}
var scoreTxt = new Text2('0', {
size: 120,
fill: 0xFFFFFF
});
@@ -1010,8 +1014,13 @@
scoreTxt.setText(score);
if (score > highScore) {
highScore = score;
storage.highScore = highScore;
+ // Update leaderboard for all users
+ if (typeof updateLeaderboard === "function") {
+ updateLeaderboard(highScore);
+ if (typeof refreshLeaderboardUI === "function") refreshLeaderboardUI();
+ }
if (typeof highScoreTxt !== "undefined") {
highScoreTxt.setText("High Score: " + highScore);
highScoreTxt.scale.set(1.2, 1.2);
tween(highScoreTxt.scale, {
@@ -1582,8 +1591,107 @@
menuInstructions.anchor.set(0.5, 0.5);
menuInstructions.x = GAME_W / 2;
menuInstructions.y = GAME_H / 2 - 80;
menuOverlay.addChild(menuInstructions);
+// --- Leaderboard UI ---
+// Each user will have a unique id (simulate with random if not present)
+if (!storage.userId) {
+ storage.userId = "user_" + Math.floor(Math.random() * 1000000000);
+}
+var userId = storage.userId;
+// Initialize leaderboard if not present
+if (!storage.leaderboard) {
+ storage.leaderboard = [];
+}
+// Helper to get sorted leaderboard (top 100)
+function getSortedLeaderboard() {
+ var lb = storage.leaderboard || [];
+ // Defensive: filter out invalid entries
+ var valid = [];
+ for (var i = 0; i < lb.length; i++) {
+ var entry = lb[i];
+ if (entry && typeof entry.score === "number" && typeof entry.userId === "string") {
+ valid.push(entry);
+ }
+ }
+ // Sort descending by score
+ valid.sort(function (a, b) {
+ return b.score - a.score;
+ });
+ // Only top 100
+ return valid.slice(0, 100);
+}
+// Add/update this user's high score in leaderboard if needed
+function updateLeaderboard(newScore) {
+ var lb = storage.leaderboard || [];
+ var found = false;
+ for (var i = 0; i < lb.length; i++) {
+ if (lb[i].userId === userId) {
+ if (newScore > lb[i].score) {
+ lb[i].score = newScore;
+ }
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ lb.push({
+ userId: userId,
+ score: newScore
+ });
+ }
+ // Only keep top 100
+ lb.sort(function (a, b) {
+ return b.score - a.score;
+ });
+ storage.leaderboard = lb.slice(0, 100);
+}
+// Show leaderboard in menu
+var leaderboardTitle = new Text2("Leaderboard (Top 100)", {
+ size: 80,
+ fill: 0xffffff,
+ stroke: 0x000000,
+ strokeThickness: 8,
+ align: "center"
+});
+leaderboardTitle.anchor.set(0.5, 0.5);
+leaderboardTitle.x = GAME_W / 2;
+leaderboardTitle.y = GAME_H / 2 + 60;
+menuOverlay.addChild(leaderboardTitle);
+// Render leaderboard entries as a single text block for performance
+function renderLeaderboard() {
+ var sorted = getSortedLeaderboard();
+ var lines = [];
+ for (var i = 0; i < sorted.length; i++) {
+ var entry = sorted[i];
+ var rank = i + 1 + ". ";
+ var name = entry.userId === userId ? "You" : "Player " + entry.userId.substr(-4);
+ var scoreStr = entry.score;
+ // Highlight current user
+ if (entry.userId === userId) {
+ lines.push("[b][color=#ffe100]" + rank + name + " - " + scoreStr + "[/color][/b]");
+ } else {
+ lines.push(rank + name + " - " + scoreStr);
+ }
+ }
+ if (lines.length === 0) {
+ lines.push("No scores yet!");
+ }
+ return lines.join("\n");
+}
+var leaderboardTxt = new Text2(renderLeaderboard(), {
+ size: 54,
+ fill: 0xffffff,
+ stroke: 0x000000,
+ strokeThickness: 6,
+ align: "left",
+ wordWrap: true,
+ wordWrapWidth: GAME_W - 400
+});
+leaderboardTxt.anchor.set(0.5, 0);
+leaderboardTxt.x = GAME_W / 2;
+leaderboardTxt.y = GAME_H / 2 + 120;
+menuOverlay.addChild(leaderboardTxt);
// Start button
var startBtn = new Text2("TAP TO START", {
size: 110,
fill: 0x00ff88,
@@ -1595,8 +1703,13 @@
startBtn.x = GAME_W / 2;
startBtn.y = GAME_H / 2 + 260;
menuOverlay.addChild(startBtn);
game.addChild(menuOverlay);
+// When menu is shown, refresh leaderboard UI
+function refreshLeaderboardUI() {
+ leaderboardTxt.setText(renderLeaderboard());
+}
+refreshLeaderboardUI();
// Pause game logic until menu is dismissed
var gamePausedForMenu = true;
var origGameUpdate = game.update;
game.update = function () {