Separate Bomb Logic

This commit is contained in:
2025-12-15 04:55:05 +08:00
parent f4a2cac16d
commit 5f0af52710
3 changed files with 24 additions and 48 deletions

View File

@@ -17,12 +17,7 @@ namespace Services
if (matchPositions == null || matchPositions.Count == 0) if (matchPositions == null || matchPositions.Count == 0)
return Array.Empty<Vector2Int>(); return Array.Empty<Vector2Int>();
// Activation: any match cell that is a bomb OR cardinal-adjacent to a bomb. HashSet<Vector2Int> candidates = new HashSet<Vector2Int>();
// NOTE: The actual "is bomb?" check depends on the board, so we only return
// the positions to be checked/queued by caller if desired.
// To keep BombService isolated, well let DetonateChainAsync validate bombs via getGemAt.
// Here we return: all matched positions + their cardinal neighbors.
HashSet<Vector2Int> candidates = new HashSet<Vector2Int>(matchPositions);
foreach (Vector2Int p in matchPositions) foreach (Vector2Int p in matchPositions)
{ {
@@ -65,13 +60,11 @@ namespace Services
processed.Add(bombPos); processed.Add(bombPos);
// Delay before neighbor blast
int neighborDelayMs = Mathf.Max(0, Mathf.RoundToInt(bombDelaySeconds * 1000f)); int neighborDelayMs = Mathf.Max(0, Mathf.RoundToInt(bombDelaySeconds * 1000f));
if (neighborDelayMs > 0) if (neighborDelayMs > 0)
await UniTask.Delay(neighborDelayMs); await UniTask.Delay(neighborDelayMs);
// Blast neighbors first (cross) foreach (Vector2Int n in DiamondNeighbors(bombPos, radius))
foreach (Vector2Int n in CrossNeighbors(bombPos, radius))
{ {
if (!inBounds(n)) if (!inBounds(n))
continue; continue;
@@ -80,7 +73,6 @@ namespace Services
if (g == null) if (g == null)
continue; continue;
// Chain: if another bomb is in blast area, queue it
if (g.Type == GemType.Bomb) if (g.Type == GemType.Bomb)
{ {
if (!processed.Contains(n)) if (!processed.Contains(n))
@@ -91,26 +83,28 @@ namespace Services
await destroyAtAsync(n); await destroyAtAsync(n);
} }
// Delay before destroying the bomb itself
int selfDelayMs = Mathf.Max(0, Mathf.RoundToInt(bombSelfDelaySeconds * 1000f)); int selfDelayMs = Mathf.Max(0, Mathf.RoundToInt(bombSelfDelaySeconds * 1000f));
if (selfDelayMs > 0) if (selfDelayMs > 0)
await UniTask.Delay(selfDelayMs); await UniTask.Delay(selfDelayMs);
// Destroy bomb last
Gem stillBomb = getGemAt(bombPos); Gem stillBomb = getGemAt(bombPos);
if (stillBomb is { Type: GemType.Bomb }) if (stillBomb is { Type: GemType.Bomb })
await destroyAtAsync(bombPos); await destroyAtAsync(bombPos);
} }
} }
private static IEnumerable<Vector2Int> CrossNeighbors(Vector2Int center, int radius) private static IEnumerable<Vector2Int> DiamondNeighbors(Vector2Int center, int radius)
{ {
for (int i = 1; i <= radius; i++) for (int x = -radius; x <= radius; x++)
{ {
yield return center + Vector2Int.left * i; int maxY = radius - Mathf.Abs(x);
yield return center + Vector2Int.right * i; for (int y = -maxY; y <= maxY; y++)
yield return center + Vector2Int.up * i; {
yield return center + Vector2Int.down * i; if (x == 0 && y == 0)
continue;
yield return new Vector2Int(center.x + x, center.y + y);
}
} }
} }
} }

View File

@@ -181,7 +181,6 @@ namespace Services {
} }
private async UniTask DestroyMatchesAsync(List<Vector2Int> protectedPositions) { private async UniTask DestroyMatchesAsync(List<Vector2Int> protectedPositions) {
// Collect match positions, excluding protected (bomb creation slots).
List<Vector2Int> matchPositions = new List<Vector2Int>(this.matchService.CurrentMatches.Count); List<Vector2Int> matchPositions = new List<Vector2Int>(this.matchService.CurrentMatches.Count);
for (int i = 0; i < this.matchService.CurrentMatches.Count; i++) { for (int i = 0; i < this.matchService.CurrentMatches.Count; i++) {
var m = this.matchService.CurrentMatches[i]; var m = this.matchService.CurrentMatches[i];
@@ -194,13 +193,12 @@ namespace Services {
matchPositions.Add(pos); matchPositions.Add(pos);
} }
// Bombs are handled by BombService so they can respect delays + chaining.
foreach (Vector2Int pos in matchPositions.Distinct().ToList()) { foreach (Vector2Int pos in matchPositions.Distinct().ToList()) {
var g = GetGem(pos); Gem gem = GetGem(pos);
if (g == null) continue; if (gem == null) continue;
if (g.Type == GemType.Bomb) continue; if (gem.Type == GemType.Bomb) continue;
this.scoreService.ScoreCheck(g.ScoreValue); this.scoreService.ScoreCheck(gem.ScoreValue);
DestroyMatchedGems(pos); DestroyMatchedGems(pos);
} }
@@ -209,22 +207,17 @@ namespace Services {
List<Vector2Int> initialBombs = new List<Vector2Int>(); List<Vector2Int> initialBombs = new List<Vector2Int>();
foreach (Vector2Int p in bombCandidates) { foreach (Vector2Int p in bombCandidates) {
if (!InBounds(p)) continue; if (!InBounds(p)) continue;
var g = GetGem(p);
if (g is { Type: GemType.Bomb }) if (protectedPositions != null && protectedPositions.Contains(p))
continue;
Gem gem = GetGem(p);
if (gem is { Type: GemType.Bomb })
initialBombs.Add(p); initialBombs.Add(p);
} }
initialBombs = initialBombs.Distinct().ToList(); initialBombs = initialBombs.Distinct().ToList();
await this.bombService.DetonateChainAsync( await this.bombService.DetonateChainAsync(initialBombs, InBounds, GetGem, DestroyAtAsync, this.gameVariables.bombRadius, this.gameVariables.bombDelay, this.gameVariables.bombSelfDelay);
initialBombs,
InBounds,
GetGem,
DestroyAtAsync,
this.gameVariables.bombRadius,
this.gameVariables.bombDelay,
this.gameVariables.bombSelfDelay
);
await MoveGemsDown(); await MoveGemsDown();
} }
@@ -238,16 +231,6 @@ namespace Services {
return UniTask.CompletedTask; return UniTask.CompletedTask;
} }
private static IEnumerable<Vector2Int> CrossNeighbors(Vector2Int center, int radius) {
// center excluded for "neighbors first"
for (int i = 1; i <= radius; i++) {
yield return center + Vector2Int.left * i;
yield return center + Vector2Int.right * i;
yield return center + Vector2Int.up * i;
yield return center + Vector2Int.down * i;
}
}
private async UniTask MoveGemsDown() { private async UniTask MoveGemsDown() {
await UniTask.Delay(50); await UniTask.Delay(50);

View File

@@ -92,7 +92,6 @@ namespace Services {
this.currentMatches = this.currentMatches.Distinct().ToList(); this.currentMatches = this.currentMatches.Distinct().ToList();
DetectBombSpawnFromLastSwap(); DetectBombSpawnFromLastSwap();
CheckForBombs();
} }
private void DetectBombSpawnFromLastSwap() { private void DetectBombSpawnFromLastSwap() {