关于 card-game
面向游戏开发的技能,讲解以数据驱动的卡牌系统,从卡牌区域和抽牌机制到回合结构与效果结算。适用于构建牌组构筑、集换式卡牌、纸牌等以卡牌为核心的游戏。
主要功能
- 01卡牌数据与效果规范
- 02牌库、手牌、场上与弃牌区
- 03抽牌、洗牌和弃牌重洗规则
- 04基于阶段的回合结构
- 05资源消耗与效果结算
- 06胜负条件与 UI 注意事项
适用场景
- 01设计牌组构筑游戏的卡牌循环
- 02实现回合与阶段规则
- 03处理卡牌效果和触发条件
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ gamedev-skills/ awesome-gamedev-agent-skills --skill card-game安装后在 Claude Code 中输入/card-game确认已加载。
附带文件references/effect-resolution.md
详细介绍
卡牌游戏
卡牌游戏指南——涵盖卡牌数据、牌库/手牌/弃牌区、回合结构,以及卡牌效果的结算方式。这是一项组合式技能:它将卡牌建模为数据,并将其连接到 UI。它不会重新讲解数据资源或 UI 节点;它定义了区域模型、抽牌机制和效果结算规则,确保卡牌游戏正确运行、没有错误。
适用场景
- 构建任何以在不同区域之间移动的卡牌为核心对象的游戏时使用(牌库 → 手牌 → 打出区 → 弃牌堆):牌库构筑游戏、TCG/CCG、接龙、Roguelike 牌库构筑游戏。
- 设计抽牌/洗牌/重新洗牌、回合结构、卡牌费用或效果结算方式时使用。
**不适用场景:**带有匹配规则的棋盘/格子状态 → puzzle。附带卡牌战斗的 RPG → 从 rpg 开始。要将卡牌定义为资源,请使用 godot-resources/unity-scriptableobjects;要构建手牌/拖拽 UI,请使用 godot-ui-control。
核心循环
**抽牌至手牌 → 消耗资源打出卡牌 → 结算效果并改变棋盘状态 → 结束回合(清理/弃牌)→ 对手/下一阶段 → 重复,直到满足胜利条件。**游戏的深度来自手牌所能构成的组合;引擎的职责是明确无误地结算这些组合。
必备系统
- 卡牌数据——ID、名称、费用、类型、文本和效果规格(数据,而非代码)。
- 区域——牌库(抽牌堆)、手牌、打出区/棋盘、弃牌堆、放逐区/移除区;每张卡牌只能存在于一个区域。
- 抽牌 + 洗牌 + 重新洗牌——从牌库抽牌至手牌;牌库为空时,将弃牌堆洗回牌库。
- 回合结构——将阶段(重置/抽牌/主要阶段/战斗/结束)作为状态机处理。
- 资源系统——法力/能量/行动点,用于限制每回合可执行的操作数量。
- 效果结算——按明确顺序应用卡牌效果;处理目标和触发效果。
- 胜负条件——生命值总量、牌库耗尽、目标。
- UI——手牌布局、拖放或点击打出、区域卡牌数量、目标选择交互。
设计选项
| 选项 | 影响 | 备注 |
|---|---|---|
| 起手牌/每回合抽牌数 | 节奏、一致性 | 抽牌越多,波动越小。 |
| 手牌上限 | 囤牌还是使用 | 在回合结束时弃牌至上限。 |
| 牌库大小(最小值) | 一致性 | 牌库越小,组合越可靠。 |
| 资源曲线 | 何时能打出哪些牌 | “法力曲线”决定力量提升的节奏。 |
| 卡牌稀有度/强度预算 | 平衡性 | 越强的卡牌费用越高/越稀有。 |
| 确定性与随机性 | 技巧与运气 | 洗牌和随机效果会增加波动。 |
| 重新洗牌规则 | 牌库耗尽、疲劳 | 将弃牌堆洗回牌库,或对牌库为空施加惩罚。 |
| 移除手段/应对手段 | 反制空间 | 卡池中必须有应对每种威胁的手段。 |
模式
1. 区域 + 自动重新洗牌的抽牌机制
# Pseudocode. A card is in exactly one zone at a time; moving = remove here, add there.
def draw(n):
for _ in range(n):
if not deck:
if not discard: # truly empty: deck-out (lose, or take fatigue)
on_deck_out(); return
deck.extend(discard) # reshuffle discard into deck
discard.clear()
shuffle(deck, rng) # use a seeded RNG (see save-systems for replays)
hand.append(deck.pop())
2. 将卡牌作为数据 + 效果结算
# Pseudocode. Effects are a data list interpreted by the engine — not bespoke code per card.
card = {
"id": "fireball", "cost": 3, "type": "spell",
"effects": [ {"op": "damage", "amount": 6, "target": "chosen_enemy"} ],
}
def play(card, caster):
if resources[caster] < card.cost: return False # can't afford
resources[caster] -= card.cost
move(card, from_zone=hand, to_zone=play_or_discard(card))
for fx in card.effects:
resolve_effect(fx, caster) # one interpreter handles every card
return True
3. 将回合结构建模为阶段状态机
# Pseudocode. Fixed phases keep timing windows (triggers, priority) unambiguous.
PHASES = ["untap", "draw", "main", "combat", "end"]
def take_turn(player):
for phase in PHASES:
enter_phase(player, phase) # fire "on_phase" triggers here
if phase == "draw": draw(1)
if phase == "main": await player_plays_cards()
if phase == "combat": resolve_combat()
if phase == "end": discard_to_hand_limit(player); clear_temporary_effects()
常见问题/故障模式
- 一张卡牌同时存在于两个区域 → 导致重复/丢失错误。强制执行“每张卡牌只能存在于一个区域”;移动时先移除再添加,并断言没有卡牌重复出现。
- 忘记重新洗牌 → 牌库为空时,抽牌会静默失败或崩溃。将弃牌堆洗回牌库,或明确定义牌库耗尽/疲劳规则(模式 1)。
- 每张卡牌都对应一个函数 → 难以维护和测试。将效果设为数据,由少量操作进行解释(模式 2)。
- 效果顺序/同时触发的效果含糊不清 → 导致结果不确定。按明确定义的顺序结算(使用队列或栈);说明采用后进先出还是先进先出(参考资料)。
- 需要回放/撤销的游戏使用未设种子的洗牌 → 无法复现。使用带种子的 RNG。
- 没有手牌上限/没有应对手段 → 导致无休止囤牌或威胁无法击败。添加手牌上限,并确保每种威胁类型都有对应的移除手段。
- 目标选择状态泄漏 → 取消出牌后,棋盘仍处于目标选择状态。让出牌操作保持原子性:先验证费用和目标,再提交操作。
组合(使用这些技能构建)
- 卡牌内容:
godot-resources/unity-scriptableobjects——将每张卡牌定义为数据资源。 - **UI:**使用
game-ui-ux实现布局、缩放和焦点导航;使用godot-ui-control实现手牌布局、拖放、区域计数和目标选择提示。 - **持久化/回放:**使用
save-systems保存卡牌收藏、对局状态(肉鸽式卡组构筑)和带种子的回放。 - **对手 AI:**使用
game-ai实现能够评估可打出卡牌并选择目标的 AI。 - **动画/反馈:**使用引擎动画技能实现卡牌移动;使用
audio-design设计提示音。 - **脚本编写:**使用
godot-gdscript/unity-csharp-scripting实现效果解释器。
参考资料
- 关于效果队列/堆栈、关键词/触发条件、目标选择、卡组构筑与构筑赛两种原型,以及洗牌公平性,请阅读
references/effect-resolution.md。
评论
支持 Markdown