这是一个使用 Python Arcade 引擎开发的回合制卡牌战斗游戏原型。项目基于"Legacy"设计理念,融合 Roguelike、战棋走位、TRPG 叙事检定等元素,采用"堆周目"驱动的长期生涯模拟设计。
当前阶段: 第一阶段核心战斗原型已完成 ✓
目标:验证"战棋 + 卡牌 + 统一 2d10 检定"的核心乐趣。
| 里程碑 | 状态 | 说明 |
|---|---|---|
| 1.1 极简战斗场景 | ✅ | 8x8 瓦片地图、玩家 vs 敌人、回合制流转 |
| 1.2 卡牌驱动与统一检定 | ✅ | 2d10+ 加值 vs DN、五级结果判定、三张核心卡牌 |
| 1.3 格挡值与事件总线 | ✅ | 格挡系统、破盾效果、事件订阅触发机制 |
| 1.4 卡牌升级与进化 | ✅ | 卡牌升级、进化链、牌库管理 |
| 1.5 魔力系统与法术 | ✅ | MP 系统、法术卡牌(冰缀/点火/奥术飞弹/法力护盾) |
目标:验证"装备构筑→检定叙事→战斗回报"的微循环。
目标:验证"大地图流动、世界状态记忆、周目传承"的完整生涯切片。
- 模块化设计:将代码拆分为多个独立模块(配置、模型、战斗系统、视图等)
- 数据驱动:使用枚举和常量管理游戏数据
- 分离关注点:逻辑层与表现层完全分离
- 类型安全:使用 dataclass 和类型注解
- 面向对象:清晰的类继承关系和职责划分
- 可扩展性:易于添加新卡牌、装备和角色
- Arcade 引擎:替代 Tkinter,提供更好的图形性能和游戏体验
- 现代化 Python:使用 Python 3.7+ 特性
- 固定棋盘格地图:使用固定的两种绿色调交替模式,确保每次启动一致
- 可视化单位:蓝色表示己方,红色表示敌方
- 移动系统:支持点击移动和键盘控制(WASD/方向键)
- 卡牌攻击融合:点击卡牌显示攻击范围,再点击目标位置使用卡牌
- 射程显示:深色区域表示卡牌的有效攻击/移动范围
- 居中显示:地图自动居中于屏幕中央
- 拖动功能:鼠标中键或右键拖动移动地图
- 缩放功能:鼠标滚轮缩放地图(0.5x - 2.0x)
- 智能坐标转换:自动处理屏幕、世界、网格坐标转换
- 边界限制:防止地图完全移出视野
- 双相机系统:独立的地图相机和 GUI 相机
- 双重限制:体积(格子数)和重量两个上限
- 物品形状:支持 6 种不同形状的物品卡牌(单格、双格、方形等)
- 可视化界面:按 B 键打开半透明背包面板
- 智能管理:自动寻找放置位置,支持物品堆叠
- 状态显示:实时显示体积和重量使用情况
- 统一 2d10 检定:所有攻击、技能、叙事检定使用同一套 2d10+ 加值 vs DN 系统
- 五级结果:大成功/成功/半成功/失败/大失败,带来不同的战术效果
- 格挡值系统:受击时先消耗格挡值再扣血,每回合自动恢复
- 破盾机制:特定卡牌可双倍消耗敌方格挡值
- MP 法力系统:法术消耗 MP,每回合根据心智属性恢复
- 发布 - 订阅模式:解耦各模块通信
- 伤害/治疗修正:支持事件拦截和数值修改
- 破盾效果集成:通过事件系统实现特殊效果
- 卡牌升级:提升数值效果或添加新词条
- 卡牌进化:卡牌可进化为上位形态,保留副本在牌库
- 牌库管理:管理玩家拥有的所有卡牌,支持卡组构建
- 常驻卡牌:某些卡牌不参与抽牌循环,始终在手牌中
- 装备赋予卡牌:装备提供可用卡牌,脱装即消失
/workspace/
├── main.py # 主程序入口
├── ui_scale.py # ★ UI 缩放工具模块(4K/高 DPI 支持)
├── config.py # 配置和常量定义
├── models.py # 核心数据模型(实体、卡牌、装备等)
├── battle_system.py # 战斗系统逻辑
├── card_database.py # 卡牌、武器、防具数据库
├── card_serializer.py # 卡牌序列化模块
├── card_evolution_system.py # 卡牌进化系统
├── inventory.py # 背包系统数据模型
├── inventory_renderer.py # 背包 UI 渲染器
├── tile_map.py # 瓦片地图系统
├── equipment_manager.py # 装备管理器
├── equipment_renderer.py # 装备 UI 渲染器
├── attack_system.py # 攻击判定系统(2d10+ 加值 vs DN)
├── dice_system.py # 掷骰子系统
├── event_system.py # 事件总线系统
├── input_handlers.py # 输入处理器
├── ui_renderers.py # UI 渲染器
├── game_view.py # Arcade 视图和渲染
├── generate_example.py # 示例生成脚本
├── cards.json # 卡牌 JSON 数据
├── demo_cards.json # 演示卡牌数据
├── test_cards.json # 测试卡牌数据
├── requirements.txt # 依赖包列表
├── README.md # 项目说明(本文件)
├── design.md # 游戏设计文档
└── roadmap.md # 开发路线图
在 Windows 4K 屏幕(或系统缩放为 150%/200%)下,Arcade/pyglet 默认不启用 Per-Monitor DPI 感知,导致:
- 逻辑坐标与物理像素不一致,UI 元素错位
- 字体、按钮、卡牌尺寸在不同屏幕上比例失调
项目新增了 ui_scale.py 模块,提供全局 UI 缩放单例,所有 UI 坐标和字体都经过统一换算。
设计分辨率:1920 × 1080(所有"设计像素"以此为基准)
API 速查:
from ui_scale import S, update_scale
# 在窗口初始化 / on_resize 时更新(main.py 已自动调用)
update_scale(window_width, window_height)
# 水平坐标或宽度换算
S.px(x) # 设计像素 → 实际像素(水平)
S.py(y) # 设计像素 → 实际像素(垂直)
S.font(size) # 字体大小缩放(等比)
S.scale(v) # 等比缩放(圆半径、边框等)
S.rect(w, h) # 返回 (scaled_w, scaled_h)在新增 UI 元素时使用:
# 绘制文字
arcade.draw_text("Hello", S.px(100), S.py(50), color, S.font(24))
# 绘制矩形
arcade.draw_lrbt_rectangle_filled(
S.px(20), S.px(420), S.py(30), S.py(80), color
)
# 绘制按钮(位置 + 尺寸均换算)
btn_x = window_width * 0.85 # 比例定位,不需换算
btn_y = S.py(80) # 绝对 y 偏移需换算
arcade.draw_lrbt_rectangle_filled(
btn_x - S.px(75), btn_x + S.px(75),
btn_y - S.py(25), btn_y + S.py(25),
arcade.color.GREEN
)| 值类型 | 换算方法 | 说明 |
|---|---|---|
| 水平坐标/宽度 | S.px(v) |
独立水平缩放 |
| 垂直坐标/高度 | S.py(v) |
独立垂直缩放 |
| 字体大小 | S.font(v) |
等比缩放(取 min(sx, sy)) |
| 圆半径/边框 | S.scale(v) |
等比缩放 |
| 百分比布局 | 直接使用 window_width * ratio |
已自适应,无需额外换算 |
main.py 在启动时自动调用 SetProcessDpiAwarenessContext(Per-Monitor V2),使 arcade/pyglet 获取真实物理分辨率,确保在 150%/200% 系统缩放下坐标映射正确。
游戏运行中按 F3 可打开/关闭调试 overlay,显示:
- 当前窗口物理尺寸
- 水平/垂直/等比缩放系数(sx, sy, s)
- 设计分辨率基准
- 字体缩放示例
这有助于验证 4K / 高 DPI 下 UI 缩放是否正确。
pip install -r requirements.txt或直接安装:
pip install arcadepython main.py- 鼠标左键点击卡牌:使用选中的卡牌
- 空格键:跳过当前回合
- ESC 键:退出游戏(战斗结束后)
- 鼠标悬停:查看卡牌详细信息
- 点击瓦片:移动玩家到该位置
- WASD/方向键:控制玩家移动
- 点击卡牌:选择卡牌并显示攻击范围(深色区域)
- 点击目标:在范围内点击目标位置使用卡牌
- 蓝色圆圈:己方单位
- 红色圆圈:敌方单位
- 深色区域:卡牌的有效攻击/移动范围
- 鼠标中键拖动:移动地图视图
- 鼠标右键拖动:移动地图视图
- 鼠标滚轮向上:放大地图
- 鼠标滚轮向下:缩小地图
- 左键:保持原有的游戏交互
- B 键:打开/关闭背包界面
- ESC 键:如果背包打开则先关闭背包
- 查看状态:顶部显示体积和重量使用情况
- 物品管理:查看和管理角色拥有的物品
- F3 键:切换调试 overlay(显示当前窗口尺寸、缩放系数),便于在 4K / 高 DPI 下验证 UI 比例
定义所有游戏常量和枚举类型:
Rarity:稀有度枚举CardType:卡牌类型枚举GameConstants:游戏配置常量
核心数据模型:
Entity:游戏实体(玩家、敌人)Card:卡牌类Weapon/Armor/Accessory:装备类Stats:角色属性(力量、敏捷、心智、魅力、幸运)Buff:增益/减益效果
战斗系统管理器:
- 回合制战斗逻辑
- AI 自动出牌
- Buff 处理
- 战斗状态管理
游戏内容数据库:
- 所有可用卡牌定义
- 武器装备库
- 预设角色创建
卡牌序列化模块:
- JSON 序列化和反序列化
- 文件保存和加载
- 复杂条件和效果处理
卡牌进化系统:
- 定义进化链(基础→一阶→二阶)
- 进化后卡牌保留来源信息
- 支持卡牌升级后进化
攻击判定系统:
- 2d10+ 加值 vs DN 的统一检定
- 五级结果判定(大成功/成功/半成功/失败/大失败)
- 根据结果计算伤害和额外效果
掷骰子系统:
- 任意骰子表达式(如 2d10, 3d6)
- 检定类封装
- 概率计算工具
事件总线系统:
- 发布 - 订阅模式
- 伤害/治疗修正事件
- 破盾效果实现
Arcade 视图层:
- UI 渲染
- 用户输入处理
- 动画效果
- 瓦片地图显示和交互
瓦片地图系统:
- 随机地图生成(两种绿色调)
- 瓦片管理和坐标转换
- 移动范围计算
- 高亮显示功能
- 相机系统:支持拖动和缩放
背包系统数据模型:
InventoryItem:物品类,支持多种形状和堆叠Inventory:背包类,双重限制(体积 + 重量)- 智能放置算法和碰撞检测
背包 UI 渲染器:
- 半透明面板绘制
- 网格和物品可视化
- 状态条显示(体积/重量)
- 鼠标悬停交互
装备管理器:
- 五槽结构(头部、躯干、手部、脚部、饰品×2)
- 覆盖规则(全身甲占四槽)
- 装备特效管理
在 card_database.py 中添加:
"new_card": Card(
name="新卡牌名称",
card_type=CardType.ATTACK_PHYSICAL,
ap_cost=2,
mp_cost=0, # 法术卡牌需要设置 MP 消耗
effects={"hp": -30},
description="卡牌描述",
rarity=Rarity.RARE
)"new_weapon": Weapon(
name="武器名称",
description="武器描述",
rarity=Rarity.UNCOMMON,
physical_bonus=15,
magical_bonus=10,
attack_modifier=2 # 攻击加值(影响命中)
)def create_new_character():
player = Entity(
name="角色名",
max_hp=250,
max_ap=4,
equipment={...},
cards=[...],
hand_size=5,
stats=Stats(strength=12, dexterity=14, intelligence=10, charisma=8)
)
return player- 单一职责原则:每个模块只负责一个功能领域
- 开闭原则:对扩展开放,对修改关闭
- 依赖倒置:高层模块不依赖低层模块的具体实现
- 数据与逻辑分离:游戏数据独立于业务逻辑
- 统一性优先:一套检定系统覆盖所有场景
- 叙事即机制:五级结果使剧情成为可玩内容
- 实装四维属性对应的检定加值
- 三个装备槽:躯干 + 武器 + 饰品×1
- 角色创建界面(极简版)
- 独立叙事场景(如"上锁的门"、"可说服的守卫")
- 五级结果叙事引擎
- 卡牌泛用第一例(火焰箭点燃场景物)
- 战斗结算(掉落卡牌或装备)
- 卡组编辑界面
- 生命骰系统(最简版)
| 特性 | 原版 (Tkinter) | 新版 (Arcade) |
|---|---|---|
| 图形性能 | 一般 | 优秀 |
| 代码结构 | 单文件,耦合度高 | 模块化,低耦合 |
| 可扩展性 | 困难 | 容易 |
| 维护性 | 较差 | 良好 |
| 跨平台 | 是 | 是 |
| 动画支持 | 有限 | 强大 |
本项目仅供学习和娱乐使用。
感谢原项目的创意和基础代码,本次重构保留了核心玩法,同时大幅提升了代码质量和可维护性。