User prompt
Please fix the bug: 'self.addChild is not a function' in or related to this line: 'self.bossGraphics = self.addChild(LK.getAsset('bossIdle', {' Line Number: 650
User prompt
Please fix the bug: 'self.attachAsset is not a function' in or related to this line: 'self.bossGraphics = self.attachAsset('bossIdle', {' Line Number: 650
User prompt
Please fix the bug: 'LK.getShape is not a function' in or related to this line: 'self.grillMenu = LK.getShape('grillMenu', {});' Line Number: 585
User prompt
Please fix the bug: 'LK.Text is not a constructor' in or related to this line: 'self.gameOverMessage = new LK.Text({' Line Number: 572
User prompt
Please fix the bug: 'LK.Text is not a constructor' in or related to this line: 'self.newBossPlusButtonText = new LK.Text({' Line Number: 557
User prompt
Please fix the bug: 'LK.getShape is not a function' in or related to this line: 'self.newBossPlusButton = LK.getShape('button_bg', {}); // Example shape button' Line Number: 550
User prompt
Please fix the bug: 'LK.Text is not a constructor' in or related to this line: 'self.startButtonText = new LK.Text({' Line Number: 535
User prompt
Please fix the bug: 'LK.getShape is not a function' in or related to this line: 'self.startButton = LK.getShape('button_bg', {}); // Example shape button' Line Number: 528
User prompt
Please fix the bug: 'DisplayObjectContainer is not defined' in or related to this line: 'self.playerHearts = new DisplayObjectContainer(); // Container for player hearts' Line Number: 522
User prompt
Please fix the bug: 'LK.getShape is not a function' in or related to this line: 'self.bossHpBar = LK.getShape('bossHpbar', {});' Line Number: 519
Code edit (1 edits merged)
Please save this source code
Code edit (6 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: self.startAttackPattern is not a function' in or related to this line: 'self.startAttackPattern();' Line Number: 470
Code edit (1 edits merged)
Please save this source code
Code edit (8 edits merged)
Please save this source code
User prompt
add assets bossAttack0 to bossattack3
User prompt
add assets bossAttack0 to bossattack3
Code edit (5 edits merged)
Please save this source code
User prompt
add asset fireball13 fireball14 fireball15 fireball16
Code edit (2 edits merged)
Please save this source code
User prompt
add assets fireball00 to fireball12
User prompt
Please fix the bug: 'TypeError: self.clearRollTimeouts is not a function' in or related to this line: 'self.clearRollTimeouts();' Line Number: 589
Code edit (1 edits merged)
Please save this source code
Code edit (2 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Uncaught ReferenceError: SpriteAnimation is not defined' in or related to this line: 'var rollAnimation = game.addChild(new SpriteAnimation({' Line Number: 448
/**** * Classes ****/ // End gameState /**** * Player class ****/ var Player = Container.expand(function () { var self = Container.call(this); // Attach player graphic (depends on asset) self.playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); self.health = 5; // Default player health (will be set by storage.maxHearts in gameState.startGame) self.speed = 8; // Player movement speed self.rollSpeed = 12; // Player roll speed self.rolling = false; self.rollDuration = 30; // Roll duration in frames (0.5 seconds at 60fps) self.rollTimer = 0; self.rollDirectionX = 0; self.rollDirectionY = 0; self.invulnerable = false; // Player invulnerability flag self.invulnerabilityDuration = 60; // Invulnerability duration after rolling/getting hit self.invulnerabilityTimer = 0; self.dead = false; // Create player roll animation (depends on assets) self.createRollAnim = function () { var frames = [LK.getAsset('roll0', {}), LK.getAsset('roll1', {}), LK.getAsset('roll2', {}), LK.getAsset('roll3', {}), LK.getAsset('roll4', {})]; var rollAnim = new SpriteAnimation({ frames: frames, frameDuration: 60, // Roll animation speed loop: true, // Roll animation loops anchorX: 0.5, anchorY: 0.5, x: 0, // Relative position y: 0 // Relative position }); return rollAnim; }; self.rollAnim = null; // Will hold the current roll animation object self.startRoll = function () { if (self.rolling || self.dead || gameState.currentState !== "game") { return; // Cannot roll if already rolling, dead, or not in game state } self.rolling = true; self.rollTimer = self.rollDuration; self.invulnerable = true; // Invulnerable during roll self.invulnerabilityTimer = self.invulnerabilityDuration; // Capture current movement direction for roll self.rollDirectionX = (LK.isDown("left") ? -1 : 0) + (LK.isDown("right") ? 1 : 0); self.rollDirectionY = (LK.isDown("up") ? -1 : 0) + (LK.isDown("down") ? 1 : 0); // Ensure there's a direction to roll, default if no input if (self.rollDirectionX === 0 && self.rollDirectionY === 0) { // Default roll direction (e.g., last movement direction, or down) // For simplicity, let's just prevent roll if no direction pressed. // Or set a default if needed: self.rollDirectionY = 1; // Example: roll down self.rolling = false; // Cancel roll if no direction input self.invulnerable = false; self.invulnerabilityTimer = 0; return; // Exit if no roll direction } // Normalize roll direction vector (optional, but good for consistent speed) var rollMagnitude = Math.sqrt(self.rollDirectionX * self.rollDirectionX + self.rollDirectionY * self.rollDirectionY); if (rollMagnitude > 0) { self.rollDirectionX /= rollMagnitude; self.rollDirectionY /= rollMagnitude; } // Remove idle graphic, add roll animation if (self.playerGraphics && self.playerGraphics.parent === self) { self.playerGraphics.parent.removeChild(self.playerGraphics); } else if (self.playerGraphics && self.playerGraphics.parent) { // Fallback self.playerGraphics.parent.removeChild(self.playerGraphics); } self.playerGraphics = null; self.rollAnim = self.addChild(self.createRollAnim()); // Add roll animation as child self.rollAnim.play(); // Start roll animation }; self.takeDamage = function (amount) { if (self.dead || self.invulnerable || gameState.currentState !== "game") { return; // Cannot take damage if dead, invulnerable, or not in game state } self.health -= amount; self.health = Math.max(0, self.health); // Health cannot go below zero LK.getSound('playerHit').play(); // Play player hit sound LK.effects.flashObject(self, 0xFF0000, 300); // Flash effect on hit self.invulnerable = true; // Become invulnerable after taking damage // Use a separate timer for hit invulnerability if needed, or just reuse roll timer logic // For simplicity, reuse invulnerabilityTimer: self.invulnerabilityTimer = self.invulnerabilityDuration; // Invulnerable for a short period // Update UI hearts immediately // ui.updateHearts(self.health, storage.maxHearts); // This is called in game.update -> ui.updateHearts if (self.health <= 0) { self.die(); // Player dies } }; self.die = function () { if (self.dead) { return; // Already dead } self.dead = true; // Stop all movement/actions self.rolling = false; self.invulnerable = false; // No longer invulnerable once dead // Stop/remove roll animation if active if (self.rollAnim) { self.rollAnim.stop(); if (self.rollAnim.parent === self) { self.rollAnim.parent.removeChild(self.rollAnim); } else if (self.rollAnim.parent) { // Fallback self.rollAnim.parent.removeChild(self.rollAnim); } self.rollAnim.destroy(); self.rollAnim = null; } // Add player death animation or graphic (if any) // For simplicity, just hide or remove the player graphic if (self.playerGraphics && self.playerGraphics.parent === self) { self.playerGraphics.parent.removeChild(self.playerGraphics); } else if (self.playerGraphics && self.playerGraphics.parent) { // Fallback self.playerGraphics.parent.removeChild(self.playerGraphics); } self.playerGraphics = null; // Clear reference // Trigger game over state after a short delay or death animation LK.setTimeout(function () { if (gameState.currentState === "game") { // Only transition if still in game state gameState.gameOver(true); // Call game over function with death reason } }, 1000); // Delay game over screen by 1 second }; self.update = function () { // Update only if in game state if (gameState.currentState !== "game") { // Stop rolling and remove animation if state changes if (self.rolling) { self.rolling = false; if (self.rollAnim) { self.rollAnim.stop(); if (self.rollAnim.parent === self) { self.rollAnim.parent.removeChild(self.rollAnim); } else if (self.rollAnim.parent) { // Fallback self.rollAnim.parent.removeChild(self.rollAnim); } self.rollAnim.destroy(); self.rollAnim = null; } // Add back idle graphic if it was removed if (!self.playerGraphics) { self.playerGraphics = self.addChild(self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5, x: 0, y: 0 // Relative position })); } } return; // Exit update if not in game state } // Do not update if player is dead if (self.dead) { return; } // --- Rolling logic --- if (self.rolling) { self.x += self.rollDirectionX * self.rollSpeed; self.y += self.rollDirectionY * self.rollSpeed; self.rollTimer--; if (self.rollTimer <= 0) { self.rolling = false; // Stop and remove roll animation if (self.rollAnim) { self.rollAnim.stop(); if (self.rollAnim.parent === self) { self.rollAnim.parent.removeChild(self.rollAnim); } else if (self.rollAnim.parent) { // Fallback self.rollAnim.parent.removeChild(self.rollAnim); } self.rollAnim.destroy(); self.rollAnim = null; } // Add back idle graphic if (!self.playerGraphics) { self.playerGraphics = self.addChild(self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5, x: 0, y: 0 // Relative position })); } } } else { // --- Movement logic (only when not rolling) --- var moveX = (LK.isDown("left") ? -1 : 0) + (LK.isDown("right") ? 1 : 0); var moveY = (LK.isDown("up") ? -1 : 0) + (LK.isDown("down") ? 1 : 0); var moveMagnitude = Math.sqrt(moveX * moveX + moveY * moveY); if (moveMagnitude > 0) { moveX /= moveMagnitude; moveY /= moveMagnitude; self.x += moveX * self.speed; self.y += moveY * self.speed; } // No specific idle animation in this example, uses static player graphic } // --- Invulnerability timer --- if (self.invulnerable) { self.invulnerabilityTimer--; if (self.invulnerabilityTimer <= 0) { self.invulnerable = false; } // Optional: add visual effect for invulnerability (e.g., alpha blinking) self.alpha = self.invulnerabilityTimer % 10 < 5 ? 0.5 : 1; // Simple blinking effect } else { self.alpha = 1; // Fully visible when not invulnerable } // --- Boundary checks (Arena borders) --- // Assuming arena borders are at 100px from edge, map 2048x2732 var halfWidth = self.width * self.scaleX / 2; var halfHeight = self.height * self.scaleY / 2; var minX = 100 + halfWidth; var maxX = 2048 - 100 - halfWidth; var minY = 100 + halfHeight; var maxY = 2732 - 100 - halfHeight; self.x = Math.max(minX, Math.min(self.x, maxX)); self.y = Math.max(minY, Math.min(self.y, maxY)); // --- Collision with Boss (only when not invulnerable) --- // Boss collision check is handled in player.update(), NOT boss.update() // It should only happen if player is NOT invulnerable // This collision check is handled in game.update -> player.update() // Let's add the check here if player.update is responsible for it. // Check collision with Boss if boss exists, is not dead, and player is not invulnerable if (boss && !boss.dead && !self.invulnerable) { var dx_b = boss.x - self.x; var dy_b = boss.y - self.y; var distance_b = Math.sqrt(dx_b * dx_b + dy_b * dy_b); var playerRadius_b = self.width / 2; var bossRadius_b = boss.width * boss.scaleX / 2; // Use scaled boss width if (distance_b < playerRadius_b + bossRadius_b) { // Collision detected with Boss body self.takeDamage(1); // Player takes 1 damage } } // Note: Collision with Boss *attacks* is handled in boss.update() }; return self; }); /**** * Initialize Game ****/ // End Player class /**** * UI object ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ /**** * Global variables ****/ var player = null; var boss = null; var ui = null; var storage = null; var isNewBossPlusMode = false; var game = null; var gameContainer = "gameContainer"; // ID elementu HTML, w którym będzie wyświetlana gra var gameOverReasonIsDeath = true; // true jeśli game over z powodu śmierci, false jeśli z powodu czasu w Boss+ /**** * Game state manager ****/ var gameState = function () { var self = {}; self.currentState = "loading"; // Initial state self.changeState = function (newState) { console.log("Changing state from", self.currentState, "to", newState); // Log state changes self.currentState = newState; // Manage visibility of game elements based on state // These position/visibility methods should be in gameState or UI, not individual element updates self.positionElements(); // Call positionElements on state change // Handle specific state transitions if (self.currentState === "title") { // Clear any game elements from previous attempts if necessary if (game) { game.removeChildren(); // Remove all children from the game container // Do not destroy game here, it's handled in createGame } // Ensure player and boss are null when returning to title player = null; boss = null; ui = null; // UI will be recreated in createGame if returning from game over // Ensure attacks are cleared if (boss && boss.attacks) { boss.attacks.forEach(function (attack) { if (attack.visual && attack.visual.destroy && !attack.visual.destroyed) { attack.visual.destroy(); } }); boss.attacks = []; } // If boss object is destroyed, self.attacks check might fail, add a check for that // Display title screen elements // In this simple example, we just show the start button via positionElements } else if (self.currentState === "game") { // Start the game loop when entering game state // The gameLoop is already running based on LK.init settings (60fps) // Player and Boss are created just before changing to 'game' state // Reset player/boss health or properties if necessary (or do it in their constructors) if (player) { player.health = storage.maxHearts; // Reset player health // ui.updateHearts(player.health, storage.maxHearts); // Update UI immediately } if (boss) { boss.health = boss.maxHealth; // Reset boss health // ui.updateBossHealth(boss.health, boss.maxHealth); // Update UI immediately boss.attackCooldown = 60; // Initial delay before first boss attack (1 second at 60fps) boss.stunned = false; // Ensure boss is not stunned boss.repositioning = false; // Ensure boss is not repositioning boss.dead = false; // Ensure boss is not dead boss.phase = 1; // Reset boss phase boss.attackSpeedMultiplier = 1; // Reset attack speed multiplier boss.attacks = []; // Clear any lingering attacks // Reset boss graphic state if needed (e.g., tint) boss.tint = 0xFFFFFF; // Reset tint } } else if (self.currentState === "gameOver") { // Stop game loop? LK manages this, or we can stop updates manually in gameLoop // In this example, gameLoop checks gameState.currentState // Display game over screen elements (handled by positionElements) // Stop boss attacks explicitly if boss exists and has a method for it if (boss) { boss.attackCooldown = 9999; // Prevent new attacks // Ensure existing attacks are cleaned up in boss.update when state changes } // Stop player movement, etc. (handled by player.update checking gameState.currentState) // Clean up game elements from screen? gameState.positionElements might hide them. } else if (self.currentState === "grillScreen") { // Similar cleanup/display logic for grill screen if (boss) { boss.attackCooldown = 9999; // Prevent new attacks } // Ensure existing attacks are cleaned up if (boss && boss.attacks) { boss.attacks.forEach(function (attack) { if (attack.visual && attack.visual.destroy && !attack.visual.destroyed) { attack.visual.destroy(); } }); boss.attacks = []; } // Hide player and boss (handled by positionElements) } }; self.positionElements = function () { // This function manages the visibility and potentially position of game elements based on the current state // It should be called whenever the state changes. var startButton = LK.getObjectById("startButton"); // Przykład pobierania przycisku var bossHpBar = LK.getObjectById("bossHpBar"); var playerHearts = LK.getObjectById("playerHearts"); // Zakładając, że UI ma kontener na serca var gameOverMessage = LK.getObjectById("gameOverMessage"); // Przykład wiadomości game over var grillMenu = LK.getObjectById("grillMenu"); // Przykład menu grill screen // Visibility logic if (startButton) { startButton.visible = self.currentState === "title"; } // Pasek HP bossa widoczny tylko w stanie "game" (lub game over po czasie w Boss+) if (bossHpBar) { bossHpBar.visible = self.currentState === "game" || self.currentState === "gameOver" && !gameOverReasonIsDeath && isNewBossPlusMode; } // Serca gracza widoczne tylko w stanie "game" if (playerHearts) { playerHearts.visible = self.currentState === "game"; } if (gameOverMessage) { gameOverMessage.visible = self.currentState === "gameOver" && gameOverReasonIsDeath; } // Game over tylko ze śmierci if (grillMenu) { grillMenu.visible = self.currentState === "grillScreen" || self.currentState === "gameOver" && !gameOverReasonIsDeath && isNewBossPlusMode; } // Menu grill screen lub game over po czasie // Show player and boss only in game state if (player) { player.visible = self.currentState === "game" || self.currentState === "gameOver" || self.currentState === "grillScreen"; } // Pokaż gracza w game, game over, grill screen if (boss) { boss.visible = self.currentState === "game" || self.currentState === "gameOver" || self.currentState === "grillScreen"; } // Pokaż bossa w game, game over, grill screen }; self.gameOver = function () { var reasonIsDeath = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; gameOverReasonIsDeath = reasonIsDeath; // Zapisz przyczynę game over self.changeState("gameOver"); // Wyświetl wiadomość Game Over lub Grill Screen w zależności od przyczyny i trybu (zajmie się tym positionElements) // Tutaj można dodać logikę czyszczenia obiektów, zatrzymania muzyki itp. LK.getSound('playerHit').stop(); // Stop player hit sound if it's playing }; self.showGrillScreen = function () { self.changeState("grillScreen"); // Logic for showing the grill screen }; // Metody zmiany stanu dla przycisków self.startGame = function () { var newBossPlus = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; isNewBossPlusMode = newBossPlus; // Set the mode storage.newBossPlusMode = isNewBossPlusMode; // Save mode to storage // Wyczyść poprzednią grę i stwórz nową instancję createGame(); // This function now contains a setTimeout delay // Change state to game is now inside the setTimeout in createGame() // self.changeState("game"); // MOVED INSIDE TIMEOUT IN createGame }; self.returnToTitle = function () { // Clean up game elements before returning to title if (game) { game.removeChildren(); // Remove all display objects from the game container // Destroy player, boss, ui objects explicitly to clear references and updates if (player && player.destroy && !player.destroyed) { player.destroy(); } if (boss && boss.destroy && !boss.destroyed) { boss.destroy(); } if (ui && ui.destroy && !ui.destroyed) { ui.destroy(); } player = null; boss = null; ui = null; // game.destroy(); // Do not destroy game container itself, it's reused } // Clean up any lingering attacks if Boss object was null if (boss && boss.attacks) { // This check is redundant if boss is null, but safe boss.attacks.forEach(function (attack) { if (attack.visual && attack.visual.destroy && !attack.visual.destroyed) { attack.visual.destroy(); } }); boss.attacks = []; } self.changeState("title"); }; return self; }(); // End Player class /**** * UI object ****/ var UI = function () { var self = {}; // Create UI elements (depend on assets/shapes) self.bossHpBar = LK.getAsset('bossHpbar', {}); self.bossHpBar.x = 1024 - self.bossHpBar.width / 2; // Center the bar self.bossHpBar.y = 50; // Position near top self.bossHpBar.visible = false; // Hide initially self.playerHearts = new Container(); // Container for player hearts // Hearts will be added as children to this container in updateHearts self.playerHearts.x = 100; // Position the hearts container self.playerHearts.y = 50; self.playerHearts.visible = false; // Hide initially // Create start button (depends on asset/shape) self.startButton = LK.getAsset('button_bg', {}); // Example shape button self.startButton.x = 1024; // Center the button self.startButton.y = 1366; // Position it self.startButton.anchorX = 0.5; self.startButton.anchorY = 0.5; self.startButton.visible = false; // Hide initially // Add text to start button (depends on font/text rendering) self.startButtonText = new Text2("Start Game", { fill: 0x000000, size: 40, font: "Arial", anchorX: 0.5, anchorY: 0.5 }); self.startButton.addChild(self.startButtonText); // Add text as child of button // Add event listener to start button self.startButton.on("click", function () { if (gameState.currentState === "title") { gameState.startGame(); // Start game in standard mode } }); // Create Boss+ button (depends on asset/shape) self.newBossPlusButton = LK.getAsset('button_bg', {}); // Example shape button self.newBossPlusButton.x = 1024; // Center self.newBossPlusButton.y = 1500; // Position below start self.newBossPlusButton.anchorX = 0.5; self.newBossPlusButton.anchorY = 0.5; self.newBossPlusButton.visible = false; // Add text to Boss+ button self.newBossPlusButtonText = new Text2("NEW BOSS+", { fill: 0x000000, size: 40, font: "Arial", anchorX: 0.5, anchorY: 0.5 }); self.newBossPlusButton.addChild(self.newBossPlusButtonText); // Add event listener to Boss+ button self.newBossPlusButton.on("click", function () { if (gameState.currentState === "title") { gameState.startGame(true); // Start game in Boss+ mode } }); // Create Game Over message (depends on text rendering) self.gameOverMessage = new Text2("Game Over!", { fill: 0xFF0000, size: 80, font: "Arial", anchorX: 0.5, anchorY: 0.5, x: 1024, // Center X y: 1366, // Center Y visible: false // Hide initially }); // Create Grill Screen menu (depends on shape) self.grillMenu = LK.getAsset('grillMenu', { anchorX: 0.5, anchorY: 0.5 }); self.grillMenu.x = 1024; self.grillMenu.y = 1366; self.grillMenu.visible = false; // Hide initially // Add buttons/text to Grill Screen if needed // Add all UI elements to the game container (depth/layering handled by addChild order or setChildIndex) // Order matters for layering: background first, then game objects, then UI on top // Assuming UI should be on top of everything else in the 'game' container // Add UI elements AFTER adding player, boss, etc. in createGame // Or add them here and manage z-index // Let's add them here and assume later added elements are on top by default or managed by setChildIndex self.updateBossHealth = function (currentHp, maxHp) { // Ensure maxHp is at least 1 to prevent division by zero var safeMaxHp = Math.max(1, maxHp); // Calculate width based on health percentage var hpPercentage = currentHp / safeMaxHp; // Assuming original bossHpBar width was 800 self.bossHpBar.scaleX = hpPercentage; // Adjust position if anchor is not 0,0 to keep the bar filling from left // If anchorX is 0.5, the bar scales from the center. Need to adjust x. self.bossHpBar.x = 1024 - self.bossHpBar.width * self.bossHpBar.scaleX / 2; }; self.updateHearts = function (currentHearts, maxHearts) { // Clear existing heart graphics self.playerHearts.removeChildren(); // Add heart graphics based on currentHearts var heartSize = 40; // Match heart asset size var padding = 10; // Spacing between hearts for (var i = 0; i < maxHearts; i++) { var heartGraphic = LK.getShape('heart', {}); // Use heart shape asset // Position hearts horizontally within the container heartGraphic.x = i * (heartSize + padding); heartGraphic.y = 0; // All on the same vertical level // Tint heart based on current health if (i < currentHearts) { heartGraphic.tint = 0xFF0000; // Full heart color (Red) } else { heartGraphic.tint = 0x888888; // Empty heart color (Grayish) } self.playerHearts.addChild(heartGraphic); // Add heart to the container } // Position the container is done in gameState.positionElements or createGame }; // Add UI elements to game container in createGame after player/boss // This is handled in the modified createGame function self.update = function () { // UI elements are mostly passive and updated by boss/player health changes // No continuous update needed for UI elements themselves in this example, // but UI object could have update logic for animations, etc. }; return self; }(); // End UI object /**** * Boss class ****/ var Boss = Container.expand(function () { var self = Container.call(this); // Definicje list klatek dla fireballi - Zdefiniowane raz na początku klasy Boss var circleFrames = [LK.getAsset('fireball0', {}), LK.getAsset('fireball00', {}), LK.getAsset('fireball01', {}), LK.getAsset('fireball02', {}), LK.getAsset('fireball03', {}), LK.getAsset('fireball04', {}), LK.getAsset('fireball05', {}), LK.getAsset('fireball06', {}), LK.getAsset('fireball07', {}), LK.getAsset('fireball08', {}), LK.getAsset('fireball09', {}), LK.getAsset('fireball1', {}), LK.getAsset('fireball10', {}), LK.getAsset('fireball11', {}), LK.getAsset('fireball12', {}), LK.getAsset('fireball13', {}), LK.getAsset('fireball14', {})]; var lineFrames = [LK.getAsset('fireball2', {}), LK.getAsset('fireball3', {}), LK.getAsset('fireball4', {}), LK.getAsset('fireball5', {}), LK.getAsset('fireball6', {}), LK.getAsset('fireball7', {}), LK.getAsset('fireball8', {}), LK.getAsset('fireball9', {}), LK.getAsset('fireball15', {}), LK.getAsset('fireball16', {})]; // *** MODYFIKACJA: Dodaj grafikę bossIdle jako DZIECKO obiektu bossa (self) *** // Używamy attachAsset, który automatycznie dodaje jako dziecko do self self.bossGraphics = self.attachAsset('bossIdle', { // Dziecko self anchorX: 0.5, anchorY: 0.5 // Pozycja relatywna na 0,0 jest domyślna i poprawna przy anchorX/Y 0.5 }); // Dodajemy funkcje animacji // Ta funkcja tworzy obiekt SpriteAnimation dla animacji ataku Bossa (nie fireballi) self.createBossAttackAnim = function () { var frames = [LK.getAsset('bossAttack0', {}), LK.getAsset('bossAttack1', {}), LK.getAsset('bossAttack2', {}), LK.getAsset('bossAttack3', {})]; var bossAttackAnim = new SpriteAnimation({ frames: frames, frameDuration: 100, // Czas trwania klatki animacji ataku Bossa (w ms) loop: false, anchorX: 0.5, anchorY: 0.5, // Pozycja animacji jako dziecka bossa - ustawiamy na 0,0 relatywnie do rodzica (self) x: 0, // MODIFIED y: 0 // MODIFIED }); return bossAttackAnim; }; // Zmieniamy sygnaturę funkcji, przyjmuje teraz typ ataku (do decydowania o grafice Bossa) // Ta funkcja zarządza grafiką Bossa (animacja ataku Bossa lub grafika idle) self.playBossAttackAnim = function (attackType) { // <--- DODANO PARAMETR // Upewnij się, że poprzednia animacja ataku Bossa jest całkowicie usunięta, zanim zaczniemy nową if (self.bossAttackAnim) { self.bossAttackAnim.stop(); // Zatrzymujemy animację // Usuń poprzednią animację z jej rodzica (Bossa) przed zniszczeniem // Sprawdź, czy rodzicem jest self przed próbą usunięcia if (self.bossAttackAnim.parent === self) { // MODIFIED check self.bossAttackAnim.parent.removeChild(self.bossAttackAnim); } else if (self.bossAttackAnim.parent) { // Fallback na wypadek, gdyby rodzic był inny self.bossAttackAnim.parent.removeChild(self.bossAttackAnim); } self.bossAttackAnim.destroy(); // Usuwamy poprzednią animację self.bossAttackAnim = null; // Ustawiamy na null po zniszczeniu } // *** Zmieniona logika: Zmiana grafiki bossa tylko jeśli to NIE jest atak szarży (attackType 2) *** if (attackType !== 2) { // Jeśli to atak koła (0) lub linii (1) // Usuń obecną główną grafikę bossa (idle) jako dziecko bossa // Sprawdź, czy rodzicem jest self przed próbą usunięcia if (self.bossGraphics && self.bossGraphics.parent === self) { // MODIFIED check self.bossGraphics.parent.removeChild(self.bossGraphics); } else if (self.bossGraphics && self.bossGraphics.parent) { // Fallback self.bossGraphics.parent.removeChild(self.bossGraphics); } self.bossGraphics = null; // Wyczyść referencję // Tworzymy nową animację bossa i dodajemy ją JAKO DZIECKO BOSSA self.bossAttackAnim = self.addChild(self.createBossAttackAnim()); // *** MODIFIED: DODANO DO self! *** // Pozycja animacji jako dziecka bossa jest już ustawiona na 0,0 w createBossAttackAnim // Metoda update dla TEJ NOWEJ animacji (definiowana tylko dla ataków 0 i 1) self.bossAttackAnim.update = function () { // Sprawdź, czy ten obiekt animacji jest nadal aktywny self.bossAttackAnim bossa // Użyj 'this' dla obiektu animacji, 'self' dla obiektu Boss if (self.bossAttackAnim !== this || !this.playing || this.frames.length === 0) { // Jeśli już nie jesteśmy aktualną animacją lub nie gramy, zakończ return; } this.frameTimer++; if (this.frameTimer >= this.frameDuration / (1000 / 60)) { // Przelicz ms na klatki gry (przy 60fps) this.frameTimer = 0; this.removeChildren(); // Usuń sprite klatki z kontenera animacji (z obiektu animacji) this.currentFrame++; if (this.currentFrame >= this.frames.length) { // Animacja skończona, wracamy do idle // *** Dodaj grafikę idle z powrotem JAKO DZIECKO BOSSA i ustaw self.bossGraphics *** self.bossGraphics = self.addChild(LK.getAsset('bossIdle', { // *** MODIFIED: DODANO DO self! *** anchorX: 0.5, anchorY: 0.5, x: 0, // Pozycja relatywna y: 0 // Pozycja relatywna })); // *** Usuń obiekt animacji z jego rodzica (Bossa) i zniszcz go *** // Sprawdź, czy rodzicem jest self przed próbą usunięcia if (this.parent === self) { // MODIFIED check this.parent.removeChild(this); // Użyj 'this' dla obiektu animacji } else if (this.parent) { // Fallback this.parent.removeChild(this); } this.destroy(); // Zniszcz obiekt animacji self.bossAttackAnim = null; // Wyczyść referencję w obiekcie bossa } else { this.addChild(this.frames[this.currentFrame]); // Dodaj sprite następnej klatki (do obiektu animacji) } } }; } // Else (attackType === 2, czyli chargeAttack): playBossAttackAnim nic nie robi z grafiką. // chargeAttack sam zadba o ustawienie grafiki 'idle' JAKO DZIECKO BOSSA. }; self.health = 100; // Domyślne zdrowie bossa (nadpisane w startGame) self.maxHealth = 100; // Domyślne max zdrowia bossa (nadpisane w startGame) self.speed = 5; // Prędkość ruchu bossa self.attackCooldown = 0; // Czas do następnego ataku (w klatkach gry) self.attackPattern = 0; self.attacks = []; // Aktywne ataki bossa (obiekty JS z pozycją, promieniem, itp.) self.stunned = false; self.stunDuration = 0; self.dead = false; self.phase = 1; self.attackSpeedMultiplier = 1; // Mnożnik prędkości ataków (1 = normalna, < 1 = szybsza) self.repositioning = false; // Flaga informująca czy boss się przemieszcza po szarży // startAttackPattern pozostaje jak w poprzedniej poprawionej wersji self.startAttackPattern = function () { // !!! Ustaw tymczasowy cooldown na początku, ZANIM sprawdzisz warunki powrotu !!! // To zapobiegnie natychmiastowemu ponownemu wywołaniu, jeśli metoda wróci wcześnie self.attackCooldown = 1; // Ustaw minimalny cooldown (np. 1 klatka) od razu // Sprawdź warunki wczesnego powrotu: boss jest martwy, gra nie jest w stanie "game" LUB boss jest w stanie "repositioning" if (self.dead || gameState.currentState !== "game" || self.repositioning) { // Dodano || self.repositioning return; // Jeśli warunek spełniony, wróć } // Decydujemy O WZORCU ATAKU przed zmianą grafiki bossa self.attackPattern = (self.attackPattern + 1) % 3; // Cykl wzorców ataków (0, 1, 2) // 🔥 Przekazujemy typ ataku do playBossAttackAnim - ta funkcja teraz decyduje CZY zmienić grafikę bossa self.playBossAttackAnim(self.attackPattern); // <--- PRZEKAZUJEMY TYP ATAKU // Następnie wywołujemy właściwą funkcję ataku (chargeAttack itp.) // Logika graficzna dla szarży jest TERAZ W chargeAttack switch (self.attackPattern) { case 0: self.circleAttack(); // Wywołaj atak koła break; case 1: self.lineAttack(); // Wywołaj atak linii break; case 2: self.chargeAttack(); // Wywołaj atak szarży break; } // Ustaw właściwy czas odnowienia dla następnego ataku self.attackCooldown = (90 + Math.floor(Math.random() * 60)) * self.attackSpeedMultiplier; // 1.5-2.5 seconds * multiplier }; // Zmodyfikowana funkcja createAttack - NIE nadpisuje lokalnie spriteAnim.update (jak w poprzedniej próbie) // Kolejność argumentów: x, y, duration (ms), activationFrame (index klatki), frameDurationMs (ms), framesList (opcjonalne) // Logika aktywacji kolizji (isActive) jest w Boss.update self.createAttack = function (x, y, duration, activationFrame, frameDurationMs, framesList) { // Użyj przekazanej framesList, domyślną oryginalną jeśli nie przekazana var frames = framesList || [LK.getAsset('fireball0', {}), LK.getAsset('fireball00', {}), LK.getAsset('fireball01', {}), LK.getAsset('fireball02', {}), LK.getAsset('fireball03', {}), LK.getAsset('fireball04', {}), LK.getAsset('fireball05', {}), LK.getAsset('fireball06', {}), LK.getAsset('fireball07', {}), LK.getAsset('fireball08', {}), LK.getAsset('fireball09', {}), LK.getAsset('fireball1', {}), LK.getAsset('fireball10', {}), LK.getAsset('fireball11', {}), LK.getAsset('fireball12', {}), LK.getAsset('fireball13', {}), LK.getAsset('fireball14', {})]; // console.log("CreateAttack called at:", x, y, " Frames array:", frames); // Debug log - można usunąć po naprawie // if (!frames || frames.length === 0 || frames.some(f => f === null || typeof f === 'undefined' || !f.texture)) { // Debug check - można usunąć po naprawie // console.error("Frames array is empty or contains invalid assets! Attack creation might fail."); // Debug log - można usunąć po naprawie // } var spriteAnim = game.addChild(new SpriteAnimation({ // Wizualizacja fireballa jest dodawana do kontenera 'game' frames: frames, frameDuration: frameDurationMs, // Użyj wartości przekazanej do konstruktora SpriteAnimation loop: false, // Animacja nie zapętla się anchorX: 0.5, anchorY: 0.5, x: x, y: y })); spriteAnim.scaleX = 1.6; // Ręczne skalowanie wizualizacji spriteAnim.scaleY = 1.6; var attack = { // Obiekt logiczny ataku x: x, y: y, radius: 60, // Promień kolizji visual: spriteAnim, // Referencja do wizualizacji (SpriteAnimation) lifeTime: Math.floor(duration * (60 / 1000)), // Czas życia w klatkach gry (przy 60fps) isActive: false, // Flaga aktywności kolizji, domyślnie false activationFrame: activationFrame // Przechowuj activationFrame w obiekcie ataku }; // USUNIĘTO: Lokalna definicja funkcji spriteAnim.update self.attacks.push(attack); // Dodaj obiekt ataku logicznego do tablicy bossa }; // Zmodyfikowana funkcja circleAttack - Z pętlą setTimeout delay (jak w poprzedniej próbie, która dała wiele pocisków) self.circleAttack = function () { LK.getSound('bossAttack').play(); // Odtwórz dźwięk ataku var center = { // Ustaw środek koła na pozycji bossa x: self.x, y: self.y }; var count = isNewBossPlusMode ? 12 : 8; // Liczba pocisków w ataku (więcej w New Boss+) var radius = 300; // Promień koła, na którym rozmieszczone są pociski var attackLifeTime = isNewBossPlusMode ? 2000 : 3000; // Czas życia pocisku w ms (krótszy w New Boss+?) // circleFrames array jest zdefiniowane raz na początku klasy Boss // Pętla tworząca wiele pocisków rozmieszczonych w kole Z MINIMALNYM OPÓŹNIENIEM DLA KAŻDEGO for (var i = 0; i < count; i++) { // Iteruj tyle razy, ile ma być pocisków (count) var angle = i / count * Math.PI * 2; // Oblicz kąt dla bieżącego pocisku (równo rozmieszczone na okręgu) var posX = center.x + Math.cos(angle) * radius; // Oblicz współrzędną X na okręgu var posY = center.y + Math.sin(angle) * radius; // Oblicz współrzędną Y na okręgu // Dodaj minimalne opóźnienie (np. 20ms) DO KAŻDEGO pocisku var delay = i * 20 + 20; // Zapewnij, że nawet pierwszy pocisk ma opóźnienie // Użyj setTimeout do stworzenia każdego pocisku po małym opóźnieniu LK.setTimeout(function (x, y) { // Używamy closure do "zamknięcia" wartości x, y (frames jest globalne/dostępne) return function () { // Sprawdź czy boss nadal istnieje i gra jest w stanie 'game' zanim stworzysz atak po opóźnieniu if (self && !self.dead && gameState.currentState === "game") { // Wywołaj funkcję createAttack dla tego pocisku z zapamiętaną pozycją i parametrami // Kolejność argumentów createAttack: x, y, duration(ms), activationFrame(index), frameDurationMs(ms), framesList // activationFrame = 8 (aktywacja od klatki fireball08) // frameDurationMs = 250ms (przykład prędkości) // framesList = circleFrames (używamy zmiennej zdefiniowanej poza funkcją) self.createAttack(x, y, attackLifeTime, 8, 250, circleFrames); // Używamy 250ms dla frameDurationMs } }; }(posX, posY), delay); // Przekaż aktualne posX, posY do closure } }; // *** START Zmodyfikowana funkcja lineAttack - Używa synchronicznej pętli i wywołuje nową createAttack *** self.lineAttack = function () { LK.getSound('bossAttack').play(); // Odtwórz dźwięk ataku // Tworzy linię ataków if (!player) { return; } var targetX = player.x; var targetY = player.y; var count = isNewBossPlusMode ? 8 : 5; // Liczba pocisków w linii var attackLifeTime = isNewBossPlusMode ? 1500 : 2000; // Czas życia pocisku w ms var delayBetweenAttacks = isNewBossPlusMode ? 100 : 200; // Opóźnienie między pociskami w ms // lineFrames array jest zdefiniowane raz na początku klasy // Pętla tworząca pociski w linii z opóźnieniem (jak w souls5.txt) for (var i = 0; i < count; i++) { var t = i / (count - 1); // Współczynnik interpolacji var posX = self.x + (targetX - self.x) * t; // Interpolowana pozycja X var posY = self.y + (targetY - self.y) * t; // Interpolowana pozycja Y var delay = i * delayBetweenAttacks * self.attackSpeedMultiplier; // Opóźnienie przed stworzeniem pocisku, skalowane LK.setTimeout(function (x, y) { // Używamy closure do przekazania pozycji return function () { // Sprawdź warunki przed stworzeniem ataku po opóźnieniu if (self && !self.dead && gameState.currentState === "game") { // Wywołaj funkcję createAttack // Kolejność argumentów createAttack: x, y, duration(ms), activationFrame(index), frameDurationMs(ms), framesList // activationFrame = 3 (indeks 'fireball5' na liście lineFrames) // frameDurationMs = 100ms (przykład prędkości) // framesList = lineFrames (używamy zmiennej zdefiniowanej poza funkcją) self.createAttack(x, y, attackLifeTime, 3, 100, lineFrames); // Przekaż parametry } }; }(posX, posY), delay); // Przekaż aktualne posX, posY do closure } }; // *** END Zmodyfikowana funkcja lineAttack *** // *** START Zmodyfikowana funkcja chargeAttack - tworzy pociski podczas szarży *** // Ta funkcja zarządza ruchem bossa (szarżą) i tworzy pociski wzdłuż ścieżki szarży self.chargeAttack = function () { LK.getSound('bossAttack').play(); // Odtwórz dźwięk szarży // Upewnij się, że gracz istnieje if (!player) { return; } // Obsługa grafiki bossa podczas szarży (pokazuje grafikę idle) if (self.bossAttackAnim) { self.bossAttackAnim.stop(); if (self.bossAttackAnim.parent === self) { self.bossAttackAnim.parent.removeChild(self.bossAttackAnim); } else if (self.bossAttackAnim.parent) { self.bossAttackAnim.parent.removeChild(self.bossAttackAnim); } self.bossAttackAnim.destroy(); self.bossAttackAnim = null; } if (self.bossGraphics && self.bossGraphics.parent === self) { self.bossGraphics.parent.removeChild(self.bossGraphics); } else if (self.bossGraphics && self.bossGraphics.parent) { self.bossGraphics.parent.removeChild(self.bossGraphics); } self.bossGraphics = self.addChild(LK.getAsset('bossIdle', { anchorX: 0.5, anchorY: 0.5, x: 0, y: 0 })); // Oblicz kierunek do gracza i parametry szarży var dx = player.x - self.x; var dy = player.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { dx /= distance; dy /= distance; } var startX = self.x; // Pozycja początkowa szarży var startY = self.y; var chargeDistance = isNewBossPlusMode ? 700 : 500; // Dystans szarży var chargeDuration = isNewBossPlusMode ? // Czas trwania szarży 600 : 800; var attacksOnPathCount = isNewBossPlusMode ? 8 : 5; // Liczba pocisków wzdłuż ścieżki var attackLifeTime = isNewBossPlusMode ? 1000 : 1500; // Czas życia pocisku // Tween (animacja ruchu) bossa podczas szarży tween(self, { x: self.x + dx * chargeDistance, y: self.y + dy * chargeDistance }, { duration: chargeDuration * self.attackSpeedMultiplier, // Czas trwania, skalowany easing: tween.easeIn, // Krzywa animacji onFinish: function onFinish() { // Po zakończeniu szarży if (self && !self.dead && gameState.currentState === "game") { // Faza repozycji self.repositioning = true; LK.setTimeout(function () { if (self && !self.dead) { self.repositioning = false; } }, 500 * self.attackSpeedMultiplier); // Tween powrotu do pozycji startowej tween(self, { x: startX, y: startY }, { duration: 1000 * self.attackSpeedMultiplier, easing: tween.easeOut }); // Utworzenie ataków (fireballi) wzdłuż ścieżki szarży // Fireballe ze szarży używają domyślnej listy klatek z createAttack (circleFrames) for (var i = 0; i < attacksOnPathCount; i++) { var t = i / (attacksOnPathCount - 1); // Współczynnik interpolacji var currentChargeX = self.x; // Aktualna pozycja bossa (koniec szarży) var currentChargeY = self.y; var posX = startX + (currentChargeX - startX) * t; // Interpolowana pozycja X var posY = startY + (currentChargeY - startY) * t; // Interpolowana pozycja Y // Utwórz atak // Kolejność argumentów createAttack: x, y, duration(ms), activationFrame(index), frameDurationMs(ms), framesList // activationFrame = 4 (domyślna klatka aktywacji dla tych pocisków) // frameDurationMs = 140ms (domyślna prędkość) // framesList = circleFrames (używamy listy klatek ataku koła) self.createAttack(posX, posY, attackLifeTime, 4, 140, circleFrames); // Przekaż parametry } } } }); }; self.takeDamage = function (amount) { // Funkcja obsługująca otrzymywanie obrażeń przez bossa if (self.dead || gameState.currentState !== "game") { // Boss otrzymuje obrażenia tylko w stanie gry return; } self.health -= amount; // Zmniejsz zdrowie self.health = Math.max(0, self.health); // Upewnij się, że zdrowie nie spadnie poniżej zera LK.effects.flashObject(self, 0xFFFFFF, 200); // Efekt błysku if (!isNewBossPlusMode) { // Przejście fazy bossa przy 50% zdrowia tylko w standardowym trybie if (self.health <= self.maxHealth / 2 && self.phase === 1) { self.phase = 2; // Zmień fazę na 2 self.speed += 2; // Boss staje się szybszy (ruch) self.attackSpeedMultiplier *= 0.8; // Boss atakuje nieco szybciej tween(self, { tint: 0xFF3300 // Pomarańczowy/czerwony odcień }, { duration: 1000, easing: tween.easeInOut }); } } if (self.health <= 0) { self.die(); // Wywołaj funkcję śmierci } // ui.updateBossHealth jest w game.update }; self.die = function () { // Funkcja obsługująca śmierć bossa if (self.dead || gameState.currentState !== "game") { return; } self.dead = true; // Ustaw flagę śmierci if (!isNewBossPlusMode) { // Dźwięk zwycięstwa tylko dla STANDARDOWEGO trybu LK.getSound('victory').play(); } // Wyczyść pozostałe ataki przy śmierci bossa self.attacks.forEach(function (attack) { if (attack.visual && attack.visual.destroy && !attack.visual.destroyed) { attack.visual.destroy(); } }); self.attacks = []; // Wyczyść tablicę ataków logicznych // Animacja śmierci bossa (zanikanie i powiększanie) tween(self, { alpha: 0, scaleX: 2, scaleY: 2 }, { duration: 2000, easing: tween.easeOut, onFinish: function onFinish() { // Po zakończeniu animacji śmierci if (self && self.destroy && !self.destroyed) { self.destroy(); // Zniszcz obiekt bossa } storage.bossesDefeated = (storage.bossesDefeated || 0) + 1; // Zwiększ licznik pokonanych bossów // ZAWSZE przechodzimy do Grill Screena gameState.showGrillScreen(); } }); }; self.update = function () { // Główna metoda aktualizacji bossa // Aktualizuj tylko w stanie gry if (gameState.currentState !== "game") { if (!self.dead && self.attacks) { // Jeśli zmieniono stan i boss nie umiera, wyczyść ataki self.attacks.forEach(function (attack) { if (attack.visual && attack.visual.destroy && !attack.visual.destroyed) { attack.visual.destroy(); } }); self.attacks = []; } return; } // Nie aktualizuj jeśli boss jest martwy (pozwól animacji śmierci działać) if (self.dead) { return; } // --- LOGIKA RUCHU BOSS --- // Poruszaj się w kierunku gracza jeśli spełnione warunki if (!self.repositioning && self.attackCooldown > 30 && player && !player.dead) { var dx = player.x - self.x; var dy = player.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); var moveSpeed = self.speed; if (distance > 150) { // Poruszaj się tylko jeśli gracz jest dalej niż 150 jednostek var moveX = dx / distance * moveSpeed; var moveY = dy / distance * moveSpeed; var nextX = self.x + moveX; var nextY = self.y + moveY; // Ograniczenia areny var halfWidth = self.width * self.scaleX / 2; var halfHeight = self.height * self.scaleY / 2; var minX = 100 + halfWidth; var maxX = 2048 - 100 - halfWidth; var minY = 100 + halfHeight; var maxY = 2732 - 100 - halfHeight; self.x = Math.max(minX, Math.min(nextX, maxX)); self.y = Math.max(minY, Math.min(nextY, maxY)); // Grafika jako dziecko podąża automatycznie. } } // --- KONIEC LOGIKA RUCHU BOSS --- // --- OBSŁUGA ATAKÓW BOSS (Kolizje i Czas Życia Pocisków) --- // Aktualizuj istniejące ataki bossa (pociski) i sprawdzaj kolizje z graczem for (var i = self.attacks.length - 1; i >= 0; i--) { var attack = self.attacks[i]; // Aktualizuj flagę isActive na podstawie aktualnej klatki visual i przechowywanego activationFrame // Sprawdź czy visual istnieje i ma currentFrame if (attack.visual && typeof attack.visual.currentFrame !== 'undefined') { if (attack.visual.currentFrame >= attack.activationFrame) { attack.isActive = true; // Aktywuj kolizję } else { attack.isActive = false; // Kolizja nieaktywna } } else { attack.isActive = false; } if (attack.lifeTime > 0) { // Zmniejszaj czas życia attack.lifeTime--; } // Sprawdź kolizję z graczem jeśli spełnione warunki if (attack.isActive && player && !player.dead && !player.invulnerable && attack.visual && !attack.visual.destroyed) { var dx_p = player.x - attack.x; var dy_p = player.y - attack.y; var distance_p = Math.sqrt(dx_p * dx_p + dy_p * dy_p); var playerRadius_p = player.width / 2; var attackRadius = attack.radius; if (distance_p < playerRadius_p + attackRadius) { player.takeDamage(1); // Gracz otrzymuje obrażenia if (attack.visual && attack.visual.destroy) { attack.visual.destroy(); } self.attacks.splice(i, 1); // Usuń trafiony atak // break; } } // Usuń atak, jeśli skończył mu się czas życia LUB wizualizacja zniszczona if (attack.lifeTime <= 0 || attack.visual && attack.visual.destroy || attack.visual && attack.visual.destroyed) { // Dodano trzeci warunek dla pewności if (attack.visual && attack.visual.destroy && !attack.visual.destroyed) { attack.visual.destroy(); } self.attacks.splice(i, 1); } } // --- KONIEC OBSŁUGA ATAKÓW BOSS --- if (self.attackCooldown > 0) { // Zmniejszaj cooldown self.attackCooldown--; } // Sprawdź, czy nadszedł czas na nowy atak if (self.attackCooldown <= 0 && !self.repositioning) { self.startAttackPattern(); } }; return self; // Zwróć instancję obiektu Boss })(); // End Boss class /**** * Game creation and loop ****/ // Global variables for game objects // Already defined at the beginning: var player, boss, ui, game, gameContainer, etc. var createGame = function createGame() { // Upewnij się, że poprzednia instancja gry jest posprzątana if (game) { game.destroy(); game = null; } game = new DisplayObjectContainer(); // Stwórz główny kontener gry LK.add(game); // Dodaj kontener gry do frameworka LK // Stwórz i dodaj podstawowe elementy tła od razu (nie zależą od assetów fireballi) gameState.createWalls(); // Tworzy i dodaje ściany gameState.createFloor(); // Tworzy i dodaje podłogę // *** MODYFIKACJA: Dodaj opóźnienie setTimeout przed tworzeniem elementów zależnych od assetów *** // Daje to assetom czas na załadowanie po odpaleniu onInit przez LK.init LK.setTimeout(function () { // *** Kod z oryginalnego createGame, który tworzył elementy zależne od assetów, PRZENIESIONY tutaj *** // Stwórz i dodaj gracza (zależy od assetów) player = new Player(); // Klasa Player prawdopodobnie używa assetów game.addChild(player); // Stwórz i dodaj bossa (mocno zależy od assetów dla grafiki i ataków) boss = new Boss(); // Klasa Boss używa wielu assetów game.addChild(boss); // Stwórz i dodaj elementy UI (niektóre elementy UI mogą używać assetów) ui = new UI(); // Klasa UI prawdopodobnie używa assetów (serca, przyciski, itp.) game.addChild(ui); // Add UI elements to the game container (order matters for layering) // Assuming UI should be on top of game elements game.addChild(ui.bossHpBar); game.addChild(ui.playerHearts); game.addChild(ui.startButton); // Start button is visible in title state game.addChild(ui.newBossPlusButton); // Boss+ button is visible in title state game.addChild(ui.gameOverMessage); // Game over message is hidden initially game.addChild(ui.grillMenu); // Grill menu is hidden initially // Start the game state (enables updates, attacks, etc.) // This was the last line in the original createGame gameState.changeState("title"); // Rozpocznij grę w stanie title console.log("Opóźnione kroki tworzenia gry wykonane."); // Opcjonalny log do potwierdzenia odpalenia timeoutu }, 500); // *** CZAS OPÓŹNIENIA (np. 500ms) - Dostosuj w razie potrzeby *** // To jest opóźnienie heurystyczne. Lepszym rozwiązaniem byłby właściwy mechanizm preładowania, jeśli dostępny. // Oryginalne linie kodu po ustawieniach createGame i przed gameState.changeState są teraz wewnątrz timeoutu // gameState.changeState("title"); // This line is moved inside the timeout }; var gameLoop = function gameLoop() { // Główne aktualizacje gry // LK automatycznie wywołuje update na obiektach dodanych do sceny (game) // Możemy dodać tutaj logikę globalną // Na przykład, aktualizacja UI, która nie jest automatycznie wywoływana na obiektach UI, chyba że UI jest DisplayObjectContainer i dodano je do sceny. // Aktualizuj UI niezależnie od stanu gry, bo jego widoczność i zawartość zależą od stanu/danych // Ale tylko jeśli UI zostało stworzone if (ui) { // UI update logic if needed (currently empty) // ui.update(); // Zakładając, że UI ma metodę update // Aktualizuj pasek zdrowia bossa (jeśli boss istnieje) if (boss) { // ui.updateBossHealth(boss.health, boss.maxHealth); // Ta linia była wcześniej, ale lepiej wywoływać ją po zmianie zdrowia bossa // Zaktualizuj UI HP Bossa w game.update, ale tylko gdy HP bossa > 0 (żeby nie migało przy śmierci) // UI HP Boss aktualizowane jest teraz w takeDamage i die Bossa. // Upewnijmy się, że jest aktualizowane też jeśli boss HP > 0. if (boss.health > 0 || gameState.currentState === "gameOver" && !gameOverReasonIsDeath && isNewBossPlusMode) { ui.updateBossHealth(boss.health, boss.maxHealth); } else { // Jeśli boss martwy i nie jest to game over po czasie, ukryj pasek if (!(gameState.currentState === "gameOver" && !gameOverReasonIsDeath && isNewBossPlusMode)) { ui.updateBossHealth(0, 1); // Ukryj pasek } } } else { // Jeśli boss nie istnieje, ukryj pasek (chyba że to wygrana Boss+ przez czas) if (!(gameState.currentState === "gameOver" && !gameOverReasonIsDeath && isNewBossPlusMode)) { // Domyślne maxHP do ukrycia paska to 1 (uniknięcie dzielenia przez 0) ui.updateBossHealth(0, 1); } } // Aktualizuj serca gracza (jeśli gracz istnieje i UI istnieje) if (player) { ui.updateHearts(player.health, storage.maxHearts); } else if (gameState.currentState !== "game" && gameState.currentState !== "gameOver") { // Ukryj serca poza grą/game over ui.updateHearts(0, storage.maxHearts); } // Pozycjonowanie/widoczność elementów UI jest zarządzana przez gameState.positionElements() w metodach zmiany stanu. } // Logika specyficzna dla stanu gry if (gameState.currentState === "game") { if (player) { player.update(); // Aktualizacja gracza (ruch turlania, nietykalność, kolizja turlania z bossem) } if (boss) { boss.update(); // Aktualizacja bossa (ruch, cooldown, tworzenie/usuwanie ataków, kolizje ataków z graczem) } } // Logika game over else if (gameState.currentState === "gameOver") { // Tutaj można dodać logikę game over, np. animację, możliwość restartu // Aktualizacja player i boss nadal jest wywoływana, ale ich metody update powinny sprawdzać stan gry if (player) { player.update(); } // Nadal aktualizuj gracza (np. animacja śmierci) if (boss) { boss.update(); } // Nadal aktualizuj bossa (np. animacja śmierci) // Można dodać logikę przycisków restartu, powrotu do menu itp. } // Logika grill screen else if (gameState.currentState === "grillScreen") { // Tutaj można dodać logikę grill screen, np. animację, możliwość przejścia dalej if (player) { player.update(); } // Nadal aktualizuj gracza (jeśli widoczny) if (boss) { boss.update(); } // Nadal aktualizuj bossa (jeśli widoczny) // Można dodać logikę przycisków przejścia dalej, powrotu do menu itp. } // Rysowanie sceny (wykonywane automatycznie przez LK po gameLoop) }; // Inicjalizacja gry LK.init(gameContainer, { onInit: function onInit() { storage = LK.localStorage; // Initialize storage here after LK.init // Load or set maxHearts from storage if needed, default to 5 storage.maxHearts = storage.maxHearts || 5; // Default max hearts // Determine game mode (Boss+ or Standard) from storage or default isNewBossPlusMode = storage.newBossPlusMode === true; // Default to false if not in storage createGame(); // Call the createGame function to set up the initial game state and objects // Game loop is set up by LK.init to call gameLoop function repeatedly (e.g., 60 times per second) } });
===================================================================
--- original.js
+++ change.js
@@ -589,15 +589,15 @@
// Definicje list klatek dla fireballi - Zdefiniowane raz na początku klasy Boss
var circleFrames = [LK.getAsset('fireball0', {}), LK.getAsset('fireball00', {}), LK.getAsset('fireball01', {}), LK.getAsset('fireball02', {}), LK.getAsset('fireball03', {}), LK.getAsset('fireball04', {}), LK.getAsset('fireball05', {}), LK.getAsset('fireball06', {}), LK.getAsset('fireball07', {}), LK.getAsset('fireball08', {}), LK.getAsset('fireball09', {}), LK.getAsset('fireball1', {}), LK.getAsset('fireball10', {}), LK.getAsset('fireball11', {}), LK.getAsset('fireball12', {}), LK.getAsset('fireball13', {}), LK.getAsset('fireball14', {})];
var lineFrames = [LK.getAsset('fireball2', {}), LK.getAsset('fireball3', {}), LK.getAsset('fireball4', {}), LK.getAsset('fireball5', {}), LK.getAsset('fireball6', {}), LK.getAsset('fireball7', {}), LK.getAsset('fireball8', {}), LK.getAsset('fireball9', {}), LK.getAsset('fireball15', {}), LK.getAsset('fireball16', {})];
// *** MODYFIKACJA: Dodaj grafikę bossIdle jako DZIECKO obiektu bossa (self) ***
- // Używamy LK.getAsset i dodajemy jako dziecko z addChild
- self.bossGraphics = self.addChild(LK.getAsset('bossIdle', {
+ // Używamy attachAsset, który automatycznie dodaje jako dziecko do self
+ self.bossGraphics = self.attachAsset('bossIdle', {
// Dziecko self
anchorX: 0.5,
anchorY: 0.5
// Pozycja relatywna na 0,0 jest domyślna i poprawna przy anchorX/Y 0.5
- }));
+ });
// Dodajemy funkcje animacji
// Ta funkcja tworzy obiekt SpriteAnimation dla animacji ataku Bossa (nie fireballi)
self.createBossAttackAnim = function () {
var frames = [LK.getAsset('bossAttack0', {}), LK.getAsset('bossAttack1', {}), LK.getAsset('bossAttack2', {}), LK.getAsset('bossAttack3', {})];