User prompt
separar los botones de jugar y seleccion de personaje.
User prompt
agregar la imagen de jugador4 a la pantalla de seleccion de personaje.
User prompt
al presionar el boton seleccion de personaje se vera otra pantalla donde apareceran las imagenes de jugador, jugador 2 y jugador 3. debajo de las imagenes aparecera un boton de jugar, al presionarlo se comenzara el juego dependiendo de que imagen halla presionado el jugador.
User prompt
agregue un botón que diga selección de personaje debajo del botón jugar en la pantalla de inicio.
User prompt
borrar la imagen detras del boton de inicio.
User prompt
crear una pantalla de inicio del juego con el titulo en grande y debajo del titulo un boton para iniciar el juego.
User prompt
el enemigo jefe aparecerá cada 2 minutos de juego. aparecerán 2 enemigos jefe al mismo tiempo. cuando aparezcan no aparecerán otros enemigos. cuando los 2 enemigos sean derrotados volverán a aparecer los enemigos normales. se repetirá el ciclo.
User prompt
si 5 enemigos sobrepasan el lado izquierdo de la pantalla el jugador pierde el juego.
User prompt
los power-up aparecen cada 5 segundos.
User prompt
enemigo rapido radio de colision 85 pixeles. enemigo escudo radio de colision 90 pixeles.
User prompt
enemigo normal radio de colision 80 pixeles.
User prompt
el enemigo normal dispara cada 3 segundos. el enemigo rapido dispara cada 2 segundos.
User prompt
aparecen objetos que ayudan al jugador.
User prompt
los enemigos disparan con menor frecuencia.
User prompt
las balas ya no persiguen al jugador.
User prompt
garantizar el orden de inicialización adecuado: - Inicializar todas las `lastX`, `lastY` y otras variables de seguimiento en el constructor de la clase - Añadir comprobaciones nulas antes de utilizar estas variables en los métodos de actualización - Utilizar indicadores de inicialización para omitir la lógica en el primer fotograma si es necesario.
User prompt
utilizar patrones de iteración más seguros: - Continuar usando la iteración inversa (lo cual es correcto) - Considerar el uso de matrices "toRemove" independientes y procesarlas después de la iteración - Añadir comprobaciones de seguridad antes de acceder a los elementos de la matriz.
User prompt
Ajusta los valores alfa a rangos válidos: - Para enemigos jefes: asegúrate de que el alfa nunca baje de 0,3 ni supere 1,0 - Para enemigos con escudo: asegúrate de que el alfa se mantenga dentro del rango de 0,5 a 1,0 - Usa `Math.max()` y `Math.min()` para aplicar estos límites.
User prompt
Haz que las posiciones de aparición de balas sean relativas al tamaño y tipo de enemigo: - Calcula el desplazamiento de aparición según el ancho del enemigo: `enemy.x - (enemy.width/2 + bulletOffset)` - Usa una lógica consistente para todos los tipos de enemigos en lugar de valores codificados como -30 o -60.
User prompt
Ajusta los límites de rebote para tener en cuenta el tamaño escalado del jefe: - En lugar de rebotar entre 200 y 2532, calcula los límites según la altura real del jefe después de escalar. - Usa límites como `(boss.height/2 + margin)` para la parte superior y `(2732 - boss.height/2 - margin)` para la parte inferior. Esto garantiza que el jefe permanezca completamente visible dentro de los límites de la pantalla.
User prompt
Implementar una limpieza adecuada: - Agregar métodos de limpieza a las clases enemigas que eliminen adecuadamente los recursos - Asegurarse de que se borren todas las referencias cuando se destruyan los enemigos - Monitorear los tamaños de las matrices e implementar límites si es necesario.
User prompt
Implementa la limpieza diferida:- Marcar balas y enemigos para eliminarlos en lugar de destruirlos inmediatamente - Limpiar objetos marcados al final del bucle de actualización.
User prompt
Estandariza la detección de colisiones: - Usa radios de colisión consistentes para tipos de interacción similares - Haz que los radios de colisión sean proporcionales al tamaño y tipo de enemigo - Considera usar diferentes radios para diferentes niveles de amenaza (balas vs. contacto directo).
User prompt
Añadir un manejo de reserva adecuado: - Comprobar si la distancia es mayor que un umbral mínimo (p. ej., 1.0) antes de normalizar - Proporcionar direcciones predeterminadas significativas en lugar de reservas arbitrarias - Añadir protectores para evitar la división por números muy pequeños.
User prompt
Implementar optimización espacial: - Solo comprobar colisiones de enemigos y balas que estén dentro de los límites de la pantalla - Usar comprobaciones de cuadro delimitador antes de realizar cálculos de distancia costosos - Considerar dividir la pantalla en zonas y solo comprobar colisiones dentro de las zonas relevantes - Ordenar las entidades por posición para permitir la terminación temprana de los bucles de colisión.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var BossEnemy = Container.expand(function () { var self = Container.call(this); var enemyGraphics = self.attachAsset('jefe', { anchorX: 0.5, anchorY: 0.5, scaleX: 2, scaleY: 2 }); self.speed = -1; // Very slow self.lastX = self.x; // Initialize in constructor self.lastY = self.y; // Initialize in constructor self.shootCooldown = 0; self.health = 10; // Takes 10 hits to destroy self.verticalSpeed = 2; self.verticalDirection = 1; self.isFirstFrame = true; // Initialization flag self.update = function () { // Skip first frame logic to ensure proper initialization if (self.isFirstFrame) { self.isFirstFrame = false; return; // Skip first frame to avoid premature trigger } // Move enemy left self.x += self.speed; // Move vertically up and down self.y += self.verticalSpeed * self.verticalDirection; // Calculate bounds based on scaled boss height to keep it fully visible var margin = 50; // Safety margin var scaledHeight = 126 * 2; // Original height * scale factor var topBound = scaledHeight / 2 + margin; var bottomBound = 2732 - scaledHeight / 2 - margin; if (self.y <= topBound || self.y >= bottomBound) { self.verticalDirection *= -1; } // Update shooting cooldown if (self.shootCooldown > 0) { self.shootCooldown--; } // Update last values for next frame self.lastX = self.x; self.lastY = self.y; }; self.canShoot = function () { return self.shootCooldown <= 0; }; self.shoot = function () { if (self.canShoot()) { self.shootCooldown = 60; // Slower shooting return true; } return false; }; self.takeDamage = function () { self.health--; // Visual feedback for taking damage enemyGraphics.alpha = Math.max(0.3, Math.min(1.0, 0.3 + self.health / 10 * 0.7)); return self.health <= 0; }; self.cleanup = function () { // Clear any references and reset properties self.lastX = undefined; self.lastY = undefined; self.shootCooldown = 0; self.speed = 0; self.health = 0; self.verticalSpeed = 0; self.verticalDirection = 1; self.isFirstFrame = true; // Remove from parent if still attached if (self.parent) { self.parent.removeChild(self); } }; return self; }); var Bullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 8; self.lastX = self.x; // Initialize in constructor self.lastY = self.y; // Initialize in constructor self.directionX = 1; // Default horizontal direction self.directionY = 0; // Default no vertical movement self.update = function () { // Null checks for safety if (self.lastX === null || self.lastX === undefined) self.lastX = self.x; if (self.lastY === null || self.lastY === undefined) self.lastY = self.y; // Set bullet rotation based on direction var angle = Math.atan2(self.directionY, self.directionX); bulletGraphics.rotation = angle; self.x += self.speed * self.directionX; self.y += self.speed * self.directionY; self.lastX = self.x; self.lastY = self.y; }; self.cleanup = function () { // Clear any references and reset properties self.lastX = undefined; self.lastY = undefined; self.speed = 0; self.directionX = 0; self.directionY = 0; // Remove from parent if still attached if (self.parent) { self.parent.removeChild(self); } }; return self; }); var CharacterSelectionScreen = Container.expand(function () { var self = Container.call(this); // Create title text var titleText = new Text2('SELECCIÓN DE PERSONAJE', { size: 140, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0.5); titleText.x = 2048 / 2; titleText.y = 400; self.addChild(titleText); // Create character images var player1Image = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2 - 600, y: 1000, scaleX: 1.5, scaleY: 1.5 }); var player2Image = self.attachAsset('jugador2', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2 - 200, y: 1000, scaleX: 1.5, scaleY: 1.5 }); var player3Image = self.attachAsset('jugador3', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2 + 200, y: 1000, scaleX: 1.5, scaleY: 1.5 }); var player4Image = self.attachAsset('jugador4', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2 + 600, y: 1000, scaleX: 1.5, scaleY: 1.5 }); // Create play button text var playText = new Text2('JUGAR', { size: 120, fill: 0xFFFFFF }); playText.anchor.set(0.5, 0.5); playText.x = 2048 / 2; playText.y = 1400; self.addChild(playText); // Store references for event handling self.player1Image = player1Image; self.player2Image = player2Image; self.player3Image = player3Image; self.player4Image = player4Image; self.playButton = playText; self.selectedCharacter = 'player'; // Default selection return self; }); var Enemy = Container.expand(function () { var self = Container.call(this); var enemyGraphics = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); self.speed = -3; self.lastX = self.x; // Initialize in constructor self.shootCooldown = 0; self.isFirstFrame = true; // Initialization flag self.update = function () { // Skip first frame logic to ensure proper initialization if (self.isFirstFrame) { self.isFirstFrame = false; return; // Skip first frame to avoid premature trigger } // Move enemy left self.x += self.speed; // Update shooting cooldown if (self.shootCooldown > 0) { self.shootCooldown--; } // Update lastX for next frame self.lastX = self.x; }; self.canShoot = function () { return self.shootCooldown <= 0; }; self.shoot = function () { if (self.canShoot()) { self.shootCooldown = 180; // 3 second cooldown return true; } return false; }; self.cleanup = function () { // Clear any references and reset properties self.lastX = undefined; self.shootCooldown = 0; self.speed = 0; self.isFirstFrame = true; // Remove from parent if still attached if (self.parent) { self.parent.removeChild(self); } }; return self; }); var EnemyBullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 6; self.lastX = self.x; // Initialize in constructor self.lastY = self.y; // Initialize in constructor self.directionX = -1; // Default moving left self.directionY = 0; // Default no vertical movement self.update = function () { // Null checks for safety if (self.lastX === null || self.lastX === undefined) self.lastX = self.x; if (self.lastY === null || self.lastY === undefined) self.lastY = self.y; // Set bullet rotation based on direction var angle = Math.atan2(self.directionY, self.directionX); bulletGraphics.rotation = angle; self.x += self.speed * self.directionX; self.y += self.speed * self.directionY; self.lastX = self.x; self.lastY = self.y; }; self.cleanup = function () { // Clear any references and reset properties self.lastX = undefined; self.lastY = undefined; self.speed = 0; self.directionX = 0; self.directionY = 0; // Remove from parent if still attached if (self.parent) { self.parent.removeChild(self); } }; return self; }); var FastEnemy = Container.expand(function () { var self = Container.call(this); var enemyGraphics = self.attachAsset('enemigorapido', { anchorX: 0.5, anchorY: 0.5 }); self.speed = -6; // Faster than regular enemy self.lastX = self.x; // Initialize in constructor self.shootCooldown = 0; self.isFirstFrame = true; // Initialization flag self.update = function () { // Skip first frame logic to ensure proper initialization if (self.isFirstFrame) { self.isFirstFrame = false; return; // Skip first frame to avoid premature trigger } // Move enemy left self.x += self.speed; // Update shooting cooldown if (self.shootCooldown > 0) { self.shootCooldown--; } // Update lastX for next frame self.lastX = self.x; }; self.canShoot = function () { return self.shootCooldown <= 0; }; self.shoot = function () { if (self.canShoot()) { self.shootCooldown = 120; // 2 second cooldown return true; } return false; }; self.cleanup = function () { // Clear any references and reset properties self.lastX = undefined; self.shootCooldown = 0; self.speed = 0; self.isFirstFrame = true; // Remove from parent if still attached if (self.parent) { self.parent.removeChild(self); } }; return self; }); var HealthPowerup = Container.expand(function () { var self = Container.call(this); var powerupGraphics = self.attachAsset('healthPowerup', { anchorX: 0.5, anchorY: 0.5 }); self.speed = -2; self.lastX = self.x; self.lastY = self.y; self.bobOffset = 0; self.isFirstFrame = true; self.update = function () { if (self.isFirstFrame) { self.isFirstFrame = false; return; } // Move left self.x += self.speed; // Bob up and down for visual appeal self.bobOffset += 0.1; powerupGraphics.y = Math.sin(self.bobOffset) * 10; // Gentle rotation powerupGraphics.rotation += 0.02; self.lastX = self.x; self.lastY = self.y; }; self.cleanup = function () { self.lastX = undefined; self.lastY = undefined; self.speed = 0; self.isFirstFrame = true; if (self.parent) { self.parent.removeChild(self); } }; return self; }); var Player = Container.expand(function () { var self = Container.call(this); var playerGraphics = self.attachAsset(selectedPlayerAsset, { anchorX: 0.5, anchorY: 0.5 }); self.shootCooldown = 0; self.update = function () { if (self.shootCooldown > 0) { self.shootCooldown--; } // Update shield visual effect if (playerShieldTime > 0) { // Pulsing blue tint when shielded var pulse = Math.sin(LK.ticks * 0.3) * 0.3 + 0.7; playerGraphics.tint = 0x4488ff; playerGraphics.alpha = pulse; } else { // Normal appearance playerGraphics.tint = 0xffffff; playerGraphics.alpha = 1.0; } }; self.canShoot = function () { return self.shootCooldown <= 0; }; self.shoot = function () { if (self.canShoot()) { // Faster shooting with weapon upgrades var cooldown = Math.max(5, 10 - (playerWeaponLevel - 1) * 2); self.shootCooldown = cooldown; return playerWeaponLevel; // Return weapon level for multi-shot } return 0; }; return self; }); var ShieldEnemy = Container.expand(function () { var self = Container.call(this); var enemyGraphics = self.attachAsset('enemigoescudo', { anchorX: 0.5, anchorY: 0.5 }); self.speed = -2; // Slower than regular enemy self.lastX = self.x; // Initialize in constructor self.shootCooldown = 0; self.health = 3; // Takes 3 hits to destroy self.isFirstFrame = true; // Initialization flag self.update = function () { // Skip first frame logic to ensure proper initialization if (self.isFirstFrame) { self.isFirstFrame = false; return; // Skip first frame to avoid premature trigger } // Move enemy left self.x += self.speed; // Update shooting cooldown if (self.shootCooldown > 0) { self.shootCooldown--; } // Update lastX for next frame self.lastX = self.x; }; self.canShoot = function () { return self.shootCooldown <= 0; }; self.shoot = function () { if (self.canShoot()) { self.shootCooldown = 150; // Much slower shooting return true; } return false; }; self.takeDamage = function () { self.health--; // Visual feedback for taking damage enemyGraphics.alpha = Math.max(0.5, Math.min(1.0, 0.5 + self.health / 3 * 0.5)); return self.health <= 0; }; self.cleanup = function () { // Clear any references and reset properties self.lastX = undefined; self.shootCooldown = 0; self.speed = 0; self.health = 0; self.isFirstFrame = true; // Remove from parent if still attached if (self.parent) { self.parent.removeChild(self); } }; return self; }); var ShieldPowerup = Container.expand(function () { var self = Container.call(this); var powerupGraphics = self.attachAsset('shieldPowerup', { anchorX: 0.5, anchorY: 0.5 }); self.speed = -2; self.lastX = self.x; self.lastY = self.y; self.bobOffset = 0; self.isFirstFrame = true; self.update = function () { if (self.isFirstFrame) { self.isFirstFrame = false; return; } // Move left self.x += self.speed; // Bob up and down for visual appeal self.bobOffset += 0.15; powerupGraphics.y = Math.sin(self.bobOffset) * 15; // Pulsing effect var pulse = Math.sin(self.bobOffset * 2) * 0.2 + 1.0; powerupGraphics.scaleX = pulse; powerupGraphics.scaleY = pulse; self.lastX = self.x; self.lastY = self.y; }; self.cleanup = function () { self.lastX = undefined; self.lastY = undefined; self.speed = 0; self.isFirstFrame = true; if (self.parent) { self.parent.removeChild(self); } }; return self; }); var StartScreen = Container.expand(function () { var self = Container.call(this); // Create title text var titleText = new Text2('SPACE SHOOTER', { size: 180, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0.5); titleText.x = 2048 / 2; titleText.y = 2732 / 2 - 300; self.addChild(titleText); // Create play button text var playText = new Text2('JUGAR', { size: 120, fill: 0xFFFFFF }); playText.anchor.set(0.5, 0.5); playText.x = 2048 / 2; playText.y = 2732 / 2 + 50; self.addChild(playText); // Create character selection button text var characterText = new Text2('SELECCIÓN DE PERSONAJE', { size: 100, fill: 0xFFFFFF }); characterText.anchor.set(0.5, 0.5); characterText.x = 2048 / 2; characterText.y = 2732 / 2 + 300; self.addChild(characterText); // Store button references for event handling self.playButton = playText; self.characterButton = characterText; return self; }); var WeaponPowerup = Container.expand(function () { var self = Container.call(this); var powerupGraphics = self.attachAsset('weaponPowerup', { anchorX: 0.5, anchorY: 0.5 }); self.speed = -2; self.lastX = self.x; self.lastY = self.y; self.bobOffset = 0; self.isFirstFrame = true; self.update = function () { if (self.isFirstFrame) { self.isFirstFrame = false; return; } // Move left self.x += self.speed; // Bob up and down for visual appeal self.bobOffset += 0.12; powerupGraphics.y = Math.sin(self.bobOffset) * 12; // Spinning effect powerupGraphics.rotation += 0.05; self.lastX = self.x; self.lastY = self.y; }; self.cleanup = function () { self.lastX = undefined; self.lastY = undefined; self.speed = 0; self.isFirstFrame = true; if (self.parent) { self.parent.removeChild(self); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x1a1a2e }); /**** * Game Code ****/ // Game state variables var gameStarted = false; var startScreen = null; var characterSelectionScreen = null; var selectedPlayerAsset = 'player'; // Track which character asset to use var player = null; var enemies = []; var fastEnemies = []; var shieldEnemies = []; var bossEnemies = []; var bullets = []; var enemyBullets = []; var enemySpawnTimer = 0; var enemySpawnRate = 120; // Start spawning every 2 seconds (120 frames) var difficultyTimer = 0; var playerLives = 3; var playerShieldTime = 0; // Shield duration in frames var playerWeaponLevel = 1; // Weapon upgrade level (1-3) var playerWeaponTime = 0; // Weapon upgrade duration in frames // Power-up arrays var healthPowerups = []; var shieldPowerups = []; var weaponPowerups = []; var powerupSpawnTimer = 0; var powerupSpawnRate = 300; // Spawn every 5 seconds var enemiesEscaped = 0; // Track how many enemies have escaped var bossTimer = 0; // Track time for boss battle cycles (2 minutes = 7200 frames) var bossPhase = false; // Track if we're in boss phase var bossesSpawned = 0; // Track how many bosses have been spawned in current phase // Arrays to track objects marked for removal (using object references for safer iteration) var bulletsToRemove = []; var healthPowerupsToRemove = []; var shieldPowerupsToRemove = []; var weaponPowerupsToRemove = []; var enemyBulletsToRemove = []; var enemiesToRemove = []; var fastEnemiesToRemove = []; var shieldEnemiesToRemove = []; var bossEnemiesToRemove = []; var isDragging = false; var scoreTxt = null; var livesTxt = null; // Initialize start screen startScreen = new StartScreen(); game.addChild(startScreen); function showCharacterSelection() { // Remove start screen if (startScreen && startScreen.parent) { startScreen.destroy(); startScreen = null; } // Show character selection screen characterSelectionScreen = new CharacterSelectionScreen(); game.addChild(characterSelectionScreen); } function startGame() { gameStarted = true; // Remove character selection screen if (characterSelectionScreen && characterSelectionScreen.parent) { characterSelectionScreen.destroy(); characterSelectionScreen = null; } // Initialize player with selected character asset player = new Player(); player.x = 150; player.y = 2732 - 150; // Near bottom with some margin game.addChild(player); // Create score display scoreTxt = new Text2('0', { size: 100, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); scoreTxt.setText(LK.getScore()); // Create lives display livesTxt = new Text2('Lives: 3', { size: 80, fill: 0xFFFFFF }); livesTxt.anchor.set(0, 0); livesTxt.x = 120; livesTxt.y = 20; LK.gui.topLeft.addChild(livesTxt); } // Touch/mouse down - handle start screen or game play game.down = function (x, y, obj) { if (!gameStarted) { // Handle start screen if (startScreen) { // Check if play button was clicked if (startScreen.playButton) { var deltaX = x - startScreen.playButton.x; var deltaY = y - startScreen.playButton.y; var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY); if (distance < 150) { // Button click radius startGame(); return; } } // Check if character selection button was clicked if (startScreen.characterButton) { var deltaX = x - startScreen.characterButton.x; var deltaY = y - startScreen.characterButton.y; var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY); if (distance < 200) { // Button click radius showCharacterSelection(); return; } } return; } // Handle character selection screen if (characterSelectionScreen) { // Check character image clicks if (characterSelectionScreen.player1Image) { var deltaX = x - characterSelectionScreen.player1Image.x; var deltaY = y - characterSelectionScreen.player1Image.y; var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY); if (distance < 150) { selectedPlayerAsset = 'player'; characterSelectionScreen.selectedCharacter = 'player'; return; } } if (characterSelectionScreen.player2Image) { var deltaX = x - characterSelectionScreen.player2Image.x; var deltaY = y - characterSelectionScreen.player2Image.y; var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY); if (distance < 150) { selectedPlayerAsset = 'jugador2'; characterSelectionScreen.selectedCharacter = 'jugador2'; return; } } if (characterSelectionScreen.player3Image) { var deltaX = x - characterSelectionScreen.player3Image.x; var deltaY = y - characterSelectionScreen.player3Image.y; var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY); if (distance < 150) { selectedPlayerAsset = 'jugador3'; characterSelectionScreen.selectedCharacter = 'jugador3'; return; } } if (characterSelectionScreen.player4Image) { var deltaX = x - characterSelectionScreen.player4Image.x; var deltaY = y - characterSelectionScreen.player4Image.y; var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY); if (distance < 150) { selectedPlayerAsset = 'jugador4'; characterSelectionScreen.selectedCharacter = 'jugador4'; return; } } // Check if play button was clicked if (characterSelectionScreen.playButton) { var deltaX = x - characterSelectionScreen.playButton.x; var deltaY = y - characterSelectionScreen.playButton.y; var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY); if (distance < 150) { // Button click radius startGame(); return; } } return; } } isDragging = true; // Move player to touch position (constrain to vertical movement) player.y = Math.max(100, Math.min(2732 - 100, y)); var weaponLevel = player.shoot(); if (weaponLevel > 0) { // Calculate direction vector from player to tap position var deltaX = x - player.x; var deltaY = y - player.y; var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY); var directionX = 1; var directionY = 0; if (distance > 1.0) { directionX = deltaX / distance; directionY = deltaY / distance; } // Create bullets based on weapon level for (var w = 0; w < weaponLevel; w++) { var bullet = new Bullet(); bullet.x = player.x + 40; // Spawn slightly ahead of player bullet.y = player.y - 40 + (w - Math.floor(weaponLevel / 2)) * 20; // Spread bullets vertically bullet.lastX = bullet.x; bullet.lastY = bullet.y; // Slight angle variation for multiple bullets var angleOffset = (w - Math.floor(weaponLevel / 2)) * 0.2; var cos = Math.cos(angleOffset); var sin = Math.sin(angleOffset); bullet.directionX = directionX * cos - directionY * sin; bullet.directionY = directionX * sin + directionY * cos; bullets.push(bullet); game.addChild(bullet); } LK.getSound('shoot').play(); } }; // Touch/mouse move - move player vertically while dragging game.move = function (x, y, obj) { if (!gameStarted || characterSelectionScreen) return; if (isDragging) { // Move player to touch position (constrain to vertical movement) player.y = Math.max(100, Math.min(2732 - 100, y)); } }; // Touch/mouse up - stop dragging game.up = function (x, y, obj) { if (!gameStarted || characterSelectionScreen) return; isDragging = false; }; game.update = function () { // Only update game logic if game has started and not in character selection if (!gameStarted || characterSelectionScreen) return; // Update enemy spawn timer and difficulty enemySpawnTimer++; difficultyTimer++; powerupSpawnTimer++; // Update power-up timers if (playerShieldTime > 0) { playerShieldTime--; } if (playerWeaponTime > 0) { playerWeaponTime--; if (playerWeaponTime <= 0) { playerWeaponLevel = 1; // Reset to normal weapon } } // Increase difficulty every 10 seconds (600 frames) if (difficultyTimer % 600 === 0 && enemySpawnRate > 30) { enemySpawnRate -= 10; // Spawn enemies more frequently } // Update boss timer bossTimer++; // Check for boss battle cycle (every 2 minutes = 7200 frames) if (bossTimer >= 7200) { bossPhase = true; bossTimer = 0; bossesSpawned = 0; } // Spawn enemies based on boss phase if (!bossPhase) { // Normal enemy spawning during non-boss phase if (enemySpawnTimer >= enemySpawnRate) { var spawnType = Math.random(); var spawnY = Math.random() * (2732 - 200) + 100; if (spawnType < 0.6) { // 60% chance for regular enemy var enemy = new Enemy(); enemy.x = 2048 + 30; enemy.y = spawnY; enemy.lastX = enemy.x; enemies.push(enemy); game.addChild(enemy); } else if (spawnType < 0.8) { // 20% chance for fast enemy var fastEnemy = new FastEnemy(); fastEnemy.x = 2048 + 30; fastEnemy.y = spawnY; fastEnemy.lastX = fastEnemy.x; fastEnemies.push(fastEnemy); game.addChild(fastEnemy); } else { // 20% chance for shield enemy var shieldEnemy = new ShieldEnemy(); shieldEnemy.x = 2048 + 30; shieldEnemy.y = spawnY; shieldEnemy.lastX = shieldEnemy.x; shieldEnemies.push(shieldEnemy); game.addChild(shieldEnemy); } enemySpawnTimer = 0; } } else { // Boss phase - spawn 2 bosses then wait for them to be defeated if (bossesSpawned < 2 && enemySpawnTimer >= 60) { // Small delay between boss spawns var spawnY1 = Math.random() * (2732 - 400) + 200; // First boss position var spawnY2 = Math.random() * (2732 - 400) + 200; // Second boss position // Ensure bosses don't spawn too close to each other while (Math.abs(spawnY2 - spawnY1) < 300) { spawnY2 = Math.random() * (2732 - 400) + 200; } // Spawn first boss var bossEnemy1 = new BossEnemy(); bossEnemy1.x = 2048 + 30; bossEnemy1.y = spawnY1; bossEnemy1.lastX = bossEnemy1.x; bossEnemies.push(bossEnemy1); game.addChild(bossEnemy1); // Spawn second boss var bossEnemy2 = new BossEnemy(); bossEnemy2.x = 2048 + 30; bossEnemy2.y = spawnY2; bossEnemy2.lastX = bossEnemy2.x; bossEnemies.push(bossEnemy2); game.addChild(bossEnemy2); bossesSpawned = 2; enemySpawnTimer = 0; } // Check if all bosses are defeated to end boss phase if (bossesSpawned >= 2 && bossEnemies.length === 0) { bossPhase = false; bossTimer = 0; // Reset timer for next boss cycle } } // Spawn power-ups if (powerupSpawnTimer >= powerupSpawnRate) { var powerupType = Math.random(); var spawnY = Math.random() * (2732 - 200) + 100; if (powerupType < 0.4) { // 40% chance for health power-up var healthPowerup = new HealthPowerup(); healthPowerup.x = 2048 + 30; healthPowerup.y = spawnY; healthPowerup.lastX = healthPowerup.x; healthPowerup.lastY = healthPowerup.y; healthPowerups.push(healthPowerup); game.addChild(healthPowerup); } else if (powerupType < 0.7) { // 30% chance for shield power-up var shieldPowerup = new ShieldPowerup(); shieldPowerup.x = 2048 + 30; shieldPowerup.y = spawnY; shieldPowerup.lastX = shieldPowerup.x; shieldPowerup.lastY = shieldPowerup.y; shieldPowerups.push(shieldPowerup); game.addChild(shieldPowerup); } else { // 30% chance for weapon power-up var weaponPowerup = new WeaponPowerup(); weaponPowerup.x = 2048 + 30; weaponPowerup.y = spawnY; weaponPowerup.lastX = weaponPowerup.x; weaponPowerup.lastY = weaponPowerup.y; weaponPowerups.push(weaponPowerup); game.addChild(weaponPowerup); } powerupSpawnTimer = 0; } // Update and check bullets for (var i = bullets.length - 1; i >= 0; i--) { var bullet = bullets[i]; // Mark bullets that go off screen for removal if (bullet.x > 2048 + 50 || bullet.y < -50) { bulletsToRemove.push(bullet); continue; } // Skip collision detection for bullets outside meaningful collision zones if (bullet.x < -50 || bullet.x > 2100 || bullet.y < -50 || bullet.y > 2800) { continue; } // Check bullet vs enemy collisions var bulletHit = false; // Check regular enemies for (var j = enemies.length - 1; j >= 0; j--) { var enemy = enemies[j]; // Skip enemies outside collision zone (bounding box check) if (enemy.x < -250 || enemy.x > 2100 || enemy.y < -50 || enemy.y > 2800) { continue; } // Check bullet collision with regular enemy using distance-based detection var deltaX = bullet.x - enemy.x; var deltaY = bullet.y - enemy.y; var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY); if (distance < 80) { // 80px collision radius for regular enemies // Bullet hit enemy LK.setScore(LK.getScore() + 10); scoreTxt.setText(LK.getScore()); // Check for victory condition if (LK.getScore() >= 10000) { LK.showYouWin(); return; } // Visual feedback tween(enemy, { scaleX: 1.5, scaleY: 1.5, alpha: 0 }, { duration: 200, onFinish: function onFinish() { if (enemy.parent) { enemy.destroy(); } } }); enemiesToRemove.push(enemy); bulletsToRemove.push(bullet); bulletHit = true; LK.getSound('hit').play(); break; } } // Check fast enemies for (var j = fastEnemies.length - 1; j >= 0; j--) { var fastEnemy = fastEnemies[j]; // Skip fast enemies outside collision zone (bounding box check) if (fastEnemy.x < -250 || fastEnemy.x > 2100 || fastEnemy.y < -50 || fastEnemy.y > 2800) { continue; } // Check bullet collision with fast enemy using distance-based detection var deltaX = bullet.x - fastEnemy.x; var deltaY = bullet.y - fastEnemy.y; var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY); if (distance < 85) { // 85px collision radius for fast enemies LK.setScore(LK.getScore() + 15); scoreTxt.setText(LK.getScore()); if (LK.getScore() >= 10000) { LK.showYouWin(); return; } tween(fastEnemy, { scaleX: 1.5, scaleY: 1.5, alpha: 0 }, { duration: 200, onFinish: function onFinish() { if (fastEnemy.parent) { fastEnemy.destroy(); } } }); fastEnemiesToRemove.push(fastEnemy); bulletsToRemove.push(bullet); bulletHit = true; LK.getSound('hit').play(); break; } } // Check shield enemies for (var j = shieldEnemies.length - 1; j >= 0; j--) { var shieldEnemy = shieldEnemies[j]; // Skip shield enemies outside collision zone (bounding box check) if (shieldEnemy.x < -250 || shieldEnemy.x > 2100 || shieldEnemy.y < -50 || shieldEnemy.y > 2800) { continue; } // Check bullet collision with shield enemy using distance-based detection var deltaX = bullet.x - shieldEnemy.x; var deltaY = bullet.y - shieldEnemy.y; var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY); if (distance < 90) { // 90px collision radius for shield enemies (larger due to shield) if (shieldEnemy.takeDamage()) { LK.setScore(LK.getScore() + 30); scoreTxt.setText(LK.getScore()); if (LK.getScore() >= 10000) { LK.showYouWin(); return; } tween(shieldEnemy, { scaleX: 1.5, scaleY: 1.5, alpha: 0 }, { duration: 200, onFinish: function onFinish() { if (shieldEnemy.parent) { shieldEnemy.destroy(); } } }); shieldEnemiesToRemove.push(shieldEnemy); } else { LK.setScore(LK.getScore() + 5); scoreTxt.setText(LK.getScore()); } bulletsToRemove.push(bullet); bulletHit = true; LK.getSound('hit').play(); break; } } // Check boss enemies for (var j = bossEnemies.length - 1; j >= 0; j--) { var bossEnemy = bossEnemies[j]; // Skip boss enemies outside collision zone (bounding box check) if (bossEnemy.x < -250 || bossEnemy.x > 2100 || bossEnemy.y < -50 || bossEnemy.y > 2800) { continue; } // Check bullet collision with boss enemy using distance-based detection var deltaX = bullet.x - bossEnemy.x; var deltaY = bullet.y - bossEnemy.y; var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY); if (distance < 80) { // 80px collision radius for boss enemies (much larger due to 2x scale and boss status) if (bossEnemy.takeDamage()) { LK.setScore(LK.getScore() + 100); scoreTxt.setText(LK.getScore()); if (LK.getScore() >= 10000) { LK.showYouWin(); return; } tween(bossEnemy, { scaleX: 3, scaleY: 3, alpha: 0 }, { duration: 500, onFinish: function onFinish() { if (bossEnemy.parent) { bossEnemy.destroy(); } } }); bossEnemiesToRemove.push(bossEnemy); } else { LK.setScore(LK.getScore() + 10); scoreTxt.setText(LK.getScore()); } bulletsToRemove.push(bullet); bulletHit = true; LK.getSound('hit').play(); break; } } if (bulletHit) continue; } // Update and check enemy bullets for (var m = enemyBullets.length - 1; m >= 0; m--) { var enemyBullet = enemyBullets[m]; // Mark enemy bullets that go off screen for removal if (enemyBullet.x < -50 || enemyBullet.y < -50 || enemyBullet.y > 2732 + 50) { enemyBulletsToRemove.push(enemyBullet); continue; } // Skip collision detection for enemy bullets outside meaningful collision zones if (enemyBullet.x < -50 || enemyBullet.x > 2100 || enemyBullet.y < -50 || enemyBullet.y > 2800) { continue; } // Check if enemy bullet hits player center (more precise collision) var deltaX = enemyBullet.x - player.x; var deltaY = enemyBullet.y - player.y; var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY); if (distance < 35) { // Only hits if within 35 pixels of player center (consistent bullet collision radius) if (playerShieldTime <= 0) { // Only take damage if not shielded playerLives--; livesTxt.setText('Lives: ' + playerLives); LK.effects.flashScreen(0xFF0000, 500); if (playerLives <= 0) { LK.showGameOver(); return; } } enemyBulletsToRemove.push(enemyBullet); } } // Update and check regular enemies for (var k = enemies.length - 1; k >= 0; k--) { var enemy = enemies[k]; // Mark enemies that go off screen for removal if (enemy.x < -200) { // Regular enemy width is 200px enemiesEscaped++; if (enemiesEscaped >= 5) { LK.showGameOver(); return; } enemiesToRemove.push(enemy); continue; } // Skip processing for enemies outside meaningful interaction zones if (enemy.x < -250 || enemy.x > 2100 || enemy.y < -50 || enemy.y > 2800) { continue; } // Calculate distance once for collision detection var deltaX = player.x - enemy.x; var deltaY = player.y - enemy.y; var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY); // Enemy shooting logic if (enemy.shoot()) { var enemyBullet = new EnemyBullet(); var bulletOffset = 10; // Additional offset beyond enemy edge enemyBullet.x = enemy.x - (enemy.width / 2 + bulletOffset); // Spawn relative to enemy width enemyBullet.y = enemy.y; enemyBullet.lastX = enemyBullet.x; enemyBullet.lastY = enemyBullet.y; // Shoot straight left - no player tracking enemyBullet.directionX = -1; enemyBullet.directionY = 0; enemyBullets.push(enemyBullet); game.addChild(enemyBullet); } // Check if enemy collides with player center using same distance calculation if (distance < 60) { // Only hits if within 60 pixels of player center (larger radius for direct contact) if (playerShieldTime <= 0) { // Only take damage if not shielded playerLives--; livesTxt.setText('Lives: ' + playerLives); LK.effects.flashScreen(0xFF0000, 500); if (playerLives <= 0) { LK.showGameOver(); return; } } enemiesToRemove.push(enemy); } } // Update and check fast enemies for (var k = fastEnemies.length - 1; k >= 0; k--) { var fastEnemy = fastEnemies[k]; // Mark fast enemies that go off screen for removal if (fastEnemy.x < -200) { // Fast enemy width is 200px enemiesEscaped++; if (enemiesEscaped >= 5) { LK.showGameOver(); return; } fastEnemiesToRemove.push(fastEnemy); continue; } // Skip processing for fast enemies outside meaningful interaction zones if (fastEnemy.x < -250 || fastEnemy.x > 2100 || fastEnemy.y < -50 || fastEnemy.y > 2800) { continue; } // Calculate distance once for collision detection var deltaX = player.x - fastEnemy.x; var deltaY = player.y - fastEnemy.y; var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY); if (fastEnemy.shoot()) { var enemyBullet = new EnemyBullet(); var bulletOffset = 10; // Additional offset beyond enemy edge enemyBullet.x = fastEnemy.x - (fastEnemy.width / 2 + bulletOffset); // Spawn relative to enemy width enemyBullet.y = fastEnemy.y; enemyBullet.lastX = enemyBullet.x; enemyBullet.lastY = enemyBullet.y; // Shoot straight left - no player tracking enemyBullet.directionX = -1; enemyBullet.directionY = 0; enemyBullets.push(enemyBullet); game.addChild(enemyBullet); } // Check if fast enemy collides with player center using same distance calculation if (distance < 65) { // Only hits if within 65 pixels of player center (slightly larger due to fast movement) if (playerShieldTime <= 0) { // Only take damage if not shielded playerLives--; livesTxt.setText('Lives: ' + playerLives); LK.effects.flashScreen(0xFF0000, 500); if (playerLives <= 0) { LK.showGameOver(); return; } } fastEnemiesToRemove.push(fastEnemy); } } // Update and check shield enemies for (var k = shieldEnemies.length - 1; k >= 0; k--) { var shieldEnemy = shieldEnemies[k]; // Mark shield enemies that go off screen for removal if (shieldEnemy.x < -200) { // Shield enemy width is 200px enemiesEscaped++; if (enemiesEscaped >= 5) { LK.showGameOver(); return; } shieldEnemiesToRemove.push(shieldEnemy); continue; } // Skip processing for shield enemies outside meaningful interaction zones if (shieldEnemy.x < -250 || shieldEnemy.x > 2100 || shieldEnemy.y < -50 || shieldEnemy.y > 2800) { continue; } // Calculate distance once for collision detection var deltaX = player.x - shieldEnemy.x; var deltaY = player.y - shieldEnemy.y; var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY); if (shieldEnemy.shoot()) { var enemyBullet = new EnemyBullet(); var bulletOffset = 10; // Additional offset beyond enemy edge enemyBullet.x = shieldEnemy.x - (shieldEnemy.width / 2 + bulletOffset); // Spawn relative to enemy width enemyBullet.y = shieldEnemy.y; enemyBullet.lastX = enemyBullet.x; enemyBullet.lastY = enemyBullet.y; // Shoot straight left - no player tracking enemyBullet.directionX = -1; enemyBullet.directionY = 0; enemyBullets.push(enemyBullet); game.addChild(enemyBullet); } // Check if shield enemy collides with player center using same distance calculation if (distance < 70) { // Only hits if within 70 pixels of player center (larger due to shield size) if (playerShieldTime <= 0) { // Only take damage if not shielded playerLives--; livesTxt.setText('Lives: ' + playerLives); LK.effects.flashScreen(0xFF0000, 500); if (playerLives <= 0) { LK.showGameOver(); return; } } shieldEnemiesToRemove.push(shieldEnemy); } } // Update and check health power-ups for (var p = healthPowerups.length - 1; p >= 0; p--) { var healthPowerup = healthPowerups[p]; // Remove if off screen if (healthPowerup.x < -100) { healthPowerupsToRemove.push(healthPowerup); continue; } // Check collision with player var deltaX = healthPowerup.x - player.x; var deltaY = healthPowerup.y - player.y; var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY); if (distance < 50) { // Player collected health power-up if (playerLives < 5) { // Max 5 lives playerLives++; livesTxt.setText('Lives: ' + playerLives); LK.getSound('powerup').play(); LK.effects.flashScreen(0x00ff00, 300); } healthPowerupsToRemove.push(healthPowerup); } } // Update and check shield power-ups for (var p = shieldPowerups.length - 1; p >= 0; p--) { var shieldPowerup = shieldPowerups[p]; // Remove if off screen if (shieldPowerup.x < -100) { shieldPowerupsToRemove.push(shieldPowerup); continue; } // Check collision with player var deltaX = shieldPowerup.x - player.x; var deltaY = shieldPowerup.y - player.y; var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY); if (distance < 50) { // Player collected shield power-up playerShieldTime = 600; // 10 seconds of invincibility LK.getSound('powerup').play(); LK.effects.flashScreen(0x0088ff, 300); shieldPowerupsToRemove.push(shieldPowerup); } } // Update and check weapon power-ups for (var p = weaponPowerups.length - 1; p >= 0; p--) { var weaponPowerup = weaponPowerups[p]; // Remove if off screen if (weaponPowerup.x < -100) { weaponPowerupsToRemove.push(weaponPowerup); continue; } // Check collision with player var deltaX = weaponPowerup.x - player.x; var deltaY = weaponPowerup.y - player.y; var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY); if (distance < 50) { // Player collected weapon power-up playerWeaponLevel = Math.min(3, playerWeaponLevel + 1); // Max level 3 playerWeaponTime = 1800; // 30 seconds of upgrade LK.getSound('powerup').play(); LK.effects.flashScreen(0xffaa00, 300); weaponPowerupsToRemove.push(weaponPowerup); } } // Update and check boss enemies for (var k = bossEnemies.length - 1; k >= 0; k--) { var bossEnemy = bossEnemies[k]; // Mark boss enemies that go off screen for removal if (bossEnemy.x < -200) { // Boss enemy width is 100px * 2 scale = 200px enemiesEscaped++; if (enemiesEscaped >= 5) { LK.showGameOver(); return; } bossEnemiesToRemove.push(bossEnemy); continue; } // Skip processing for boss enemies outside meaningful interaction zones if (bossEnemy.x < -250 || bossEnemy.x > 2100 || bossEnemy.y < -50 || bossEnemy.y > 2800) { continue; } // Calculate distance once for collision detection var deltaX = player.x - bossEnemy.x; var deltaY = player.y - bossEnemy.y; var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY); if (bossEnemy.shoot()) { var enemyBullet = new EnemyBullet(); var bulletOffset = 10; // Additional offset beyond enemy edge enemyBullet.x = bossEnemy.x - (bossEnemy.width / 2 + bulletOffset); // Spawn relative to enemy width (scaled) enemyBullet.y = bossEnemy.y; enemyBullet.lastX = enemyBullet.x; enemyBullet.lastY = enemyBullet.y; // Shoot straight left - no player tracking enemyBullet.directionX = -1; enemyBullet.directionY = 0; enemyBullets.push(enemyBullet); game.addChild(enemyBullet); } // Check if boss enemy collides with player center using same distance calculation if (distance < 90) { // Only hits if within 90 pixels of player center (much larger due to 2x scale and boss size) if (playerShieldTime <= 0) { // Only take damage if not shielded playerLives--; livesTxt.setText('Lives: ' + playerLives); LK.effects.flashScreen(0xFF0000, 500); if (playerLives <= 0) { LK.showGameOver(); return; } } bossEnemiesToRemove.push(bossEnemy); } } // Deferred cleanup - process all marked objects for removal using safer object-based iteration // Process bullets marked for removal for (var i = bulletsToRemove.length - 1; i >= 0; i--) { var bulletToRemove = bulletsToRemove[i]; if (bulletToRemove && bulletToRemove.parent) { var index = bullets.indexOf(bulletToRemove); if (index !== -1 && index < bullets.length) { bullets[index].cleanup(); bullets[index].destroy(); bullets.splice(index, 1); } } } bulletsToRemove = []; // Process enemy bullets marked for removal for (var i = enemyBulletsToRemove.length - 1; i >= 0; i--) { var enemyBulletToRemove = enemyBulletsToRemove[i]; if (enemyBulletToRemove && enemyBulletToRemove.parent) { var index = enemyBullets.indexOf(enemyBulletToRemove); if (index !== -1 && index < enemyBullets.length) { enemyBullets[index].cleanup(); enemyBullets[index].destroy(); enemyBullets.splice(index, 1); } } } enemyBulletsToRemove = []; // Process regular enemies marked for removal for (var i = enemiesToRemove.length - 1; i >= 0; i--) { var enemyToRemove = enemiesToRemove[i]; if (enemyToRemove && enemyToRemove.parent) { var index = enemies.indexOf(enemyToRemove); if (index !== -1 && index < enemies.length) { enemies[index].cleanup(); enemies[index].destroy(); enemies.splice(index, 1); } } } enemiesToRemove = []; // Process fast enemies marked for removal for (var i = fastEnemiesToRemove.length - 1; i >= 0; i--) { var fastEnemyToRemove = fastEnemiesToRemove[i]; if (fastEnemyToRemove && fastEnemyToRemove.parent) { var index = fastEnemies.indexOf(fastEnemyToRemove); if (index !== -1 && index < fastEnemies.length) { fastEnemies[index].cleanup(); fastEnemies[index].destroy(); fastEnemies.splice(index, 1); } } } fastEnemiesToRemove = []; // Process shield enemies marked for removal for (var i = shieldEnemiesToRemove.length - 1; i >= 0; i--) { var shieldEnemyToRemove = shieldEnemiesToRemove[i]; if (shieldEnemyToRemove && shieldEnemyToRemove.parent) { var index = shieldEnemies.indexOf(shieldEnemyToRemove); if (index !== -1 && index < shieldEnemies.length) { shieldEnemies[index].cleanup(); shieldEnemies[index].destroy(); shieldEnemies.splice(index, 1); } } } shieldEnemiesToRemove = []; // Process boss enemies marked for removal for (var i = bossEnemiesToRemove.length - 1; i >= 0; i--) { var bossEnemyToRemove = bossEnemiesToRemove[i]; if (bossEnemyToRemove && bossEnemyToRemove.parent) { var index = bossEnemies.indexOf(bossEnemyToRemove); if (index !== -1 && index < bossEnemies.length) { bossEnemies[index].cleanup(); bossEnemies[index].destroy(); bossEnemies.splice(index, 1); } } } bossEnemiesToRemove = []; // Process health power-ups marked for removal for (var i = healthPowerupsToRemove.length - 1; i >= 0; i--) { var healthPowerupToRemove = healthPowerupsToRemove[i]; if (healthPowerupToRemove && healthPowerupToRemove.parent) { var index = healthPowerups.indexOf(healthPowerupToRemove); if (index !== -1 && index < healthPowerups.length) { healthPowerups[index].cleanup(); healthPowerups[index].destroy(); healthPowerups.splice(index, 1); } } } healthPowerupsToRemove = []; // Process shield power-ups marked for removal for (var i = shieldPowerupsToRemove.length - 1; i >= 0; i--) { var shieldPowerupToRemove = shieldPowerupsToRemove[i]; if (shieldPowerupToRemove && shieldPowerupToRemove.parent) { var index = shieldPowerups.indexOf(shieldPowerupToRemove); if (index !== -1 && index < shieldPowerups.length) { shieldPowerups[index].cleanup(); shieldPowerups[index].destroy(); shieldPowerups.splice(index, 1); } } } shieldPowerupsToRemove = []; // Process weapon power-ups marked for removal for (var i = weaponPowerupsToRemove.length - 1; i >= 0; i--) { var weaponPowerupToRemove = weaponPowerupsToRemove[i]; if (weaponPowerupToRemove && weaponPowerupToRemove.parent) { var index = weaponPowerups.indexOf(weaponPowerupToRemove); if (index !== -1 && index < weaponPowerups.length) { weaponPowerups[index].cleanup(); weaponPowerups[index].destroy(); weaponPowerups.splice(index, 1); } } } weaponPowerupsToRemove = []; // Monitor array sizes and implement limits to prevent memory leaks var maxBullets = 100; var maxEnemyBullets = 200; var maxEnemies = 50; // Limit bullets array size with safety checks if (bullets.length > maxBullets) { for (var i = bullets.length - 1; i >= maxBullets; i--) { if (i < bullets.length && bullets[i]) { bullets[i].cleanup(); bullets[i].destroy(); bullets.splice(i, 1); } } } // Limit enemy bullets array size with safety checks if (enemyBullets.length > maxEnemyBullets) { for (var i = enemyBullets.length - 1; i >= maxEnemyBullets; i--) { if (i < enemyBullets.length && enemyBullets[i]) { enemyBullets[i].cleanup(); enemyBullets[i].destroy(); enemyBullets.splice(i, 1); } } } // Limit enemies array size with safety checks if (enemies.length > maxEnemies) { for (var i = enemies.length - 1; i >= maxEnemies; i--) { if (i < enemies.length && enemies[i]) { enemies[i].cleanup(); enemies[i].destroy(); enemies.splice(i, 1); } } } // Limit fast enemies array size with safety checks if (fastEnemies.length > maxEnemies) { for (var i = fastEnemies.length - 1; i >= maxEnemies; i--) { if (i < fastEnemies.length && fastEnemies[i]) { fastEnemies[i].cleanup(); fastEnemies[i].destroy(); fastEnemies.splice(i, 1); } } } // Limit shield enemies array size with safety checks if (shieldEnemies.length > maxEnemies) { for (var i = shieldEnemies.length - 1; i >= maxEnemies; i--) { if (i < shieldEnemies.length && shieldEnemies[i]) { shieldEnemies[i].cleanup(); shieldEnemies[i].destroy(); shieldEnemies.splice(i, 1); } } } // Limit boss enemies array size with safety checks if (bossEnemies.length > maxEnemies) { for (var i = bossEnemies.length - 1; i >= maxEnemies; i--) { if (i < bossEnemies.length && bossEnemies[i]) { bossEnemies[i].cleanup(); bossEnemies[i].destroy(); bossEnemies.splice(i, 1); } } } }; // Play background music LK.playMusic('bgmusic');
===================================================================
--- original.js
+++ change.js
@@ -499,18 +499,18 @@
fill: 0xFFFFFF
});
playText.anchor.set(0.5, 0.5);
playText.x = 2048 / 2;
- playText.y = 2732 / 2 + 100;
+ playText.y = 2732 / 2 + 50;
self.addChild(playText);
// Create character selection button text
var characterText = new Text2('SELECCIÓN DE PERSONAJE', {
size: 100,
fill: 0xFFFFFF
});
characterText.anchor.set(0.5, 0.5);
characterText.x = 2048 / 2;
- characterText.y = 2732 / 2 + 250;
+ characterText.y = 2732 / 2 + 300;
self.addChild(characterText);
// Store button references for event handling
self.playButton = playText;
self.characterButton = characterText;
tommy vercetti de gta vice city hecho con pixeles apuntando con un rifle de asalto m4 con la perspcetiva lateral. In-Game asset. 2d. High contrast. No shadows
un mafioso italiano usando un m4 con la perspectiva lateral de cuerpo completo In-Game asset. 2d. High contrast. No shadows
un pandillero mexicano apuntando con un SMG con la perspectiva lateral. In-Game asset. 2d. High contrast. No shadows de cuerpo completo
un pandillero negro con camisa azul oscuro y pantalon blanco usando una escopeta con la perspectiva lateral de cuerpo completo. In-Game asset. 2d. High contrast. No shadows
chaleco antibalas. In-Game asset. 2d. High contrast. No shadows
corazon verde dibujado. In-Game asset. 2d. High contrast. No shadows
escopeta dibujada. In-Game asset. 2d. High contrast. No shadows
claude speed de gta 3 apuntando con una ak47 desde una perspectiva lateral de cuerpo completo In-Game asset. 2d. High contrast. No shadows
las letras play con un color celeste y rosa combinados con una cursiva In-Game asset. 2d. High contrast. No shadows con contorno negro
letras que dicen seleccion de personaje con un color rosa y un color celeste y con contorno azul y rosa cursiva. In-Game asset. 2d. High contrast. No shadows
las letras vidas con un color rosa y azul con contorno rosa y azul combinados hechos con pixeles. In-Game asset. 2d. High contrast. No shadows
una mansion con piso rojo vista completa y totalmente desde arriba y desde dentro con una escalera grande igual que la de scarface la pelicula y pasillos a los lados. In-Game asset. 2d. High contrast. No shadows
no va a tener ese brazo especificamente
un motociclista vestido de negro apuntando con una smg de cuerpo completo con perspectiva lateral In-Game asset. 2d. High contrast. No shadows sin casco y sin moto
letras de color rosa y azul y con cursiva que digan vice city wars. In-Game asset. 2d. High contrast. No shadows
un hombre usando una chaqueta negra pantalones azules disparando un ak47. In-Game asset. 2d. High contrast. No shadows con la perspectiva lateral de cuerpo completo
letras de color rosa que dicen seleccion de personaje en cursiva y con contorno blanco