Cleanup
This commit is contained in:
@@ -7,6 +7,7 @@ using Models.Interfaces;
|
||||
using Presenter;
|
||||
using ScriptableObjects;
|
||||
using Services.Interfaces;
|
||||
using Structs;
|
||||
using UnityEngine;
|
||||
using Utils;
|
||||
using VContainer.Unity;
|
||||
@@ -43,10 +44,10 @@ namespace Services {
|
||||
|
||||
public void Tick() {
|
||||
foreach (GemPresenter gemPresenter in gemPresenters) {
|
||||
gemPresenter.Tick();
|
||||
gemPresenter.Tick(this.gameVariables.gemSpeed);
|
||||
}
|
||||
|
||||
this.scorePresenter.Tick();
|
||||
this.scorePresenter.Tick(this.gameVariables.scoreSpeed);
|
||||
}
|
||||
|
||||
//Instantiates background tiles and calls SpawnGems
|
||||
@@ -77,16 +78,32 @@ namespace Services {
|
||||
|
||||
//Uses the ObjectPool to spawn a gem at the given position
|
||||
private void SpawnGem(Vector2Int position, GemType gemType) {
|
||||
if (Random.Range(0, 100f) < this.gameVariables.bombChance)
|
||||
gemType = GemType.Bomb;
|
||||
|
||||
GemView gemView = this.objectPool.Get(gemType, position, this.gameVariables.dropHeight);
|
||||
gemView.name = "Gem - " + position.x + ", " + position.y + ' ' + gemType;
|
||||
Gem gem = new Gem(gemType, position, 50);
|
||||
|
||||
// If we randomly spawned a bomb, give it a random color group (so it can match by color).
|
||||
int scoreValue = GemUtils.GetGemValues(gemType, this.gameVariables.gemsPrefabs).scoreValue;
|
||||
Gem gem = new Gem(gemType, position, scoreValue);
|
||||
|
||||
gemView.Bind(gem);
|
||||
|
||||
|
||||
this.gemPresenters.Add(new GemPresenter(gem, gemView));
|
||||
SetGem(new Vector2Int(position.x,position.y), gem);
|
||||
SetGem(new Vector2Int(position.x, position.y), gem);
|
||||
}
|
||||
|
||||
private void SpawnBomb(Vector2Int position, GemType color) {
|
||||
// remove existing gem/view at that position
|
||||
DestroyMatchedGems(position);
|
||||
|
||||
GemView gemView = this.objectPool.Get(GemType.Bomb, position, this.gameVariables.dropHeight);
|
||||
gemView.name = "Gem - " + position.x + ", " + position.y + ' ' + GemType.Bomb;
|
||||
|
||||
int scoreValue = GemUtils.GetGemValues(color, this.gameVariables.gemsPrefabs).scoreValue;
|
||||
Gem bombGem = new Gem(GemType.Bomb, position, scoreValue, color);
|
||||
gemView.Bind(bombGem);
|
||||
|
||||
this.gemPresenters.Add(new GemPresenter(bombGem, gemView));
|
||||
SetGem(position, bombGem);
|
||||
}
|
||||
|
||||
//Sets the gem on the GameBoard
|
||||
@@ -121,7 +138,7 @@ namespace Services {
|
||||
ApplySwap(from, to, fromGem, toGem);
|
||||
|
||||
await UniTask.Delay(600);
|
||||
|
||||
this.matchService.SetLastSwap(from, to);
|
||||
this.matchService.FindAllMatches();
|
||||
bool hasMatch = this.matchService.CurrentMatches.Count > 0;
|
||||
|
||||
@@ -131,8 +148,10 @@ namespace Services {
|
||||
this.currentState = GameState.Move;
|
||||
return false;
|
||||
}
|
||||
|
||||
List<Vector2Int> protectedPositions = ApplyPendingBombSpawns();
|
||||
|
||||
DestroyMatches();
|
||||
await DestroyMatchesAsync(protectedPositions);
|
||||
this.currentState = GameState.Move;
|
||||
return true;
|
||||
}
|
||||
@@ -146,17 +165,131 @@ namespace Services {
|
||||
SetGem(posA, gemB);
|
||||
SetGem(posB, gemA);
|
||||
}
|
||||
|
||||
private List<Vector2Int> ApplyPendingBombSpawns() {
|
||||
List<Vector2Int> positions = new List<Vector2Int>();
|
||||
|
||||
//If there are matches, destroys them and moves the gems down
|
||||
private void DestroyMatches() {
|
||||
for (int i = 0; i < this.matchService.CurrentMatches.Count; i++)
|
||||
if (this.matchService.CurrentMatches[i] != null)
|
||||
{
|
||||
this.scoreService.ScoreCheck(this.matchService.CurrentMatches[i].ScoreValue);
|
||||
DestroyMatchedGems(this.matchService.CurrentMatches[i].Position);
|
||||
foreach (BombSpawnRequest bomSpawnRequest in this.matchService.PendingBombSpawns) {
|
||||
positions.Add(bomSpawnRequest.Position);
|
||||
SpawnBomb(bomSpawnRequest.Position, bomSpawnRequest.Color);
|
||||
}
|
||||
|
||||
this.matchService.ClearPendingBombs();
|
||||
return positions;
|
||||
}
|
||||
|
||||
private async UniTask DestroyMatchesAsync(List<Vector2Int> protectedPositions) {
|
||||
// Build initial queues from current matches
|
||||
Queue<Vector2Int> bombsToProcess = new Queue<Vector2Int>();
|
||||
List<Vector2Int> processedBombs = new List<Vector2Int>();
|
||||
List<Vector2Int> regularToDestroy = new List<Vector2Int>();
|
||||
|
||||
for (int i = 0; i < this.matchService.CurrentMatches.Count; i++) {
|
||||
Gem matchedGem = this.matchService.CurrentMatches[i];
|
||||
if (matchedGem == null)
|
||||
continue;
|
||||
|
||||
Vector2Int pos = matchedGem.Position;
|
||||
|
||||
// If a bomb was spawned at this cell due to 4+ creation, it must survive this destruction pass.
|
||||
if (protectedPositions != null && protectedPositions.Contains(pos))
|
||||
continue;
|
||||
|
||||
Gem current = GetGem(pos);
|
||||
if (current == null)
|
||||
continue;
|
||||
|
||||
if (current.Type == GemType.Bomb) {
|
||||
bombsToProcess.Enqueue(pos);
|
||||
} else {
|
||||
regularToDestroy.Add(pos);
|
||||
}
|
||||
}
|
||||
|
||||
// Process bombs: neighbors first (after delay), then the bomb itself (after delay).
|
||||
while (bombsToProcess.Count > 0) {
|
||||
Vector2Int bombPos = bombsToProcess.Dequeue();
|
||||
if (processedBombs.Contains(bombPos))
|
||||
continue;
|
||||
|
||||
Gem bomb = GetGem(bombPos);
|
||||
if (bomb is not { Type: GemType.Bomb })
|
||||
continue;
|
||||
|
||||
processedBombs.Add(bombPos);
|
||||
|
||||
// Delay before destroying neighbor group
|
||||
if (this.gameVariables.bombDelay > 0f) {
|
||||
int msDelay = Mathf.RoundToInt(this.gameVariables.bombDelay * 1000f);
|
||||
await UniTask.Delay(msDelay);
|
||||
}
|
||||
|
||||
MoveGemsDown();
|
||||
// Collect cross neighbors
|
||||
foreach (Vector2Int neighborPosition in CrossNeighbors(bombPos, this.gameVariables.bombRadius)) {
|
||||
if (!InBounds(neighborPosition))
|
||||
continue;
|
||||
|
||||
Gem g = GetGem(neighborPosition);
|
||||
if (g == null)
|
||||
continue;
|
||||
|
||||
// If we encounter another bomb, queue it (so it explodes too).
|
||||
if (g.Type == GemType.Bomb) {
|
||||
if (!processedBombs.Contains(neighborPosition))
|
||||
bombsToProcess.Enqueue(neighborPosition);
|
||||
continue;
|
||||
}
|
||||
|
||||
regularToDestroy.Add(neighborPosition);
|
||||
}
|
||||
|
||||
// Destroy the neighbor group now
|
||||
foreach (Vector2Int position in regularToDestroy.ToList()) {
|
||||
Gem gem = GetGem(position);
|
||||
if (gem == null)
|
||||
continue;
|
||||
|
||||
this.scoreService.ScoreCheck(gem.ScoreValue);
|
||||
DestroyMatchedGems(position);
|
||||
}
|
||||
regularToDestroy.Clear();
|
||||
|
||||
// Delay before destroying the bomb itself
|
||||
if (this.gameVariables.bombSelfDelay > 0f) {
|
||||
int ms = Mathf.RoundToInt(this.gameVariables.bombSelfDelay * 1000f);
|
||||
await UniTask.Delay(ms);
|
||||
}
|
||||
|
||||
// Destroy the bomb
|
||||
Gem b = GetGem(bombPos);
|
||||
if (b != null && b.Type == GemType.Bomb) {
|
||||
this.scoreService.ScoreCheck(b.ScoreValue);
|
||||
DestroyMatchedGems(bombPos);
|
||||
}
|
||||
}
|
||||
|
||||
// Destroy any remaining regular matches (non-bomb) after bomb processing
|
||||
foreach (Vector2Int pos in regularToDestroy) {
|
||||
Gem g = GetGem(pos);
|
||||
if (g == null)
|
||||
continue;
|
||||
|
||||
this.scoreService.ScoreCheck(g.ScoreValue);
|
||||
DestroyMatchedGems(pos);
|
||||
}
|
||||
|
||||
// Now we can cascade
|
||||
await MoveGemsDown();
|
||||
}
|
||||
|
||||
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() {
|
||||
@@ -189,14 +322,14 @@ namespace Services {
|
||||
await UniTask.Delay(5);
|
||||
RefillBoard();
|
||||
await UniTask.Delay(5);
|
||||
|
||||
this.matchService.FindAllMatches();
|
||||
if (this.matchService.CurrentMatches.Count > 0)
|
||||
{
|
||||
if (this.matchService.CurrentMatches.Count > 0) {
|
||||
await UniTask.Delay(5);
|
||||
DestroyMatches();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// In cascades, there is no "creating slot" bomb protection.
|
||||
await DestroyMatchesAsync(new List<Vector2Int>());
|
||||
} else {
|
||||
await UniTask.Delay(5);
|
||||
this.currentState = GameState.Move;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user