Cleanup GameBOardService
This commit is contained in:
@@ -21,10 +21,6 @@ namespace Services
|
||||
|
||||
private BombSpawnRequest? pendingBombSpawn;
|
||||
public BombSpawnRequest? PendingBombSpawn => this.pendingBombSpawn;
|
||||
|
||||
public void ClearPendingBombs() {
|
||||
this.pendingBombSpawn = null;
|
||||
}
|
||||
|
||||
public BombService(GameVariables gameVariables, IGameBoard gameBoard) {
|
||||
this.gameVariables = gameVariables;
|
||||
@@ -34,6 +30,38 @@ namespace Services
|
||||
public void SetLastSwap(Vector2Int from, Vector2Int to) {
|
||||
this.lastSwapFrom = from;
|
||||
this.lastSwapTo = to;
|
||||
|
||||
ClearPendingBombs();
|
||||
}
|
||||
|
||||
public UniTask<List<Vector2Int>> GetInitialBombs(List<Vector2Int> protectedPositions, List<Vector2Int> bombCandidates) {
|
||||
List<Vector2Int> initialBombs = new List<Vector2Int>();
|
||||
foreach (Vector2Int p in bombCandidates) {
|
||||
if (!GemUtils.IsInBounds(p, this.gameBoard)) continue;
|
||||
|
||||
if (protectedPositions != null && protectedPositions.Contains(p))
|
||||
continue;
|
||||
|
||||
Gem gem = this.gameBoard.GetGemAt(p);
|
||||
if (gem is { Type: GemType.Bomb })
|
||||
initialBombs.Add(p);
|
||||
}
|
||||
|
||||
return UniTask.FromResult(initialBombs.Distinct().ToList());
|
||||
}
|
||||
|
||||
public List<Vector2Int> ApplyPendingBombSpawns(Action<Vector2Int, GemType, bool> spawnGem) {
|
||||
List<Vector2Int> positions = new List<Vector2Int>();
|
||||
BombSpawnRequest? bombSpawnRequest = PendingBombSpawn;
|
||||
|
||||
if (bombSpawnRequest != null) {
|
||||
BombSpawnRequest bombRequest = PendingBombSpawn.GetValueOrDefault();
|
||||
positions.Add(bombRequest.Position);
|
||||
spawnGem(bombRequest.Position, bombRequest.Color, true);
|
||||
}
|
||||
|
||||
ClearPendingBombs();
|
||||
return positions;
|
||||
}
|
||||
|
||||
public void DetectBombSpawnFromLastSwap(List<Gem> currentMatches) {
|
||||
@@ -201,5 +229,9 @@ namespace Services
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
public void ClearPendingBombs() {
|
||||
this.pendingBombSpawn = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -100,7 +100,7 @@ namespace Services {
|
||||
//Uses the ObjectPool to spawn a gem at the given position
|
||||
private void SpawnGem(Vector2Int position, GemType gemType, bool isBomb = false) {
|
||||
if (isBomb) {
|
||||
DestroyMatchedGems(position);
|
||||
ReleaseMatchedGems(position);
|
||||
}
|
||||
|
||||
GemView gemView = this.objectPool.Get(isBomb ? GemType.Bomb : gemType, position, isBomb ? 0 : this.gameVariables.dropHeight);
|
||||
@@ -121,8 +121,8 @@ namespace Services {
|
||||
|
||||
if (!GemUtils.IsInBounds(from, this.gameBoard) || !GemUtils.IsInBounds(to, this.gameBoard))
|
||||
return false;
|
||||
|
||||
if (!AreAdjacentCardinal(from, to))
|
||||
|
||||
if (!from.IsAdjacent(to))
|
||||
return false;
|
||||
|
||||
this.currentState = GameState.Wait;
|
||||
@@ -131,7 +131,6 @@ namespace Services {
|
||||
|
||||
await UniTask.Delay(600);
|
||||
this.bombService.SetLastSwap(from, to);
|
||||
this.bombService.ClearPendingBombs();
|
||||
this.matchService.FindAllMatches();
|
||||
this.bombService.DetectBombSpawnFromLastSwap(this.matchService.CurrentMatches);
|
||||
|
||||
@@ -142,7 +141,7 @@ namespace Services {
|
||||
return false;
|
||||
}
|
||||
|
||||
List<Vector2Int> protectedPositions = ApplyPendingBombSpawns();
|
||||
List<Vector2Int> protectedPositions = this.bombService.ApplyPendingBombSpawns(SpawnGem);
|
||||
await DestroyMatchesAsync(protectedPositions);
|
||||
this.currentState = GameState.Move;
|
||||
return true;
|
||||
@@ -160,47 +159,9 @@ namespace Services {
|
||||
this.gameBoard.SetGemAt(to, fromGem);
|
||||
}
|
||||
|
||||
private List<Vector2Int> ApplyPendingBombSpawns() {
|
||||
List<Vector2Int> positions = new List<Vector2Int>();
|
||||
BombSpawnRequest? bombSpawnRequest = this.bombService.PendingBombSpawn;
|
||||
|
||||
if (bombSpawnRequest != null) {
|
||||
BombSpawnRequest bombRequest = this.bombService.PendingBombSpawn.GetValueOrDefault();
|
||||
positions.Add(bombRequest.Position);
|
||||
SpawnGem(bombRequest.Position, bombRequest.Color, isBomb: true);
|
||||
}
|
||||
|
||||
this.bombService.ClearPendingBombs();
|
||||
return positions;
|
||||
}
|
||||
|
||||
private async UniTask DestroyMatchesAsync(List<Vector2Int> protectedPositions) {
|
||||
List<Vector2Int> matchPositions = new List<Vector2Int>(this.matchService.CurrentMatches.Count);
|
||||
for (int i = 0; i < this.matchService.CurrentMatches.Count; i++) {
|
||||
Gem match = this.matchService.CurrentMatches[i];
|
||||
if (match == null) continue;
|
||||
|
||||
Vector2Int pos = match.Position;
|
||||
if (protectedPositions != null && protectedPositions.Contains(pos))
|
||||
continue;
|
||||
|
||||
matchPositions.Add(pos);
|
||||
}
|
||||
|
||||
IReadOnlyList<Vector2Int> bombCandidates = matchPositions.Distinct().ToList();
|
||||
|
||||
List<Vector2Int> initialBombs = new List<Vector2Int>();
|
||||
foreach (Vector2Int p in bombCandidates) {
|
||||
if (!GemUtils.IsInBounds(p, this.gameBoard)) continue;
|
||||
|
||||
if (protectedPositions != null && protectedPositions.Contains(p))
|
||||
continue;
|
||||
|
||||
Gem gem = this.gameBoard.GetGemAt(p);
|
||||
if (gem is { Type: GemType.Bomb })
|
||||
initialBombs.Add(p);
|
||||
}
|
||||
initialBombs = initialBombs.Distinct().ToList();
|
||||
List<Vector2Int> matchPositions = await this.matchService.GetMatchPositionsAsync(protectedPositions);
|
||||
List<Vector2Int> initialBombs = await this.bombService.GetInitialBombs(protectedPositions, matchPositions.Distinct().ToList());
|
||||
|
||||
// If a bomb is part of the match, do NOT destroy matching pieces immediately.
|
||||
// Let the bomb's manhattan-distance explosion destroy them in sequence.
|
||||
@@ -210,29 +171,27 @@ namespace Services {
|
||||
DestroyAtAsync,
|
||||
this.gameBoard);
|
||||
|
||||
await UniTask.Delay(600);
|
||||
|
||||
await MoveGemsDown();
|
||||
return;
|
||||
}
|
||||
|
||||
// For audio SFX
|
||||
bool willBreakAnyNonBombGem = matchPositions.Select(pos => this.gameBoard.GetGemAt(pos)).Where(gem => gem != null).Any(gem => gem.Type != GemType.Bomb);
|
||||
|
||||
if (willBreakAnyNonBombGem)
|
||||
this.audioPresenter.OnMatch(this.gameVariables.matchSfx);
|
||||
|
||||
// For score counting
|
||||
foreach (Vector2Int pos in matchPositions.Distinct().ToList()) {
|
||||
Gem gem = this.gameBoard.GetGemAt(pos);
|
||||
if (gem == null) continue;
|
||||
if (gem.Type == GemType.Bomb) continue;
|
||||
|
||||
this.scoreService.ScoreCheck(gem.ScoreValue);
|
||||
DestroyMatchedGems(pos);
|
||||
ReleaseMatchedGems(pos);
|
||||
}
|
||||
|
||||
await this.bombService.DetonateChainAsync(
|
||||
initialBombs,
|
||||
DestroyAtAsync,
|
||||
this.gameBoard);
|
||||
|
||||
await MoveGemsDown();
|
||||
}
|
||||
|
||||
@@ -245,9 +204,25 @@ namespace Services {
|
||||
this.audioPresenter.OnBombExplosion(this.gameVariables.bombExplodeSfx);
|
||||
|
||||
this.scoreService.ScoreCheck(gem.ScoreValue);
|
||||
DestroyMatchedGems(pos);
|
||||
ReleaseMatchedGems(pos);
|
||||
return UniTask.CompletedTask;
|
||||
}
|
||||
|
||||
private void ReleaseMatchedGems(Vector2Int position) {
|
||||
List<GemView> gemsViews = this.gemsHolder.GetComponentsInChildren<GemView>().ToList();
|
||||
Gem currentGem = this.gameBoard.GetGemAt(position);
|
||||
if (currentGem != null)
|
||||
{
|
||||
GemView gemView = gemsViews.FirstOrDefault(gv => gv.Gem == currentGem);
|
||||
if (gemView is null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.objectPool.Release(gemView);
|
||||
RemovePresenterFor(gemView);
|
||||
this.gameBoard.SetGemAt(position, null);
|
||||
}
|
||||
}
|
||||
|
||||
private async UniTask MoveGemsDown() {
|
||||
await UniTask.Delay(50);
|
||||
@@ -313,22 +288,6 @@ namespace Services {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DestroyMatchedGems(Vector2Int position) {
|
||||
List<GemView> gemsViews = this.gemsHolder.GetComponentsInChildren<GemView>().ToList();
|
||||
Gem currentGem = this.gameBoard.GetGemAt(position);
|
||||
if (currentGem != null)
|
||||
{
|
||||
GemView gemView = gemsViews.FirstOrDefault(gv => gv.Gem == currentGem);
|
||||
if (gemView is null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.objectPool.Release(gemView);
|
||||
RemovePresenterFor(gemView);
|
||||
this.gameBoard.SetGemAt(position, null);
|
||||
}
|
||||
}
|
||||
|
||||
#region Utils
|
||||
private void RemovePresenterFor(GemView gemView) {
|
||||
@@ -339,11 +298,6 @@ namespace Services {
|
||||
GemPresenter presenter = this.gemPresenters.FirstOrDefault(p => p.GemView == gemView);
|
||||
this.gemPresenters.Remove(presenter);
|
||||
}
|
||||
|
||||
private static bool AreAdjacentCardinal(Vector2Int a, Vector2Int b) {
|
||||
Vector2Int d = b - a;
|
||||
return (Mathf.Abs(d.x) == 1 && d.y == 0) || (Mathf.Abs(d.y) == 1 && d.x == 0);
|
||||
}
|
||||
#endregion
|
||||
|
||||
public void Dispose() {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Enums;
|
||||
using Models.Interfaces;
|
||||
using Structs;
|
||||
using UnityEngine;
|
||||
@@ -12,9 +13,10 @@ namespace Services.Interfaces
|
||||
public BombSpawnRequest? PendingBombSpawn { get; }
|
||||
|
||||
void SetLastSwap(Vector2Int from, Vector2Int to);
|
||||
void ClearPendingBombs();
|
||||
|
||||
void DetectBombSpawnFromLastSwap(List<Gem> currentMatches);
|
||||
List<Vector2Int> ApplyPendingBombSpawns(Action<Vector2Int, GemType, bool> spawnGem);
|
||||
UniTask<List<Vector2Int>> GetInitialBombs(List<Vector2Int> protectedPositions, List<Vector2Int> bombCandidates);
|
||||
|
||||
UniTask DetonateChainAsync(
|
||||
IReadOnlyList<Vector2Int> initialBombs,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using Enums;
|
||||
using Structs;
|
||||
@@ -6,6 +7,7 @@ using Structs;
|
||||
namespace Services.Interfaces {
|
||||
public interface IMatchService {
|
||||
List<Gem> CurrentMatches { get; }
|
||||
UniTask<List<Vector2Int>> GetMatchPositionsAsync(List<Vector2Int> protectedPositions);
|
||||
bool MatchesAt(Vector2Int positionToCheck, GemType gemTypeToCheck);
|
||||
void FindAllMatches();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Enums;
|
||||
using Models.Interfaces;
|
||||
using Services.Interfaces;
|
||||
@@ -50,6 +51,22 @@ namespace Services {
|
||||
return false;
|
||||
}
|
||||
|
||||
public UniTask<List<Vector2Int>> GetMatchPositionsAsync(List<Vector2Int> protectedPositions) {
|
||||
List<Vector2Int> matchPositions = new List<Vector2Int>(CurrentMatches.Count);
|
||||
for (int i = 0; i < CurrentMatches.Count; i++) {
|
||||
Gem match = CurrentMatches[i];
|
||||
if (match == null) continue;
|
||||
|
||||
Vector2Int pos = match.Position;
|
||||
if (protectedPositions != null && protectedPositions.Contains(pos))
|
||||
continue;
|
||||
|
||||
matchPositions.Add(pos);
|
||||
}
|
||||
|
||||
return UniTask.FromResult(matchPositions);
|
||||
}
|
||||
|
||||
public void FindAllMatches() {
|
||||
this.currentMatches.Clear();
|
||||
|
||||
|
||||
@@ -14,5 +14,10 @@ namespace Utils {
|
||||
public static Vector2Int ToVector2Int(this Vector2 v) {
|
||||
return new Vector2Int((int)v.x, (int)v.y);
|
||||
}
|
||||
|
||||
public static bool IsAdjacent(this Vector2Int a, Vector2Int b) {
|
||||
Vector2Int d = b - a;
|
||||
return (Mathf.Abs(d.x) == 1 && d.y == 0) || (Mathf.Abs(d.y) == 1 && d.x == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user