跳到主要内容

数据库管理

Guide

GameCardManager 统一注册六类 GCS 数据库,Active 集合决定 Game Card Editor 与 GCSApi 主动发现哪些内容

GameCardManager 决定内容发现范围

卡牌、卡组或遭遇战资产即使已经出现在 Project 窗口中,也不会自动进入当前场景的创作与查询范围,只有注册到场景中的 GameCardManager 并保持 Active,Game Card Editor 与 GCSApi 才能主动发现它们,如果从空场景开始,先通过以下菜单打开 Game Card System 面板,再点击 Initialize System

Tools > TinyGiants > GCS > Game Card System

首次初始化会创建 GameCardManagerGameCardEncounterBootstrap,并把六个预设数据库注册为 Active,此后再次初始化时,数据库部分只会补齐缺少的预设项,不会删除项目自己的数据库,也不会把已经设为 Inactive 的预设重新启用,当你在 Hierarchy 中选中 GameCardManager,Inspector 会同时显示六类数据库的注册项、Active 数量与内容数量:

Game Card Manager Inspector 中的六类预设数据库,每类均显示 1/1 Active,并提供 New、Add、定位与移除操作

上图中的六个区块分别管理 Card、Deck、Player Unit、Enemy Unit、Status 与 Encounter 数据库,1/1 Active 表示该类型只注册了一套数据库。为方便管理,每个区块还把创建、注册和日常维护功能放在了同一位置,如下是数据库探测与激活的工作原理,了解这些将有助于你更好的去管理数据资产:

第一条路径控制 GCS 能否主动枚举数据库内容,另一条路径保留已经装配在卡组、玩家与遭遇战中的 Unity 直接引用

实体选择器的回退规则

Game Card Editor 顶部的 Database 下拉框只列出 Active 数据库

卡牌、单位、状态与遭遇战等实体选择器会优先列出 Active 内容,当场景中没有 Manager,或该实体类型在全部 Active 数据库中一个条目都没有时,选择器会回退到项目范围搜索,因此在选择器里看到一项内容,并不能单独证明它所属的数据库当前处于 Active

六类数据库组成一场战斗

注册并设为 Active 后,数据库会出现在 Game Card Editor 的对应模式中,内容归属以库内登记的条目为准,仅把资产移动到同名文件夹不会把它加入数据库

数据库编辑模式保存的内容在战斗中的职责
GameCardDatabaseCard卡牌费用、目标、标签、升级与卡牌 Behavior
GameDeckDatabaseDeck卡组卡牌条目、副本数量、起始卡组与奖励卡池
GamePlayerUnitDatabasePlayer玩家单位生命、能量、起始卡组与玩家表现资源
GameEnemyUnitDatabaseEnemy敌人单位生命区间、层级、Intent、Behavior 与敌人表现资源
GameStatusDatabaseStatus状态Buff、Debuff、叠加、衰减、Hook 与状态 Behavior
GameEncounterDatabaseEncounter遭遇战玩家、敌人阵容、战斗规则与奖励卡组

这六类内容不是彼此孤立的清单,一场战斗通常从 GameEncounter 向下展开,Encounter 选择玩家、敌人、规则与奖励卡组,玩家通过 Starting Deck 连接卡组,卡组再通过条目连接卡牌。卡牌、敌人与状态的 FlowGraph 最终会在同一场战斗中执行,定义怎样生成独立战斗实例见运行时数据模型,Behavior 怎样读取和修改这些实例见FlowGraph 模型

在 Project 窗口中选中数据库资产时,专用 Inspector 会直接给出库内统计,以 GameCardDatabase 为例,它会把卡牌总数、类型和稀有度集中显示在一份 Summary 中:

Preset Card Database 的专用 Inspector,显示资产路径、卡牌类型与稀有度统计,以及 Open in Card Mode 入口

点击上图中的 Open in Card Mode,Game Card Editor 会直接打开当前卡牌数据库,其他类型的 Inspector 也提供对应模式的快捷入口

提示

六类 Inspector 都会显示资产路径与内容总数,Enemy Database 另按 Tier 统计,Status Database 区分 Buff 与 Debuff,类型和稀有度则是 Card Database 独有的统计维度

创建并注册项目自己的数据库

预设数据库适合用来查看可运行的内容结构,项目自己的数据库则应保存在插件目录之外,使用 + New 创建时,默认根目录是 Assets/TinyGiantsData/GameCardSystem/

类型+ New 默认目录
CardCardDatabases/
DeckDeckDatabases/
Player UnitPlayerUnits/
Enemy UnitEnemyUnits/
StatusStatusDatabases/
EncounterEncounterDatabases/

在 Manager Inspector 中,每个数据库区块都提供同一套操作

操作结果
+ New在对应的项目数据目录创建数据库,立即注册并设为 Active
+ Add列出项目中同类型且尚未注册的数据库,选中后立即注册并设为 Active
拖放从 Project 窗口一次注册一个或多个同类型数据库,已经注册的同一资产不会重复加入
Active控制该数据库是否进入当前 Manager 的主动发现范围
定位在 Project 窗口中定位数据库资产
移除只取消当前 Manager 的注册,不删除磁盘上的数据库
双击名称直接重命名数据库资产文件

也可以在 Project 窗口的目标目录中直接创建数据库,再回到 Manager 使用 + Add 或拖放完成注册:

Assets > Create > TinyGiants > GCS > Card Database

注册完成后,打开 Game Card Editor,切换到对应模式,再从顶部的 Database 下拉框选择要编辑的 Active 数据库

一套完整的项目数据库工作流可以按以下顺序完成:

  1. GameCardManager 的对应区块使用 + New,或用 + Add 注册已有数据库
  2. 确认数据库行处于 Active,并检查区块标题中的 Active 数量
  3. 打开 Game Card Editor,切换到对应内容模式
  4. Database 下拉框中选择目标数据库
  5. 创建内容,并在数据库 Inspector 或 Editor 列表中确认条目已经写入正确位置
删除边界
  • Manager 行上的移除按钮只会取消注册,Project 窗口中的 Delete 则会删除数据库文件及其内容子资产

  • 数据库被删除后,卡组、玩家或遭遇战中的直接引用可能变成 Missing,因此,在删除前请先检查引用关系

用 Active 集合划分 Demo、正式内容与测试内容

Active 状态属于当前 GameCardManager,不属于数据库资产本身,因此,同一套数据库可以在 Demo 场景中保持 Active,在正式场景中保留注册但切换为 Inactive,也可以只在专用测试场景中启用

拆分维度数据库示例Active 策略
内容来源预设数据库与项目数据库正式场景启用项目库,需要对照时再临时启用预设库
职业Warrior、Mage、Hunter、Priest只启用当前模式需要创作或查询的职业内容
章节Act 1、Act 2、Boss按场景或游戏模式选择需要暴露的内容集合
测试范围机制验证库与生产库测试库只在验证场景启用,避免混入正式查询结果

按场景维护 Active 集合后,Game Card Editor 的可选数据库、GCSApi 返回内容与 GUID 查找范围都会随场景一起切换,Demo、正式流程和测试场景不会再共用同一组主动发现结果

当前 FlowGraph 的多数据库边界
  • GCSApi 会合并同类型的全部 Active 数据库,但当前战斗执行上下文在解析状态、卡牌与敌人 ID 时,只使用 Manager 注册顺序中的第一套 Active 数据库
  • Change StatusSpawn Unit 都受这项边界限制,Transform Card 只在解析 New Card 字段时受限,Add Cards 则只在 Cards 输入没有收到 CardInstance、改用行内 Cards 选择器时按同样方式解析卡牌
  • 使用这些节点的行内内容字段时,应把目标状态、卡牌或敌人放在对应类型的第一套 Active 数据库中,即使同时启用多套 Card、Status 或 Enemy Unit Database,这些节点也不会自动跨库搜索

在代码中读取同一组内容

Game Card Editor 的 Database 下拉框与 GCSApi 使用当前 Manager 的同一组 Active 数据库,代码既可以读取六类数据库,也可以直接取得其中的全部内容:

using TinyGiants.GCS.Runtime;

var cardDatabases = GCSApi.ActiveCardDatabases();
var deckDatabases = GCSApi.ActiveDeckDatabases();
var playerDatabases = GCSApi.ActivePlayerUnitDatabases();
var enemyDatabases = GCSApi.ActiveEnemyUnitDatabases();
var statusDatabases = GCSApi.ActiveStatusDatabases();
var encounterDatabases = GCSApi.ActiveEncounterDatabases();

var cards = GCSApi.Cards();
var decks = GCSApi.Decks();
var players = GCSApi.PlayerUnits();
var enemies = GCSApi.EnemyUnits();
var statuses = GCSApi.Statuses();
var encounters = GCSApi.Encounters();

按 GUID 查找时,六类内容也使用同一组 Active 数据库:

var card = GCSApi.FindCard(cardGuid);
var deck = GCSApi.FindDeck(deckGuid);
var player = GCSApi.FindPlayerUnit(playerGuid);
var enemy = GCSApi.FindEnemyUnit(enemyGuid);
var status = GCSApi.FindStatus(statusGuid);
var encounter = GCSApi.FindEncounter(encounterGuid);
提示
  • Manager 存在时,六个 Active*Databases() 与六个内容集合方法每次调用都会创建新列表,高频读取时应缓存结果,不要在 Update 或每次 UI 刷新中重复调用
  • 场景中没有有效 Manager 时,列表方法返回空集合,Find* 返回 null

战斗控制、内容发现与完整方法签名见 GCSApi 指南API 参考

沿着内容链排查缺失项

数据库问题最容易被误判成卡牌、FlowGraph 或战斗启动问题,建议排查时先确定当前功能依赖的是 Active 枚举还是 Unity 直接引用,再沿着对应路径检查

现象先检查继续检查
Game Card Editor 的 Database 下拉框没有目标数据库确认当前场景存在 GameCardManager,目标数据库已经注册并设为 Active确认数据库类型与当前编辑模式一致
Database 下拉框存在,但内容列表为空确认当前选中的是目标数据库,并查看数据库 Inspector 中的 Total检查新内容是否写入了另一套 Active 数据库
实体选择器仍然出现 Inactive 内容检查该实体类型在全部 Active 数据库中是否一个条目都没有,从而触发项目范围回退回到 Manager 核对真实 Active 集合,不用选择器结果反推状态
GCSApi.Cards() 等方法返回空集合确认 Manager 有效,并且对应类型至少有一套 Active 数据库检查 Active 数据库内部是否确实包含内容
GCSApi.Find* 返回 null确认目标内容位于 Active 数据库,并核对传入的 GUID检查重复 GUID,并确认 Manager 注册顺序中的首个匹配项
Change StatusTransform CardSpawn Unit 或使用行内 Cards 选择器的 Add Cards 没有效果确认目标内容位于对应类型的第一套 Active 数据库确认 FlowGraph 实际执行到该节点,并核对输入与目标
卡组中的卡仍能抽到,但卡牌数据库已经 Inactive这是因为 Starting Deck 与 Deck Entry 保存的直接引用仍然有效若代码还需要枚举或按 GUID 查找这张卡,再启用所属数据库
Bootstrap Inspector 提示默认 Encounter 不在 Active 数据库注册并启用保存该 Encounter 的数据库,让 Inspector 恢复 Ready该警告不会阻止 Bootstrap 使用直接引用启动战斗,再检查 Encounter 的玩家、敌人、规则与奖励卡组引用

核对一场遭遇战的完整内容链时,请从 GameEncounter 开始,依次检查玩家、Starting Deck、卡牌、敌人、奖励卡组,以及 FlowGraph 的使用状态,更深入的现象定位详见常见症状创作错误运行时错误