From 3d97b5ce2ca89dfe2d04e3852ed14dea730eb25d Mon Sep 17 00:00:00 2001 From: "Torsten Schulz (local)" Date: Thu, 28 Aug 2025 12:30:04 +0200 Subject: [PATCH] feat(match3): Erweiterung der Match-Logik mit Regenbogen-Power-ups und Optimierung der Erkennung MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Einführung von Regenbogen-Power-ups, die durch 5er-Matches aktiviert werden. - Anpassung der Logik zur Erkennung und Priorisierung von 5er-Matches vor L-Form-Matches. - Verbesserung der Darstellung und Animationen für neue Power-ups. - Erweiterung der Debug-Ausgaben zur Nachverfolgbarkeit von Matches und Power-ups. - Implementierung neuer Methoden zur Aktivierung und Handhabung von Regenbogen-Power-ups im Spiel. --- frontend/src/views/minigames/Match3Game.vue | 666 ++++++++++++++++---- 1 file changed, 528 insertions(+), 138 deletions(-) diff --git a/frontend/src/views/minigames/Match3Game.vue b/frontend/src/views/minigames/Match3Game.vue index a064d1b..e4bd821 100644 --- a/frontend/src/views/minigames/Match3Game.vue +++ b/frontend/src/views/minigames/Match3Game.vue @@ -92,9 +92,10 @@ 'empty': !tile, 'dragging': draggedTileIndex === index, 'drag-hover': isDragging && adjacentTilesForHover.includes(index), - 'rocket-horizontal': tile && tile.type === 'rocket-horizontal', - 'rocket-vertical': tile && tile.type === 'rocket-vertical', - 'bomb': tile && tile.type === 'bomb' + 'rocket-horizontal': tile && tile.type === 'rocket-horizontal', + 'rocket-vertical': tile && tile.type === 'rocket-vertical', + 'bomb': tile && tile.type === 'bomb', + 'rainbow': tile && tile.type === 'rainbow' }]" :data-index="index" :data-type="tile ? tile.type : null" @@ -1038,15 +1039,61 @@ export default { findMatchesOnBoard(board, showDebug = true) { const matches = []; - // L-Form Matches finden (alle 4 Richtungen) - PRIORITÄT vor regulären Matches + // Zuerst alle 5er-Matches finden (höchste Priorität) + const foundFiveMatches = new Set(); + + // Horizontale 5er-Matches for (let row = 0; row < this.boardHeight; row++) { - for (let col = 0; col < this.boardWidth; col++) { - // Prüfe ob an dieser Position ein Tile existiert - const centerIndex = this.coordsToIndex(row, col); - if (!centerIndex || !board[centerIndex]) continue; + for (let col = 0; col < this.boardWidth - 4; col++) { + const index1 = this.coordsToIndex(row, col); + const index2 = this.coordsToIndex(row, col + 1); + const index3 = this.coordsToIndex(row, col + 2); + const index4 = this.coordsToIndex(row, col + 3); + const index5 = this.coordsToIndex(row, col + 4); - const centerType = board[centerIndex].type; - if (this.isPowerUpTile(centerType)) continue; // Power-ups können nicht Teil von L-Formen sein + if (this.isValidMatch(index1, index2, index3, board) && + this.isValidMatch(index2, index3, index4, board) && + this.isValidMatch(index3, index4, index5, board)) { + matches.push([index1, index2, index3, index4, index5]); + // Markiere alle Positionen als Teil eines 5er-Matches + [index1, index2, index3, index4, index5].forEach(idx => foundFiveMatches.add(idx)); + if (showDebug) console.log(`🔍 5er-Match horizontal: [${row},${col}] bis [${row},${col+4}]`); + } + } + } + + // Vertikale 5er-Matches + for (let row = 0; row < this.boardHeight - 4; row++) { + for (let col = 0; col < this.boardWidth; col++) { + const index1 = this.coordsToIndex(row, col); + const index2 = this.coordsToIndex(row + 1, col); + const index3 = this.coordsToIndex(row + 2, col); + const index4 = this.coordsToIndex(row + 3, col); + const index5 = this.coordsToIndex(row + 4, col); + + if (this.isValidMatch(index1, index2, index3, board) && + this.isValidMatch(index2, index3, index4, board) && + this.isValidMatch(index3, index4, index5, board)) { + matches.push([index1, index2, index3, index4, index5]); + // Markiere alle Positionen als Teil eines 5er-Matches + [index1, index2, index3, index4, index5].forEach(idx => foundFiveMatches.add(idx)); + if (showDebug) console.log(`🔍 5er-Match vertikal: [${row},${col}] bis [${row+4},${col}]`); + } + } + } + + // L-Form Matches finden (mittlere Priorität) - aber nur wenn nicht Teil eines 5er-Matches + for (let row = 0; row < this.boardHeight; row++) { + for (let col = 0; col < this.boardWidth; col++) { + // Prüfe ob an dieser Position ein Tile existiert + const centerIndex = this.coordsToIndex(row, col); + if (!centerIndex || !board[centerIndex]) continue; + + // Überspringe Positionen, die bereits Teil eines 5er-Matches sind + if (foundFiveMatches.has(centerIndex)) continue; + + const centerType = board[centerIndex].type; + if (this.isPowerUpTile(centerType)) continue; // Power-ups können nicht Teil von L-Formen sein // L-Form nach rechts unten (┌) if (row + 2 < this.boardHeight && col + 2 < this.boardWidth) { @@ -1088,15 +1135,23 @@ export default { if (index) lShapeIndices.push(index); } - matches.push({ - type: 'l-shape', - indices: lShapeIndices, - corner: centerIndex, - direction: 'bottom-right', - verticalLength, - horizontalLength - }); - if (showDebug) console.log(`🔍 L-Form Match (┌): [${row},${col}] mit ${verticalLength}er vertikal und ${horizontalLength}er horizontal`); + // Prüfe ob irgendein Teil der L-Form bereits Teil eines 5er-Matches ist + const isPartOfFiveMatch = lShapeIndices.some(idx => foundFiveMatches.has(idx)); + + // Nur hinzufügen, wenn kein Teil eines 5er-Matches + if (!isPartOfFiveMatch) { + matches.push({ + type: 'l-shape', + indices: lShapeIndices, + corner: centerIndex, + direction: 'bottom-right', + verticalLength, + horizontalLength + }); + if (showDebug) console.log(`🔍 L-Form Match (┌): [${row},${col}] mit ${verticalLength}er vertikal und ${horizontalLength}er horizontal`); + } else { + if (showDebug) console.log(`🔍 L-Form Match (┌) übersprungen: [${row},${col}] - Teil eines 5er-Matches`); + } } } @@ -1140,15 +1195,23 @@ export default { if (index) lShapeIndices.push(index); } - matches.push({ - type: 'l-shape', - indices: lShapeIndices, - corner: centerIndex, - direction: 'bottom-left', - verticalLength, - horizontalLength - }); - if (showDebug) console.log(`🔍 L-Form Match (┐): [${row},${col}] mit ${verticalLength}er vertikal und ${horizontalLength}er horizontal`); + // Prüfe ob irgendein Teil der L-Form bereits Teil eines 5er-Matches ist + const isPartOfFiveMatch = lShapeIndices.some(idx => foundFiveMatches.has(idx)); + + // Nur hinzufügen, wenn kein Teil eines 5er-Matches + if (!isPartOfFiveMatch) { + matches.push({ + type: 'l-shape', + indices: lShapeIndices, + corner: centerIndex, + direction: 'bottom-left', + verticalLength, + horizontalLength + }); + if (showDebug) console.log(`🔍 L-Form Match (┐): [${row},${col}] mit ${verticalLength}er vertikal und ${horizontalLength}er horizontal`); + } else { + if (showDebug) console.log(`🔍 L-Form Match (┐) übersprungen: [${row},${col}] - Teil eines 5er-Matches`); + } } } @@ -1192,15 +1255,23 @@ export default { if (index) lShapeIndices.push(index); } - matches.push({ - type: 'l-shape', - indices: lShapeIndices, - corner: centerIndex, - direction: 'top-right', - verticalLength, - horizontalLength - }); - if (showDebug) console.log(`🔍 L-Form Match (└): [${row},${col}] mit ${verticalLength}er vertikal und ${horizontalLength}er horizontal`); + // Prüfe ob irgendein Teil der L-Form bereits Teil eines 5er-Matches ist + const isPartOfFiveMatch = lShapeIndices.some(idx => foundFiveMatches.has(idx)); + + // Nur hinzufügen, wenn kein Teil eines 5er-Matches + if (!isPartOfFiveMatch) { + matches.push({ + type: 'l-shape', + indices: lShapeIndices, + corner: centerIndex, + direction: 'top-right', + verticalLength, + horizontalLength + }); + if (showDebug) console.log(`🔍 L-Form Match (└): [${row},${col}] mit ${verticalLength}er vertikal und ${horizontalLength}er horizontal`); + } else { + if (showDebug) console.log(`🔍 L-Form Match (└) übersprungen: [${row},${col}] - Teil eines 5er-Matches`); + } } } @@ -1244,15 +1315,23 @@ export default { if (index) lShapeIndices.push(index); } - matches.push({ - type: 'l-shape', - indices: lShapeIndices, - corner: centerIndex, - direction: 'top-left', - verticalLength, - horizontalLength - }); - if (showDebug) console.log(`🔍 L-Form Match (┘): [${row},${col}] mit ${verticalLength}er vertikal und ${horizontalLength}er horizontal`); + // Prüfe ob irgendein Teil der L-Form bereits Teil eines 5er-Matches ist + const isPartOfFiveMatch = lShapeIndices.some(idx => foundFiveMatches.has(idx)); + + // Nur hinzufügen, wenn kein Teil eines 5er-Matches + if (!isPartOfFiveMatch) { + matches.push({ + type: 'l-shape', + indices: lShapeIndices, + corner: centerIndex, + direction: 'top-left', + verticalLength, + horizontalLength + }); + if (showDebug) console.log(`🔍 L-Form Match (┘): [${row},${col}] mit ${verticalLength}er vertikal und ${horizontalLength}er horizontal`); + } else { + if (showDebug) console.log(`🔍 L-Form Match (┘) übersprungen: [${row},${col}] - Teil eines 5er-Matches`); + } } } } @@ -1266,15 +1345,18 @@ export default { } }); - // Horizontale Matches finden (3er, 4er, 5er) - NACH L-Form Matches - for (let row = 0; row < this.boardHeight; row++) { - for (let col = 0; col < this.boardWidth - 2; col++) { - // Prüfe ob diese Position bereits Teil einer L-Form ist - const currentIndex = this.coordsToIndex(row, col); - if (lShapeIndices.has(currentIndex)) { - if (showDebug) console.log(`🔍 Überspringe Position [${row},${col}] - bereits Teil einer L-Form`); - continue; - } + // Kombiniere alle bereits verwendeten Indizes (5er-Matches + L-Form-Matches) + const usedIndices = new Set([...foundFiveMatches, ...lShapeIndices]); + + // Horizontale Matches finden (3er, 4er) - NACH 5er-Matches und L-Form Matches + for (let row = 0; row < this.boardHeight; row++) { + for (let col = 0; col < this.boardWidth - 2; col++) { + // Prüfe ob diese Position bereits Teil eines 5er-Matches oder L-Form ist + const currentIndex = this.coordsToIndex(row, col); + if (usedIndices.has(currentIndex)) { + if (showDebug) console.log(`🔍 Überspringe Position [${row},${col}] - bereits Teil eines höherwertigen Matches`); + continue; + } // Prüfe auf 3er-Match if (col + 2 < this.boardWidth) { @@ -1282,8 +1364,8 @@ export default { const index2 = this.coordsToIndex(row, col + 1); const index3 = this.coordsToIndex(row, col + 2); - // Prüfe ob alle drei Positionen bereits Teil einer L-Form sind - if (!lShapeIndices.has(index1) && !lShapeIndices.has(index2) && !lShapeIndices.has(index3) && + // Prüfe ob alle drei Positionen bereits Teil eines höherwertigen Matches sind + if (!usedIndices.has(index1) && !usedIndices.has(index2) && !usedIndices.has(index3) && this.isValidMatch(index1, index2, index3, board)) { matches.push([index1, index2, index3]); if (showDebug) console.log(`🔍 3er-Match horizontal: [${row},${col}] bis [${row},${col+2}]`); @@ -1297,8 +1379,8 @@ export default { const index3 = this.coordsToIndex(row, col + 2); const index4 = this.coordsToIndex(row, col + 3); - // Prüfe ob alle vier Positionen bereits Teil einer L-Form sind - if (!lShapeIndices.has(index1) && !lShapeIndices.has(index2) && !lShapeIndices.has(index3) && !lShapeIndices.has(index4) && + // Prüfe ob alle vier Positionen bereits Teil eines höherwertigen Matches sind + if (!usedIndices.has(index1) && !usedIndices.has(index2) && !usedIndices.has(index3) && !usedIndices.has(index4) && this.isValidMatch(index1, index2, index3, board) && this.isValidMatch(index2, index3, index4, board)) { matches.push([index1, index2, index3, index4]); @@ -1306,33 +1388,17 @@ export default { } } - // Prüfe auf 5er-Match - if (col + 4 < this.boardWidth) { - const index1 = this.coordsToIndex(row, col); - const index2 = this.coordsToIndex(row, col + 1); - const index3 = this.coordsToIndex(row, col + 2); - const index4 = this.coordsToIndex(row, col + 3); - const index5 = this.coordsToIndex(row, col + 4); - - // Prüfe ob alle fünf Positionen bereits Teil einer L-Form sind - if (!lShapeIndices.has(index1) && !lShapeIndices.has(index2) && !lShapeIndices.has(index3) && !lShapeIndices.has(index4) && !lShapeIndices.has(index5) && - this.isValidMatch(index1, index2, index3, board) && - this.isValidMatch(index2, index3, index4, board) && - this.isValidMatch(index3, index4, index5, board)) { - matches.push([index1, index2, index3, index4, index5]); - if (showDebug) console.log(`🔍 5er-Match horizontal: [${row},${col}] bis [${row},${col+4}]`); - } - } + } } - // Vertikale Matches finden (3er, 4er, 5er) - NACH L-Form Matches + // Vertikale Matches finden (3er, 4er) - NACH 5er-Matches und L-Form Matches for (let row = 0; row < this.boardHeight - 2; row++) { for (let col = 0; col < this.boardWidth; col++) { - // Prüfe ob diese Position bereits Teil einer L-Form ist + // Prüfe ob diese Position bereits Teil eines höherwertigen Matches ist const currentIndex = this.coordsToIndex(row, col); - if (lShapeIndices.has(currentIndex)) { - if (showDebug) console.log(`🔍 Überspringe Position [${row},${col}] - bereits Teil einer L-Form`); + if (usedIndices.has(currentIndex)) { + if (showDebug) console.log(`🔍 Überspringe Position [${row},${col}] - bereits Teil eines höherwertigen Matches`); continue; } @@ -1342,8 +1408,8 @@ export default { const index2 = this.coordsToIndex(row + 1, col); const index3 = this.coordsToIndex(row + 2, col); - // Prüfe ob alle drei Positionen bereits Teil einer L-Form sind - if (!lShapeIndices.has(index1) && !lShapeIndices.has(index2) && !lShapeIndices.has(index3) && + // Prüfe ob alle drei Positionen bereits Teil eines höherwertigen Matches sind + if (!usedIndices.has(index1) && !usedIndices.has(index2) && !usedIndices.has(index3) && this.isValidMatch(index1, index2, index3, board)) { matches.push([index1, index2, index3]); if (showDebug) console.log(`🔍 3er-Match vertikal: [${row},${col}] bis [${row+2},${col}]`); @@ -1357,8 +1423,8 @@ export default { const index3 = this.coordsToIndex(row + 2, col); const index4 = this.coordsToIndex(row + 3, col); - // Prüfe ob alle vier Positionen bereits Teil einer L-Form sind - if (!lShapeIndices.has(index1) && !lShapeIndices.has(index2) && !lShapeIndices.has(index3) && !lShapeIndices.has(index4) && + // Prüfe ob alle vier Positionen bereits Teil eines höherwertigen Matches sind + if (!usedIndices.has(index1) && !usedIndices.has(index2) && !usedIndices.has(index3) && !usedIndices.has(index4) && this.isValidMatch(index1, index2, index3, board) && this.isValidMatch(index2, index3, index4, board)) { matches.push([index1, index2, index3, index4]); @@ -1366,23 +1432,7 @@ export default { } } - // Prüfe auf 5er-Match - if (row + 4 < this.boardHeight) { - const index1 = this.coordsToIndex(row, col); - const index2 = this.coordsToIndex(row + 1, col); - const index3 = this.coordsToIndex(row + 2, col); - const index4 = this.coordsToIndex(row + 3, col); - const index5 = this.coordsToIndex(row + 4, col); - - // Prüfe ob alle fünf Positionen bereits Teil einer L-Form sind - if (!lShapeIndices.has(index1) && !lShapeIndices.has(index2) && !lShapeIndices.has(index3) && !lShapeIndices.has(index4) && !lShapeIndices.has(index5) && - this.isValidMatch(index1, index2, index3, board) && - this.isValidMatch(index2, index3, index4, board) && - this.isValidMatch(index3, index4, index5, board)) { - matches.push([index1, index2, index3, index4, index5]); - if (showDebug) console.log(`🔍 5er-Match vertikal: [${row},${col}] bis [${row+4},${col}]`); - } - } + } } @@ -1398,17 +1448,27 @@ export default { return tileType === 'rocket' || tileType === 'rocket-horizontal' || tileType === 'rocket-vertical'; }, + // Hilfsmethode: Prüfe ob ein Tile ein Regenbogen-Power-up ist + isRainbowTile(tileType) { + return tileType === 'rainbow'; + }, + // Hilfsmethode: Prüfe ob ein Tile ein Power-up ist isPowerUpTile(tileType) { - return this.isRocketTile(tileType) || tileType === 'bomb' || tileType === 'rocket-horizontal' || tileType === 'rocket-vertical'; + if (!tileType) return false; + return this.isRocketTile(tileType) || tileType === 'bomb' || tileType === 'rocket-horizontal' || tileType === 'rocket-vertical' || this.isRainbowTile(tileType); }, // Hilfsmethode: Debug-Ausgabe für Power-ups debugPowerUps() { console.log('🔍 Debug: Alle Power-ups auf dem Board:'); for (let i = 0; i < this.board.length; i++) { - if (this.board[i] && this.isPowerUpTile(this.board[i].type)) { - console.log(`🔍 Power-up ${this.board[i].type} an Position ${i}`); + if (this.board[i]) { + const isPowerUp = this.isPowerUpTile(this.board[i].type); + console.log(`🔍 Position ${i}: Tile ${this.board[i].type}, isPowerUpTile: ${isPowerUp}`); + if (isPowerUp) { + console.log(`🔍 ✅ Power-up erkannt: ${this.board[i].type} an Position ${i}`); + } } } }, @@ -1653,8 +1713,8 @@ export default { // WICHTIG: Prüfe auf Regenbogen-Tile Tausch (vor normalen Matches) // Prüfe beide Kombinationen: temp + board[index1] und board[index1] + temp - if (this.handleRainbowSwap(temp, this.board[index1]) || - this.handleRainbowSwap(this.board[index1], temp)) { + if (await this.handleRainbowSwap(temp, this.board[index1]) || + await this.handleRainbowSwap(this.board[index1], temp)) { // Regenbogen-Tausch erfolgreich - Zug-Zähler wird bereits in handleRainbowSwap erhöht return; // Beende hier, da Regenbogen-Tausch bereits verarbeitet wurde } @@ -1873,14 +1933,20 @@ export default { console.log('🔧 Debug: Alle Power-ups nach Power-up-Verarbeitung:'); this.debugPowerUps(); - // Debug: Zeige alle Power-ups im Template nach der Verarbeitung - console.log('🔧 Debug: Power-ups im Template nach Verarbeitung:'); - for (let i = 0; i < this.board.length; i++) { - if (this.board[i] && this.isPowerUpTile(this.board[i].type)) { + // Debug: Zeige alle Power-ups im Template nach der Verarbeitung + console.log('🔧 Debug: Power-ups im Template nach Verarbeitung:'); + for (let i = 0; i < this.board.length; i++) { + if (this.board[i]) { + const isPowerUp = this.isPowerUpTile(this.board[i].type); + console.log(`🔧 Position ${i}: Tile ${this.board[i].type}, isPowerUpTile: ${isPowerUp}`); + if (isPowerUp) { console.log(`🔧 ✅ Power-up im Template: ${this.board[i].type} an Position ${i}`); } } } + + + } }, // Fall-Down-Logik: Bewege Tiles nach unten in leere Positionen @@ -2046,19 +2112,53 @@ export default { console.log(`🔧 ${newTilesAdded} neue Tiles hinzugefügt`); }, - // Erstelle Power-ups für 4er-Matches und L-Form-Matches + // Erstelle Power-ups für 4er-Matches, 5er-Matches und L-Form-Matches async createPowerUpsForMatches(matches) { console.log('🔧 Prüfe auf Power-up-Erstellung...'); let powerUpsCreated = 0; const bombs = []; const rockets = []; + const rainbows = []; + // Sammle alle Positionen, die bereits von höherwertigen Power-ups verwendet werden + const usedPositions = new Set(); + + // Verarbeite zuerst 5er-Matches (höchste Priorität) + matches.forEach(match => { + if (Array.isArray(match) && match.length === 5) { + console.log(`🔧 5er-Match gefunden: ${match.join(', ')} - erstelle Regenbogen-Tile`); + + // Regenbogen-Tile erscheint an der Position des mittleren Tiles (Index 2) + const rainbowIndex = match[2]; + + // Markiere alle Positionen des 5er-Matches als verwendet + match.forEach(pos => usedPositions.add(pos)); + + // Erstelle Regenbogen-Tile + this.board[rainbowIndex] = { type: 'rainbow' }; + + console.log(`🌈 Regenbogen-Tile an Position ${rainbowIndex} erstellt`); + console.log(`🔧 Board[${rainbowIndex}] = ${JSON.stringify(this.board[rainbowIndex])}`); + powerUpsCreated++; + rainbows.push(rainbowIndex); + } + }); + + // Verarbeite dann L-Form-Matches (mittlere Priorität) matches.forEach(match => { - // Prüfe auf L-Form-Matches (Bomben) if (match.type === 'l-shape') { console.log(`🔧 L-Form-Match gefunden: ${match.direction} an Ecke ${match.corner} - erstelle Bombe`); + // Prüfe ob die Ecke bereits von einem 5er-Match verwendet wird + if (usedPositions.has(match.corner)) { + console.log(`🔧 Überspringe L-Form-Match - Position ${match.corner} bereits von 5er-Match verwendet`); + return; + } + + // Markiere die Ecke als verwendet + usedPositions.add(match.corner); + // Bombe an der Ecke erstellen this.board[match.corner] = { type: 'bomb' }; @@ -2067,13 +2167,25 @@ export default { powerUpsCreated++; bombs.push(match.corner); } - // Prüfe auf normale 4er-Matches (Arrays) - else if (Array.isArray(match) && match.length === 4) { + }); + + // Verarbeite zuletzt 4er-Matches (niedrigste Priorität) + matches.forEach(match => { + if (Array.isArray(match) && match.length === 4) { console.log(`🔧 4er-Match gefunden: ${match.join(', ')} - erstelle Rakete`); // Rakete erscheint an der Position des zweiten Tiles const rocketIndex = match[1]; + // Prüfe ob die Position bereits von einem höherwertigen Power-up verwendet wird + if (usedPositions.has(rocketIndex)) { + console.log(`🔧 Überspringe 4er-Match - Position ${rocketIndex} bereits von höherwertigem Power-up verwendet`); + return; + } + + // Markiere die Position als verwendet + usedPositions.add(rocketIndex); + // Erstelle Rakete basierend auf der Richtung des Matches const rocketType = this.determineRocketType(match); this.board[rocketIndex] = { type: rocketType }; @@ -2095,7 +2207,8 @@ export default { return { count: powerUpsCreated, bombs: bombs, - rockets: rockets + rockets: rockets, + rainbows: rainbows }; }, @@ -2571,6 +2684,12 @@ export default { return await this.activateBomb(fromIndex, toIndex); } + // Prüfe ob ein Tile ein Regenbogen-Tile ist + if (this.board[fromIndex].type === 'rainbow' || this.board[toIndex].type === 'rainbow') { + console.log('🌈 Regenbogen-Tile wird aktiviert!'); + return await this.activateRainbow(fromIndex, toIndex); + } + // Prüfe ob das Ziel ein leeres Feld ist if (!this.board[toIndex]) { console.log('⚠️ Verschieben auf leeres Feld nicht erlaubt'); @@ -2714,6 +2833,76 @@ export default { return true; }, + // Aktiviere ein Regenbogen-Tile (durch Verschieben) + async activateRainbow(rainbowIndex, targetIndex) { + console.log(`🌈 Aktiviere Regenbogen-Tile an Position ${rainbowIndex}`); + + // Bestimme das Zentrum der Regenbogen-Aktivität + let activationCenter; + + if (this.board[rainbowIndex].type === 'rainbow') { + // Regenbogen-Tile wird auf ein Nachbarfeld verschoben + activationCenter = targetIndex; + } else { + // Ein Tile wird auf das Regenbogen-Tile verschoben + activationCenter = rainbowIndex; + } + + // Zeige Regenbogen-Effekt-Animation + await this.showRainbowEffectAnimation(activationCenter); + + // Sammle alle Tiles des gleichen Typs wie das Ziel-Tile + const targetTile = this.board[activationCenter]; + if (targetTile && !this.isPowerUpTile(targetTile.type)) { + const tilesToRemove = new Set(); + + // Gehe durch alle Tiles im Board + for (let i = 0; i < this.board.length; i++) { + if (this.board[i] && this.board[i].type === targetTile.type) { + tilesToRemove.add(i); + } + } + + if (tilesToRemove.size > 0) { + console.log(`🌈 Entferne ${tilesToRemove.size} Tiles vom Typ ${targetTile.type}`); + + // Starte Schrumpf-Animation für alle zu entfernenden Tiles + await this.animateTileRemoval(Array.from(tilesToRemove)); + + // Entferne alle Tiles nach der Animation + tilesToRemove.forEach(index => { + if (this.board[index]) { + console.log(`🌈 Entferne Tile ${this.board[index].type} an Position ${index}`); + this.board[index] = null; + } + }); + + // Entferne auch das Regenbogen-Tile selbst + if (this.board[rainbowIndex].type === 'rainbow') { + console.log(`🌈 Entferne Regenbogen-Tile an Position ${rainbowIndex}`); + this.board[rainbowIndex] = null; + } + + // Aktualisiere die Anzeige + this.$forceUpdate(); + + // Führe Fall-Down-Logik aus + await this.fallTilesDown(); + + // Fülle leere Positionen mit neuen Tiles auf + await this.fillEmptyPositions(); + + // Erhöhe den Zug-Zähler + this.moves++; + this.movesLeft--; + + return true; + } + } + + return false; + }, + // Aktiviere eine Rakete automatisch (für sofortige Aktivierung nach der Erstellung) async activateRocketAutomatically(rocketIndex) { console.log(`🚀 Aktiviere Rakete automatisch an Position ${rocketIndex}`); @@ -4383,24 +4572,12 @@ export default { return; } - if (tile.isSpecial) { - // Power-Up als Zug zählen - this.countPowerUpMove(); - - if (tile.type === 'rainbow') { - // Spiele Regenbogen-Sound - this.playSound('rainbow'); - - // Regenbogen-Tile: Zufälligen Tile-Typ entfernen - const randomTileType = this.tileTypes[Math.floor(Math.random() * this.tileTypes.length)]; - this.removeAllTilesOfType(randomTileType); - } else if (tile.type === 'bomb') { - // Bomben-Tile: 9 Tiles rundherum entfernen - this.explodeBomb(index, 1, true); // 1 Ring = 3x3 Bereich - manuelle Aktivierung - } else if (tile.type === 'rocket') { - // Raketen-Tile: 4 Nachbarfelder löschen und Rakete starten - this.handleRocketDoubleClick(index); - } + // Prüfe auf Regenbogen-Tiles + if (tile.type === 'rainbow') { + console.log(`🌈 Doppelklick auf Regenbogen-Tile an Position ${index}`); + // Regenbogen-Tile durch Doppelklick aktivieren + await this.activateRainbowByDoubleClick(index); + return; } }, @@ -4458,7 +4635,7 @@ export default { await this.showBombEffectAnimation(bombIndex); // Aktiviere die Bombe (3x3 Bereich) - this.explodeBomb(bombIndex, 1, true); + this.explodeBomb(bombIndex, 1, true); // Entferne die Bombe selbst console.log(`💣 Entferne Bombe an Position ${bombIndex}`); @@ -4478,6 +4655,24 @@ export default { this.movesLeft--; }, + // Aktiviere Regenbogen-Tile durch Doppelklick + async activateRainbowByDoubleClick(rainbowIndex) { + console.log(`🌈 Regenbogen-Tile an Position ${rainbowIndex} durch Doppelklick aktiviert`); + + // Wähle zufällig eine vorhandene Tile-Art aus (außer Power-ups) + const availableTypes = this.getAvailableTileTypes(); + if (availableTypes.length === 0) { + console.log('⚠️ Keine verfügbaren Tile-Typen für Regenbogen-Aktivierung'); + return; + } + + const randomType = availableTypes[Math.floor(Math.random() * availableTypes.length)]; + console.log(`🌈 Zufällig ausgewählter Tile-Typ: ${randomType}`); + + // Aktiviere den Regenbogen mit dem zufälligen Typ + await this.activateRainbow(rainbowIndex, null, randomType); + }, + // Neue Methode: Entferne alle Tiles eines bestimmten Typs removeAllTilesOfType(tileType) { const tilesToRemove = []; @@ -4510,8 +4705,98 @@ export default { } }, + // Hilfsmethode: Hole alle verfügbaren Tile-Typen (außer Power-ups) + getAvailableTileTypes() { + const types = new Set(); + + // Sammle alle Tile-Typen vom Board (außer Power-ups) + for (let i = 0; i < this.board.length; i++) { + if (this.board[i] && !this.isPowerUpTile(this.board[i].type)) { + types.add(this.board[i].type); + } + } + + return Array.from(types); + }, + + // Neue Methode: Aktiviere Regenbogen-Tile durch Doppelklick + async activateRainbowByDoubleClick(rainbowIndex) { + console.log(`🌈 Aktiviere Regenbogen-Tile durch Doppelklick an Position ${rainbowIndex}`); + + // Wähle zufällig eine vorhandene Tile-Art aus (außer Power-ups) + const availableTypes = this.getAvailableTileTypes(); + if (availableTypes.length === 0) { + console.log('⚠️ Keine verfügbaren Tile-Typen für Regenbogen-Aktivierung'); + return; + } + + const randomType = availableTypes[Math.floor(Math.random() * availableTypes.length)]; + console.log(`🌈 Zufällig ausgewählter Tile-Typ: ${randomType}`); + + // Aktiviere den Regenbogen mit dem zufälligen Typ + await this.activateRainbowByType(rainbowIndex, randomType); + }, + + // Neue Methode: Aktiviere Regenbogen-Tile mit spezifischem Typ + async activateRainbowByType(rainbowIndex, targetType) { + console.log(`🌈 Aktiviere Regenbogen-Tile an Position ${rainbowIndex} mit Typ: ${targetType}`); + + // Spiele Regenbogen-Sound + this.playSound('rainbow'); + + // Überspringe Power-ups + if (this.isPowerUpTile(targetType)) { + console.log(`⚠️ Überspringe Power-up Typ: ${targetType}`); + return; + } + + console.log(`🌈 Entferne alle Tiles vom Typ: ${targetType}`); + + // Sammle alle Tiles des Ziel-Typs + const tilesToRemove = []; + for (let i = 0; i < this.board.length; i++) { + if (this.board[i] && this.board[i].type === targetType) { + tilesToRemove.push(i); + } + } + + if (tilesToRemove.length === 0) { + console.log(`⚠️ Keine Tiles vom Typ ${targetType} gefunden`); + return; + } + + // Zeige Regenbogen-Effekt-Animation + await this.showRainbowEffectAnimation(rainbowIndex); + + // Starte Schrumpf-Animation für alle zu entfernenden Tiles + await this.animateTileRemoval(tilesToRemove); + + // Entferne alle Tiles des Ziel-Typs + tilesToRemove.forEach(index => { + this.board[index] = null; + }); + + // Entferne den Regenbogen selbst + this.board[rainbowIndex] = null; + + // Aktualisiere die Anzeige + this.$forceUpdate(); + + // Führe Fall-Down-Logik aus + await this.fallTilesDown(); + + // Fülle leere Positionen mit neuen Tiles auf + await this.fillEmptyPositions(); + + // Erhöhe den Zug-Zähler + this.moves++; + this.movesLeft--; + + console.log(`🌈 ${tilesToRemove.length} Tiles vom Typ ${targetType} entfernt`); + }, + // Neue Methode: Behandle Power-Up Tile Tausch - handleRainbowSwap(originalTile1, originalTile2) { + async handleRainbowSwap(originalTile1, originalTile2) { // Power-Up Tausch als Zug zählen (wird auch über swapTiles aufgerufen) this.countPowerUpMove(); @@ -4519,8 +4804,9 @@ export default { // Spiele Regenbogen-Sound this.playSound('rainbow'); - // Zwei Regenbogen-Tiles getauscht: Entferne alle Tiles - this.removeAllTilesFromBoard(); + // Zwei Regenbogen-Tiles getauscht: Entferne alle Tiles vom gesamten Board + console.log('🌈 Zwei Regenbogen-Tiles kombiniert - entferne alle Tiles vom Board!'); + await this.removeAllTilesFromBoardIncludingRainbows(); return true; } else if (originalTile1.type === 'rainbow' || originalTile2.type === 'rainbow') { // Spiele Regenbogen-Sound @@ -4528,7 +4814,11 @@ export default { // Ein Regenbogen-Tile mit normalem Tile getauscht: Entferne alle Tiles des normalen Typs const normalTile = originalTile1.type === 'rainbow' ? originalTile2 : originalTile1; - this.removeAllTilesOfType(normalTile.type); + const rainbowIndex = originalTile1.type === 'rainbow' ? this.findTileIndex(originalTile1) : this.findTileIndex(originalTile2); + + if (rainbowIndex !== null) { + await this.activateRainbowByType(rainbowIndex, normalTile.type); + } return true; } else if (originalTile1.type === 'bomb' && originalTile2.type === 'bomb') { // Zwei Bomben-Tiles getauscht: Entferne 2 Ringe (5x5 Bereich) @@ -4641,6 +4931,54 @@ export default { this.score += points; } }, + + // Neue Methode: Entferne ALLE Tiles vom Board (einschließlich Regenbögen) + async removeAllTilesFromBoardIncludingRainbows() { + const allTileIndices = []; + + // Sammle alle Tile-Indizes (einschließlich Regenbögen) + for (let i = 0; i < this.board.length; i++) { + if (this.board[i]) { + allTileIndices.push(i); + } + } + + if (allTileIndices.length > 0) { + console.log(`🌈 Entferne alle ${allTileIndices.length} Tiles vom Board (einschließlich Regenbögen)`); + + // Zeige Regenbogen-Effekt-Animation in der Mitte des Boards + const centerIndex = Math.floor(this.board.length / 2); + await this.showRainbowEffectAnimation(centerIndex); + + // Starte Schrumpf-Animation für alle Tiles + await this.animateTileRemoval(allTileIndices); + + // Entferne alle Tiles (einschließlich Regenbögen) + allTileIndices.forEach(index => { + this.board[index] = null; + }); + + // Aktualisiere die Anzeige + this.$forceUpdate(); + + // Führe Fall-Down-Logik aus + await this.fallTilesDown(); + + // Fülle leere Positionen mit neuen Tiles auf + await this.fillEmptyPositions(); + + // Erhöhe den Zug-Zähler + this.moves++; + this.movesLeft--; + + // Punkte hinzufügen (höhere Punktzahl für diese spezielle Kombination) + const points = allTileIndices.length * 50 * this.currentLevel; + this.levelScore += points; + this.score += points; + + console.log(`🌈 Alle Tiles erfolgreich entfernt! +${points} Punkte`); + } + }, // Neue Methode: Explodiere Bombe mit bestimmter Reichweite explodeBomb(centerIndex, rings, isManualActivation = false) { @@ -5022,6 +5360,32 @@ export default { }); }, + // Neue Methode: Zeige Regenbogen-Effekt-Animation + showRainbowEffectAnimation(centerIndex) { + // Warte bis das DOM gerendert ist + this.$nextTick(() => { + const tileElement = document.querySelector(`[data-index="${centerIndex}"]`); + const gameBoard = document.querySelector('.game-board-container'); + + if (tileElement && gameBoard) { + const tileRect = tileElement.getBoundingClientRect(); + const boardRect = gameBoard.getBoundingClientRect(); + + this.rainbowCenter = { + x: tileRect.left - boardRect.left + tileRect.width / 2 - 30, + y: tileRect.top - boardRect.top + tileRect.height / 2 - 30 + }; + + this.showRainbowEffect = true; + + // Verstecke Animation nach der Dauer + setTimeout(() => { + this.showRainbowEffect = false; + }, 500); + } + }); + }, + // Neue Methode: Behandle Doppelklick auf Rakete handleRocketDoubleClick(rocketIndex) { const { row: rocketRow, col: rocketCol } = this.indexToCoords(rocketIndex); @@ -6063,6 +6427,32 @@ export default { } } +/* Regenbogen-Power-ups */ +.game-tile.rainbow { + background: linear-gradient(45deg, #ff6b6b, #ffd93d, #6bcf7f, #4d9de0, #a855f7) !important; + position: relative; + z-index: 10; + box-shadow: 0 0 20px rgba(255, 107, 107, 0.6); +} + +/* Regenbogen-Symbol */ +.rainbow-symbol { + font-size: 24px; + color: white; + text-shadow: 2px 2px 4px rgba(0,0,0,0.5); + font-weight: bold; + animation: rainbowGlow 3s ease-in-out infinite; +} + +@keyframes rainbowGlow { + 0%, 100% { + filter: hue-rotate(0deg) brightness(1); + } + 50% { + filter: hue-rotate(180deg) brightness(1.2); + } +} + /* Raketen-Explosions-Effekt */ .rocket-explosion { width: 80px;