跳到主要内容

多角色队伍

Guide

配置最多三名玩家角色,在共享回合、牌堆和能量的战斗中选择行动角色与目标

GameEncounter 可以配置一至三名玩家角色,每名角色都有独立的生命、护甲、状态、Hook 和场景表现,全队默认共享玩家回合、牌堆和能量,现有单角色配置仍可直接使用

上图展示了多角色战斗的配置与执行流程,Encounter 创建队伍并分配角色槽位,成员共用牌堆和能量,出牌时由指定角色执行 FlowGraph,事件和场景表现通过角色 ID 对应到实际来源与目标

功能边界

多角色队伍用于本地战斗,支持自定义行动与出牌策略,不包含网络连接、状态同步、回滚、房间或账号系统

用 Encounter 建立初始队伍​

在 Player Units 中配置初始队伍,第 1 行是主角色,第 2、3 行是追加成员,编辑器和运行时均最多支持三名玩家角色

配置运行结果
Player Units[0]创建槽位 0 的主角色,旧版 PlayerUnit 和 GCSApi.Player() 仍解析该成员
Player Units[1..2]按行顺序创建额外的 PlayerUnitState
行顺序直接映射场景槽位 0、1、2,不需要额外配置槽位

Workbench 会报告空成员、超过三人、越界槽位与重复槽位,Encounter 预览会在 VS 左侧显示玩家队伍,进入 Play Mode 前可在此核对阵容

角色身份贯穿整场战斗​

战斗中的每名单位都有独立身份,使用 UnitId 查找实例,使用 Team 和 TeamId 判断阵营,使用 SlotIndex 安排位置,使用 JoinOrder 记录加入顺序,角色资产名和列表下标不能代替这些字段

身份作用
UnitId唯一标识本场战斗中的一个单位实例,同一 Player Unit 资产被创建两次时会得到两个不同值
Team / TeamId决定友军与敌军关系,内置玩家和敌人分别使用 Player 与 Enemy
SlotIndex把运行时单位映射到玩家或敌人侧的可见槽位
JoinOrder保留成员进入队伍的先后顺序,增援与主角色变更不会打乱其余成员

GCSApi.Player() 返回主角色,GCSApi.ActivePlayer() 返回当前行动角色,GCSApi.PlayerParty() 返回全部队伍成员,包括死亡成员,需要只显示存活或死亡角色时,分别使用 AlivePlayers() 或 DeadPlayers()

一次玩家回合由整支队伍共同完成​

默认每回合只有一次玩家阶段,回合开始时处理各成员的护甲、状态与回合触发,再为全队刷新一次能量和抽牌,玩家可在此阶段切换角色并出牌,点击 End Turn 后结束全队回合并进入敌人阶段

SkipNextTurns 只影响对应成员,其他成员仍可行动,全部存活成员都被跳过时,本次队伍回合直接结束

默认只有全队成员都死亡时才判定失败,主角色死亡后其余成员可以继续战斗,胜利检查要求 HasEncounteredEnemy 为 true,因此 Encounter 可以先不配置敌人,再在运行时生成首名敌人

需要按顺序行动时,将 BattlePolicySet.ActivationPolicy 设为 OrderedPartyActivationPolicy,通过 EndActivePlayerActivation() 结束当前成员的行动并切换到下一名成员

把 BattlePolicySet 传给 GCSApi.StartBattle 后,GCS 会在创建单位和卡牌前补齐默认策略,本场战斗的 ActivePolicies 为只读配置,修改规则需要为下一场战斗传入新的策略集

策略决定的规则
IPartyActivationPolicy自由选择或按顺序激活成员
IAutomaticPartyActivationPolicy在顺序回合中自动执行同伴行动
IActionWindowPolicy哪些阶段接受玩家出牌请求
IReactionWindowPolicy敌方行动前是否打开可暂停的反应窗口
ICardPlayPolicy项目自己的行动来源或卡牌许可
IUnitTargetPolicy不依赖画面选中对象,为行动者解析默认敌对目标
IBattleResultPolicy当前状态是否进入胜利或失败阶段

全队共享卡牌与能量​

全队共用 Hand、Draw、Discard、Exhaust 和当前能量,起手、回合抽牌、洗牌、手牌上限、能量变化与卡牌移动均按队伍结算一次

持久 Master Deck 为空时,使用 Player Unit 1 的 Starting Deck 创建共享 Draw 牌堆,其他成员的 Starting Deck 不会合并进当前战斗,在其他 Encounter 中成为主角色时仍可使用自己的卡组

卡牌的 OwnerUnitId 记录创建时的原始所有者,切换行动角色不会改变该值,符合出牌条件的其他成员也可以打出共享卡牌

指定卡牌的行动来源​

TryPlayCard(card, target) 使用当前 ActivePlayer() 作为行动来源,FlowGraph 的 Self、来源 Hook 和出牌事件均使用该角色,卡牌的 OwnerUnitId 保持不变

需要指定行动角色时,使用 CardPlayRequest 提交 SourceUnit 和目标,按索引选择第二名存活成员前,需确认队伍至少有两名存活角色

PlayerUnitState member = GCSApi.AlivePlayers()[1] as PlayerUnitState;
GCSApi.TrySetActivePlayerUnit(member);

foreach (CardInstance card in GCSApi.Hand(member))
{
var request = new CardPlayRequest(card, member, GCSApi.FirstAliveEnemy());
int cost = GCSApi.GetEffectiveEnergyCost(card);
int energy = GCSApi.Energy(member);
if (cost <= energy && GCSApi.CanPlayCard(request))
{
GCSApi.TryPlayCard(request);
}
}

出牌成功后,CardInstance.LastPlayContext 保存只读的出牌记录,包括出牌前区域、原始所有者、实际行动来源和目标列表,OnCardPlayed 也提供这些身份信息,自定义 UI 和统计可直接读取实际执行者

卡牌可以选择友军并按相对阵营结算​

Card Target 除了原有敌方目标外,还提供 Single Ally、Other Ally、All Allies、Random Ally、Random Opponent 与 Any Unit,单体友军和任意单位输入会在 Demo 中使用同一套拖拽箭头与合法目标高亮,范围和随机目标则由运行时自动解析

Card Target玩家输入Behavior 的对应来源
Single Ally选择任意一名存活友军,允许选择来源角色Opponent 不适用,使用已提交 Target 或目标端口
Other Ally选择来源角色以外的存活友军使用已提交 Target,运行时会拒绝来源角色本身
All Allies不需要单体输入All Allies
Random Ally不需要单体输入运行时从全部存活友军中选择一名,并通过 Target 交给 Behavior
Random Opponent不需要单体输入运行时从来源角色的对方阵营选择一名存活单位,并通过 Target 交给 Behavior
Any Unit选择任意一名存活玩家或敌人使用已提交 Target,不限制双方阵营

FlowGraph 的 All Allies 和 All Opponents 分别读取当前宿主的存活友军与对手,可用于玩家卡牌、敌人和状态,Active Player 返回当前选中的存活玩家,All Dead Allies 返回可供复活的死亡友军,完整规则见目标选择

在战斗中增援、替换与复活成员​

Spawn Unit 按 Team 创建玩家或敌人,玩家队伍最多三人,增援成功后分配槽位并发布 OnPlayerUnitAdded,沿用全队共享的牌堆和能量

ReplacePlayer 在原槽位替换成员,Despawn Unit 移除单位并发布 OnUnitRemoved,普通死亡发布 OnUnitDied 并保留成员与槽位,Revive Unit 复活后发布 OnUnitRevived

PlayerUnitState joined = GCSApi.SummonPlayer(playerDefinition, 2, GCSApi.ActivePlayer());
if (joined != null)
{
GCSApi.SetEnergy(joined, GCSApi.MaxEnergyFor(joined));
}

GCSApi.RemoveUnit(joined);

移除的成员不能再复活,同一次死亡只发布一次死亡事件,移除或替换成员不会改变共享牌堆和能量,使用 OnUnitRemoved 区分离队,使用 OnUnitDied 区分留在队伍中的死亡成员

Demo BattleBoard 会订阅成员加入、单位移除、死亡、复活与当前角色变化,单角色场景只显示一个玩家槽位,第二或第三名玩家加入时,运行时在同一个 Player Area 根对象下展开子槽位,Party Showcase 直接保存三个子槽位,Dashboard 的 Initialize System 也会创建这套层级

在 Party Showcase 中验证完整链路​

打开 Demo/Scenes/Multi-Character/Party Showcase 后进入 Play Mode,棋盘应同时显示 Scout、Squire、Apprentice、Plague Stalker、Spore Brute 与 Mire Reaper,底部只保留一组共享手牌和能量显示

Party Showcase 同时显示三名玩家、三名敌人、共享手牌与共享能量

Player Unit 1 的 Scout 提供 Party Tactics,运行时据此创建全队共享的八张卡牌

  1. 确认三个玩家槽位分别显示生命、护甲与状态区域
  2. 点击不同成员,确认当前角色与能量显示同步变化
  3. 切换成员后打出共享 Party Tactics 中的攻击牌,确认费用由同一份队伍能量支付、当前成员成为 SourceUnit,卡牌原始 OwnerUnitId 保持不变
  4. 依次使用 Field Mend、Interpose、Shared Resolve 与 Emergency Aid,确认指定队友、排除自身、全体队友与随机队友四条目标路径
  5. 结束队伍回合,确认所有成员完成回合生命周期后敌人才开始行动
  6. 打开 Game Card Monitor,核对每名成员的 UnitId、槽位、当前行动状态、共享能量与状态

Monitor 中的行动来源与目标应对应场景中的实际角色,单角色 Encounter 只需保留一行 Player Units