7. 特殊方块与效果
2026/4/14大约 7 分钟
休闲益智——特殊方块与效果
你玩三消游戏时一定遇到过这种情况:不小心消了 4 个方块,然后其中一个变成了带条纹的"特殊方块"。你好奇地点了一下它——轰!整行(或整列)全消了!紧接着连锁反应炸开了,屏幕上一片烟花。
特殊方块是三消游戏的"大招系统"——平时积累,关键时刻释放,带来远超普通消除的爽快感。本章我们就来实现这套系统。
本章你将学到
- 四种特殊方块的设计和触发条件
- 条纹方块(行清除/列清除)
- 炸弹方块(十字消除)
- 彩虹方块(全色消除)
- 特殊方块的组合效果
特殊方块一览
| 特殊方块 | 触发条件 | 效果 | 视觉特征 |
|---|---|---|---|
| 条纹方块 | 一次消除 4 个 | 清除整行或整列 | 方块上有横向/纵向条纹 |
| 炸弹方块 | 形成 L 形或 T 形消除 | 炸掉周围 3x3 范围 | 方块上有炸弹图标 |
| 彩虹方块 | 一次消除 5 个 | 消除棋盘上所有同色方块 | 彩色旋转方块 |
设计原则
特殊方块是"奖励",不是"必需品"。玩家用普通的三消也能过关,但用特殊方块能过得更轻松、得分更高。这就像做菜时的调料——没有也能吃,有了更美味。
方块类型扩展
首先,扩展我们的方块类型枚举,加入特殊方块。关键设计是:每个特殊方块都带有自己的基础颜色,这样它既能在匹配检测中被识别,又拥有特殊效果。
C
/// <summary>
/// 方块类型枚举 —— 包含普通方块和特殊方块。
/// 特殊方块有自己的基础颜色,同时携带特殊效果。
/// 编号规则:1-5 是普通方块,10+ 是条纹,20+ 是炸弹,30 是彩虹。
/// </summary>
public enum PieceType
{
Empty = 0, // 空格子
Red = 1, // 普通红色
Blue = 2, // 普通蓝色
Green = 3, // 普通绿色
Yellow = 4, // 普通黄色
Purple = 5, // 普通紫色
// 特殊方块(10起,避免和普通方块编号冲突)
StripedH_Red = 10, // 横条纹红色(清除整行)
StripedV_Red = 11, // 纵条纹红色(清除整列)
StripedH_Blue = 12,
StripedV_Blue = 13,
StripedH_Green = 14,
StripedV_Green = 15,
StripedH_Yellow = 16,
StripedV_Yellow = 17,
StripedH_Purple = 18,
StripedV_Purple = 19,
Bomb_Red = 20, // 炸弹红色
Bomb_Blue = 21,
Bomb_Green = 22,
Bomb_Yellow = 23,
Bomb_Purple = 24,
Rainbow = 30 // 彩虹方块
}
/// <summary>判断是否是特殊方块</summary>
public static bool IsSpecial(this PieceType type)
{
return (int)type >= 10;
}
/// <summary>获取特殊方块的基础颜色编号(1-5)</summary>
public static int GetBaseColor(this PieceType type)
{
int val = (int)type;
if (val <= 5) return val;
if (val >= 10 && val <= 19) return ((val - 10) / 2) + 1;
if (val >= 20 && val <= 24) return (val - 20) + 1;
return 0;
}GDScript
## 方块类型枚举
enum PieceType {
EMPTY = 0,
RED = 1, BLUE = 2, GREEN = 3, YELLOW = 4, PURPLE = 5,
# 特殊方块(10起)
STRIPED_H_RED = 10, STRIPED_V_RED = 11,
STRIPED_H_BLUE = 12, STRIPED_V_BLUE = 13,
STRIPED_H_GREEN = 14, STRIPED_V_GREEN = 15,
STRIPED_H_YELLOW = 16, STRIPED_V_YELLOW = 17,
STRIPED_H_PURPLE = 18, STRIPED_V_PURPLE = 19,
BOMB_RED = 20, BOMB_BLUE = 21,
BOMB_GREEN = 22, BOMB_YELLOW = 23, BOMB_PURPLE = 24,
RAINBOW = 30
}
## 判断是否是特殊方块
func is_special(type: int) -> bool:
return type >= 10
## 获取特殊方块的基础颜色编号
func get_base_color(type: int) -> int:
if type <= 5: return type
if type >= 10 and type <= 19: return ((type - 10) / 2) + 1
if type >= 20 and type <= 24: return (type - 20) + 1
return 0条纹方块:行列清除
当一次消除 4 个同色方块时,在被消除的位置生成一个条纹方块。条纹方向取决于消除方向:纵向消除(同一列上的4个)生成横条纹(清一行),横向消除(同一行上的4个)生成纵条纹(清一列)。
C
/// <summary>
/// 处理匹配后生成特殊方块。
/// 4个 → 条纹方块,5个 → 彩虹方块。
/// 特殊方块生成在匹配组的中间位置。
/// </summary>
private void HandleSpecialPieceSpawn(List<Vector2I> match)
{
if (match.Count == 4)
{
// 判断是横向还是纵向匹配
bool colsSame = match.All(m => m.Y == match[0].Y);
Vector2I spawnPos = match[match.Count / 2];
int baseColor = (int)board[match[0].X, match[0].Y];
// 纵向匹配(同一列)→ 横条纹(清一行)
// 横向匹配(同一行)→ 纵条纹(清一列)
PieceType specialType = colsSame
? (PieceType)(10 + (baseColor - 1) * 2)
: (PieceType)(10 + (baseColor - 1) * 2 + 1);
board[spawnPos.X, spawnPos.Y] = specialType;
}
else if (match.Count >= 5)
{
// 5个 → 彩虹方块
Vector2I spawnPos = match[match.Count / 2];
board[spawnPos.X, spawnPos.Y] = PieceType.Rainbow;
}
}
/// <summary>
/// 激活条纹方块 —— 清除整行或整列
/// </summary>
private List<Vector2I> ActivateStripedPiece(int row, int col)
{
var cleared = new List<Vector2I>();
int type = (int)board[row, col];
if (type >= 10 && type <= 19)
{
bool isHorizontalStriped = (type - 10) % 2 == 0;
if (isHorizontalStriped)
{
// 横条纹 → 清除整行
for (int c = 0; c < Cols; c++)
cleared.Add(new Vector2I(row, c));
}
else
{
// 纵条纹 → 清除整列
for (int r = 0; r < Rows; r++)
cleared.Add(new Vector2I(r, col));
}
}
return cleared;
}GDScript
## 处理匹配后生成特殊方块
func handle_special_piece_spawn(match: Array) -> void:
if match.size() == 4:
var cols_same: bool = true
for i in range(1, match.size()):
if match[i].y != match[0].y:
cols_same = false
break
var spawn_pos: Vector2i = match[match.size() / 2]
var base_color: int = board[match[0].x][match[0].y]
var special_type: int
if cols_same:
special_type = 10 + (base_color - 1) * 2
else:
special_type = 10 + (base_color - 1) * 2 + 1
board[spawn_pos.x][spawn_pos.y] = special_type
elif match.size() >= 5:
var spawn_pos: Vector2i = match[match.size() / 2]
board[spawn_pos.x][spawn_pos.y] = PieceType.RAINBOW
## 激活条纹方块 —— 清除整行或整列
func activate_striped_piece(row: int, col: int) -> Array:
var cleared: Array = []
var type: int = board[row][col]
if type >= 10 and type <= 19:
var is_horizontal: bool = (type - 10) % 2 == 0
if is_horizontal:
for c in range(COLS):
cleared.append(Vector2i(row, c))
else:
for r in range(ROWS):
cleared.append(Vector2i(r, col))
return cleared炸弹方块:十字消除
当消除形成 L 形或 T 形时(两组匹配在某一个位置交叉),在交叉点生成炸弹方块。炸弹激活时炸掉以自己为中心 3x3 范围内的所有方块。
C
/// <summary>
/// 检查是否有 L 形或 T 形匹配(两组匹配在某一个位置交叉)。
/// 如果有,在交叉点生成炸弹方块。
/// </summary>
private void CheckBombSpawn(List<List<Vector2I>> allMatches)
{
for (int i = 0; i < allMatches.Count; i++)
{
for (int j = i + 1; j < allMatches.Count; j++)
{
foreach (var posA in allMatches[i])
{
foreach (var posB in allMatches[j])
{
if (posA == posB)
{
int baseColor = (int)board[posA.X, posA.Y];
PieceType bombType = (PieceType)(20 + baseColor - 1);
board[posA.X, posA.Y] = bombType;
return; // 每次只生成一个炸弹
}
}
}
}
}
}
/// <summary>
/// 激活炸弹方块 —— 清除 3x3 范围
/// </summary>
private List<Vector2I> ActivateBomb(int row, int col)
{
var cleared = new List<Vector2I>();
for (int dr = -1; dr <= 1; dr++)
{
for (int dc = -1; dc <= 1; dc++)
{
int r = row + dr;
int c = col + dc;
if (r >= 0 && r < Rows && c >= 0 && c < Cols)
{
cleared.Add(new Vector2I(r, c));
}
}
}
return cleared;
}GDScript
## 检查是否有 L 形或 T 形匹配
func check_bomb_spawn(all_matches: Array) -> void:
for i in range(all_matches.size()):
for j in range(i + 1, all_matches.size()):
for pos_a in all_matches[i]:
for pos_b in all_matches[j]:
if pos_a == pos_b:
var base_color: int = board[pos_a.x][pos_a.y]
var bomb_type: int = 20 + base_color - 1
board[pos_a.x][pos_a.y] = bomb_type
return
## 激活炸弹方块 —— 清除 3x3 范围
func activate_bomb(row: int, col: int) -> Array:
var cleared: Array = []
for dr in range(-1, 2):
for dc in range(-1, 2):
var r: int = row + dr
var c: int = col + dc
if r >= 0 and r < ROWS and c >= 0 and c < COLS:
cleared.append(Vector2i(r, c))
return cleared彩虹方块:全色消除
彩虹方块是最稀有的特殊方块——一次消除 5 个才能生成。它可以和任何颜色的方块交换,效果是消除棋盘上所有该颜色的方块。
C
/// <summary>
/// 激活彩虹方块 —— 消除所有指定颜色的方块。
/// 与彩虹方块交换的那个方块决定了消除哪种颜色。
/// </summary>
private List<Vector2I> ActivateRainbow(int rainbowRow, int rainbowCol, int targetColor)
{
var cleared = new List<Vector2I>();
for (int row = 0; row < Rows; row++)
{
for (int col = 0; col < Cols; col++)
{
int baseColor = PieceType.GetBaseColor(board[row, col]);
if (baseColor == targetColor)
{
cleared.Add(new Vector2I(row, col));
}
}
}
return cleared;
}GDScript
## 激活彩虹方块 —— 消除所有指定颜色的方块
func activate_rainbow(rainbow_row: int, rainbow_col: int, target_color: int) -> Array:
var cleared: Array = []
for row in range(ROWS):
for col in range(COLS):
var base_color: int = get_base_color(board[row][col])
if base_color == target_color:
cleared.append(Vector2i(row, col))
return cleared特殊方块的组合效果
当两个特殊方块相邻并被交换时,会触发比单独使用更强的组合效果。这让高段位玩家有更多的策略空间。
| 组合 | 效果 | 威力 |
|---|---|---|
| 条纹 + 条纹 | 同时清除一行和一列(十字形) | 清除 17 个格子 |
| 条纹 + 炸弹 | 清除 3 行和 3 列(大十字) | 清除约 40 个格子 |
| 炸弹 + 炸弹 | 清除 5x5 范围 | 清除 25 个格子 |
| 彩虹 + 任何颜色 | 消除该颜色所有方块 + 额外效果 | 清除 8-16 个格子 |
| 彩虹 + 彩虹 | 消除整个棋盘 | 清除 64 个格子 |
设计建议
组合效果不需要在第一版就全部实现。先做最基本的"条纹+条纹"和"炸弹+炸弹",其他的后续迭代添加。先把基础体验做好,再逐步增加深度。
下一章预告
特殊方块让游戏的策略深度大增。接下来我们做游戏 UI——让玩家看到分数、步数、关卡目标,以及过关和失败的界面。
