/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { highScore: 0, coins: 0, currentSkin: "basic", ownedSkins: ["basic"], playerName: "Player" }); /**** * Classes ****/ var Asteroid = Container.expand(function () { var self = Container.call(this); var asteroid = self.attachAsset('asteroid', { anchorX: 0.5, anchorY: 0.5 }); self.health = 2; self.speed = { y: 2 + Math.random() * 2, x: (Math.random() - 0.5) * 2 }; self.rotation = Math.random() * 0.1 - 0.05; self.scoreValue = 15; // Random size variation var scale = 0.7 + Math.random() * 0.8; asteroid.scale.set(scale, scale); self.damage = function (amount) { self.health -= amount || 1; tween(asteroid, { tint: 0xffffff }, { duration: 200, onFinish: function onFinish() { asteroid.tint = 0x95a5a6; } }); return self.health <= 0; }; self.update = function () { self.y += self.speed.y; self.x += self.speed.x; asteroid.rotation += self.rotation; }; return self; }); var Boss = Container.expand(function (level) { var self = Container.call(this); var ship = self.attachAsset('boss', { anchorX: 0.5, anchorY: 0.5 }); self.level = level || 1; self.maxHealth = 20 * self.level; self.health = self.maxHealth; self.scoreValue = 200 * self.level; self.phase = 0; self.phaseTime = 0; self.patterns = ['side-to-side', 'charge', 'retreat']; self.currentPattern = 0; self.targetX = 0; self.targetY = 0; // Adjust boss based on level if (self.level > 1) { ship.tint = 0xcc00cc; } // Health bar self.healthBar = new Container(); self.addChild(self.healthBar); var healthBarBg = self.healthBar.attachAsset('playerLaser', { anchorX: 0, anchorY: 0.5, scaleX: 2, scaleY: 0.5 }); healthBarBg.tint = 0x333333; healthBarBg.width = 200; self.healthBarFill = self.healthBar.attachAsset('playerLaser', { anchorX: 0, anchorY: 0.5, scaleX: 2, scaleY: 0.4 }); self.healthBarFill.tint = 0xff3333; self.healthBarFill.width = 200; self.healthBar.y = -120; self.damage = function (amount) { self.health -= amount || 1; // Update health bar var healthPercent = self.health / self.maxHealth; self.healthBarFill.width = 200 * healthPercent; tween(ship, { tint: 0xffffff }, { duration: 100, onFinish: function onFinish() { ship.tint = self.level > 1 ? 0xcc00cc : 0x9b59b6; } }); // Change patterns more quickly when damaged if (self.health < self.maxHealth * 0.5 && self.phaseTime > 150) { self.changePattern(); } return self.health <= 0; }; self.changePattern = function () { self.currentPattern = (self.currentPattern + 1) % self.patterns.length; self.phaseTime = 0; self.phase = 0; }; self.update = function () { self.phaseTime++; // Change pattern every so often if (self.phaseTime > 300) { self.changePattern(); } var pattern = self.patterns[self.currentPattern]; switch (pattern) { case 'side-to-side': // Move side to side self.targetX = 1024 + Math.sin(self.phaseTime * 0.02) * 800; if (self.phaseTime < 60) { self.targetY = Math.min(self.y + 2, 400); } else { self.targetY = 400; } break; case 'charge': // Charge down then back up if (self.phase === 0) { self.targetY = self.y + 5; if (self.y > 800) { self.phase = 1; } } else { self.targetY = Math.max(self.y - 3, 300); if (self.y <= 300) { self.phase = 0; } } self.targetX = 1024 + Math.sin(self.phaseTime * 0.03) * 500; break; case 'retreat': // Stay near top and move quickly self.targetY = 300; self.targetX = 1024 + Math.sin(self.phaseTime * 0.05) * 900; break; } // Move toward target position self.x += (self.targetX - self.x) * 0.05; self.y += (self.targetY - self.y) * 0.05; }; return self; }); var Enemy = Container.expand(function (type) { var self = Container.call(this); self.type = type || 'basic'; var assetType = self.type === 'fast' ? 'enemy' : 'enemy'; var ship = self.attachAsset(assetType, { anchorX: 0.5, anchorY: 0.5 }); // Different enemy types if (self.type === 'basic') { self.health = 1; self.speed = 2; self.scoreValue = 10; self.shootChance = 0.01; } else if (self.type === 'fast') { self.health = 1; self.speed = 3.5; self.scoreValue = 15; ship.scaleX = 0.8; ship.scaleY = 0.8; self.shootChance = 0.005; ship.tint = 0xff9966; } else if (self.type === 'tank') { self.health = 3; self.speed = 1.5; self.scoreValue = 25; ship.scaleX = 1.2; ship.scaleY = 1.2; self.shootChance = 0.015; ship.tint = 0x66ff66; } self.movement = { pattern: 'straight', phase: Math.random() * Math.PI * 2, amplitude: 60 + Math.random() * 60 }; self.initialX = 0; self.damage = function (amount) { self.health -= amount || 1; tween(ship, { tint: 0xffffff }, { duration: 200, onFinish: function onFinish() { ship.tint = self.type === 'fast' ? 0xff9966 : self.type === 'tank' ? 0x66ff66 : 0xe74c3c; } }); return self.health <= 0; }; self.update = function () { // Basic movement self.y += self.speed; // Pattern movement if (self.movement.pattern === 'sine') { self.x = self.initialX + Math.sin(LK.ticks * 0.05 + self.movement.phase) * self.movement.amplitude; } else if (self.movement.pattern === 'zigzag') { var timeScale = 0.02; var t = LK.ticks * timeScale + self.movement.phase; var triangleWave = Math.abs(t % 2 - 1) * 2 - 1; self.x = self.initialX + triangleWave * self.movement.amplitude; } }; return self; }); var EnemyLaser = Container.expand(function () { var self = Container.call(this); var laser = self.attachAsset('enemyLaser', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 8; self.update = function () { self.y += self.speed; }; return self; }); var Explosion = Container.expand(function () { var self = Container.call(this); var explosion = self.attachAsset('explosion', { anchorX: 0.5, anchorY: 0.5, alpha: 0.9 }); // Set up fade and scale tween(explosion, { alpha: 0, scaleX: 2, scaleY: 2 }, { duration: 500, onFinish: function onFinish() { self.destroy(); } }); return self; }); var Player = Container.expand(function (skinType) { var self = Container.call(this); self.skinType = skinType || storage.currentSkin || 'basic'; // Choose asset based on skin type var assetName = 'player'; if (self.skinType === 'fast') assetName = 'playerFast';else if (self.skinType === 'tank') assetName = 'playerTank';else if (self.skinType === 'elite') assetName = 'playerElite'; var ship = self.attachAsset(assetName, { anchorX: 0.5, anchorY: 0.5 }); // Apply skin-specific visual effects if (self.skinType === 'fast') { ship.tint = 0x00ff88; // Green tint for speed } else if (self.skinType === 'tank') { ship.tint = 0xff6600; // Orange tint for armor ship.scaleX = 1.2; ship.scaleY = 1.2; } else if (self.skinType === 'elite') { ship.tint = 0x9966ff; // Purple tint for elite } self.shield = self.attachAsset('shield', { anchorX: 0.5, anchorY: 0.5, alpha: 0 }); // Set skin-specific stats if (self.skinType === 'basic') { self.lives = 3; self.fireRate = 20; self.power = 1; } else if (self.skinType === 'fast') { self.lives = 2; self.fireRate = 12; // Faster shooting self.power = 1; } else if (self.skinType === 'tank') { self.lives = 5; // More lives self.fireRate = 25; // Slower shooting self.power = 2; // More damage } else if (self.skinType === 'elite') { self.lives = 4; self.fireRate = 15; self.power = 2; } self.shieldActive = false; self.lastShot = 0; self.canShoot = true; self.invulnerable = false; self.activateShield = function (duration) { self.shieldActive = true; self.shield.alpha = 0.4; LK.setTimeout(function () { self.shieldActive = false; tween(self.shield, { alpha: 0 }, { duration: 500 }); }, duration); }; self.damage = function () { if (self.invulnerable || self.shieldActive) { return; } self.lives--; LK.getSound('playerDamage').play(); // Make player temporarily invulnerable self.invulnerable = true; // Flash the player to show invulnerability var flashCount = 0; var flashInterval = LK.setInterval(function () { ship.alpha = ship.alpha === 0.3 ? 1 : 0.3; flashCount++; if (flashCount >= 10) { LK.clearInterval(flashInterval); ship.alpha = 1; self.invulnerable = false; } }, 150); }; self.upgrade = function (type) { LK.getSound('powerup').play(); if (type === 'shield') { self.activateShield(8000); } else if (type === 'power') { self.power = Math.min(self.power + 1, 3); // Reset power after some time LK.setTimeout(function () { self.power = Math.max(1, self.power - 1); }, 10000); } else if (type === 'life') { self.lives = Math.min(self.lives + 1, 5); } else if (type === 'speed') { var oldFireRate = self.fireRate; self.fireRate = Math.max(self.fireRate - 5, 10); // Reset fire rate after some time LK.setTimeout(function () { self.fireRate = oldFireRate; }, 10000); } }; return self; }); var PlayerLaser = Container.expand(function () { var self = Container.call(this); var laser = self.attachAsset('playerLaser', { anchorX: 0.5, anchorY: 0.5 }); self.speed = -15; self.power = 1; self.update = function () { self.y += self.speed; }; return self; }); var Portal = Container.expand(function (type) { var self = Container.call(this); self.type = type || 'speed'; // 'speed' or 'normal' var assetName = self.type === 'speed' ? 'speedPortal' : 'normalPortal'; var portal = self.attachAsset(assetName, { anchorX: 0.5, anchorY: 0.5 }); // Set visual effects based on type if (self.type === 'speed') { portal.tint = 0x00ffff; // Cyan for speed } else { portal.tint = 0xff8800; // Orange for normal } self.speed = 2; self.rotationSpeed = 0.08; self.pulsePhase = Math.random() * Math.PI * 2; self.update = function () { self.y += self.speed; portal.rotation += self.rotationSpeed; // Pulsing effect self.pulsePhase += 0.1; var pulse = 1 + Math.sin(self.pulsePhase) * 0.3; portal.scale.set(pulse, pulse); }; return self; }); var Powerup = Container.expand(function (type) { var self = Container.call(this); self.type = type || ['shield', 'power', 'life', 'speed'][Math.floor(Math.random() * 4)]; var powerup = self.attachAsset('powerup', { anchorX: 0.5, anchorY: 0.5 }); // Set color based on type if (self.type === 'shield') { powerup.tint = 0x3498db; // Blue } else if (self.type === 'power') { powerup.tint = 0xe74c3c; // Red } else if (self.type === 'life') { powerup.tint = 0x2ecc71; // Green } else if (self.type === 'speed') { powerup.tint = 0xf1c40f; // Yellow } self.speed = 3; self.update = function () { self.y += self.speed; powerup.rotation += 0.05; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000022 }); /**** * Game Code ****/ // Game variables var player; var playerLasers = []; var enemies = []; var enemyLasers = []; var asteroids = []; var powerups = []; var portals = []; var explosions = []; var boss = null; var isSpeedMode = false; var speedModeTimer = 0; var speedModeDuration = 8000; // 8 seconds var gameState = 'start'; var shopState = 'closed'; var difficultyState = 'hidden'; var score = 0; var waveNumber = 1; var enemiesThisWave = 0; var enemiesDefeated = 0; var waveDelay = 0; var bossWave = false; var dragStartPosition = { x: 0, y: 0 }; var gameDifficulty = 'normal'; var playerName = storage.playerName || 'Player'; var multiplayerPlayers = []; // UI elements var scoreTxt = new Text2('SCORE: 0', { size: 40, fill: 0xFFFFFF }); scoreTxt.anchor.set(0, 0); LK.gui.topRight.addChild(scoreTxt); scoreTxt.x = -250; scoreTxt.y = 50; scoreTxt.visible = false; var waveText = new Text2('WAVE: 1', { size: 40, fill: 0xFFFFFF }); waveText.anchor.set(0.5, 0); LK.gui.top.addChild(waveText); waveText.y = 50; waveText.visible = false; var livesText = new Text2('LIVES: 3', { size: 40, fill: 0xFFFFFF }); livesText.anchor.set(0, 0); LK.gui.topLeft.addChild(livesText); livesText.x = 150; // Keep away from the top-left menu icon livesText.y = 50; livesText.visible = false; // Start screen UI elements var startScreenContainer = new Container(); game.addChild(startScreenContainer); var titleText = new Text2('COSMIC DEFENDER', { size: 120, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 800; startScreenContainer.addChild(titleText); var subtitleText = new Text2('Space Shooter', { size: 60, fill: 0xAAAAAAA }); subtitleText.anchor.set(0.5, 0.5); subtitleText.x = 1024; subtitleText.y = 920; startScreenContainer.addChild(subtitleText); var instructionText = new Text2('TAP TO START', { size: 80, fill: 0x00FF00 }); instructionText.anchor.set(0.5, 0.5); instructionText.x = 1024; instructionText.y = 1400; startScreenContainer.addChild(instructionText); var controlsText = new Text2('DRAG TO MOVE • TAP TO SHOOT', { size: 40, fill: 0xCCCCCC }); controlsText.anchor.set(0.5, 0.5); controlsText.x = 1024; controlsText.y = 1600; startScreenContainer.addChild(controlsText); var highScoreText = new Text2('HIGH SCORE: ' + storage.highScore, { size: 50, fill: 0xFFD700 }); highScoreText.anchor.set(0.5, 0.5); highScoreText.x = 1024; highScoreText.y = 1200; startScreenContainer.addChild(highScoreText); // Coins display var coinsText = new Text2('COINS: ' + storage.coins, { size: 40, fill: 0xFFD700 }); coinsText.anchor.set(0.5, 0.5); coinsText.x = 1024; coinsText.y = 1100; startScreenContainer.addChild(coinsText); // Skin shop button var shopButton = new Text2('SKIN SHOP', { size: 60, fill: 0x00AAFF }); shopButton.anchor.set(0.5, 0.5); shopButton.x = 1024; shopButton.y = 1800; startScreenContainer.addChild(shopButton); // Current skin display var currentSkinText = new Text2('CURRENT: ' + storage.currentSkin.toUpperCase(), { size: 35, fill: 0xAAAAAAA }); currentSkinText.anchor.set(0.5, 0.5); currentSkinText.x = 1024; currentSkinText.y = 1000; startScreenContainer.addChild(currentSkinText); // Difficulty selection container var difficultyContainer = new Container(); game.addChild(difficultyContainer); difficultyContainer.visible = false; // Difficulty background var difficultyBg = difficultyContainer.attachAsset('player', { anchorX: 0.5, anchorY: 0.5, scaleX: 20, scaleY: 15 }); difficultyBg.x = 1024; difficultyBg.y = 1366; difficultyBg.tint = 0x001122; difficultyBg.alpha = 0.9; // Difficulty title var difficultyTitle = new Text2('SELECT DIFFICULTY', { size: 80, fill: 0xFFFFFF }); difficultyTitle.anchor.set(0.5, 0.5); difficultyTitle.x = 1024; difficultyTitle.y = 600; difficultyContainer.addChild(difficultyTitle); // Normal mode button var normalModeButton = new Text2('NORMAL MODE', { size: 90, fill: 0x00FF88 }); normalModeButton.anchor.set(0.5, 0.5); normalModeButton.x = 1024; normalModeButton.y = 1000; difficultyContainer.addChild(normalModeButton); // Normal mode description var normalModeDesc = new Text2('Standard difficulty\nSingle player experience', { size: 40, fill: 0xCCCCCC }); normalModeDesc.anchor.set(0.5, 0.5); normalModeDesc.x = 1024; normalModeDesc.y = 1100; difficultyContainer.addChild(normalModeDesc); // Multiplayer mode button var multiplayerModeButton = new Text2('MULTIPLAYER MODE', { size: 90, fill: 0xFF6644 }); multiplayerModeButton.anchor.set(0.5, 0.5); multiplayerModeButton.x = 1024; multiplayerModeButton.y = 1400; difficultyContainer.addChild(multiplayerModeButton); // Multiplayer mode description var multiplayerModeDesc = new Text2('Increased difficulty\nFaster enemies and more challenges', { size: 40, fill: 0xCCCCCC }); multiplayerModeDesc.anchor.set(0.5, 0.5); multiplayerModeDesc.x = 1024; multiplayerModeDesc.y = 1500; difficultyContainer.addChild(multiplayerModeDesc); // Difficulty back button var difficultyBackButton = new Text2('BACK', { size: 50, fill: 0xFF4444 }); difficultyBackButton.anchor.set(0.5, 0.5); difficultyBackButton.x = 1024; difficultyBackButton.y = 1800; difficultyContainer.addChild(difficultyBackButton); // Multiplayer players display container var playersContainer = new Container(); game.addChild(playersContainer); playersContainer.visible = false; // Players list background var playersBg = playersContainer.attachAsset('player', { anchorX: 0, anchorY: 0, scaleX: 6, scaleY: 8 }); playersBg.x = 50; playersBg.y = 150; playersBg.tint = 0x001144; playersBg.alpha = 0.8; // Players list title var playersTitle = new Text2('PLAYERS', { size: 40, fill: 0xFFFFFF }); playersTitle.anchor.set(0, 0); playersTitle.x = 70; playersTitle.y = 170; playersContainer.addChild(playersTitle); // Skin shop container var skinShopContainer = new Container(); game.addChild(skinShopContainer); skinShopContainer.visible = false; // Shop background var shopBg = skinShopContainer.attachAsset('player', { anchorX: 0.5, anchorY: 0.5, scaleX: 20, scaleY: 15 }); shopBg.x = 1024; shopBg.y = 1366; shopBg.tint = 0x000044; shopBg.alpha = 0.9; // Shop title var shopTitle = new Text2('SKIN SHOP', { size: 80, fill: 0xFFFFFF }); shopTitle.anchor.set(0.5, 0.5); shopTitle.x = 1024; shopTitle.y = 400; skinShopContainer.addChild(shopTitle); // Back button var backButton = new Text2('BACK', { size: 50, fill: 0xFF4444 }); backButton.anchor.set(0.5, 0.5); backButton.x = 1024; backButton.y = 2200; skinShopContainer.addChild(backButton); // Skin definitions var skinShopData = [{ name: 'basic', price: 0, description: 'Standard ship\n3 Lives, Normal Speed' }, { name: 'fast', price: 100, description: 'Speed Demon\n2 Lives, Fast Fire Rate' }, { name: 'tank', price: 200, description: 'Heavy Armor\n5 Lives, High Damage' }, { name: 'elite', price: 500, description: 'Elite Fighter\n4 Lives, Balanced Stats' }]; // Create skin shop items var skinItems = []; for (var i = 0; i < skinShopData.length; i++) { var skinData = skinShopData[i]; var skinItem = new Container(); skinItem.skinData = skinData; var yPos = 600 + i * 300; skinItem.x = 1024; skinItem.y = yPos; // Skin name var nameText = new Text2(skinData.name.toUpperCase(), { size: 60, fill: 0xFFFFFF }); nameText.anchor.set(0.5, 0.5); nameText.y = -80; skinItem.addChild(nameText); // Price/Status var isOwned = storage.ownedSkins.indexOf(skinData.name) >= 0; var isCurrent = storage.currentSkin === skinData.name; var statusText; if (isCurrent) { statusText = new Text2('EQUIPPED', { size: 40, fill: 0x00FF00 }); } else if (isOwned) { statusText = new Text2('OWNED - TAP TO EQUIP', { size: 40, fill: 0x00AAFF }); } else { statusText = new Text2('PRICE: ' + skinData.price + ' COINS', { size: 40, fill: 0xFFD700 }); } statusText.anchor.set(0.5, 0.5); statusText.y = -20; skinItem.addChild(statusText); // Description var descText = new Text2(skinData.description, { size: 30, fill: 0xCCCCCC }); descText.anchor.set(0.5, 0.5); descText.y = 40; skinItem.addChild(descText); skinItems.push(skinItem); skinShopContainer.addChild(skinItem); } // Animate the "TAP TO START" text var flashTimer = 0; function updateStartScreen() { flashTimer++; if (flashTimer % 60 < 30) { instructionText.alpha = 1; } else { instructionText.alpha = 0.3; } } // Update shop display function updateShopDisplay() { coinsText.setText('COINS: ' + storage.coins); currentSkinText.setText('CURRENT: ' + storage.currentSkin.toUpperCase()); for (var i = 0; i < skinItems.length; i++) { var item = skinItems[i]; var skinData = item.skinData; var statusText = item.children[1]; // Status text is second child var isOwned = storage.ownedSkins.indexOf(skinData.name) >= 0; var isCurrent = storage.currentSkin === skinData.name; if (isCurrent) { statusText.setText('EQUIPPED'); statusText.tint = 0x00FF00; } else if (isOwned) { statusText.setText('OWNED - TAP TO EQUIP'); statusText.tint = 0x00AAFF; } else { statusText.setText('PRICE: ' + skinData.price + ' COINS'); statusText.tint = 0xFFD700; } } } // Generate multiplayer players list function generateMultiplayerPlayers() { var playerNames = ['SpaceAce', 'StarHunter', 'CosmicRider', 'NovaBlast', 'GalaxyGuard', 'StellarWing', 'QuantumPilot', 'VoidRunner', 'NebulaDash', 'OrbitMaster']; multiplayerPlayers = []; // Add current player multiplayerPlayers.push({ name: storage.playerName, score: 0, isCurrentPlayer: true }); // Add 3-5 other players var numOtherPlayers = 3 + Math.floor(Math.random() * 3); for (var i = 0; i < numOtherPlayers; i++) { var randomName = playerNames[Math.floor(Math.random() * playerNames.length)]; // Make sure name is unique while (multiplayerPlayers.some(function (p) { return p.name === randomName; })) { randomName = playerNames[Math.floor(Math.random() * playerNames.length)]; } multiplayerPlayers.push({ name: randomName, score: Math.floor(Math.random() * 500), isCurrentPlayer: false }); } // Sort by score (descending) multiplayerPlayers.sort(function (a, b) { return b.score - a.score; }); } // Update multiplayer players display function updatePlayersDisplay() { // Clear existing player texts for (var i = playersContainer.children.length - 1; i >= 0; i--) { var child = playersContainer.children[i]; if (child.isPlayerText) { playersContainer.removeChild(child); } } // Add player texts for (var i = 0; i < multiplayerPlayers.length && i < 6; i++) { var playerData = multiplayerPlayers[i]; var playerText = new Text2(playerData.name + ': ' + playerData.score, { size: 28, fill: playerData.isCurrentPlayer ? 0x00FF88 : 0xFFFFFF }); playerText.anchor.set(0, 0); playerText.x = 70; playerText.y = 220 + i * 35; playerText.isPlayerText = true; playersContainer.addChild(playerText); } } // Handle skin purchase or equip function handleSkinInteraction(skinData) { var isOwned = storage.ownedSkins.indexOf(skinData.name) >= 0; var isCurrent = storage.currentSkin === skinData.name; if (isCurrent) { return; // Already equipped } else if (isOwned) { // Equip owned skin storage.currentSkin = skinData.name; updateShopDisplay(); } else { // Try to buy skin if (storage.coins >= skinData.price) { storage.coins -= skinData.price; storage.ownedSkins.push(skinData.name); storage.currentSkin = skinData.name; updateShopDisplay(); } } } // Create game elements function initGame() { // Reset game variables playerLasers = []; enemies = []; enemyLasers = []; asteroids = []; powerups = []; portals = []; explosions = []; boss = null; isSpeedMode = false; speedModeTimer = 0; gameState = 'playing'; score = 0; waveNumber = 1; // Adjust initial wave size based on difficulty if (gameDifficulty === 'multiplayer') { enemiesThisWave = 15; } else { enemiesThisWave = 10; } enemiesDefeated = 0; waveDelay = 0; bossWave = false; // Hide start screen startScreenContainer.visible = false; // Show game UI scoreTxt.visible = true; waveText.visible = true; livesText.visible = true; // Show multiplayer players list if in multiplayer mode if (gameDifficulty === 'multiplayer') { generateMultiplayerPlayers(); playersContainer.visible = true; updatePlayersDisplay(); } else { playersContainer.visible = false; } // Update UI scoreTxt.setText('SCORE: ' + score); waveText.setText('WAVE: ' + waveNumber); // Create player player = new Player(storage.currentSkin); player.x = 1024; player.y = 2200; game.addChild(player); livesText.setText('LIVES: ' + player.lives); // Start with player moving up tween(player, { y: 2000 }, { duration: 1000 }); // Start the music LK.playMusic('gameMusic', { fade: { start: 0, end: 0.7, duration: 1000 } }); // Create first wave createWave(); } // Create a new wave of enemies function createWave() { waveNumber++; waveText.setText('WAVE: ' + waveNumber); // Check for final boss after wave 100 if (waveNumber > 100) { // Create final boss LK.getSound('bossAlert').play(); boss = new Boss(20); // Super powerful final boss boss.x = 1024; boss.y = -200; boss.isFinalBoss = true; game.addChild(boss); tween(boss, { y: 300 }, { duration: 2000 }); // Show final boss text var finalBossText = new Text2('FINAL BOSS!', { size: 100, fill: 0xFF0000 }); finalBossText.anchor.set(0.5, 0.5); finalBossText.x = 1024; finalBossText.y = 800; game.addChild(finalBossText); tween(finalBossText, { alpha: 0, y: 700 }, { duration: 3000, onFinish: function onFinish() { finalBossText.destroy(); } }); return; } // Every 5 waves is a boss wave bossWave = waveNumber % 5 === 0; if (bossWave) { // Create a boss var bossLevel = Math.ceil(waveNumber / 5); LK.getSound('bossAlert').play(); boss = new Boss(bossLevel); boss.x = 1024; boss.y = -200; game.addChild(boss); tween(boss, { y: 300 }, { duration: 2000 }); // Show boss wave text var bossText = new Text2('BOSS WAVE!', { size: 80, fill: 0xFF0000 }); bossText.anchor.set(0.5, 0.5); bossText.x = 1024; bossText.y = 800; game.addChild(bossText); tween(bossText, { alpha: 0, y: 700 }, { duration: 2000, onFinish: function onFinish() { bossText.destroy(); } }); return; } // Regular wave - adjust based on difficulty if (gameDifficulty === 'multiplayer') { enemiesThisWave = 15 + waveNumber * 3; } else { enemiesThisWave = 10 + waveNumber * 2; } enemiesDefeated = 0; // Show wave text var newWaveText = new Text2('WAVE ' + waveNumber, { size: 80, fill: 0xFFFFFF }); newWaveText.anchor.set(0.5, 0.5); newWaveText.x = 1024; newWaveText.y = 800; game.addChild(newWaveText); tween(newWaveText, { alpha: 0, y: 700 }, { duration: 2000, onFinish: function onFinish() { newWaveText.destroy(); } }); // Start spawning enemies after a short delay waveDelay = 120; } // Create a new enemy function spawnEnemy() { var types = ['basic']; // Add more enemy types as waves progress - faster in multiplayer if (gameDifficulty === 'multiplayer') { if (waveNumber >= 1) { types.push('fast'); } if (waveNumber >= 2) { types.push('tank'); } } else { if (waveNumber >= 2) { types.push('fast'); } if (waveNumber >= 3) { types.push('tank'); } } var type = types[Math.floor(Math.random() * types.length)]; var enemy = new Enemy(type); // Position the enemy enemy.x = Math.random() * 1800 + 124; enemy.y = -100; enemy.initialX = enemy.x; // Increase speed in multiplayer mode if (gameDifficulty === 'multiplayer') { enemy.speed *= 1.3; enemy.shootChance *= 1.5; } // Set random movement pattern var patterns = ['straight']; if (waveNumber >= 2) { patterns.push('sine'); } if (waveNumber >= 4) { patterns.push('zigzag'); } enemy.movement.pattern = patterns[Math.floor(Math.random() * patterns.length)]; // Add to game enemies.push(enemy); game.addChild(enemy); } // Create a new asteroid function spawnAsteroid() { var asteroid = new Asteroid(); // Position the asteroid asteroid.x = Math.random() * 1800 + 124; asteroid.y = -100; // Add to game asteroids.push(asteroid); game.addChild(asteroid); } // Create a player laser function firePlayerLaser() { if (!player || !player.canShoot || player.lastShot + player.fireRate > LK.ticks) { return; } player.lastShot = LK.ticks; LK.getSound('playerShoot').play(); // Fire based on power level if (player.power === 1) { var laser = new PlayerLaser(); laser.x = player.x; laser.y = player.y - 50; laser.power = player.power; playerLasers.push(laser); game.addChild(laser); } else if (player.power === 2) { for (var i = -1; i <= 1; i += 2) { var laser = new PlayerLaser(); laser.x = player.x + i * 30; laser.y = player.y - 40; laser.power = player.power; playerLasers.push(laser); game.addChild(laser); } } else if (player.power >= 3) { var centerLaser = new PlayerLaser(); centerLaser.x = player.x; centerLaser.y = player.y - 50; centerLaser.power = player.power; playerLasers.push(centerLaser); game.addChild(centerLaser); for (var i = -1; i <= 1; i += 2) { var sideLaser = new PlayerLaser(); sideLaser.x = player.x + i * 40; sideLaser.y = player.y - 30; sideLaser.power = player.power - 1; playerLasers.push(sideLaser); game.addChild(sideLaser); } } } // Create an enemy laser function fireEnemyLaser(enemy) { var laser = new EnemyLaser(); laser.x = enemy.x; laser.y = enemy.y + 40; enemyLasers.push(laser); game.addChild(laser); LK.getSound('enemyShoot').play({ volume: 0.2 }); } // Fire boss laser pattern function fireBossLasers() { if (!boss) { return; } // Different patterns based on boss level and health var healthPercent = boss.health / boss.maxHealth; var pattern = 'spread'; if (boss.level >= 2 && healthPercent < 0.5) { pattern = 'circle'; } if (pattern === 'spread') { for (var i = -2; i <= 2; i++) { var laser = new EnemyLaser(); laser.x = boss.x + i * 50; laser.y = boss.y + 80; enemyLasers.push(laser); game.addChild(laser); } } else if (pattern === 'circle') { var numLasers = 8; for (var i = 0; i < numLasers; i++) { var angle = i / numLasers * Math.PI * 2; var laser = new EnemyLaser(); laser.x = boss.x + Math.cos(angle) * 100; laser.y = boss.y + Math.sin(angle) * 100; enemyLasers.push(laser); game.addChild(laser); // Add directional motion laser.update = function () { var dx = this.x - boss.x; var dy = this.y - boss.y; var length = Math.sqrt(dx * dx + dy * dy); this.x += dx / length * 5; this.y += dy / length * 5; }; } } LK.getSound('enemyShoot').play({ volume: 0.4 }); } // Create explosion animation function createExplosion(x, y, scale) { var explosion = new Explosion(); explosion.x = x; explosion.y = y; if (scale) { explosion.scale.set(scale, scale); } explosions.push(explosion); game.addChild(explosion); LK.getSound('explosion').play(); } // Create a powerup function spawnPowerup(x, y, type) { var powerup = new Powerup(type); powerup.x = x; powerup.y = y; powerups.push(powerup); game.addChild(powerup); } // Create a portal function spawnPortal(type) { var portal = new Portal(type); portal.x = Math.random() * 1600 + 224; portal.y = -100; portals.push(portal); game.addChild(portal); // Portal entry effect tween(portal, { scaleX: 1.5, scaleY: 1.5 }, { duration: 500, onFinish: function onFinish() { tween(portal, { scaleX: 1, scaleY: 1 }, { duration: 300 }); } }); } // Activate speed mode function activateSpeedMode() { if (isSpeedMode) return; isSpeedMode = true; speedModeTimer = speedModeDuration; // Visual effect on player if (player) { tween(player, { tint: 0x00ffff }, { duration: 300 }); // Speed trail effect var trail = player.attachAsset('player', { anchorX: 0.5, anchorY: 0.5, alpha: 0.3 }); trail.tint = 0x00ffff; tween(trail, { alpha: 0, scaleX: 1.5, scaleY: 1.5 }, { duration: 1000, onFinish: function onFinish() { trail.destroy(); } }); } LK.getSound('portalEnter').play(); } // Deactivate speed mode function deactivateSpeedMode() { if (!isSpeedMode) return; isSpeedMode = false; speedModeTimer = 0; // Return player to normal color if (player) { tween(player, { tint: 0xffffff }, { duration: 500 }); } LK.getSound('portalEnter').play(); } // Handle player shooting and movement function handlePlayerInput() { // Keep player in bounds player.x = Math.max(100, Math.min(player.x, 2048 - 100)); player.y = Math.max(100, Math.min(player.y, 2732 - 100)); // Auto-fire (faster in speed mode) var fireRate = isSpeedMode ? 5 : 10; if (LK.ticks % fireRate === 0) { firePlayerLaser(); } } // Handle collisions between game objects function handleCollisions() { // Player lasers vs enemies for (var i = playerLasers.length - 1; i >= 0; i--) { var laser = playerLasers[i]; var hitSomething = false; // Check against enemies for (var j = enemies.length - 1; j >= 0; j--) { var enemy = enemies[j]; if (laser.intersects(enemy)) { // Damage enemy if (enemy.damage(laser.power)) { // Enemy destroyed createExplosion(enemy.x, enemy.y); // Add score score += 10; scoreTxt.setText('SCORE: ' + score); // Update multiplayer score if in multiplayer mode if (gameDifficulty === 'multiplayer') { for (var p = 0; p < multiplayerPlayers.length; p++) { if (multiplayerPlayers[p].isCurrentPlayer) { multiplayerPlayers[p].score = score; break; } } // Update other players' scores occasionally if (Math.random() < 0.3) { var randomPlayer = Math.floor(Math.random() * multiplayerPlayers.length); if (!multiplayerPlayers[randomPlayer].isCurrentPlayer) { multiplayerPlayers[randomPlayer].score += Math.floor(Math.random() * 15); } } // Re-sort and update display multiplayerPlayers.sort(function (a, b) { return b.score - a.score; }); updatePlayersDisplay(); } // Add coins storage.coins += Math.floor(enemy.scoreValue / 5); // Count enemy as defeated enemiesDefeated++; // Chance to spawn powerup if (Math.random() < 0.1) { spawnPowerup(enemy.x, enemy.y); } enemy.destroy(); enemies.splice(j, 1); } // Remove laser laser.destroy(); playerLasers.splice(i, 1); hitSomething = true; break; } } // Only check other collisions if we haven't hit an enemy if (!hitSomething) { // Check against boss if (boss && laser.intersects(boss)) { // Damage boss if (boss.damage(laser.power)) { // Boss destroyed createExplosion(boss.x, boss.y, 2); // Add score score += boss.scoreValue; scoreTxt.setText('SCORE: ' + score); // Check if final boss was defeated if (boss.isFinalBoss) { // Player wins the game! // Save high score if (score > storage.highScore) { storage.highScore = score; } // Add bonus coins for winning storage.coins += 1000; // Show victory message and play again button var victoryContainer = new Container(); game.addChild(victoryContainer); var victoryBg = victoryContainer.attachAsset('player', { anchorX: 0.5, anchorY: 0.5, scaleX: 25, scaleY: 20 }); victoryBg.x = 1024; victoryBg.y = 1366; victoryBg.tint = 0x001122; victoryBg.alpha = 0.95; var victoryText = new Text2('VICTORY!', { size: 120, fill: 0x00FF00 }); victoryText.anchor.set(0.5, 0.5); victoryText.x = 1024; victoryText.y = 800; victoryContainer.addChild(victoryText); var finalScoreText = new Text2('FINAL SCORE: ' + score, { size: 60, fill: 0xFFFFFF }); finalScoreText.anchor.set(0.5, 0.5); finalScoreText.x = 1024; finalScoreText.y = 1000; victoryContainer.addChild(finalScoreText); var playAgainButton = new Text2('PLAY AGAIN', { size: 80, fill: 0x00AAFF }); playAgainButton.anchor.set(0.5, 0.5); playAgainButton.x = 1024; playAgainButton.y = 1400; victoryContainer.addChild(playAgainButton); // Add victory effect tween(victoryText, { scaleX: 1.2, scaleY: 1.2 }, { duration: 1000, easing: tween.easeInOut, onFinish: function onFinish() { tween(victoryText, { scaleX: 1, scaleY: 1 }, { duration: 1000, easing: tween.easeInOut }); } }); // Handle play again button interaction game.victoryContainer = victoryContainer; game.playAgainButton = playAgainButton; boss.destroy(); boss = null; return; } // Update multiplayer score if in multiplayer mode if (gameDifficulty === 'multiplayer') { for (var p = 0; p < multiplayerPlayers.length; p++) { if (multiplayerPlayers[p].isCurrentPlayer) { multiplayerPlayers[p].score = score; break; } } // Update other players' scores for boss defeat for (var p = 0; p < multiplayerPlayers.length; p++) { if (!multiplayerPlayers[p].isCurrentPlayer && Math.random() < 0.8) { multiplayerPlayers[p].score += Math.floor(Math.random() * boss.scoreValue * 0.7); } } // Re-sort and update display multiplayerPlayers.sort(function (a, b) { return b.score - a.score; }); updatePlayersDisplay(); } // Add coins for boss storage.coins += Math.floor(boss.scoreValue / 3); // Spawn multiple powerups for (var p = 0; p < 3; p++) { var powerupType = ['shield', 'power', 'life', 'speed'][Math.floor(Math.random() * 4)]; spawnPowerup(boss.x + (Math.random() * 200 - 100), boss.y + (Math.random() * 200 - 100), powerupType); } boss.destroy(); boss = null; // Move to next wave createWave(); } // Remove laser laser.destroy(); playerLasers.splice(i, 1); hitSomething = true; } // Check against asteroids for (var k = asteroids.length - 1; k >= 0; k--) { var asteroid = asteroids[k]; if (laser.intersects(asteroid)) { // Damage asteroid if (asteroid.damage(laser.power)) { // Asteroid destroyed createExplosion(asteroid.x, asteroid.y, 0.7); // Add score score += asteroid.scoreValue; scoreTxt.setText('SCORE: ' + score); // Update multiplayer score if in multiplayer mode if (gameDifficulty === 'multiplayer') { for (var p = 0; p < multiplayerPlayers.length; p++) { if (multiplayerPlayers[p].isCurrentPlayer) { multiplayerPlayers[p].score = score; break; } } // Occasionally update other players' scores if (Math.random() < 0.2) { var randomPlayer = Math.floor(Math.random() * multiplayerPlayers.length); if (!multiplayerPlayers[randomPlayer].isCurrentPlayer) { multiplayerPlayers[randomPlayer].score += Math.floor(Math.random() * asteroid.scoreValue); } } // Re-sort and update display multiplayerPlayers.sort(function (a, b) { return b.score - a.score; }); updatePlayersDisplay(); } // Add coins storage.coins += Math.floor(asteroid.scoreValue / 8); asteroid.destroy(); asteroids.splice(k, 1); } // Remove laser laser.destroy(); playerLasers.splice(i, 1); hitSomething = true; break; } } } // Remove laser if it's off screen if (!hitSomething && laser.y < -50) { laser.destroy(); playerLasers.splice(i, 1); } } // Enemy lasers vs player for (var i = enemyLasers.length - 1; i >= 0; i--) { var laser = enemyLasers[i]; if (player && laser.intersects(player)) { // Damage player player.damage(); // Update UI livesText.setText('LIVES: ' + player.lives); // Check for game over if (player.lives <= 0) { // Game over createExplosion(player.x, player.y, 1.5); player.destroy(); player = null; // Save high score if needed if (score > storage.highScore) { storage.highScore = score; } // Show game over after a delay LK.setTimeout(function () { LK.showGameOver(); }, 1000); } // Remove laser laser.destroy(); enemyLasers.splice(i, 1); } else if (laser.y > 2732 + 50) { // Remove laser if it's off screen laser.destroy(); enemyLasers.splice(i, 1); } } // Player vs enemies for (var i = enemies.length - 1; i >= 0; i--) { var enemy = enemies[i]; if (player && player.intersects(enemy)) { // Damage player player.damage(); // Damage enemy enemy.damage(1); // Update UI livesText.setText('LIVES: ' + player.lives); // Check for enemy death if (enemy.health <= 0) { // Enemy destroyed createExplosion(enemy.x, enemy.y); // Add score score += enemy.scoreValue; scoreTxt.setText('SCORE: ' + score); // Count enemy as defeated enemiesDefeated++; enemy.destroy(); enemies.splice(i, 1); } // Check for game over if (player.lives <= 0) { // Game over createExplosion(player.x, player.y, 1.5); player.destroy(); player = null; // Save high score if needed if (score > storage.highScore) { storage.highScore = score; } // Show game over after a delay LK.setTimeout(function () { LK.showGameOver(); }, 1000); } } // Remove enemy if it's off screen if (enemy.y > 2732 + 100) { enemy.destroy(); enemies.splice(i, 1); } } // Player vs asteroids for (var i = asteroids.length - 1; i >= 0; i--) { var asteroid = asteroids[i]; if (player && player.intersects(asteroid)) { // Damage player player.damage(); // Damage asteroid asteroid.damage(1); // Update UI livesText.setText('LIVES: ' + player.lives); // Check for asteroid death if (asteroid.health <= 0) { // Asteroid destroyed createExplosion(asteroid.x, asteroid.y, 0.7); // Add score score += asteroid.scoreValue; scoreTxt.setText('SCORE: ' + score); asteroid.destroy(); asteroids.splice(i, 1); } // Check for game over if (player.lives <= 0) { // Game over createExplosion(player.x, player.y, 1.5); player.destroy(); player = null; // Save high score if needed if (score > storage.highScore) { storage.highScore = score; } // Show game over after a delay LK.setTimeout(function () { LK.showGameOver(); }, 1000); } } // Remove asteroid if it's off screen if (asteroid.y > 2732 + 100 || asteroid.x < -100 || asteroid.x > 2048 + 100) { asteroid.destroy(); asteroids.splice(i, 1); } } // Player vs powerups for (var i = powerups.length - 1; i >= 0; i--) { var powerup = powerups[i]; if (player && player.intersects(powerup)) { // Apply powerup player.upgrade(powerup.type); // Update UI if life powerup if (powerup.type === 'life') { livesText.setText('LIVES: ' + player.lives); } // Remove powerup powerup.destroy(); powerups.splice(i, 1); } else if (powerup.y > 2732 + 50) { // Remove powerup if it's off screen powerup.destroy(); powerups.splice(i, 1); } } // Player vs portals for (var i = portals.length - 1; i >= 0; i--) { var portal = portals[i]; if (player && player.intersects(portal)) { // Apply portal effect if (portal.type === 'speed') { activateSpeedMode(); } else if (portal.type === 'normal') { deactivateSpeedMode(); } // Portal activation effect createExplosion(portal.x, portal.y, 1.2); // Remove portal portal.destroy(); portals.splice(i, 1); } else if (portal.y > 2732 + 50) { // Remove portal if it's off screen portal.destroy(); portals.splice(i, 1); } } // Player vs boss if (player && boss && player.intersects(boss)) { // Damage player player.damage(); // Update UI livesText.setText('LIVES: ' + player.lives); // Check for game over if (player.lives <= 0) { // Game over createExplosion(player.x, player.y, 1.5); player.destroy(); player = null; // Save high score if needed if (score > storage.highScore) { storage.highScore = score; } // Show game over after a delay LK.setTimeout(function () { LK.showGameOver(); }, 1000); } } } // Don't initialize game automatically - wait for start screen interaction // Game down event handler game.down = function (x, y, obj) { // Check for play again button if victory screen is showing if (game.victoryContainer && game.victoryContainer.visible !== false) { var playAgainBounds = { x: game.playAgainButton.x - 200, y: game.playAgainButton.y - 40, width: 400, height: 80 }; if (x >= playAgainBounds.x && x <= playAgainBounds.x + playAgainBounds.width && y >= playAgainBounds.y && y <= playAgainBounds.y + playAgainBounds.height) { // Reset game to start screen game.victoryContainer.destroy(); game.victoryContainer = null; game.playAgainButton = null; gameState = 'start'; shopState = 'closed'; difficultyState = 'hidden'; startScreenContainer.visible = true; scoreTxt.visible = false; waveText.visible = false; livesText.visible = false; playersContainer.visible = false; difficultyContainer.visible = false; skinShopContainer.visible = false; // Update high score display highScoreText.setText('HIGH SCORE: ' + storage.highScore); updateShopDisplay(); LK.stopMusic(); return; } } if (gameState === 'start') { if (shopState === 'closed') { // Check if shop button was tapped var shopButtonBounds = { x: shopButton.x - 150, y: shopButton.y - 30, width: 300, height: 60 }; if (x >= shopButtonBounds.x && x <= shopButtonBounds.x + shopButtonBounds.width && y >= shopButtonBounds.y && y <= shopButtonBounds.y + shopButtonBounds.height) { // Open shop shopState = 'open'; skinShopContainer.visible = true; startScreenContainer.visible = false; updateShopDisplay(); return; } // Show difficulty selection instead of starting game directly difficultyState = 'visible'; difficultyContainer.visible = true; startScreenContainer.visible = false; return; } else if (shopState === 'open') { // Check back button var backButtonBounds = { x: backButton.x - 100, y: backButton.y - 25, width: 200, height: 50 }; if (x >= backButtonBounds.x && x <= backButtonBounds.x + backButtonBounds.width && y >= backButtonBounds.y && y <= backButtonBounds.y + backButtonBounds.height) { // Close shop shopState = 'closed'; skinShopContainer.visible = false; startScreenContainer.visible = true; return; } // Check skin items for (var i = 0; i < skinItems.length; i++) { var item = skinItems[i]; var itemBounds = { x: item.x - 400, y: item.y - 100, width: 800, height: 200 }; if (x >= itemBounds.x && x <= itemBounds.x + itemBounds.width && y >= itemBounds.y && y <= itemBounds.y + itemBounds.height) { handleSkinInteraction(item.skinData); return; } } return; } } if (difficultyState === 'visible') { // Check normal mode button - use proper bounds based on text size and position var normalButtonBounds = { x: normalModeButton.x - 450, y: normalModeButton.y - 60, width: 900, height: 120 }; if (x >= normalButtonBounds.x && x <= normalButtonBounds.x + normalButtonBounds.width && y >= normalButtonBounds.y && y <= normalButtonBounds.y + normalButtonBounds.height) { gameDifficulty = 'normal'; difficultyState = 'hidden'; difficultyContainer.visible = false; initGame(); return; } // Check multiplayer mode button - use proper bounds based on text size and position var multiplayerButtonBounds = { x: multiplayerModeButton.x - 500, y: multiplayerModeButton.y - 60, width: 1000, height: 120 }; if (x >= multiplayerButtonBounds.x && x <= multiplayerButtonBounds.x + multiplayerButtonBounds.width && y >= multiplayerButtonBounds.y && y <= multiplayerButtonBounds.y + multiplayerButtonBounds.height) { gameDifficulty = 'multiplayer'; difficultyState = 'hidden'; difficultyContainer.visible = false; initGame(); return; } // Check difficulty back button var difficultyBackBounds = { x: difficultyBackButton.x - 100, y: difficultyBackButton.y - 25, width: 200, height: 50 }; if (x >= difficultyBackBounds.x && x <= difficultyBackBounds.x + difficultyBackBounds.width && y >= difficultyBackBounds.y && y <= difficultyBackBounds.y + difficultyBackBounds.height) { difficultyState = 'hidden'; difficultyContainer.visible = false; startScreenContainer.visible = true; return; } } if (!player) { return; } dragStartPosition.x = x; dragStartPosition.y = y; // Fire lasers on tap firePlayerLaser(); }; // Game move event handler game.move = function (x, y, obj) { if (!player) { return; } // Move player with drag player.x = x; player.y = y; }; // Game update handler game.update = function () { if (gameState === 'start') { if (shopState === 'closed') { updateStartScreen(); } return; } if (gameState !== 'playing') { return; } // Handle player input if (player) { handlePlayerInput(); } // Handle wave creation if (waveDelay > 0) { waveDelay--; } else if (!bossWave && enemies.length === 0 && enemiesDefeated >= enemiesThisWave) { // All enemies for this wave defeated, create next wave createWave(); } else if (!bossWave && enemies.length < 5 && enemiesDefeated < enemiesThisWave && LK.ticks % 30 === 0) { // Spawn more enemies for this wave spawnEnemy(); } // Spawn asteroids occasionally if (LK.ticks % 180 === 0 && Math.random() < 0.7) { spawnAsteroid(); } // Spawn portals occasionally if (LK.ticks % 600 === 0 && Math.random() < 0.4) { // Spawn speed portal if not in speed mode, or normal portal if in speed mode var portalType = isSpeedMode ? 'normal' : 'speed'; spawnPortal(portalType); } // Handle speed mode timer if (isSpeedMode) { speedModeTimer -= 16; // Approximate 60fps if (speedModeTimer <= 0) { deactivateSpeedMode(); } } // Boss shooting if (boss && LK.ticks % 90 === 0) { fireBossLasers(); } // Enemy shooting for (var i = 0; i < enemies.length; i++) { if (Math.random() < enemies[i].shootChance) { fireEnemyLaser(enemies[i]); } } // Collision detection handleCollisions(); };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
highScore: 0,
coins: 0,
currentSkin: "basic",
ownedSkins: ["basic"],
playerName: "Player"
});
/****
* Classes
****/
var Asteroid = Container.expand(function () {
var self = Container.call(this);
var asteroid = self.attachAsset('asteroid', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 2;
self.speed = {
y: 2 + Math.random() * 2,
x: (Math.random() - 0.5) * 2
};
self.rotation = Math.random() * 0.1 - 0.05;
self.scoreValue = 15;
// Random size variation
var scale = 0.7 + Math.random() * 0.8;
asteroid.scale.set(scale, scale);
self.damage = function (amount) {
self.health -= amount || 1;
tween(asteroid, {
tint: 0xffffff
}, {
duration: 200,
onFinish: function onFinish() {
asteroid.tint = 0x95a5a6;
}
});
return self.health <= 0;
};
self.update = function () {
self.y += self.speed.y;
self.x += self.speed.x;
asteroid.rotation += self.rotation;
};
return self;
});
var Boss = Container.expand(function (level) {
var self = Container.call(this);
var ship = self.attachAsset('boss', {
anchorX: 0.5,
anchorY: 0.5
});
self.level = level || 1;
self.maxHealth = 20 * self.level;
self.health = self.maxHealth;
self.scoreValue = 200 * self.level;
self.phase = 0;
self.phaseTime = 0;
self.patterns = ['side-to-side', 'charge', 'retreat'];
self.currentPattern = 0;
self.targetX = 0;
self.targetY = 0;
// Adjust boss based on level
if (self.level > 1) {
ship.tint = 0xcc00cc;
}
// Health bar
self.healthBar = new Container();
self.addChild(self.healthBar);
var healthBarBg = self.healthBar.attachAsset('playerLaser', {
anchorX: 0,
anchorY: 0.5,
scaleX: 2,
scaleY: 0.5
});
healthBarBg.tint = 0x333333;
healthBarBg.width = 200;
self.healthBarFill = self.healthBar.attachAsset('playerLaser', {
anchorX: 0,
anchorY: 0.5,
scaleX: 2,
scaleY: 0.4
});
self.healthBarFill.tint = 0xff3333;
self.healthBarFill.width = 200;
self.healthBar.y = -120;
self.damage = function (amount) {
self.health -= amount || 1;
// Update health bar
var healthPercent = self.health / self.maxHealth;
self.healthBarFill.width = 200 * healthPercent;
tween(ship, {
tint: 0xffffff
}, {
duration: 100,
onFinish: function onFinish() {
ship.tint = self.level > 1 ? 0xcc00cc : 0x9b59b6;
}
});
// Change patterns more quickly when damaged
if (self.health < self.maxHealth * 0.5 && self.phaseTime > 150) {
self.changePattern();
}
return self.health <= 0;
};
self.changePattern = function () {
self.currentPattern = (self.currentPattern + 1) % self.patterns.length;
self.phaseTime = 0;
self.phase = 0;
};
self.update = function () {
self.phaseTime++;
// Change pattern every so often
if (self.phaseTime > 300) {
self.changePattern();
}
var pattern = self.patterns[self.currentPattern];
switch (pattern) {
case 'side-to-side':
// Move side to side
self.targetX = 1024 + Math.sin(self.phaseTime * 0.02) * 800;
if (self.phaseTime < 60) {
self.targetY = Math.min(self.y + 2, 400);
} else {
self.targetY = 400;
}
break;
case 'charge':
// Charge down then back up
if (self.phase === 0) {
self.targetY = self.y + 5;
if (self.y > 800) {
self.phase = 1;
}
} else {
self.targetY = Math.max(self.y - 3, 300);
if (self.y <= 300) {
self.phase = 0;
}
}
self.targetX = 1024 + Math.sin(self.phaseTime * 0.03) * 500;
break;
case 'retreat':
// Stay near top and move quickly
self.targetY = 300;
self.targetX = 1024 + Math.sin(self.phaseTime * 0.05) * 900;
break;
}
// Move toward target position
self.x += (self.targetX - self.x) * 0.05;
self.y += (self.targetY - self.y) * 0.05;
};
return self;
});
var Enemy = Container.expand(function (type) {
var self = Container.call(this);
self.type = type || 'basic';
var assetType = self.type === 'fast' ? 'enemy' : 'enemy';
var ship = self.attachAsset(assetType, {
anchorX: 0.5,
anchorY: 0.5
});
// Different enemy types
if (self.type === 'basic') {
self.health = 1;
self.speed = 2;
self.scoreValue = 10;
self.shootChance = 0.01;
} else if (self.type === 'fast') {
self.health = 1;
self.speed = 3.5;
self.scoreValue = 15;
ship.scaleX = 0.8;
ship.scaleY = 0.8;
self.shootChance = 0.005;
ship.tint = 0xff9966;
} else if (self.type === 'tank') {
self.health = 3;
self.speed = 1.5;
self.scoreValue = 25;
ship.scaleX = 1.2;
ship.scaleY = 1.2;
self.shootChance = 0.015;
ship.tint = 0x66ff66;
}
self.movement = {
pattern: 'straight',
phase: Math.random() * Math.PI * 2,
amplitude: 60 + Math.random() * 60
};
self.initialX = 0;
self.damage = function (amount) {
self.health -= amount || 1;
tween(ship, {
tint: 0xffffff
}, {
duration: 200,
onFinish: function onFinish() {
ship.tint = self.type === 'fast' ? 0xff9966 : self.type === 'tank' ? 0x66ff66 : 0xe74c3c;
}
});
return self.health <= 0;
};
self.update = function () {
// Basic movement
self.y += self.speed;
// Pattern movement
if (self.movement.pattern === 'sine') {
self.x = self.initialX + Math.sin(LK.ticks * 0.05 + self.movement.phase) * self.movement.amplitude;
} else if (self.movement.pattern === 'zigzag') {
var timeScale = 0.02;
var t = LK.ticks * timeScale + self.movement.phase;
var triangleWave = Math.abs(t % 2 - 1) * 2 - 1;
self.x = self.initialX + triangleWave * self.movement.amplitude;
}
};
return self;
});
var EnemyLaser = Container.expand(function () {
var self = Container.call(this);
var laser = self.attachAsset('enemyLaser', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.update = function () {
self.y += self.speed;
};
return self;
});
var Explosion = Container.expand(function () {
var self = Container.call(this);
var explosion = self.attachAsset('explosion', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.9
});
// Set up fade and scale
tween(explosion, {
alpha: 0,
scaleX: 2,
scaleY: 2
}, {
duration: 500,
onFinish: function onFinish() {
self.destroy();
}
});
return self;
});
var Player = Container.expand(function (skinType) {
var self = Container.call(this);
self.skinType = skinType || storage.currentSkin || 'basic';
// Choose asset based on skin type
var assetName = 'player';
if (self.skinType === 'fast') assetName = 'playerFast';else if (self.skinType === 'tank') assetName = 'playerTank';else if (self.skinType === 'elite') assetName = 'playerElite';
var ship = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
// Apply skin-specific visual effects
if (self.skinType === 'fast') {
ship.tint = 0x00ff88; // Green tint for speed
} else if (self.skinType === 'tank') {
ship.tint = 0xff6600; // Orange tint for armor
ship.scaleX = 1.2;
ship.scaleY = 1.2;
} else if (self.skinType === 'elite') {
ship.tint = 0x9966ff; // Purple tint for elite
}
self.shield = self.attachAsset('shield', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
});
// Set skin-specific stats
if (self.skinType === 'basic') {
self.lives = 3;
self.fireRate = 20;
self.power = 1;
} else if (self.skinType === 'fast') {
self.lives = 2;
self.fireRate = 12; // Faster shooting
self.power = 1;
} else if (self.skinType === 'tank') {
self.lives = 5; // More lives
self.fireRate = 25; // Slower shooting
self.power = 2; // More damage
} else if (self.skinType === 'elite') {
self.lives = 4;
self.fireRate = 15;
self.power = 2;
}
self.shieldActive = false;
self.lastShot = 0;
self.canShoot = true;
self.invulnerable = false;
self.activateShield = function (duration) {
self.shieldActive = true;
self.shield.alpha = 0.4;
LK.setTimeout(function () {
self.shieldActive = false;
tween(self.shield, {
alpha: 0
}, {
duration: 500
});
}, duration);
};
self.damage = function () {
if (self.invulnerable || self.shieldActive) {
return;
}
self.lives--;
LK.getSound('playerDamage').play();
// Make player temporarily invulnerable
self.invulnerable = true;
// Flash the player to show invulnerability
var flashCount = 0;
var flashInterval = LK.setInterval(function () {
ship.alpha = ship.alpha === 0.3 ? 1 : 0.3;
flashCount++;
if (flashCount >= 10) {
LK.clearInterval(flashInterval);
ship.alpha = 1;
self.invulnerable = false;
}
}, 150);
};
self.upgrade = function (type) {
LK.getSound('powerup').play();
if (type === 'shield') {
self.activateShield(8000);
} else if (type === 'power') {
self.power = Math.min(self.power + 1, 3);
// Reset power after some time
LK.setTimeout(function () {
self.power = Math.max(1, self.power - 1);
}, 10000);
} else if (type === 'life') {
self.lives = Math.min(self.lives + 1, 5);
} else if (type === 'speed') {
var oldFireRate = self.fireRate;
self.fireRate = Math.max(self.fireRate - 5, 10);
// Reset fire rate after some time
LK.setTimeout(function () {
self.fireRate = oldFireRate;
}, 10000);
}
};
return self;
});
var PlayerLaser = Container.expand(function () {
var self = Container.call(this);
var laser = self.attachAsset('playerLaser', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -15;
self.power = 1;
self.update = function () {
self.y += self.speed;
};
return self;
});
var Portal = Container.expand(function (type) {
var self = Container.call(this);
self.type = type || 'speed'; // 'speed' or 'normal'
var assetName = self.type === 'speed' ? 'speedPortal' : 'normalPortal';
var portal = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
// Set visual effects based on type
if (self.type === 'speed') {
portal.tint = 0x00ffff; // Cyan for speed
} else {
portal.tint = 0xff8800; // Orange for normal
}
self.speed = 2;
self.rotationSpeed = 0.08;
self.pulsePhase = Math.random() * Math.PI * 2;
self.update = function () {
self.y += self.speed;
portal.rotation += self.rotationSpeed;
// Pulsing effect
self.pulsePhase += 0.1;
var pulse = 1 + Math.sin(self.pulsePhase) * 0.3;
portal.scale.set(pulse, pulse);
};
return self;
});
var Powerup = Container.expand(function (type) {
var self = Container.call(this);
self.type = type || ['shield', 'power', 'life', 'speed'][Math.floor(Math.random() * 4)];
var powerup = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5
});
// Set color based on type
if (self.type === 'shield') {
powerup.tint = 0x3498db; // Blue
} else if (self.type === 'power') {
powerup.tint = 0xe74c3c; // Red
} else if (self.type === 'life') {
powerup.tint = 0x2ecc71; // Green
} else if (self.type === 'speed') {
powerup.tint = 0xf1c40f; // Yellow
}
self.speed = 3;
self.update = function () {
self.y += self.speed;
powerup.rotation += 0.05;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000022
});
/****
* Game Code
****/
// Game variables
var player;
var playerLasers = [];
var enemies = [];
var enemyLasers = [];
var asteroids = [];
var powerups = [];
var portals = [];
var explosions = [];
var boss = null;
var isSpeedMode = false;
var speedModeTimer = 0;
var speedModeDuration = 8000; // 8 seconds
var gameState = 'start';
var shopState = 'closed';
var difficultyState = 'hidden';
var score = 0;
var waveNumber = 1;
var enemiesThisWave = 0;
var enemiesDefeated = 0;
var waveDelay = 0;
var bossWave = false;
var dragStartPosition = {
x: 0,
y: 0
};
var gameDifficulty = 'normal';
var playerName = storage.playerName || 'Player';
var multiplayerPlayers = [];
// UI elements
var scoreTxt = new Text2('SCORE: 0', {
size: 40,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0, 0);
LK.gui.topRight.addChild(scoreTxt);
scoreTxt.x = -250;
scoreTxt.y = 50;
scoreTxt.visible = false;
var waveText = new Text2('WAVE: 1', {
size: 40,
fill: 0xFFFFFF
});
waveText.anchor.set(0.5, 0);
LK.gui.top.addChild(waveText);
waveText.y = 50;
waveText.visible = false;
var livesText = new Text2('LIVES: 3', {
size: 40,
fill: 0xFFFFFF
});
livesText.anchor.set(0, 0);
LK.gui.topLeft.addChild(livesText);
livesText.x = 150; // Keep away from the top-left menu icon
livesText.y = 50;
livesText.visible = false;
// Start screen UI elements
var startScreenContainer = new Container();
game.addChild(startScreenContainer);
var titleText = new Text2('COSMIC DEFENDER', {
size: 120,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 800;
startScreenContainer.addChild(titleText);
var subtitleText = new Text2('Space Shooter', {
size: 60,
fill: 0xAAAAAAA
});
subtitleText.anchor.set(0.5, 0.5);
subtitleText.x = 1024;
subtitleText.y = 920;
startScreenContainer.addChild(subtitleText);
var instructionText = new Text2('TAP TO START', {
size: 80,
fill: 0x00FF00
});
instructionText.anchor.set(0.5, 0.5);
instructionText.x = 1024;
instructionText.y = 1400;
startScreenContainer.addChild(instructionText);
var controlsText = new Text2('DRAG TO MOVE • TAP TO SHOOT', {
size: 40,
fill: 0xCCCCCC
});
controlsText.anchor.set(0.5, 0.5);
controlsText.x = 1024;
controlsText.y = 1600;
startScreenContainer.addChild(controlsText);
var highScoreText = new Text2('HIGH SCORE: ' + storage.highScore, {
size: 50,
fill: 0xFFD700
});
highScoreText.anchor.set(0.5, 0.5);
highScoreText.x = 1024;
highScoreText.y = 1200;
startScreenContainer.addChild(highScoreText);
// Coins display
var coinsText = new Text2('COINS: ' + storage.coins, {
size: 40,
fill: 0xFFD700
});
coinsText.anchor.set(0.5, 0.5);
coinsText.x = 1024;
coinsText.y = 1100;
startScreenContainer.addChild(coinsText);
// Skin shop button
var shopButton = new Text2('SKIN SHOP', {
size: 60,
fill: 0x00AAFF
});
shopButton.anchor.set(0.5, 0.5);
shopButton.x = 1024;
shopButton.y = 1800;
startScreenContainer.addChild(shopButton);
// Current skin display
var currentSkinText = new Text2('CURRENT: ' + storage.currentSkin.toUpperCase(), {
size: 35,
fill: 0xAAAAAAA
});
currentSkinText.anchor.set(0.5, 0.5);
currentSkinText.x = 1024;
currentSkinText.y = 1000;
startScreenContainer.addChild(currentSkinText);
// Difficulty selection container
var difficultyContainer = new Container();
game.addChild(difficultyContainer);
difficultyContainer.visible = false;
// Difficulty background
var difficultyBg = difficultyContainer.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 20,
scaleY: 15
});
difficultyBg.x = 1024;
difficultyBg.y = 1366;
difficultyBg.tint = 0x001122;
difficultyBg.alpha = 0.9;
// Difficulty title
var difficultyTitle = new Text2('SELECT DIFFICULTY', {
size: 80,
fill: 0xFFFFFF
});
difficultyTitle.anchor.set(0.5, 0.5);
difficultyTitle.x = 1024;
difficultyTitle.y = 600;
difficultyContainer.addChild(difficultyTitle);
// Normal mode button
var normalModeButton = new Text2('NORMAL MODE', {
size: 90,
fill: 0x00FF88
});
normalModeButton.anchor.set(0.5, 0.5);
normalModeButton.x = 1024;
normalModeButton.y = 1000;
difficultyContainer.addChild(normalModeButton);
// Normal mode description
var normalModeDesc = new Text2('Standard difficulty\nSingle player experience', {
size: 40,
fill: 0xCCCCCC
});
normalModeDesc.anchor.set(0.5, 0.5);
normalModeDesc.x = 1024;
normalModeDesc.y = 1100;
difficultyContainer.addChild(normalModeDesc);
// Multiplayer mode button
var multiplayerModeButton = new Text2('MULTIPLAYER MODE', {
size: 90,
fill: 0xFF6644
});
multiplayerModeButton.anchor.set(0.5, 0.5);
multiplayerModeButton.x = 1024;
multiplayerModeButton.y = 1400;
difficultyContainer.addChild(multiplayerModeButton);
// Multiplayer mode description
var multiplayerModeDesc = new Text2('Increased difficulty\nFaster enemies and more challenges', {
size: 40,
fill: 0xCCCCCC
});
multiplayerModeDesc.anchor.set(0.5, 0.5);
multiplayerModeDesc.x = 1024;
multiplayerModeDesc.y = 1500;
difficultyContainer.addChild(multiplayerModeDesc);
// Difficulty back button
var difficultyBackButton = new Text2('BACK', {
size: 50,
fill: 0xFF4444
});
difficultyBackButton.anchor.set(0.5, 0.5);
difficultyBackButton.x = 1024;
difficultyBackButton.y = 1800;
difficultyContainer.addChild(difficultyBackButton);
// Multiplayer players display container
var playersContainer = new Container();
game.addChild(playersContainer);
playersContainer.visible = false;
// Players list background
var playersBg = playersContainer.attachAsset('player', {
anchorX: 0,
anchorY: 0,
scaleX: 6,
scaleY: 8
});
playersBg.x = 50;
playersBg.y = 150;
playersBg.tint = 0x001144;
playersBg.alpha = 0.8;
// Players list title
var playersTitle = new Text2('PLAYERS', {
size: 40,
fill: 0xFFFFFF
});
playersTitle.anchor.set(0, 0);
playersTitle.x = 70;
playersTitle.y = 170;
playersContainer.addChild(playersTitle);
// Skin shop container
var skinShopContainer = new Container();
game.addChild(skinShopContainer);
skinShopContainer.visible = false;
// Shop background
var shopBg = skinShopContainer.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 20,
scaleY: 15
});
shopBg.x = 1024;
shopBg.y = 1366;
shopBg.tint = 0x000044;
shopBg.alpha = 0.9;
// Shop title
var shopTitle = new Text2('SKIN SHOP', {
size: 80,
fill: 0xFFFFFF
});
shopTitle.anchor.set(0.5, 0.5);
shopTitle.x = 1024;
shopTitle.y = 400;
skinShopContainer.addChild(shopTitle);
// Back button
var backButton = new Text2('BACK', {
size: 50,
fill: 0xFF4444
});
backButton.anchor.set(0.5, 0.5);
backButton.x = 1024;
backButton.y = 2200;
skinShopContainer.addChild(backButton);
// Skin definitions
var skinShopData = [{
name: 'basic',
price: 0,
description: 'Standard ship\n3 Lives, Normal Speed'
}, {
name: 'fast',
price: 100,
description: 'Speed Demon\n2 Lives, Fast Fire Rate'
}, {
name: 'tank',
price: 200,
description: 'Heavy Armor\n5 Lives, High Damage'
}, {
name: 'elite',
price: 500,
description: 'Elite Fighter\n4 Lives, Balanced Stats'
}];
// Create skin shop items
var skinItems = [];
for (var i = 0; i < skinShopData.length; i++) {
var skinData = skinShopData[i];
var skinItem = new Container();
skinItem.skinData = skinData;
var yPos = 600 + i * 300;
skinItem.x = 1024;
skinItem.y = yPos;
// Skin name
var nameText = new Text2(skinData.name.toUpperCase(), {
size: 60,
fill: 0xFFFFFF
});
nameText.anchor.set(0.5, 0.5);
nameText.y = -80;
skinItem.addChild(nameText);
// Price/Status
var isOwned = storage.ownedSkins.indexOf(skinData.name) >= 0;
var isCurrent = storage.currentSkin === skinData.name;
var statusText;
if (isCurrent) {
statusText = new Text2('EQUIPPED', {
size: 40,
fill: 0x00FF00
});
} else if (isOwned) {
statusText = new Text2('OWNED - TAP TO EQUIP', {
size: 40,
fill: 0x00AAFF
});
} else {
statusText = new Text2('PRICE: ' + skinData.price + ' COINS', {
size: 40,
fill: 0xFFD700
});
}
statusText.anchor.set(0.5, 0.5);
statusText.y = -20;
skinItem.addChild(statusText);
// Description
var descText = new Text2(skinData.description, {
size: 30,
fill: 0xCCCCCC
});
descText.anchor.set(0.5, 0.5);
descText.y = 40;
skinItem.addChild(descText);
skinItems.push(skinItem);
skinShopContainer.addChild(skinItem);
}
// Animate the "TAP TO START" text
var flashTimer = 0;
function updateStartScreen() {
flashTimer++;
if (flashTimer % 60 < 30) {
instructionText.alpha = 1;
} else {
instructionText.alpha = 0.3;
}
}
// Update shop display
function updateShopDisplay() {
coinsText.setText('COINS: ' + storage.coins);
currentSkinText.setText('CURRENT: ' + storage.currentSkin.toUpperCase());
for (var i = 0; i < skinItems.length; i++) {
var item = skinItems[i];
var skinData = item.skinData;
var statusText = item.children[1]; // Status text is second child
var isOwned = storage.ownedSkins.indexOf(skinData.name) >= 0;
var isCurrent = storage.currentSkin === skinData.name;
if (isCurrent) {
statusText.setText('EQUIPPED');
statusText.tint = 0x00FF00;
} else if (isOwned) {
statusText.setText('OWNED - TAP TO EQUIP');
statusText.tint = 0x00AAFF;
} else {
statusText.setText('PRICE: ' + skinData.price + ' COINS');
statusText.tint = 0xFFD700;
}
}
}
// Generate multiplayer players list
function generateMultiplayerPlayers() {
var playerNames = ['SpaceAce', 'StarHunter', 'CosmicRider', 'NovaBlast', 'GalaxyGuard', 'StellarWing', 'QuantumPilot', 'VoidRunner', 'NebulaDash', 'OrbitMaster'];
multiplayerPlayers = [];
// Add current player
multiplayerPlayers.push({
name: storage.playerName,
score: 0,
isCurrentPlayer: true
});
// Add 3-5 other players
var numOtherPlayers = 3 + Math.floor(Math.random() * 3);
for (var i = 0; i < numOtherPlayers; i++) {
var randomName = playerNames[Math.floor(Math.random() * playerNames.length)];
// Make sure name is unique
while (multiplayerPlayers.some(function (p) {
return p.name === randomName;
})) {
randomName = playerNames[Math.floor(Math.random() * playerNames.length)];
}
multiplayerPlayers.push({
name: randomName,
score: Math.floor(Math.random() * 500),
isCurrentPlayer: false
});
}
// Sort by score (descending)
multiplayerPlayers.sort(function (a, b) {
return b.score - a.score;
});
}
// Update multiplayer players display
function updatePlayersDisplay() {
// Clear existing player texts
for (var i = playersContainer.children.length - 1; i >= 0; i--) {
var child = playersContainer.children[i];
if (child.isPlayerText) {
playersContainer.removeChild(child);
}
}
// Add player texts
for (var i = 0; i < multiplayerPlayers.length && i < 6; i++) {
var playerData = multiplayerPlayers[i];
var playerText = new Text2(playerData.name + ': ' + playerData.score, {
size: 28,
fill: playerData.isCurrentPlayer ? 0x00FF88 : 0xFFFFFF
});
playerText.anchor.set(0, 0);
playerText.x = 70;
playerText.y = 220 + i * 35;
playerText.isPlayerText = true;
playersContainer.addChild(playerText);
}
}
// Handle skin purchase or equip
function handleSkinInteraction(skinData) {
var isOwned = storage.ownedSkins.indexOf(skinData.name) >= 0;
var isCurrent = storage.currentSkin === skinData.name;
if (isCurrent) {
return; // Already equipped
} else if (isOwned) {
// Equip owned skin
storage.currentSkin = skinData.name;
updateShopDisplay();
} else {
// Try to buy skin
if (storage.coins >= skinData.price) {
storage.coins -= skinData.price;
storage.ownedSkins.push(skinData.name);
storage.currentSkin = skinData.name;
updateShopDisplay();
}
}
}
// Create game elements
function initGame() {
// Reset game variables
playerLasers = [];
enemies = [];
enemyLasers = [];
asteroids = [];
powerups = [];
portals = [];
explosions = [];
boss = null;
isSpeedMode = false;
speedModeTimer = 0;
gameState = 'playing';
score = 0;
waveNumber = 1;
// Adjust initial wave size based on difficulty
if (gameDifficulty === 'multiplayer') {
enemiesThisWave = 15;
} else {
enemiesThisWave = 10;
}
enemiesDefeated = 0;
waveDelay = 0;
bossWave = false;
// Hide start screen
startScreenContainer.visible = false;
// Show game UI
scoreTxt.visible = true;
waveText.visible = true;
livesText.visible = true;
// Show multiplayer players list if in multiplayer mode
if (gameDifficulty === 'multiplayer') {
generateMultiplayerPlayers();
playersContainer.visible = true;
updatePlayersDisplay();
} else {
playersContainer.visible = false;
}
// Update UI
scoreTxt.setText('SCORE: ' + score);
waveText.setText('WAVE: ' + waveNumber);
// Create player
player = new Player(storage.currentSkin);
player.x = 1024;
player.y = 2200;
game.addChild(player);
livesText.setText('LIVES: ' + player.lives);
// Start with player moving up
tween(player, {
y: 2000
}, {
duration: 1000
});
// Start the music
LK.playMusic('gameMusic', {
fade: {
start: 0,
end: 0.7,
duration: 1000
}
});
// Create first wave
createWave();
}
// Create a new wave of enemies
function createWave() {
waveNumber++;
waveText.setText('WAVE: ' + waveNumber);
// Check for final boss after wave 100
if (waveNumber > 100) {
// Create final boss
LK.getSound('bossAlert').play();
boss = new Boss(20); // Super powerful final boss
boss.x = 1024;
boss.y = -200;
boss.isFinalBoss = true;
game.addChild(boss);
tween(boss, {
y: 300
}, {
duration: 2000
});
// Show final boss text
var finalBossText = new Text2('FINAL BOSS!', {
size: 100,
fill: 0xFF0000
});
finalBossText.anchor.set(0.5, 0.5);
finalBossText.x = 1024;
finalBossText.y = 800;
game.addChild(finalBossText);
tween(finalBossText, {
alpha: 0,
y: 700
}, {
duration: 3000,
onFinish: function onFinish() {
finalBossText.destroy();
}
});
return;
}
// Every 5 waves is a boss wave
bossWave = waveNumber % 5 === 0;
if (bossWave) {
// Create a boss
var bossLevel = Math.ceil(waveNumber / 5);
LK.getSound('bossAlert').play();
boss = new Boss(bossLevel);
boss.x = 1024;
boss.y = -200;
game.addChild(boss);
tween(boss, {
y: 300
}, {
duration: 2000
});
// Show boss wave text
var bossText = new Text2('BOSS WAVE!', {
size: 80,
fill: 0xFF0000
});
bossText.anchor.set(0.5, 0.5);
bossText.x = 1024;
bossText.y = 800;
game.addChild(bossText);
tween(bossText, {
alpha: 0,
y: 700
}, {
duration: 2000,
onFinish: function onFinish() {
bossText.destroy();
}
});
return;
}
// Regular wave - adjust based on difficulty
if (gameDifficulty === 'multiplayer') {
enemiesThisWave = 15 + waveNumber * 3;
} else {
enemiesThisWave = 10 + waveNumber * 2;
}
enemiesDefeated = 0;
// Show wave text
var newWaveText = new Text2('WAVE ' + waveNumber, {
size: 80,
fill: 0xFFFFFF
});
newWaveText.anchor.set(0.5, 0.5);
newWaveText.x = 1024;
newWaveText.y = 800;
game.addChild(newWaveText);
tween(newWaveText, {
alpha: 0,
y: 700
}, {
duration: 2000,
onFinish: function onFinish() {
newWaveText.destroy();
}
});
// Start spawning enemies after a short delay
waveDelay = 120;
}
// Create a new enemy
function spawnEnemy() {
var types = ['basic'];
// Add more enemy types as waves progress - faster in multiplayer
if (gameDifficulty === 'multiplayer') {
if (waveNumber >= 1) {
types.push('fast');
}
if (waveNumber >= 2) {
types.push('tank');
}
} else {
if (waveNumber >= 2) {
types.push('fast');
}
if (waveNumber >= 3) {
types.push('tank');
}
}
var type = types[Math.floor(Math.random() * types.length)];
var enemy = new Enemy(type);
// Position the enemy
enemy.x = Math.random() * 1800 + 124;
enemy.y = -100;
enemy.initialX = enemy.x;
// Increase speed in multiplayer mode
if (gameDifficulty === 'multiplayer') {
enemy.speed *= 1.3;
enemy.shootChance *= 1.5;
}
// Set random movement pattern
var patterns = ['straight'];
if (waveNumber >= 2) {
patterns.push('sine');
}
if (waveNumber >= 4) {
patterns.push('zigzag');
}
enemy.movement.pattern = patterns[Math.floor(Math.random() * patterns.length)];
// Add to game
enemies.push(enemy);
game.addChild(enemy);
}
// Create a new asteroid
function spawnAsteroid() {
var asteroid = new Asteroid();
// Position the asteroid
asteroid.x = Math.random() * 1800 + 124;
asteroid.y = -100;
// Add to game
asteroids.push(asteroid);
game.addChild(asteroid);
}
// Create a player laser
function firePlayerLaser() {
if (!player || !player.canShoot || player.lastShot + player.fireRate > LK.ticks) {
return;
}
player.lastShot = LK.ticks;
LK.getSound('playerShoot').play();
// Fire based on power level
if (player.power === 1) {
var laser = new PlayerLaser();
laser.x = player.x;
laser.y = player.y - 50;
laser.power = player.power;
playerLasers.push(laser);
game.addChild(laser);
} else if (player.power === 2) {
for (var i = -1; i <= 1; i += 2) {
var laser = new PlayerLaser();
laser.x = player.x + i * 30;
laser.y = player.y - 40;
laser.power = player.power;
playerLasers.push(laser);
game.addChild(laser);
}
} else if (player.power >= 3) {
var centerLaser = new PlayerLaser();
centerLaser.x = player.x;
centerLaser.y = player.y - 50;
centerLaser.power = player.power;
playerLasers.push(centerLaser);
game.addChild(centerLaser);
for (var i = -1; i <= 1; i += 2) {
var sideLaser = new PlayerLaser();
sideLaser.x = player.x + i * 40;
sideLaser.y = player.y - 30;
sideLaser.power = player.power - 1;
playerLasers.push(sideLaser);
game.addChild(sideLaser);
}
}
}
// Create an enemy laser
function fireEnemyLaser(enemy) {
var laser = new EnemyLaser();
laser.x = enemy.x;
laser.y = enemy.y + 40;
enemyLasers.push(laser);
game.addChild(laser);
LK.getSound('enemyShoot').play({
volume: 0.2
});
}
// Fire boss laser pattern
function fireBossLasers() {
if (!boss) {
return;
}
// Different patterns based on boss level and health
var healthPercent = boss.health / boss.maxHealth;
var pattern = 'spread';
if (boss.level >= 2 && healthPercent < 0.5) {
pattern = 'circle';
}
if (pattern === 'spread') {
for (var i = -2; i <= 2; i++) {
var laser = new EnemyLaser();
laser.x = boss.x + i * 50;
laser.y = boss.y + 80;
enemyLasers.push(laser);
game.addChild(laser);
}
} else if (pattern === 'circle') {
var numLasers = 8;
for (var i = 0; i < numLasers; i++) {
var angle = i / numLasers * Math.PI * 2;
var laser = new EnemyLaser();
laser.x = boss.x + Math.cos(angle) * 100;
laser.y = boss.y + Math.sin(angle) * 100;
enemyLasers.push(laser);
game.addChild(laser);
// Add directional motion
laser.update = function () {
var dx = this.x - boss.x;
var dy = this.y - boss.y;
var length = Math.sqrt(dx * dx + dy * dy);
this.x += dx / length * 5;
this.y += dy / length * 5;
};
}
}
LK.getSound('enemyShoot').play({
volume: 0.4
});
}
// Create explosion animation
function createExplosion(x, y, scale) {
var explosion = new Explosion();
explosion.x = x;
explosion.y = y;
if (scale) {
explosion.scale.set(scale, scale);
}
explosions.push(explosion);
game.addChild(explosion);
LK.getSound('explosion').play();
}
// Create a powerup
function spawnPowerup(x, y, type) {
var powerup = new Powerup(type);
powerup.x = x;
powerup.y = y;
powerups.push(powerup);
game.addChild(powerup);
}
// Create a portal
function spawnPortal(type) {
var portal = new Portal(type);
portal.x = Math.random() * 1600 + 224;
portal.y = -100;
portals.push(portal);
game.addChild(portal);
// Portal entry effect
tween(portal, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 500,
onFinish: function onFinish() {
tween(portal, {
scaleX: 1,
scaleY: 1
}, {
duration: 300
});
}
});
}
// Activate speed mode
function activateSpeedMode() {
if (isSpeedMode) return;
isSpeedMode = true;
speedModeTimer = speedModeDuration;
// Visual effect on player
if (player) {
tween(player, {
tint: 0x00ffff
}, {
duration: 300
});
// Speed trail effect
var trail = player.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.3
});
trail.tint = 0x00ffff;
tween(trail, {
alpha: 0,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 1000,
onFinish: function onFinish() {
trail.destroy();
}
});
}
LK.getSound('portalEnter').play();
}
// Deactivate speed mode
function deactivateSpeedMode() {
if (!isSpeedMode) return;
isSpeedMode = false;
speedModeTimer = 0;
// Return player to normal color
if (player) {
tween(player, {
tint: 0xffffff
}, {
duration: 500
});
}
LK.getSound('portalEnter').play();
}
// Handle player shooting and movement
function handlePlayerInput() {
// Keep player in bounds
player.x = Math.max(100, Math.min(player.x, 2048 - 100));
player.y = Math.max(100, Math.min(player.y, 2732 - 100));
// Auto-fire (faster in speed mode)
var fireRate = isSpeedMode ? 5 : 10;
if (LK.ticks % fireRate === 0) {
firePlayerLaser();
}
}
// Handle collisions between game objects
function handleCollisions() {
// Player lasers vs enemies
for (var i = playerLasers.length - 1; i >= 0; i--) {
var laser = playerLasers[i];
var hitSomething = false;
// Check against enemies
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (laser.intersects(enemy)) {
// Damage enemy
if (enemy.damage(laser.power)) {
// Enemy destroyed
createExplosion(enemy.x, enemy.y);
// Add score
score += 10;
scoreTxt.setText('SCORE: ' + score);
// Update multiplayer score if in multiplayer mode
if (gameDifficulty === 'multiplayer') {
for (var p = 0; p < multiplayerPlayers.length; p++) {
if (multiplayerPlayers[p].isCurrentPlayer) {
multiplayerPlayers[p].score = score;
break;
}
}
// Update other players' scores occasionally
if (Math.random() < 0.3) {
var randomPlayer = Math.floor(Math.random() * multiplayerPlayers.length);
if (!multiplayerPlayers[randomPlayer].isCurrentPlayer) {
multiplayerPlayers[randomPlayer].score += Math.floor(Math.random() * 15);
}
}
// Re-sort and update display
multiplayerPlayers.sort(function (a, b) {
return b.score - a.score;
});
updatePlayersDisplay();
}
// Add coins
storage.coins += Math.floor(enemy.scoreValue / 5);
// Count enemy as defeated
enemiesDefeated++;
// Chance to spawn powerup
if (Math.random() < 0.1) {
spawnPowerup(enemy.x, enemy.y);
}
enemy.destroy();
enemies.splice(j, 1);
}
// Remove laser
laser.destroy();
playerLasers.splice(i, 1);
hitSomething = true;
break;
}
}
// Only check other collisions if we haven't hit an enemy
if (!hitSomething) {
// Check against boss
if (boss && laser.intersects(boss)) {
// Damage boss
if (boss.damage(laser.power)) {
// Boss destroyed
createExplosion(boss.x, boss.y, 2);
// Add score
score += boss.scoreValue;
scoreTxt.setText('SCORE: ' + score);
// Check if final boss was defeated
if (boss.isFinalBoss) {
// Player wins the game!
// Save high score
if (score > storage.highScore) {
storage.highScore = score;
}
// Add bonus coins for winning
storage.coins += 1000;
// Show victory message and play again button
var victoryContainer = new Container();
game.addChild(victoryContainer);
var victoryBg = victoryContainer.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 25,
scaleY: 20
});
victoryBg.x = 1024;
victoryBg.y = 1366;
victoryBg.tint = 0x001122;
victoryBg.alpha = 0.95;
var victoryText = new Text2('VICTORY!', {
size: 120,
fill: 0x00FF00
});
victoryText.anchor.set(0.5, 0.5);
victoryText.x = 1024;
victoryText.y = 800;
victoryContainer.addChild(victoryText);
var finalScoreText = new Text2('FINAL SCORE: ' + score, {
size: 60,
fill: 0xFFFFFF
});
finalScoreText.anchor.set(0.5, 0.5);
finalScoreText.x = 1024;
finalScoreText.y = 1000;
victoryContainer.addChild(finalScoreText);
var playAgainButton = new Text2('PLAY AGAIN', {
size: 80,
fill: 0x00AAFF
});
playAgainButton.anchor.set(0.5, 0.5);
playAgainButton.x = 1024;
playAgainButton.y = 1400;
victoryContainer.addChild(playAgainButton);
// Add victory effect
tween(victoryText, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(victoryText, {
scaleX: 1,
scaleY: 1
}, {
duration: 1000,
easing: tween.easeInOut
});
}
});
// Handle play again button interaction
game.victoryContainer = victoryContainer;
game.playAgainButton = playAgainButton;
boss.destroy();
boss = null;
return;
}
// Update multiplayer score if in multiplayer mode
if (gameDifficulty === 'multiplayer') {
for (var p = 0; p < multiplayerPlayers.length; p++) {
if (multiplayerPlayers[p].isCurrentPlayer) {
multiplayerPlayers[p].score = score;
break;
}
}
// Update other players' scores for boss defeat
for (var p = 0; p < multiplayerPlayers.length; p++) {
if (!multiplayerPlayers[p].isCurrentPlayer && Math.random() < 0.8) {
multiplayerPlayers[p].score += Math.floor(Math.random() * boss.scoreValue * 0.7);
}
}
// Re-sort and update display
multiplayerPlayers.sort(function (a, b) {
return b.score - a.score;
});
updatePlayersDisplay();
}
// Add coins for boss
storage.coins += Math.floor(boss.scoreValue / 3);
// Spawn multiple powerups
for (var p = 0; p < 3; p++) {
var powerupType = ['shield', 'power', 'life', 'speed'][Math.floor(Math.random() * 4)];
spawnPowerup(boss.x + (Math.random() * 200 - 100), boss.y + (Math.random() * 200 - 100), powerupType);
}
boss.destroy();
boss = null;
// Move to next wave
createWave();
}
// Remove laser
laser.destroy();
playerLasers.splice(i, 1);
hitSomething = true;
}
// Check against asteroids
for (var k = asteroids.length - 1; k >= 0; k--) {
var asteroid = asteroids[k];
if (laser.intersects(asteroid)) {
// Damage asteroid
if (asteroid.damage(laser.power)) {
// Asteroid destroyed
createExplosion(asteroid.x, asteroid.y, 0.7);
// Add score
score += asteroid.scoreValue;
scoreTxt.setText('SCORE: ' + score);
// Update multiplayer score if in multiplayer mode
if (gameDifficulty === 'multiplayer') {
for (var p = 0; p < multiplayerPlayers.length; p++) {
if (multiplayerPlayers[p].isCurrentPlayer) {
multiplayerPlayers[p].score = score;
break;
}
}
// Occasionally update other players' scores
if (Math.random() < 0.2) {
var randomPlayer = Math.floor(Math.random() * multiplayerPlayers.length);
if (!multiplayerPlayers[randomPlayer].isCurrentPlayer) {
multiplayerPlayers[randomPlayer].score += Math.floor(Math.random() * asteroid.scoreValue);
}
}
// Re-sort and update display
multiplayerPlayers.sort(function (a, b) {
return b.score - a.score;
});
updatePlayersDisplay();
}
// Add coins
storage.coins += Math.floor(asteroid.scoreValue / 8);
asteroid.destroy();
asteroids.splice(k, 1);
}
// Remove laser
laser.destroy();
playerLasers.splice(i, 1);
hitSomething = true;
break;
}
}
}
// Remove laser if it's off screen
if (!hitSomething && laser.y < -50) {
laser.destroy();
playerLasers.splice(i, 1);
}
}
// Enemy lasers vs player
for (var i = enemyLasers.length - 1; i >= 0; i--) {
var laser = enemyLasers[i];
if (player && laser.intersects(player)) {
// Damage player
player.damage();
// Update UI
livesText.setText('LIVES: ' + player.lives);
// Check for game over
if (player.lives <= 0) {
// Game over
createExplosion(player.x, player.y, 1.5);
player.destroy();
player = null;
// Save high score if needed
if (score > storage.highScore) {
storage.highScore = score;
}
// Show game over after a delay
LK.setTimeout(function () {
LK.showGameOver();
}, 1000);
}
// Remove laser
laser.destroy();
enemyLasers.splice(i, 1);
} else if (laser.y > 2732 + 50) {
// Remove laser if it's off screen
laser.destroy();
enemyLasers.splice(i, 1);
}
}
// Player vs enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (player && player.intersects(enemy)) {
// Damage player
player.damage();
// Damage enemy
enemy.damage(1);
// Update UI
livesText.setText('LIVES: ' + player.lives);
// Check for enemy death
if (enemy.health <= 0) {
// Enemy destroyed
createExplosion(enemy.x, enemy.y);
// Add score
score += enemy.scoreValue;
scoreTxt.setText('SCORE: ' + score);
// Count enemy as defeated
enemiesDefeated++;
enemy.destroy();
enemies.splice(i, 1);
}
// Check for game over
if (player.lives <= 0) {
// Game over
createExplosion(player.x, player.y, 1.5);
player.destroy();
player = null;
// Save high score if needed
if (score > storage.highScore) {
storage.highScore = score;
}
// Show game over after a delay
LK.setTimeout(function () {
LK.showGameOver();
}, 1000);
}
}
// Remove enemy if it's off screen
if (enemy.y > 2732 + 100) {
enemy.destroy();
enemies.splice(i, 1);
}
}
// Player vs asteroids
for (var i = asteroids.length - 1; i >= 0; i--) {
var asteroid = asteroids[i];
if (player && player.intersects(asteroid)) {
// Damage player
player.damage();
// Damage asteroid
asteroid.damage(1);
// Update UI
livesText.setText('LIVES: ' + player.lives);
// Check for asteroid death
if (asteroid.health <= 0) {
// Asteroid destroyed
createExplosion(asteroid.x, asteroid.y, 0.7);
// Add score
score += asteroid.scoreValue;
scoreTxt.setText('SCORE: ' + score);
asteroid.destroy();
asteroids.splice(i, 1);
}
// Check for game over
if (player.lives <= 0) {
// Game over
createExplosion(player.x, player.y, 1.5);
player.destroy();
player = null;
// Save high score if needed
if (score > storage.highScore) {
storage.highScore = score;
}
// Show game over after a delay
LK.setTimeout(function () {
LK.showGameOver();
}, 1000);
}
}
// Remove asteroid if it's off screen
if (asteroid.y > 2732 + 100 || asteroid.x < -100 || asteroid.x > 2048 + 100) {
asteroid.destroy();
asteroids.splice(i, 1);
}
}
// Player vs powerups
for (var i = powerups.length - 1; i >= 0; i--) {
var powerup = powerups[i];
if (player && player.intersects(powerup)) {
// Apply powerup
player.upgrade(powerup.type);
// Update UI if life powerup
if (powerup.type === 'life') {
livesText.setText('LIVES: ' + player.lives);
}
// Remove powerup
powerup.destroy();
powerups.splice(i, 1);
} else if (powerup.y > 2732 + 50) {
// Remove powerup if it's off screen
powerup.destroy();
powerups.splice(i, 1);
}
}
// Player vs portals
for (var i = portals.length - 1; i >= 0; i--) {
var portal = portals[i];
if (player && player.intersects(portal)) {
// Apply portal effect
if (portal.type === 'speed') {
activateSpeedMode();
} else if (portal.type === 'normal') {
deactivateSpeedMode();
}
// Portal activation effect
createExplosion(portal.x, portal.y, 1.2);
// Remove portal
portal.destroy();
portals.splice(i, 1);
} else if (portal.y > 2732 + 50) {
// Remove portal if it's off screen
portal.destroy();
portals.splice(i, 1);
}
}
// Player vs boss
if (player && boss && player.intersects(boss)) {
// Damage player
player.damage();
// Update UI
livesText.setText('LIVES: ' + player.lives);
// Check for game over
if (player.lives <= 0) {
// Game over
createExplosion(player.x, player.y, 1.5);
player.destroy();
player = null;
// Save high score if needed
if (score > storage.highScore) {
storage.highScore = score;
}
// Show game over after a delay
LK.setTimeout(function () {
LK.showGameOver();
}, 1000);
}
}
}
// Don't initialize game automatically - wait for start screen interaction
// Game down event handler
game.down = function (x, y, obj) {
// Check for play again button if victory screen is showing
if (game.victoryContainer && game.victoryContainer.visible !== false) {
var playAgainBounds = {
x: game.playAgainButton.x - 200,
y: game.playAgainButton.y - 40,
width: 400,
height: 80
};
if (x >= playAgainBounds.x && x <= playAgainBounds.x + playAgainBounds.width && y >= playAgainBounds.y && y <= playAgainBounds.y + playAgainBounds.height) {
// Reset game to start screen
game.victoryContainer.destroy();
game.victoryContainer = null;
game.playAgainButton = null;
gameState = 'start';
shopState = 'closed';
difficultyState = 'hidden';
startScreenContainer.visible = true;
scoreTxt.visible = false;
waveText.visible = false;
livesText.visible = false;
playersContainer.visible = false;
difficultyContainer.visible = false;
skinShopContainer.visible = false;
// Update high score display
highScoreText.setText('HIGH SCORE: ' + storage.highScore);
updateShopDisplay();
LK.stopMusic();
return;
}
}
if (gameState === 'start') {
if (shopState === 'closed') {
// Check if shop button was tapped
var shopButtonBounds = {
x: shopButton.x - 150,
y: shopButton.y - 30,
width: 300,
height: 60
};
if (x >= shopButtonBounds.x && x <= shopButtonBounds.x + shopButtonBounds.width && y >= shopButtonBounds.y && y <= shopButtonBounds.y + shopButtonBounds.height) {
// Open shop
shopState = 'open';
skinShopContainer.visible = true;
startScreenContainer.visible = false;
updateShopDisplay();
return;
}
// Show difficulty selection instead of starting game directly
difficultyState = 'visible';
difficultyContainer.visible = true;
startScreenContainer.visible = false;
return;
} else if (shopState === 'open') {
// Check back button
var backButtonBounds = {
x: backButton.x - 100,
y: backButton.y - 25,
width: 200,
height: 50
};
if (x >= backButtonBounds.x && x <= backButtonBounds.x + backButtonBounds.width && y >= backButtonBounds.y && y <= backButtonBounds.y + backButtonBounds.height) {
// Close shop
shopState = 'closed';
skinShopContainer.visible = false;
startScreenContainer.visible = true;
return;
}
// Check skin items
for (var i = 0; i < skinItems.length; i++) {
var item = skinItems[i];
var itemBounds = {
x: item.x - 400,
y: item.y - 100,
width: 800,
height: 200
};
if (x >= itemBounds.x && x <= itemBounds.x + itemBounds.width && y >= itemBounds.y && y <= itemBounds.y + itemBounds.height) {
handleSkinInteraction(item.skinData);
return;
}
}
return;
}
}
if (difficultyState === 'visible') {
// Check normal mode button - use proper bounds based on text size and position
var normalButtonBounds = {
x: normalModeButton.x - 450,
y: normalModeButton.y - 60,
width: 900,
height: 120
};
if (x >= normalButtonBounds.x && x <= normalButtonBounds.x + normalButtonBounds.width && y >= normalButtonBounds.y && y <= normalButtonBounds.y + normalButtonBounds.height) {
gameDifficulty = 'normal';
difficultyState = 'hidden';
difficultyContainer.visible = false;
initGame();
return;
}
// Check multiplayer mode button - use proper bounds based on text size and position
var multiplayerButtonBounds = {
x: multiplayerModeButton.x - 500,
y: multiplayerModeButton.y - 60,
width: 1000,
height: 120
};
if (x >= multiplayerButtonBounds.x && x <= multiplayerButtonBounds.x + multiplayerButtonBounds.width && y >= multiplayerButtonBounds.y && y <= multiplayerButtonBounds.y + multiplayerButtonBounds.height) {
gameDifficulty = 'multiplayer';
difficultyState = 'hidden';
difficultyContainer.visible = false;
initGame();
return;
}
// Check difficulty back button
var difficultyBackBounds = {
x: difficultyBackButton.x - 100,
y: difficultyBackButton.y - 25,
width: 200,
height: 50
};
if (x >= difficultyBackBounds.x && x <= difficultyBackBounds.x + difficultyBackBounds.width && y >= difficultyBackBounds.y && y <= difficultyBackBounds.y + difficultyBackBounds.height) {
difficultyState = 'hidden';
difficultyContainer.visible = false;
startScreenContainer.visible = true;
return;
}
}
if (!player) {
return;
}
dragStartPosition.x = x;
dragStartPosition.y = y;
// Fire lasers on tap
firePlayerLaser();
};
// Game move event handler
game.move = function (x, y, obj) {
if (!player) {
return;
}
// Move player with drag
player.x = x;
player.y = y;
};
// Game update handler
game.update = function () {
if (gameState === 'start') {
if (shopState === 'closed') {
updateStartScreen();
}
return;
}
if (gameState !== 'playing') {
return;
}
// Handle player input
if (player) {
handlePlayerInput();
}
// Handle wave creation
if (waveDelay > 0) {
waveDelay--;
} else if (!bossWave && enemies.length === 0 && enemiesDefeated >= enemiesThisWave) {
// All enemies for this wave defeated, create next wave
createWave();
} else if (!bossWave && enemies.length < 5 && enemiesDefeated < enemiesThisWave && LK.ticks % 30 === 0) {
// Spawn more enemies for this wave
spawnEnemy();
}
// Spawn asteroids occasionally
if (LK.ticks % 180 === 0 && Math.random() < 0.7) {
spawnAsteroid();
}
// Spawn portals occasionally
if (LK.ticks % 600 === 0 && Math.random() < 0.4) {
// Spawn speed portal if not in speed mode, or normal portal if in speed mode
var portalType = isSpeedMode ? 'normal' : 'speed';
spawnPortal(portalType);
}
// Handle speed mode timer
if (isSpeedMode) {
speedModeTimer -= 16; // Approximate 60fps
if (speedModeTimer <= 0) {
deactivateSpeedMode();
}
}
// Boss shooting
if (boss && LK.ticks % 90 === 0) {
fireBossLasers();
}
// Enemy shooting
for (var i = 0; i < enemies.length; i++) {
if (Math.random() < enemies[i].shootChance) {
fireEnemyLaser(enemies[i]);
}
}
// Collision detection
handleCollisions();
};
space ship. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
asteroid. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
space enemy. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
explosion. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
shield. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
powerup. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
space boss ufo. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
green laser. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
red laser. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
Fancy spaceship image. In-Game asset. 2d. High contrast
The image of the world fastest spaceship. In-Game asset. 2d. High contrast
Giant and strong spaceship. In-Game asset. 2d. High contrast
3 arrows is facing upwards. In-Game asset. 2d. High contrast
1 arrow is facing upwards. In-Game asset. 2d. High contrast