From de2de35b1b3a708026408653099777b3edabc935 Mon Sep 17 00:00:00 2001 From: Jesus Castro Date: Wed, 17 Dec 2025 00:11:17 +0800 Subject: [PATCH] Adjust Bomb Behavior --- Assets/GameVariables.asset | 2 +- .../ScriptableObjects/GameVariables.cs | 2 - Assets/Scripts/Services/BombService.cs | 118 ++++++++++++------ Assets/Scripts/Services/GameBoardService.cs | 6 +- .../Services/Interfaces/IBombService.cs | 3 +- 5 files changed, 84 insertions(+), 47 deletions(-) diff --git a/Assets/GameVariables.asset b/Assets/GameVariables.asset index 8b56d1b..aef3568 100644 --- a/Assets/GameVariables.asset +++ b/Assets/GameVariables.asset @@ -53,7 +53,7 @@ MonoBehaviour: scoreValue: 10 width: 7 height: 7 - bombDelay: 1 + bombDelay: 2 bombSelfDelay: 1 bombRadius: 2 dropHeight: 2 diff --git a/Assets/Scripts/ScriptableObjects/GameVariables.cs b/Assets/Scripts/ScriptableObjects/GameVariables.cs index ff9c2da..dd529bb 100644 --- a/Assets/Scripts/ScriptableObjects/GameVariables.cs +++ b/Assets/Scripts/ScriptableObjects/GameVariables.cs @@ -18,8 +18,6 @@ namespace ScriptableObjects { [Header("Bomb")] [Tooltip("How long before the gems around the bomb explode")] public float bombDelay = 0.1f; - [Tooltip("How long before the bomb itself explodes")] - public float bombSelfDelay = 0.05f; [Tooltip("How far the explosion reaches")] public int bombRadius = 1; diff --git a/Assets/Scripts/Services/BombService.cs b/Assets/Scripts/Services/BombService.cs index b4b0ea8..b72528e 100644 --- a/Assets/Scripts/Services/BombService.cs +++ b/Assets/Scripts/Services/BombService.cs @@ -42,67 +42,98 @@ namespace Services Func getGemAt, Func destroyAtAsync, int radius, - float bombDelaySeconds, - float bombSelfDelaySeconds) + float bombDelaySeconds) { if (initialBombs == null || initialBombs.Count == 0) return; - Queue queue = new Queue(initialBombs); - HashSet processed = new HashSet(); + int waveDelayMs = Mathf.Max(0, Mathf.RoundToInt(bombDelaySeconds * 1000f)); - while (queue.Count > 0) - { - Vector2Int bombPos = queue.Dequeue(); - if (processed.Contains(bombPos)) - continue; + HashSet processedBombs = new HashSet(); - if (!inBounds(bombPos)) - continue; - - Gem bomb = getGemAt(bombPos); - if (bomb is not { Type: GemType.Bomb }) - continue; - - processed.Add(bombPos); - - int ringDelayMs = Mathf.RoundToInt(bombDelaySeconds * 1000f); - - for (int dist = 1; dist <= radius; dist++) + Queue waveQueue = new Queue( + initialBombs.Where(p => { - if (ringDelayMs > 0) - await UniTask.Delay(ringDelayMs); + if (!inBounds(p)) return false; + Gem g = getGemAt(p); + return g is { Type: GemType.Bomb }; + }) + ); - foreach (Vector2Int n in DiamondRing(bombPos, dist)) + while (waveQueue.Count > 0) + { + // current wave (per bomb) + List waveBombs = new List(); + while (waveQueue.Count > 0) + { + Vector2Int b = waveQueue.Dequeue(); + if (processedBombs.Contains(b)) + continue; + + if (!inBounds(b)) + continue; + + Gem g = getGemAt(b); + if (g is not { Type: GemType.Bomb }) + continue; + + processedBombs.Add(b); + waveBombs.Add(b); + } + + if (waveBombs.Count == 0) + continue; + + // delay once per wave + if (waveDelayMs > 0) + await UniTask.Delay(waveDelayMs); + + HashSet nextWaveBombs = new HashSet(); + HashSet toDestroyNow = new HashSet(); + + for (int i = 0; i < waveBombs.Count; i++) + { + Vector2Int bombPos = waveBombs[i]; + + // destroy self when it detonates + toDestroyNow.Add(bombPos); + + foreach (Vector2Int p in DiamondAreaInclusive(bombPos, radius)) { - if (!inBounds(n)) + if (!inBounds(p)) continue; - Gem g = getGemAt(n); - if (g == null) + if (p == bombPos) continue; - if (g.Type == GemType.Bomb) + Gem cellGem = getGemAt(p); + if (cellGem == null) + continue; + + if (cellGem.Type == GemType.Bomb) { - if (!processed.Contains(n)) - queue.Enqueue(n); + // bombs in range are NOT destroyed now. triggered to explode in a later wave. + if (!processedBombs.Contains(p)) + nextWaveBombs.Add(p); + continue; } - await destroyAtAsync(n); + // Non-bomb gem gets destroyed by this bomb + toDestroyNow.Add(p); } } - int selfDelayMs = Mathf.Max(0, Mathf.RoundToInt(bombSelfDelaySeconds * 1000f)); - if (selfDelayMs > 0) - await UniTask.Delay(selfDelayMs); + // Destroy everything for this wave (non-bombs in range + the detonating bombs themselves) + foreach (Vector2Int p in toDestroyNow) + await destroyAtAsync(p); - Gem stillBomb = getGemAt(bombPos); - if (stillBomb is { Type: GemType.Bomb }) - await destroyAtAsync(bombPos); + // Schedule the next wave (triggered bombs) + foreach (Vector2Int b in nextWaveBombs) + waveQueue.Enqueue(b); } } - + private static IEnumerable DiamondRing(Vector2Int center, int distance) { for (int distanceX = -distance; distanceX <= distance; distanceX++) @@ -119,5 +150,16 @@ namespace Services } } } + + private static IEnumerable DiamondAreaInclusive(Vector2Int center, int radius) + { + yield return center; + + for (int dist = 1; dist <= radius; dist++) + { + foreach (Vector2Int pivot in DiamondRing(center, dist)) + yield return pivot; + } + } } } \ No newline at end of file diff --git a/Assets/Scripts/Services/GameBoardService.cs b/Assets/Scripts/Services/GameBoardService.cs index 9802938..a2c9575 100644 --- a/Assets/Scripts/Services/GameBoardService.cs +++ b/Assets/Scripts/Services/GameBoardService.cs @@ -217,8 +217,7 @@ namespace Services { GetGem, DestroyAtAsync, this.gameVariables.bombRadius, - this.gameVariables.bombDelay, - this.gameVariables.bombSelfDelay); + this.gameVariables.bombDelay); await MoveGemsDown(); return; @@ -239,8 +238,7 @@ namespace Services { GetGem, DestroyAtAsync, this.gameVariables.bombRadius, - this.gameVariables.bombDelay, - this.gameVariables.bombSelfDelay); + this.gameVariables.bombDelay); await MoveGemsDown(); } diff --git a/Assets/Scripts/Services/Interfaces/IBombService.cs b/Assets/Scripts/Services/Interfaces/IBombService.cs index 1dd8d0a..19e4ed6 100644 --- a/Assets/Scripts/Services/Interfaces/IBombService.cs +++ b/Assets/Scripts/Services/Interfaces/IBombService.cs @@ -15,7 +15,6 @@ namespace Services.Interfaces Func getGemAt, Func destroyAtAsync, int radius, - float bombDelaySeconds, - float bombSelfDelaySeconds); + float bombDelaySeconds); } } \ No newline at end of file