feat(match3): Erweiterung der Match-Logik mit Regenbogen-Power-ups und Optimierung der Erkennung

- 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.
This commit is contained in:
Torsten Schulz (local)
2025-08-28 12:30:04 +02:00
parent cfe8b02519
commit 3d97b5ce2c

View File

@@ -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
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;
// Zuerst alle 5er-Matches finden (höchste Priorität)
const foundFiveMatches = new Set();
const centerType = board[centerIndex].type;
if (this.isPowerUpTile(centerType)) continue; // Power-ups können nicht Teil von L-Formen sein
// Horizontale 5er-Matches
for (let row = 0; row < this.boardHeight; row++) {
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);
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)
@@ -4642,6 +4932,54 @@ export default {
}
},
// 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) {
const { row: centerRow, col: centerCol } = this.indexToCoords(centerIndex);
@@ -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;