跳到主要内容

CommandGraph:基于节点的事件脚本

CommandGraph 是 MCE 的可视化脚本系统,用于创建 NPC 行为、过场动画、任务和交互事件。它提供一个基于节点的编辑器,你只需连接命令来定义事件序列,无需编写 C# 代码。

它是各个版本中使用 MCE 的游戏设计师的主要工具,包括不含源码的编译版本。

图所产生的内容

那个对话框是一个两节点图的输出:一块玩家交互过的告示牌,以及一条 ShowSignDialog 命令。其中没有任何内容是用 C# 写的 —— 同样的形态可以扩展为带分支的过场动画,而运行时分辨不出区别。

什么是 CommandGraph?​

CommandGraph(ActorCommandGraph)是存储在 Actor(世界中任何可交互实体)上的节点图。当演员被触发时,图会作为协程运行,一个节点接一个节点。

每个演员都有若干图槽位,每个槽位对应一个你可能想要响应的时刻:

槽位运行时机
On Enable Command Graph演员被启用时。
Loop Command Graph在演员的其他图都没有运行时,反复运行。
Interact Command Graph玩家与演员交互时。
On Demand Command Graph 0 to 3仅在另一个图请求时(RunOnDemand、RunMultipleOnDemand)。

专用演员会增加自己的槽位:TriggerActor 有“玩家即将进入 / 已进入 / 即将被传送 / 已被传送”和“演员被推入其中”的图,ActorCharacter 有 “spot player” 图,PushableActor 有 “push” 图。

把图想象成一份可视化脚本,其中每个节点都是一个游戏动作:

[Root] → [ShowDialog] → [IfPlayerHasBadge]
├─ True → [GivePlayerItem] → ...
└─ False → [ShowDialog: "Come back later"]

创建你的第一个事件​

步骤 1:创建演员​

最快的方式是层级菜单:右键点击并选择 GameObject > MCE > 下现成的演员之一:

菜单创建
Blank/Character、Blank/EmptyTrigger、Blank/Invisible一个空的角色、触发器或不可见演员,供你自行填充
NPCs/Simple dialog、NPCs/Give item、NPCs/Give monster带有现成对话、赠送道具或赠送怪物图的 NPC
Trainers/Static、Circle、Look around、Random look around、Random walk具有常见行为的训练师
Other/Sign、Pick up item、可砍的树、可破坏的岩石、巨石、漩涡经典的世界道具

你也可以自己添加组件。具体的演员类型有:

演员类型触发用途
SimpleActor玩家交互(没有图形或额外逻辑)不可见的交互点
ActorCharacter玩家交互;可以行走、环顾并发现玩家NPC、训练师
TriggerActor玩家踩上去(不阻挡移动)自动触发器、传送点、隐藏事件
ActorItem玩家交互,给出其道具并消失地面上的拾取道具
PushableActor玩家推动它(是一个 ActorCharacter)巨石、谜题方块

Actor 和 GridSubscribingActor 是抽象基类;你不能直接添加它们。

步骤 2:打开 CommandGraph 编辑器​

  1. 选择演员的 GameObject。
  2. 在 Inspector 中找到你想要的图槽位(例如 Interact Command Graph)。
  3. 点击 Edit graph 打开节点编辑器窗口。Delete graph 会清空它。

步骤 3:添加节点​

  1. 在图编辑器中右键点击。
  2. 选择 Create Command / <类别> / <节点>。类别就是节点所在的文件夹(见下文)。
  3. 通过从一个节点的输出端口拖动到另一个节点的输入端口来连接节点。

步骤 4:配置节点​

点击节点即可在 Inspector 面板中编辑它的字段:对话的文本、赠礼的道具和数量、传送的图块、条件的变量。

节点类别​

这些是它们在 Create Command 菜单中出现的类别。下面的列表给出了每个类别中最有用的节点;完整集合在菜单中。

Dialogs​

节点说明
ShowDialog显示普通对话
ShowChoiceDialog显示让玩家做出选择的对话(每个选项一个输出端口)
ShowSignDialog显示告示牌对话
ShowNoSkippableDialog显示玩家无法跳过的对话
NextDialog跳到下一段对话
ShowUsedMoveDialog说明某只怪物使用了招式的对话
ShowMonsterPicture把怪物的正面图片放入带框窗口,或撤下

Variables​

条件和变量变更。每个 If... 节点都有两个输出端口:True 和 False。

节点说明
SetBoolVariable、SetIntVariable设置游戏变量
IfBool、IfIntEquals、IfIntCompare根据布尔值或与某个值比较的整数进行分支(小于、大于、等于……)
IfIntVariablesCompare把一个整数变量与另一个整数变量比较
SwitchIntVariable整数变量的每个取值对应一个输出端口
WhileBool、WhileCondition条件成立时循环
IfPlayerCharacterIs、IfPlayerDirectionIs根据所选玩家角色或其朝向分支
SetTemporalBoolVariable、SetTemporalIntVariable、IfTemporalBool运行中演员的变量,不会随游戏一起保存

游戏变量通过变量引用来选择(全局存储或场景的存储)。它们保存在存档数据中,可以被任何图或脚本读取。

Items​

节点说明
GivePlayerItem、TakePlayerItem在玩家的背包中添加或移除道具
GivePlayerMoney给玩家金钱
IfPlayerHasItem根据玩家是否拥有某道具分支
ChooseItemDialog让玩家选择一个道具并据此运行命令

Monsters​

节点说明
GiveMonsters给玩家怪物(固定物种或随机)。在在线层中需要 grant id:参见怪物赠礼
HealPlayerRoster治疗整个队伍
ChooseMonsterDialog、ChooseTwoMonstersDialog让玩家选择一只或两只怪物
ChangeMonsterNickname、RemoveMonsterNickname重命名怪物
MoveTutor、RemindPreviouslyLearntMoves教授招式或回忆以前学过的招式
IfMonsterCanLearnMove、IfRosterHasMove根据招式分支
OpenStorage打开怪物存储

Battles​

节点说明
SingleTrainerFight与单个训练师战斗
SingleWildFight、DoubleWildFight触发与野生怪物的战斗
FightFromTemplate从战斗模板发起战斗
RandomFightAgainstRandomRosters与一支或两支随机队伍的随机战斗
StartTowerRun开始一次对战塔挑战
IfCanHaveDoubleBattle根据是否可以进行双打战斗分支

Badges, Dex, Quests​

节点说明
GiveBadge、IfPlayerHasBadge给予徽章 / 检查是否拥有
GiveDex、IfPlayerHasDex、IfDexIsComplete、RegisterMonsterAsSeen图鉴处理
StartQuest、UpdateQuestObjective、ProgressQuestObjective、CompleteQuest、FailQuest任务进度(参见任务系统)
IfPlayerHasQuest、IfCompletedQuest、IfQuestFailed、IfCurrentQuestObjective根据任务状态分支

Animations​

角色、玩家和屏幕。

节点说明
Move、MovePlayer、WalkToPlayer让角色、玩家行走,或走向玩家
Look、LookAtPlayer、ForcePlayerToLook让角色转向
JumpCharacter、WanderWithinRange跳跃;围绕起始图块游荡
HideCharacter、ShowCharacter、HidePlayer、ShowPlayer显示或隐藏图形
MoveFollower、LookFollower让跟随玩家的怪物行走或转向
FadeScreenToBlack、OpenDoor屏幕渐黑;打开演员所在图块的门
PlayExclamation、PlayEmotion在角色头顶显示气泡:参见情绪气泡与表情

Sounds​

节点说明
PlayMusic、StopMusic、SaveMusic、RestoreSceneMusic叠加在地图自身音乐之上的世界音乐
PlaySound、PlayMonsterCry、WaitForAudio声音与叫声

Shops, Trade, Saves, Breeding​

节点说明
BuyInShop、SellInShop运行买入或卖出的商店逻辑
TradeSelectedMonster交换玩家选择的怪物
AutoSaveIfEnabled如果配置中启用则自动存档
StoreTwoSelectedMonstersInNursery、IfEggIsReady、BreedEggInNurseryAndGiveToPlayer育儿所

Utils​

节点说明
TeleportPlayer把玩家传送到另一个位置(在线时由服务器验证)
TeleportActorInsideScene、PlaceActor在当前场景内移动演员
WaitTime、LoopXTimes、RunInParallel计时与流程
LockPlayerInput在过场动画期间锁定或解锁玩家移动
SetActorActive、AutoDestroy关闭另一个对象,或销毁该演员
SwitchOnDayMoment、SwitchTimeOfDay根据一天中的时段分支,或设置时段
SetLastHealLocation、SetLastHealLocationToCurrent玩家战败后重生的位置
LogMessage向控制台记录一条消息

连接节点​

CommandGraph 使用基于流的连接模型:

  • 每个图从一个 Root 节点开始。
  • 每个节点有一个输入端口和一个或多个输出端口。
  • 大多数节点恰好有一个输出端口(下一条命令)。If... 节点有 True 和 False;ShowChoiceDialog 每个选项一个端口;SwitchOnDayMoment 每个时段一个端口。
  • 没有连接输出端口的节点会结束图的该条路径。

示例:商店 NPC​

[Root]
→ [ShowDialog: "Welcome! Would you like to browse my wares?"]
→ [ShowChoiceDialog: "Buy" / "Sell" / "No thanks"]
├─ "Buy" → [BuyInShop]
├─ "Sell" → [SellInShop]
└─ "No thanks" → [ShowDialog: "Come back anytime!"]

示例:任务发布者​

[Root]
→ [IfBool: rescued_lost_monster]
├─ True → [IfBool: quest_reward_given]
│ ├─ True → [ShowDialog: "Thanks again!"]
│ └─ False → [GivePlayerItem: TM, 1]
│ → [SetBoolVariable: quest_reward_given = true]
│ → [ShowDialog: "Take this as thanks!"]
└─ False → [ShowDialog: "Please help me find my lost monster!"]
→ [SetBoolVariable: quest_find_monster = true]

示例:道馆馆主​

[Root]
→ [IfPlayerHasBadge: Boulder Badge]
├─ True → [ShowDialog: "You've already proven yourself!"]
└─ False
→ [ShowDialog: "I am the Gym Leader! Prepare for battle!"]
→ [SingleTrainerFight]
├─ On Player Won → [ShowDialog: "Impressive! You've earned this."]
│ → [GiveBadge: Boulder Badge]
└─ On Player Lost → [ShowDialog: "Train harder and come back!"]

SingleTrainerFight 有三个输出端口:普通的下一条命令端口、On Player Won 和 On Player Lost。“失败”路径只有在该节点被设置为战败后不让玩家重生时才会运行。

测试事件​

  1. 在编辑器中进入 Play Mode。
  2. 让你的角色走到演员处。
  3. 按下交互键。
  4. 图开始执行,你可以观察其流程。
调试图

如果图的行为不符合预期:

  1. 检查控制台中的错误。
  2. 验证被引用的游戏变量、道具和怪物是否存在。
  3. 确保所有输出端口都已连接 —— 未连接的端口会悄悄结束该路径。
  4. 添加一个 LogMessage 节点,在执行期间打印数值。

最佳实践​

  1. 给你的演员起描述性的名称。“NPC_Professor_Lab” 比 “Actor (3)” 好。
  2. 用游戏变量保存状态。不要仅依靠启用/禁用演员。
  3. 测试两个分支。每个 If... 节点对 True 和 False 都应该有效。
  4. 保持图可读。利用空间布局让流程清晰,把相关节点放在一起。
  5. 复用模式。一旦你有了一个可用的商店 NPC,就复制并修改它用于其他商店。
  6. 测试前先保存。CommandGraph 的更改是场景级别的更改,如果 Unity 崩溃可能会丢失。

关于 C# 方面 —— 从代码运行图或编写你自己的节点 —— 参见 CommandGraph API。