Change Bomb Implementation

- L and T shapes are no longer considered a match
- Bomb explodes WITH gems
- Bomb will  have a small sprite of the creating gem
This commit is contained in:
2025-12-17 00:44:23 +08:00
parent 9f9bf9a3f5
commit 85b9767201
3 changed files with 37 additions and 203 deletions

View File

@@ -34,19 +34,30 @@ namespace Services {
public bool MatchesAt(Vector2Int positionToCheck, GemType gemTypeToCheck) {
Gem[,] gems = this.gameBoard.GemsGrid;
// We don't prevent spawning bombs via this rule (and bombs shouldn't be treated as a normal color here).
if (gemTypeToCheck == GemType.Bomb)
return false;
if (positionToCheck.x > 1)
{
if (gems[positionToCheck.x - 1, positionToCheck.y].Type == gemTypeToCheck && gems[positionToCheck.x - 2, positionToCheck.y].Type == gemTypeToCheck)
// Check horizontal: would placing gemTypeToCheck at positionToCheck create XXX with 2-left?
if (positionToCheck.x > 1) {
Gem left1 = gems[positionToCheck.x - 1, positionToCheck.y];
Gem left2 = gems[positionToCheck.x - 2, positionToCheck.y];
if (left1 != null && left2 != null &&
left1.MatchColor == gemTypeToCheck &&
left2.MatchColor == gemTypeToCheck)
return true;
}
if (positionToCheck.y > 1)
{
if (gems[positionToCheck.x, positionToCheck.y - 1].Type == gemTypeToCheck && gems[positionToCheck.x, positionToCheck.y - 2].Type == gemTypeToCheck)
// Check vertical: would placing gemTypeToCheck at positionToCheck create XXX with 2-down?
if (positionToCheck.y > 1) {
Gem down1 = gems[positionToCheck.x, positionToCheck.y - 1];
Gem down2 = gems[positionToCheck.x, positionToCheck.y - 2];
if (down1 != null && down2 != null &&
down1.MatchColor == gemTypeToCheck &&
down2.MatchColor == gemTypeToCheck)
return true;
}
@@ -88,80 +99,12 @@ namespace Services {
}
}
if (this.currentMatches.Count > 0)
this.currentMatches = this.currentMatches.Distinct().ToList();
ExpandMatchesForLTShapes();
if (this.currentMatches.Count > 0)
this.currentMatches = this.currentMatches.Distinct().ToList();
DetectBombSpawnFromLastSwap();
}
private void ExpandMatchesForLTShapes() {
if (this.currentMatches.Count == 0)
return;
List<Gem> seeds = this.currentMatches.ToList();
foreach (Gem pivotGem in seeds) {
if (pivotGem == null)
continue;
Vector2Int pivot = pivotGem.Position;
int left = CountLine(pivot, Vector2Int.left);
int right = CountLine(pivot, Vector2Int.right);
int up = CountLine(pivot, Vector2Int.up);
int down = CountLine(pivot, Vector2Int.down);
int horizontalLen = left + 1 + right;
int verticalLen = up + 1 + down;
bool hasHorizontalMatch = horizontalLen >= 3;
bool hasVerticalMatch = verticalLen >= 3;
// one more in the perpendicular direction = length = 2
bool hasHorizontalArm = horizontalLen >= 2;
bool hasVerticalArm = verticalLen >= 2;
// Main horizontal + vertical arm = include vertical run
if (hasHorizontalMatch && hasVerticalArm) {
AddRun(pivot, Vector2Int.up);
AddRun(pivot, Vector2Int.down);
this.currentMatches.Add(pivotGem);
}
// Main vertical + horizontal arm = include horizontal run
if (hasVerticalMatch && hasHorizontalArm) {
AddRun(pivot, Vector2Int.left);
AddRun(pivot, Vector2Int.right);
this.currentMatches.Add(pivotGem);
}
}
}
private void AddRun(Vector2Int start, Vector2Int direction) {
Gem startGem = this.gameBoard.GetGemAt(start);
if (startGem == null)
return;
GemType color = startGem.MatchColor;
Vector2Int position = start + direction;
while (position.x >= 0 && position.x < this.gameBoard.Width &&
position.y >= 0 && position.y < this.gameBoard.Height) {
Gem g = this.gameBoard.GetGemAt(position);
if (g == null || g.MatchColor != color)
break;
this.currentMatches.Add(g);
position += direction;
}
}
private void DetectBombSpawnFromLastSwap() {
Vector2Int from = this.lastSwapFrom;
Vector2Int to = this.lastSwapTo;
@@ -182,9 +125,8 @@ namespace Services {
if (this.currentMatches.All(g => g.Position != pivot))
return;
// NEW RULE:
// If the match group that includes this pivot (including L/T expansions) has 4+ gems, spawn a bomb.
int groupSize = GetMatchedGroupSizeIncludingLT(pivot);
// If the matched group that includes this pivot has 4+ connected gems, spawn a bomb.
int groupSize = GetMatchedGroupSize(pivot);
if (groupSize < 4)
return;
@@ -195,14 +137,13 @@ namespace Services {
this.pendingBombSpawns.Add(new BombSpawnRequest(pivot, pivotGem.MatchColor));
}
private int GetMatchedGroupSizeIncludingLT(Vector2Int pivot) {
private int GetMatchedGroupSize(Vector2Int pivot) {
Gem pivotGem = this.gameBoard.GetGemAt(pivot);
if (pivotGem == null)
return 0;
GemType color = pivotGem.MatchColor;
// Only count gems that are actually in currentMatches (which already includes L/T expansions).
HashSet<Vector2Int> matchedPositions = new HashSet<Vector2Int>(
this.currentMatches
.Where(g => g != null && g.MatchColor == color)
@@ -243,90 +184,5 @@ namespace Services {
return visited.Count;
}
private int CountLine(Vector2Int start, Vector2Int direction) {
Gem startGem = this.gameBoard.GetGemAt(start);
if (startGem == null)
return 0;
GemType color = startGem.MatchColor;
int count = 0;
Vector2Int position = start + direction;
while (position.x >= 0 && position.x < this.gameBoard.Width && position.y >= 0 && position.y < this.gameBoard.Height) {
Gem g = this.gameBoard.GetGemAt(position);
if (g == null || g.MatchColor != color)
break;
count++;
position += direction;
}
return count;
}
private void CheckForBombs() {
Gem[,] gems = this.gameBoard.GemsGrid;
int width = this.gameBoard.Width;
int height = this.gameBoard.Height;
for (int i = 0; i < this.currentMatches.Count; i++)
{
Gem gem = this.currentMatches[i];
int x = gem.Position.x;
int y = gem.Position.y;
Vector2Int[] directions =
{
Vector2Int.left,
Vector2Int.right,
Vector2Int.down,
Vector2Int.up
};
foreach (Vector2Int direction in directions)
{
int newX = x + direction.x;
int newY = y + direction.y;
if (newX < 0 || newX >= width || newY < 0 || newY >= height)
continue;
Gem neighbor = gems[newX, newY];
if (neighbor?.Type == GemType.Bomb)
MarkBombCross(new Vector2Int(newX, newY), 1);
}
}
}
private void MarkBombCross(Vector2Int bombPosition, int radius) {
Gem[,] gems = this.gameBoard.GemsGrid;
int width = this.gameBoard.Width;
int height = this.gameBoard.Height;
void Mark(Vector2Int p) {
if (p.x < 0 || p.x >= width || p.y < 0 || p.y >= height)
return;
Gem g = gems[p.x, p.y];
if (g == null)
return;
this.currentMatches.Add(g);
}
Mark(bombPosition);
for (int i = 1; i <= radius; i++) {
Mark(bombPosition + Vector2Int.left * i);
Mark(bombPosition + Vector2Int.right * i);
Mark(bombPosition + Vector2Int.up * i);
Mark(bombPosition + Vector2Int.down * i);
}
this.currentMatches = this.currentMatches.Distinct().ToList();
}
}
}