添加或删除UI元素时更新数据
打开StoryGraphView.cs,新增以下方法并完成调用:
C#
// 当视图发生变化
private void OnGraphViewChanged()
{
// 定义事件
graphViewChanged = (changes) =>
{
// 当即将创建连线时
if (changes.edgesToCreate != null)
{
// 遍历所有创建的连线
foreach (Edge edge in changes.edgesToCreate)
{
OnCreateEdge(edge);
}
}
// 当即将删除元素时
if (changes.elementsToRemove != null)
{
// 遍历所有元素,执行对应事件
foreach (GraphElement element in changes.elementsToRemove)
{
// 如果是节点
if (element is BaseNode node)
{
OnDeleteNode(node);
}
// 如果是分组
else if (element is BaseGroup group)
{
OnDeleteGroup(group);
}
// 如果是连线
else if (element is Edge edge)
{
OnDeleteEdge(edge);
}
}
}
// 当有元素移动后
if (changes.movedElements != null)
{
//Debug.Log(changes.moveDelta);
}
return changes;
};
}
// 即将创建连线时
private void OnCreateEdge(Edge edge)
{
// 获取连线输入端的节点(下一个节点)
BaseNode nextNode = (BaseNode)edge.input.node;
// 获取连线输出端的节点(上一个节点)引用的选项数据
ChoiceData choiceData = (ChoiceData)edge.output.userData;
// 记录下一个节点的GUID
choiceData.NextNodeID = nextNode.GUID;
}
// 即将删除节点时
private void OnDeleteNode(BaseNode node)
{
//Debug.Log("正在删除节点");
}
// 即将删除分组时
private void OnDeleteGroup(BaseGroup group)
{
//Debug.Log("正在删除分组");
}
// 即将删除连线时
private void OnDeleteEdge(Edge edge)
{
//Debug.Log("正在删除连线");
// 当连线的输出端口为空时,跳过
if (edge.output == null) return;
// 获取连线输出端的节点(上一个节点)引用的选项数据
ChoiceData choiceData = (ChoiceData)edge.output.userData;
// 清空记录
choiceData.NextNodeID = "";
}
// 创建连线
public Edge CreateEdge(Port lastOutput, Port nextInput)
{
Edge edge = lastOutput.ConnectTo(nextInput);
AddElement(edge);
OnCreateEdge(edge); /* 在此处新增调用 */
return edge;
}
// 构造器
public StoryGraphView(StoryEditorWindow window)
{
/* ... 此处代码已省略 ... */
OnGraphViewChanged(); /* 在此处新增调用 */
}避免删除开始节点和结束节点
继续新增以下方法并完成调用:
C#
// 当元素准备删除时
private void OnElementsReadyDelete()
{
// 在此处对选中的元素进行过滤
deleteSelection = (operationName, askUser) =>
{
List<ISelectable> readyToDelete = new();
// 遍历当前选中目标
foreach (GraphElement element in selection)
{
// 如果是节点
if (element is BaseNode node)
{
// 过滤掉开始节点
if (node is StartNode)
{
string str = "不可以删除开始节点。";
EditorUtility.DisplayDialog("警告", str, "明白");
continue;
}
// 过滤掉最后一个结束节点
if (node is EndNode)
{
if (GetEndNodesAmount() == 1)
{
string str = "不可以删除最后一个结束节点。";
EditorUtility.DisplayDialog("警告", str, "明白");
continue;
}
}
// 加入待删除列表
readyToDelete.Add(node);
}
// 如果是分组
else if (element is BaseGroup group)
{
readyToDelete.Add(group);
}
// 如果是连线
else if (element is Edge edge)
{
readyToDelete.Add(edge);
}
}
// 更新选中目标
selection = readyToDelete;
// 执行删除
DeleteSelection();
};
}
// 获取结束节点数量
private int GetEndNodesAmount()
{
return graphElements.Where(e => e is EndNode).ToList().Count;
}
// 构造器
public StoryGraphView(StoryEditorWindow window)
{
/* ... 此处代码已省略 ... */
OnElementsReadyDelete(); /* 在此处新增调用 */
}修改OnGraphViewChanged方法:
C#
// 当视图发生变化
private void OnGraphViewChanged()
{
// 定义事件
graphViewChanged = (changes) =>
{
/* ... 此处代码已省略 ... */
// 当即将删除元素时
if (changes.elementsToRemove != null)
{
/* 避免当开始节点和结束节点位于分组里时删除分组被一并删除 */
// 获取开始节点
GraphElement startNodes = changes.elementsToRemove.FirstOrDefault(n => n is StartNode);
// 将其移出删除列表
changes.elementsToRemove.Remove(startNodes);
// 获取结束节点列表
List<GraphElement> endNodes = changes.elementsToRemove.Where(n => n is EndNode).ToList();
// 如果与视图中所有结束节点的总数相同
if (endNodes.Count == GetEndNodesAmount())
{
// 获取最后一个结束节点
GraphElement lastEndNode = endNodes[^1];
// 将其移出删除列表
changes.elementsToRemove.Remove(lastEndNode);
}
/* ... 此处代码已省略 ... */
}
/* ... 此处代码已省略 ... */
return changes;
};
}将节点移入或移出分组时更新数据
继续新增以下方法并完成调用:
C#
// 当往分组里加入节点时
private void OnGroupElementsAdded()
{
elementsAddedToGroup = (group, elements) =>
{
BaseGroup baseGroup = (BaseGroup)group;
foreach (GraphElement element in elements)
{
// 如果添加的是节点
if (element is BaseNode node)
{
// 记录节点所属分组
node.Group = baseGroup;
}
}
};
}
// 当从分组里移出节点时
private void OnGroupElementsRemoved()
{
elementsRemovedFromGroup = (group, elements) =>
{
BaseGroup baseGroup = (BaseGroup)group;
foreach (GraphElement element in elements)
{
// 如果添加的是节点
if (element is BaseNode node)
{
// 清除分组信息
node.Group = null;
}
}
};
}
// 构造器
public StoryGraphView(StoryEditorWindow window)
{
/* ... 此处代码已省略 ... */
OnGroupElementsAdded(); /* 在此处新增调用 */
OnGroupElementsRemoved(); /* 在此处新增调用 */
}过滤重命名分组标题时的字符
打开StoryGraphView.cs,新增OnGroupRenamed方法并完成调用:
C#
// 当重命名分组时
private void OnGroupRenamed()
{
groupTitleChanged = (group, newTitle) =>
{
BaseGroup baseGroup = (BaseGroup)group;
// 清除无效字符
string temp = newTitle;
temp = temp.RemoveWhitespaces();
temp = temp.RemoveSpecialCharacters();
baseGroup.title = temp;
};
}
// 构造器
public StoryGraphView(StoryEditorWindow window)
{
/* ... 此处代码已省略 ... */
OnGroupRenamed(); /* 在此处新增调用 */
}测试效果
最终窗口效果如下:

相关链接
- 完整代码:https://gitee.com/helloestar/e-story/wikis/DevelopNotes/12
- 视频版本:制作中……


