feat(match3): Erweiterung der Match-Logik und Einführung neuer Power-Ups

- Hinzufügen von Regenbogen-Power-ups zur Spielmechanik, die durch 5er-Matches aktiviert werden.
- Anpassung der Logik zur Erkennung von 5er-Matches und deren Priorisierung vor L-Form-Matches.
- Verbesserung der Darstellung und Animationen für Bomben und Regenbogen-Power-ups.
- Erweiterung der Debug-Ausgaben zur besseren Nachverfolgbarkeit von Power-ups und Matches.
- Implementierung von neuen Methoden zur Aktivierung und Handhabung von Power-ups im Spiel.
This commit is contained in:
Torsten Schulz (local)
2025-08-27 18:13:50 +02:00
parent 7b07b07bec
commit cfe8b02519

View File

@@ -1502,12 +1502,41 @@ export default {
console.log(`🔧 Versuch ${attempts + 1}: ${initialMatches.length} Matches gefunden`); console.log(`🔧 Versuch ${attempts + 1}: ${initialMatches.length} Matches gefunden`);
// Wähle einen zufälligen Match // Wähle einen zufälligen Match
if (initialMatches.length === 0) {
console.log('🔧 Keine Matches mehr gefunden, Level ist bereit');
break;
}
const randomMatch = initialMatches[Math.floor(Math.random() * initialMatches.length)]; const randomMatch = initialMatches[Math.floor(Math.random() * initialMatches.length)];
// Prüfe ob der Match gültig ist
if (!Array.isArray(randomMatch) || randomMatch.length === 0) {
console.warn('⚠️ Ungültiger Match gefunden, überspringe diesen Versuch');
attempts++;
continue;
}
const randomTileIndex = randomMatch[Math.floor(Math.random() * randomMatch.length)]; const randomTileIndex = randomMatch[Math.floor(Math.random() * randomMatch.length)];
// Prüfe ob der Index gültig ist und ein Tile existiert
if (randomTileIndex === null || randomTileIndex === undefined ||
randomTileIndex < 0 || randomTileIndex >= this.board.length ||
!this.board[randomTileIndex]) {
console.warn(`⚠️ Ungültiger Tile-Index: ${randomTileIndex}, überspringe diesen Versuch`);
attempts++;
continue;
}
const currentType = this.board[randomTileIndex].type; const currentType = this.board[randomTileIndex].type;
// Wähle einen anderen Tile-Typ // Wähle einen anderen Tile-Typ
const availableTypes = this.tileTypes.filter(type => type !== currentType); const availableTypes = this.tileTypes.filter(type => type !== currentType);
if (availableTypes.length === 0) {
console.warn('⚠️ Keine alternativen Tile-Typen verfügbar, überspringe diesen Versuch');
attempts++;
continue;
}
const newType = availableTypes[Math.floor(Math.random() * availableTypes.length)]; const newType = availableTypes[Math.floor(Math.random() * availableTypes.length)];
// Ändere den Tile-Typ // Ändere den Tile-Typ
@@ -1772,6 +1801,20 @@ export default {
console.log('🔧 Erstelle Power-ups nach der Tile-Entfernung...'); console.log('🔧 Erstelle Power-ups nach der Tile-Entfernung...');
const powerUpsCreated = await this.createPowerUpsForMatches(matches); const powerUpsCreated = await this.createPowerUpsForMatches(matches);
// Wenn Raketen erstellt wurden, lass sie im nächsten Zug starten
if (powerUpsCreated && powerUpsCreated.rockets && powerUpsCreated.rockets.length > 0) {
console.log(`🚀 ${powerUpsCreated.rockets.length} Raketen erstellt - werden im nächsten Zug aktiviert`);
// Aktualisiere die Anzeige
this.$forceUpdate();
// Warte kurz, damit die Rakete sichtbar wird
await this.wait(300);
// KEINE automatische Aktivierung - Raketen bleiben auf dem Board
// und werden erst durch Spieler-Aktionen aktiviert
}
// Debug: Zeige alle Power-ups nach der Erstellung // Debug: Zeige alle Power-ups nach der Erstellung
console.log('🔧 Debug: Alle Power-ups nach createPowerUpsForMatches:'); console.log('🔧 Debug: Alle Power-ups nach createPowerUpsForMatches:');
this.debugPowerUps(); this.debugPowerUps();
@@ -1820,11 +1863,11 @@ export default {
// Prüfe ob Power-ups erstellt wurden - wenn ja, keine Cascade-Matches prüfen // Prüfe ob Power-ups erstellt wurden - wenn ja, keine Cascade-Matches prüfen
// Verwende den Rückgabewert von createPowerUpsForMatches // Verwende den Rückgabewert von createPowerUpsForMatches
if (!powerUpsCreated) { if (!powerUpsCreated || powerUpsCreated.count === 0) {
// Nur Cascade-Matches prüfen, wenn keine Power-ups erstellt wurden // Nur Cascade-Matches prüfen, wenn keine Power-ups erstellt wurden
await this.checkForCascadeMatches(); await this.checkForCascadeMatches();
} else { } else {
console.log(`🔧 ${powerUpsCreated} Power-ups erstellt - überspringe Cascade-Match-Prüfung`); console.log(`🔧 ${powerUpsCreated.count} Power-ups erstellt - überspringe Cascade-Match-Prüfung`);
// Debug: Zeige alle Power-ups nach der Verarbeitung // Debug: Zeige alle Power-ups nach der Verarbeitung
console.log('🔧 Debug: Alle Power-ups nach Power-up-Verarbeitung:'); console.log('🔧 Debug: Alle Power-ups nach Power-up-Verarbeitung:');
@@ -2008,6 +2051,8 @@ export default {
console.log('🔧 Prüfe auf Power-up-Erstellung...'); console.log('🔧 Prüfe auf Power-up-Erstellung...');
let powerUpsCreated = 0; let powerUpsCreated = 0;
const bombs = [];
const rockets = [];
matches.forEach(match => { matches.forEach(match => {
// Prüfe auf L-Form-Matches (Bomben) // Prüfe auf L-Form-Matches (Bomben)
@@ -2020,6 +2065,7 @@ export default {
console.log(`💣 Bombe an Position ${match.corner} erstellt`); console.log(`💣 Bombe an Position ${match.corner} erstellt`);
console.log(`🔧 Board[${match.corner}] = ${JSON.stringify(this.board[match.corner])}`); console.log(`🔧 Board[${match.corner}] = ${JSON.stringify(this.board[match.corner])}`);
powerUpsCreated++; powerUpsCreated++;
bombs.push(match.corner);
} }
// Prüfe auf normale 4er-Matches (Arrays) // Prüfe auf normale 4er-Matches (Arrays)
else if (Array.isArray(match) && match.length === 4) { else if (Array.isArray(match) && match.length === 4) {
@@ -2035,6 +2081,7 @@ export default {
console.log(`🚀 Rakete ${rocketType} an Position ${rocketIndex} erstellt`); console.log(`🚀 Rakete ${rocketType} an Position ${rocketIndex} erstellt`);
console.log(`🔧 Board[${rocketIndex}] = ${JSON.stringify(this.board[rocketIndex])}`); console.log(`🔧 Board[${rocketIndex}] = ${JSON.stringify(this.board[rocketIndex])}`);
powerUpsCreated++; powerUpsCreated++;
rockets.push(rocketIndex);
} }
}); });
@@ -2044,7 +2091,12 @@ export default {
console.log(`🔧 ${powerUpsCreated} Power-ups erstellt und Board aktualisiert`); console.log(`🔧 ${powerUpsCreated} Power-ups erstellt und Board aktualisiert`);
} }
return powerUpsCreated; // Gib detaillierte Informationen über erstellte Power-ups zurück
return {
count: powerUpsCreated,
bombs: bombs,
rockets: rockets
};
}, },
// Bestimme den Raketen-Typ basierend auf der Match-Richtung // Bestimme den Raketen-Typ basierend auf der Match-Richtung
@@ -2513,6 +2565,12 @@ export default {
return await this.activateRocket(fromIndex, toIndex); return await this.activateRocket(fromIndex, toIndex);
} }
// Prüfe ob ein Tile eine Bombe ist
if (this.board[fromIndex].type === 'bomb' || this.board[toIndex].type === 'bomb') {
console.log('💣 Bombe wird aktiviert!');
return await this.activateBomb(fromIndex, toIndex);
}
// Prüfe ob das Ziel ein leeres Feld ist // Prüfe ob das Ziel ein leeres Feld ist
if (!this.board[toIndex]) { if (!this.board[toIndex]) {
console.log('⚠️ Verschieben auf leeres Feld nicht erlaubt'); console.log('⚠️ Verschieben auf leeres Feld nicht erlaubt');
@@ -2613,6 +2671,113 @@ export default {
return false; return false;
}, },
// Aktiviere eine Bombe (durch Verschieben oder Doppelklick)
async activateBomb(bombIndex, targetIndex) {
console.log(`💣 Aktiviere Bombe an Position ${bombIndex}`);
// Bestimme das Zentrum der Bomben-Explosion
let explosionCenter;
if (this.board[bombIndex].type === 'bomb') {
// Bombe wird auf ein Nachbarfeld verschoben
explosionCenter = targetIndex;
} else {
// Ein Tile wird auf die Bombe verschoben
explosionCenter = bombIndex;
}
// Zeige Bomben-Effekt-Animation
await this.showBombEffectAnimation(explosionCenter);
// Explodiere die Bombe mit 1 Ring (3x3 Bereich) - manuelle Aktivierung
this.explodeBomb(explosionCenter, 1, true);
// Entferne die Bombe nach der Explosion
if (this.board[bombIndex].type === 'bomb') {
console.log(`💣 Entferne Bombe an Position ${bombIndex}`);
this.board[bombIndex] = 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;
},
// Aktiviere eine Rakete automatisch (für sofortige Aktivierung nach der Erstellung)
async activateRocketAutomatically(rocketIndex) {
console.log(`🚀 Aktiviere Rakete automatisch an Position ${rocketIndex}`);
// Wähle ein zufälliges Ziel für die Rakete
const availableTargets = [];
for (let i = 0; i < this.board.length; i++) {
if (i !== rocketIndex && this.board[i] && !this.isRocketTile(this.board[i].type)) {
availableTargets.push(i);
}
}
if (availableTargets.length === 0) {
console.warn('⚠️ Keine Ziele für Rakete verfügbar');
return false;
}
// Wähle ein zufälliges Ziel
const randomTarget = availableTargets[Math.floor(Math.random() * availableTargets.length)];
console.log(`🚀 Rakete startet auf zufälliges Ziel an Position ${randomTarget}`);
// Zeige Raketen-Explosions-Animation (einfache Version ohne Flug)
await this.showRocketExplosionAnimationSimple(randomTarget);
// Entferne die Tiles um das Explosionszentrum
const tilesToRemove = this.getRocketExplosionTiles(randomTarget);
if (tilesToRemove.size > 0) {
console.log(`🚀 Entferne ${tilesToRemove.size} Tiles um Position ${randomTarget}`);
// 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 die Rakete selbst
console.log(`🚀 Entferne Rakete an Position ${rocketIndex}`);
this.board[rocketIndex] = 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;
},
// Hole alle Tiles, die von der Raketen-Explosion betroffen sind // Hole alle Tiles, die von der Raketen-Explosion betroffen sind
getRocketExplosionTiles(centerIndex) { getRocketExplosionTiles(centerIndex) {
const tilesToRemove = new Set(); const tilesToRemove = new Set();
@@ -2660,9 +2825,27 @@ export default {
// Verstecke Animation // Verstecke Animation
this.showRocketEffect = false; this.showRocketEffect = false;
},
// Rakete fliegt zu einem zufälligen belegten Feld // Zeige Raketen-Explosions-Animation für automatische Aktivierung (ohne Flug)
await this.rocketFlightToRandomTile(); async showRocketExplosionAnimationSimple(centerIndex) {
const centerPos = this.indexToCoords(centerIndex);
const tileElement = document.querySelector(`[data-index="${centerIndex}"]`);
if (tileElement) {
const rect = tileElement.getBoundingClientRect();
this.rocketCenter = { x: rect.left + rect.width / 2, y: rect.top + rect.height / 2 };
}
// Zeige Explosions-Animation
this.showRocketEffect = true;
this.playSound('rocket');
// Warte auf Animation
await this.wait(1000);
// Verstecke Animation
this.showRocketEffect = false;
}, },
// Rakete fliegt zu einem zufälligen belegten Feld // Rakete fliegt zu einem zufälligen belegten Feld
@@ -4213,7 +4396,7 @@ export default {
this.removeAllTilesOfType(randomTileType); this.removeAllTilesOfType(randomTileType);
} else if (tile.type === 'bomb') { } else if (tile.type === 'bomb') {
// Bomben-Tile: 9 Tiles rundherum entfernen // Bomben-Tile: 9 Tiles rundherum entfernen
this.explodeBomb(index, 1); // 1 Ring = 3x3 Bereich this.explodeBomb(index, 1, true); // 1 Ring = 3x3 Bereich - manuelle Aktivierung
} else if (tile.type === 'rocket') { } else if (tile.type === 'rocket') {
// Raketen-Tile: 4 Nachbarfelder löschen und Rakete starten // Raketen-Tile: 4 Nachbarfelder löschen und Rakete starten
this.handleRocketDoubleClick(index); this.handleRocketDoubleClick(index);
@@ -4275,7 +4458,7 @@ export default {
await this.showBombEffectAnimation(bombIndex); await this.showBombEffectAnimation(bombIndex);
// Aktiviere die Bombe (3x3 Bereich) // Aktiviere die Bombe (3x3 Bereich)
this.explodeBomb(bombIndex, 1); this.explodeBomb(bombIndex, 1, true);
// Entferne die Bombe selbst // Entferne die Bombe selbst
console.log(`💣 Entferne Bombe an Position ${bombIndex}`); console.log(`💣 Entferne Bombe an Position ${bombIndex}`);
@@ -4351,7 +4534,7 @@ export default {
// Zwei Bomben-Tiles getauscht: Entferne 2 Ringe (5x5 Bereich) // Zwei Bomben-Tiles getauscht: Entferne 2 Ringe (5x5 Bereich)
const bombIndex = this.findBombIndex(originalTile1, originalTile2); const bombIndex = this.findBombIndex(originalTile1, originalTile2);
if (bombIndex !== null) { if (bombIndex !== null) {
this.explodeBomb(bombIndex, 2); // 2 Ringe = 5x5 Bereich this.explodeBomb(bombIndex, 2, true); // 2 Ringe = 5x5 Bereich - manuelle Aktivierung
} }
return true; return true;
} else if (originalTile1.type === 'bomb' || originalTile2.type === 'bomb') { } else if (originalTile1.type === 'bomb' || originalTile2.type === 'bomb') {
@@ -4362,7 +4545,7 @@ export default {
// Finde die neue Position der Bombe // Finde die neue Position der Bombe
const newBombIndex = this.findTileIndex(bombTile); const newBombIndex = this.findTileIndex(bombTile);
if (newBombIndex !== null) { if (newBombIndex !== null) {
this.explodeBomb(newBombIndex, 1); // 1 Ring = 3x3 Bereich this.explodeBomb(newBombIndex, 1, true); // 1 Ring = 3x3 Bereich - manuelle Aktivierung
} }
return true; return true;
} else if ((originalTile1.type === 'bomb' && originalTile2.type === 'rainbow') || } else if ((originalTile1.type === 'bomb' && originalTile2.type === 'rainbow') ||
@@ -4460,7 +4643,7 @@ export default {
}, },
// Neue Methode: Explodiere Bombe mit bestimmter Reichweite // Neue Methode: Explodiere Bombe mit bestimmter Reichweite
explodeBomb(centerIndex, rings) { explodeBomb(centerIndex, rings, isManualActivation = false) {
const { row: centerRow, col: centerCol } = this.indexToCoords(centerIndex); const { row: centerRow, col: centerCol } = this.indexToCoords(centerIndex);
const tilesToRemove = []; const tilesToRemove = [];
const powerUpsToTrigger = []; // Sammle Power-Ups für Kettenreaktionen const powerUpsToTrigger = []; // Sammle Power-Ups für Kettenreaktionen
@@ -4512,7 +4695,8 @@ export default {
this.score += points; this.score += points;
// Löse Kettenreaktionen nur für Power-Ups aus, die noch existieren // Löse Kettenreaktionen nur für Power-Ups aus, die noch existieren
if (powerUpsToTrigger.length > 0) { // UND nur wenn es sich um eine manuelle Aktivierung handelt
if (powerUpsToTrigger.length > 0 && isManualActivation) {
setTimeout(() => { setTimeout(() => {
// Prüfe nochmal, ob die Power-Ups noch existieren, bevor sie ausgelöst werden // Prüfe nochmal, ob die Power-Ups noch existieren, bevor sie ausgelöst werden
const validPowerUps = powerUpsToTrigger.filter(powerUp => const validPowerUps = powerUpsToTrigger.filter(powerUp =>
@@ -4533,7 +4717,7 @@ export default {
powerUps.forEach(powerUp => { powerUps.forEach(powerUp => {
if (powerUp.type === 'bomb') { if (powerUp.type === 'bomb') {
// Bombe explodiert mit 1 Ring (3x3 Bereich) // Bombe explodiert mit 1 Ring (3x3 Bereich)
this.explodeBomb(powerUp.index, 1); this.explodeBomb(powerUp.index, 1, true);
} else if (powerUp.type === 'rocket') { } else if (powerUp.type === 'rocket') {
// Rakete startet auf zufälliges Feld // Rakete startet auf zufälliges Feld
this.launchRocketToRandomField(powerUp.index); this.launchRocketToRandomField(powerUp.index);
@@ -4596,7 +4780,7 @@ export default {
// Löse alle Bomben aus // Löse alle Bomben aus
bombIndices.forEach(index => { bombIndices.forEach(index => {
this.explodeBomb(index, 1); this.explodeBomb(index, 1, true);
}); });
@@ -4720,7 +4904,7 @@ export default {
const landingIndex = availableIndices[randomIndex]; const landingIndex = availableIndices[randomIndex];
// Explodiere am Landungsort (9 Felder = 1 Ring) // Explodiere am Landungsort (9 Felder = 1 Ring)
this.explodeBomb(landingIndex, 1); this.explodeBomb(landingIndex, 1, true);
} }
@@ -5857,6 +6041,8 @@ export default {
.game-tile.bomb { .game-tile.bomb {
background: linear-gradient(45deg, #ff6b6b, #ff8e53) !important; background: linear-gradient(45deg, #ff6b6b, #ff8e53) !important;
position: relative; position: relative;
z-index: 10;
box-shadow: 0 0 15px rgba(255, 107, 107, 0.8);
} }
/* Bomben-Symbol */ /* Bomben-Symbol */
@@ -5865,6 +6051,16 @@ export default {
color: white; color: white;
text-shadow: 2px 2px 4px rgba(0,0,0,0.5); text-shadow: 2px 2px 4px rgba(0,0,0,0.5);
font-weight: bold; font-weight: bold;
animation: bombPulse 2s ease-in-out infinite;
}
@keyframes bombPulse {
0%, 100% {
transform: scale(1);
}
50% {
transform: scale(1.1);
}
} }
/* Raketen-Explosions-Effekt */ /* Raketen-Explosions-Effekt */