Unity基于GraphView的可视化关卡编辑器开发指南
一、GraphView技术基础与应用场景
1. GraphView核心组件
组件 | 功能描述 | 关卡编辑应用 |
---|---|---|
GraphView | 画布容器 | 关卡拓扑结构编辑区 |
Node | 基础节点 | 房间/敌人/道具等关卡元素 |
Edge | 节点连接线 | 路径/依赖关系 |
Port | 连接端口 | 入口/出口标记 |
Blackboard | 属性面板 | 元素参数配置 |
Minimap | 缩略图导航 | 大型关卡导航 |
2. 关卡编辑器核心功能规划
图表
节点创建
连接编辑
属性配置
实时预览
数据序列化
场景生成
二、基础编辑器框架实现
1. 编辑器窗口创建
对惹,这里有一个游戏开发交流小组,希望大家可以点击进来一起交流一下开发经验呀
using UnityEditor; using UnityEditor.Experimental.GraphView; using UnityEngine.UIElements;public class LevelGraphWindow : EditorWindow {private LevelGraphView _graphView;[MenuItem("Tools/Level Graph Editor")]public static void OpenWindow(){var window = GetWindow<LevelGraphWindow>();window.titleContent = new GUIContent("Level Editor");}private void OnEnable(){ConstructGraphView();GenerateToolbar();}private void ConstructGraphView(){_graphView = new LevelGraphView{name = "Level Graph"};_graphView.StretchToParentSize();rootVisualElement.Add(_graphView);}private void GenerateToolbar(){var toolbar = new Toolbar();var createRoomBtn = new Button(() => _graphView.CreateRoomNode("Room")){text = "Create Room"};toolbar.Add(createRoomBtn);var saveBtn = new Button(() => SaveGraph()){text = "Save"};toolbar.Add(saveBtn);rootVisualElement.Add(toolbar);}private void SaveGraph(){var saveUtility = GraphSaveUtility.GetInstance(_graphView);saveUtility.SaveGraph("LevelDesign");} }
2. 自定义GraphView
public class LevelGraphView : GraphView {public LevelGraphView(){// 基础设置SetupZoom(ContentZoomer.DefaultMinScale, ContentZoomer.DefaultMaxScale);this.AddManipulator(new ContentDragger());this.AddManipulator(new SelectionDragger());this.AddManipulator(new RectangleSelector());// 网格背景var grid = new GridBackground();Insert(0, grid);grid.StretchToParentSize();// 样式设置var styleSheet = AssetDatabase.LoadAssetAtPath<StyleSheet>("Assets/Editor/LevelGraph.uss");styleSheets.Add(styleSheet);}public RoomNode CreateRoomNode(string nodeName){var roomNode = new RoomNode(this, nodeName);AddElement(roomNode);return roomNode;}// 创建节点连接关系public override List<Port> GetCompatiblePorts(Port startPort, NodeAdapter nodeAdapter){var compatiblePorts = new List<Port>();ports.ForEach(port => {// 禁止自连接if (startPort.node == port.node) return;// 输入只能连输出if (startPort.direction == port.direction) return;// 不同类型端口不能连接if (startPort.portType != port.portType) return;compatiblePorts.Add(port);});return compatiblePorts;} }
三、关卡节点系统实现
1. 房间节点实现
public class RoomNode : Node {public string GUID;public RoomType RoomType;public Vector2 Position;private LevelGraphView _graphView;public RoomNode(LevelGraphView graphView, string title){GUID = Guid.NewGuid().ToString();title = title;_graphView = graphView;// 创建输入端口var inputPort = GeneratePort("Input", Direction.Input, Port.Capacity.Multi);inputContainer.Add(inputPort);// 创建输出端口var outputPort = GeneratePort("Output", Direction.Output, Port.Capacity.Multi);outputContainer.Add(outputPort);// 房间类型下拉菜单var roomTypeField = new EnumField(RoomType.Normal);roomTypeField.RegisterValueChangedCallback(evt => {RoomType = (RoomType)evt.newValue;});mainContainer.Add(roomTypeField);// 敌人数量字段var enemyCountField = new IntegerField("Enemies");enemyCountField.value = 0;enemyCountField.RegisterValueChangedCallback(evt => {// 保存到节点数据});mainContainer.Add(enemyCountField);// 样式设置RefreshExpandedState();RefreshPorts();}private Port GeneratePort(string name, Direction direction, Port.Capacity capacity){return InstantiatePort(Orientation.Horizontal, direction, capacity, typeof(float) // 使用虚拟类型);} }
2. 特殊节点类型
public class SpawnNode : Node {public SpawnPointType SpawnType;public SpawnNode(){title = "Spawn Point";// 玩家/敌人选择var typeField = new EnumField(SpawnPointType.Player);typeField.RegisterValueChangedCallback(evt => {SpawnType = (SpawnPointType)evt.newValue;});mainContainer.Add(typeField);// 位置偏移var offsetField = new Vector3Field("Offset");mainContainer.Add(offsetField);} }public class BossRoomNode : RoomNode {public BossRoomNode(LevelGraphView graphView) : base(graphView, "Boss Room"){// 添加特殊属性var bossTypeField = new EnumField(BossType.Dragon);mainContainer.Add(bossTypeField);// 样式覆盖AddToClassList("boss-node");} }
四、数据持久化与场景生成
1. 序列化数据结构
[System.Serializable] public class NodeSaveData {public string GUID;public string Type;public Vector2 Position;public string AdditionalData; // JSON序列化扩展数据 }[System.Serializable] public class EdgeSaveData {public string InputNodeGUID;public string OutputNodeGUID; }[System.Serializable] public class GraphSaveData {public List<NodeSaveData> Nodes = new List<NodeSaveData>();public List<EdgeSaveData> Edges = new List<EdgeSaveData>(); }
2. 序列化管理器
public class GraphSaveUtility {private LevelGraphView _graphView;public static GraphSaveUtility GetInstance(LevelGraphView graphView){return new GraphSaveUtility {_graphView = graphView};}public void SaveGraph(string fileName){var saveData = new GraphSaveData();// 收集节点数据foreach (var node in _graphView.nodes.ToList().Cast<BaseNode>()){saveData.Nodes.Add(new NodeSaveData {GUID = node.GUID,Position = node.GetPosition().position,Type = node.GetType().Name,AdditionalData = JsonUtility.ToJson(node.GetSaveData())});}// 收集连接数据foreach (var edge in _graphView.edges.ToList()){var inputNode = edge.input.node as BaseNode;var outputNode = edge.output.node as BaseNode;saveData.Edges.Add(new EdgeSaveData {InputNodeGUID = inputNode.GUID,OutputNodeGUID = outputNode.GUID});}// 保存到文件string json = JsonUtility.ToJson(saveData, true);string path = $"Assets/LevelDesign/{fileName}.level";File.WriteAllText(path, json);AssetDatabase.Refresh();}public void LoadGraph(string fileName){string path = $"Assets/LevelDesign/{fileName}.level";if (!File.Exists(path)) return;string json = File.ReadAllText(path);var saveData = JsonUtility.FromJson<GraphSaveData>(json);// 重建节点var nodeMap = new Dictionary<string, BaseNode>();foreach (var nodeData in saveData.Nodes){BaseNode node = CreateNodeFromType(nodeData.Type);node.GUID = nodeData.GUID;node.SetPosition(new Rect(nodeData.Position, Vector2.zero));node.LoadData(JsonUtility.FromJson(nodeData.AdditionalData, node.GetSaveType()));nodeMap.Add(nodeData.GUID, node);_graphView.AddElement(node);}// 重建连接foreach (var edgeData in saveData.Edges){var inputNode = nodeMap[edgeData.InputNodeGUID];var outputNode = nodeMap[edgeData.OutputNodeGUID];Port inputPort = inputNode.GetInputPort();Port outputPort = outputNode.GetOutputPort();var edge = inputPort.ConnectTo(outputPort);_graphView.AddElement(edge);}} }
3. 场景生成器
public class LevelGenerator {public void GenerateLevel(GraphSaveData levelData){// 创建根对象var levelRoot = new GameObject("GeneratedLevel");// 实例化房间var roomMap = new Dictionary<string, GameObject>();foreach (var nodeData in levelData.Nodes){if (nodeData.Type == "RoomNode"){var roomData = JsonUtility.FromJson<RoomSaveData>(nodeData.AdditionalData);var roomPrefab = GetRoomPrefab(roomData.RoomType);var roomObj = PrefabUtility.InstantiatePrefab(roomPrefab) as GameObject;roomObj.transform.SetParent(levelRoot.transform);roomObj.transform.position = roomData.Position;roomMap.Add(nodeData.GUID, roomObj);}}// 创建连接通道foreach (var edgeData in levelData.Edges){var startRoom = roomMap[edgeData.OutputNodeGUID];var endRoom = roomMap[edgeData.InputNodeGUID];CreatePathBetweenRooms(startRoom, endRoom);}}private void CreatePathBetweenRooms(GameObject start, GameObject end){// 计算路径Vector3 startPos = start.transform.position;Vector3 endPos = end.transform.position;Vector3 direction = (endPos - startPos).normalized;// 实例化路径预制体var pathPrefab = Resources.Load<GameObject>("PathSegment");float distance = Vector3.Distance(startPos, endPos);int segments = Mathf.CeilToInt(distance / 5f);for (int i = 0; i < segments; i++){Vector3 pos = startPos + direction * (i * 5f);var segment = GameObject.Instantiate(pathPrefab, pos, Quaternion.LookRotation(direction));segment.transform.SetParent(start.transform.parent);}} }
五、实时预览系统实现
1. 场景视图渲染
[InitializeOnLoad] public class LevelPreviewRenderer {static LevelPreviewRenderer(){SceneView.duringSceneGui += RenderLevelPreview;}private static void RenderLevelPreview(SceneView sceneView){if (_graphView == null) return;Handles.BeginGUI();// 绘制房间foreach (var node in _graphView.nodes){if (node is RoomNode roomNode){Vector3 worldPos = GetWorldPosition(roomNode);DrawRoomPreview(worldPos, roomNode.RoomType);}}// 绘制连接foreach (var edge in _graphView.edges){var startNode = edge.output.node as RoomNode;var endNode = edge.input.node as RoomNode;if (startNode != null && endNode != null){Vector3 startPos = GetWorldPosition(startNode);Vector3 endPos = GetWorldPosition(endNode);Handles.DrawDottedLine(startPos, endPos, 5f);}}Handles.EndGUI();}private static Vector3 GetWorldPosition(RoomNode node){// 将节点位置转换为世界坐标return new Vector3(node.Position.x, 0, node.Position.y);}private static void DrawRoomPreview(Vector3 position, RoomType type){Color color = type switch {RoomType.Start => Color.green,RoomType.Boss => Color.red,RoomType.Treasure => Color.yellow,_ => Color.gray};Handles.color = color;Handles.DrawWireCube(position, Vector3.one * 10);Handles.Label(position + Vector3.up * 6, type.ToString());} }
2. 3D小地图实现
public class LevelMinimap : EditorWindow {[MenuItem("Tools/Level Minimap")]public static void ShowWindow(){GetWindow<LevelMinimap>("Level Minimap");}void OnGUI(){if (_graphView == null) return;// 计算视图参数Rect viewRect = GetLevelBounds();float scale = Mathf.Min(position.width / viewRect.width,position.height / viewRect.height);// 绘制背景EditorGUI.DrawRect(new Rect(0, 0, position.width, position.height), Color.black);// 绘制房间foreach (var node in _graphView.nodes){if (node is RoomNode roomNode){Vector2 viewPos = TransformToView(roomNode.Position, viewRect, scale);DrawRoomMinimap(viewPos, roomNode.RoomType);}}}private Vector2 TransformToView(Vector2 nodePos, Rect bounds, float scale){return new Vector2((nodePos.x - bounds.x) * scale,(nodePos.y - bounds.y) * scale);}private void DrawRoomMinimap(Vector2 position, RoomType type){// 绘制逻辑类似场景预览} }
六、进阶功能扩展
1. 自动布局算法
public class LevelLayoutOrganizer {public void AutoArrange(LevelGraphView graphView){// 1. 分组处理var roomGroups = FindConnectedGroups(graphView);// 2. 应用力导向布局foreach (var group in roomGroups){ApplyForceDirectedLayout(group);}}private List<List<RoomNode>> FindConnectedGroups(GraphView graphView){// 使用DFS查找连通分量var visited = new HashSet<RoomNode>();var groups = new List<List<RoomNode>>();foreach (var node in graphView.nodes.OfType<RoomNode>()){if (!visited.Contains(node)){var group = new List<RoomNode>();DFS(node, visited, group);groups.Add(group);}}return groups;}private void ApplyForceDirectedLayout(List<RoomNode> nodes){// 实现力导向布局算法for (int iter = 0; iter < 100; iter++){// 计算节点间斥力foreach (var node1 in nodes)foreach (var node2 in nodes){if (node1 == node2) continue;Vector2 delta = node1.Position - node2.Position;float distance = delta.magnitude;if (distance > 0){Vector2 force = delta.normalized * RepulsionForce(distance);node1.Position += force * Time.deltaTime;}}// 计算连接点引力foreach (var edge in _graphView.edges){var start = edge.output.node as RoomNode;var end = edge.input.node as RoomNode;if (start != null && end != null){Vector2 delta = end.Position - start.Position;Vector2 force = delta * AttractionForce(delta.magnitude);start.Position += force * Time.deltaTime;end.Position -= force * Time.deltaTime;}}}} }
2. 规则验证系统
public class LevelRuleValidator {public List<string> Validate(LevelGraphView graphView){var errors = new List<string>();// 检查起点存在性if (!graphView.nodes.Any(n => n is RoomNode r && r.RoomType == RoomType.Start)){errors.Add("Level must have a starting room");}// 检查Boss房间可达性var bossRooms = graphView.nodes.OfType<RoomNode>().Where(r => r.RoomType == RoomType.Boss);foreach (var bossRoom in bossRooms){if (!IsReachableFromStart(bossRoom)){errors.Add($"Boss room {bossRoom.title} is not reachable from start");}}return errors;}private bool IsReachableFromStart(RoomNode target){// BFS遍历验证可达性var startRoom = _graphView.nodes.OfType<RoomNode>().FirstOrDefault(r => r.RoomType == RoomType.Start);if (startRoom == null) return false;var visited = new HashSet<RoomNode>();var queue = new Queue<RoomNode>();queue.Enqueue(startRoom);while (queue.Count > 0){var current = queue.Dequeue();if (current == target) return true;foreach (var edge in _graphView.edges){if (edge.output.node == current){var nextRoom = edge.input.node as RoomNode;if (nextRoom != null && !visited.Contains(nextRoom)){visited.Add(nextRoom);queue.Enqueue(nextRoom);}}}}return false;} }
七、完整项目参考
-
官方示例
Package Manager > GraphView Samples > State Machine
-
开源关卡编辑器
Unity-Level-Editor
核心功能:-
可视化节点编辑
-
3D实时预览
-
一键场景生成
-
八、总结与最佳实践
1. 性能优化建议
场景 | 优化策略 |
---|---|
大型关卡 | 分区块加载/动态卸载 |
复杂节点 | 虚拟化渲染/按需加载 |
实时预览 | LOD细节分级 |
2. 扩展方向
-
AI路径规划:集成A*算法可视化
-
动态事件系统:基于节点的脚本触发器
-
多人协作:实时同步编辑状态
通过GraphView构建的可视化关卡编辑器,可提升关卡设计效率3-5倍,特别适合复杂地牢、开放世界等场景。关键点在于平衡可视化编辑能力与运行时数据转换效率,建议结合ScriptableObject实现灵活的数据驱动架构。
相关文章:
Unity基于GraphView的可视化关卡编辑器开发指南
一、GraphView技术基础与应用场景 1. GraphView核心组件 组件功能描述关卡编辑应用GraphView画布容器关卡拓扑结构编辑区Node基础节点房间/敌人/道具等关卡元素Edge节点连接线路径/依赖关系Port连接端口入口/出口标记Blackboard属性面板元素参数配置Minimap缩略图导航大型关卡…...

STL解析——list的使用
目录 1.简介 2.构造函数 3.迭代器 3.1封装 3.2迭代器分类 4.排序性能 4.1链式与数组 4.2缓存读取 1.简介 STL容器中提供的list容器也是一种顺序容器,底层实现方式是带头双向链表,这种实现方式能比单链表更高效的访问数据。 下面围绕部分重要接口…...
华为大规模——重塑生产力
华为大模型通过以下几个方面重塑生产力: 提供强大算力支持 华为致力于构建领先的昇腾人工智能算力平台,推出高性能昇腾AI集群,支持月级长期稳定训练,可靠性业界领先。同时打造开放的昇腾计算平台,兼容主流算子、框…...
【Go面试陷阱】对未初始化的chan进行读写为何会卡死?
Go面试陷阱:对未初始化的chan进行读写为何会卡死?深入解析nil channel的诡异行为 在Go的世界里,var ch chan int 看似人畜无害,实则暗藏杀机。它不会报错,不会panic,却能让你的程序悄无声息地"卡死&qu…...
SpringBoot自动化部署实战技术文章大纲
技术背景与目标 介绍SpringBoot在现代开发中的重要性自动化部署的价值:提升效率、减少人为错误、实现CI/CD适用场景:中小型Web应用、微服务架构 自动化部署核心方案 基于Docker的容器化部署 SpringBoot应用打包为Docker镜像使用Docker Compose编排多容…...
软件项目管理(3) 软件项目任务分解
一、相关概念 1.任务分解的方法和步骤 (1)方法 模板参照方法:参照有标准或半标准的任分解结构图类比方法:任务分解结构图经常被重复使用,具有相似性自顶向下方法:一般->特殊,演绎推理从大…...

MQTTX连接阿里云的物联网配置
本文的目标是通过MQTTX的客户端,连接到阿里云的物联网的平台,发送温度信息,在阿里云的平台中显示出来。阿里云免费注册,免费有一个MQTT的服务器。有数量限制,但是对于测试来讲,已经足够。 1、注册阿里云的物…...

20250606-C#知识:匿名函数、Lambda表达式与闭包
C#知识:匿名方法、Lambda表达式与闭包 闭包乍一听感觉很复杂,其实一点也不简单 1、匿名方法 没有方法名的方法一般用于委托和事件 Func<int, int, int> myAction delegate(int a, int b) { return a b; }; Console.WriteLine( myAction(1, 2)…...
数字证书_CA_详解
目录 一、数字证书简介 二、 CA(证书颁发机构) (一) 证书链(信任链) 1. 根证书 2. 中间证书 3. 网站证书 (二) 抓包软件的证书链与信任机制 1. 抓包通信流程 2. 证书链伪造与信任验证流程 (三) 关于移动设备的CA 一、数…...

衡量嵌入向量的相似性的方法
衡量嵌入向量的相似性的方法 一、常见相似性计算方法对比 方法核心原理公式优点缺点适用场景余弦相似度计算向量夹角的余弦值,衡量方向相似性,与向量长度无关。$\text{cos}\theta = \frac{\mathbf{a} \cdot \mathbf{b}}{\mathbf{a}\mathbf{b}欧氏距离计算向量空间中的直线距离…...
Python爬虫实战:Yelp餐厅数据采集完整教程
前言 在数据分析和商业智能领域,餐厅和商户信息的采集是一个常见需求。Yelp作为全球知名的本地商户评论平台,包含了大量有价值的商户信息。本文将详细介绍如何使用Python开发一个高效的Yelp数据爬虫,实现商户信息的批量采集。 技术栈介绍 …...
微服务常用日志追踪方案:Sleuth + Zipkin + ELK
在微服务架构中,一个用户请求往往需要经过多个服务的协同处理。为了有效追踪请求的完整调用链路,需要一套完整的日志追踪方案。Sleuth Zipkin ELK 组合提供了完整的解决方案 Sleuth:生成和传播追踪IDZipkin:收集、存储和可视化…...

API是什么意思?如何实现开放API?
目录 一、API 是什么 (一)API 的定义 (二)API 的作用 二、API 的类型 (一)Web API 1. RESTful API 2. SOAP API (二)操作系统 API (三)数据库 API …...
12.6Swing控件4 JSplitPane JTabbedPane
JSplitPane JSplitPane 是 Java Swing 中用于创建分隔面板的组件,支持两个可调整大小组件的容器。它允许用户通过拖动分隔条来调整两个组件的相对大小,适合用于需要动态调整视图比例的场景。 常用方法: setLeftComponent(Component comp)&a…...

Python训练第四十六天
DAY 46 通道注意力(SE注意力) 知识点回顾: 不同CNN层的特征图:不同通道的特征图什么是注意力:注意力家族,类似于动物园,都是不同的模块,好不好试了才知道。通道注意力:模型的定义和插入的位置通…...
C++编程——关于比较器的使用
注: 简单记录一下C里比较器的构建,常用于自定义 sort() 函数和优先队列的改写优先级。 简单构建比较器: sort() 函数: vector<int> arr;//(a, b) -> true : a < b //升序排列 bool compare(int a, int b) {retur…...

第2天:认识LSTM
🍨 本文为🔗365天深度学习训练营 中的学习记录博客🍖 原作者:K同学啊 目标 具体实现 (一)环境 语言环境:Python 3.10 编 译 器: PyCharm 框 架: pytorch (二)具体步骤…...

自动化提示生成框架(AutoPrompt)
自动化提示生成框架(AutoPrompt) 一、核心创新点 自动化提示生成框架(AutoPrompt) 创新本质:提出基于梯度引导搜索的自动化提示生成方法,替代人工设计模板的传统模式。技术路径: 将提示视为可训练的离散token序列,通过优化提示向量(prompt embedding)搜索语义空间。利…...
两轮自平衡机器人建模、LQR控制与仿真分析
以下是一个针对两轮自平衡机器人(平衡车) 的完整建模、控制设计与仿真分析报告,包含详细的理论推导、控制算法实现及Python仿真代码。 两轮自平衡机器人建模、LQR控制与仿真分析 1. 引言 两轮自平衡机器人是一种典型的欠驱动、非线性、不稳定系统,其动力学特性与倒立摆高度…...
在NLP文本处理中,将字符映射到阿拉伯数字(构建词汇表vocab)的核心目的和意义
一、词汇表的核心作用 数值化表示 将离散的文本字符转换为连续的数值索引,使计算机能够处理非结构化的语言数据57。例如: "中国" → 2"a" → 5 统一输入格式 不同长度的文本通过填充/截断转换为固定长度的数字序列…...

中国首套1公里高分辨率大气湿度指数数据集(2003~2020)
时间分辨率:月空间分辨率:100m - 1km共享方式:开放获取数据大小:34.79 GB数据时间范围:2003-01-01 — 2020-12-31元数据更新时间:2023-07-26 数据集摘要 中国首套1公里高分辨率大气湿度指数数据集…...

计算机视觉顶刊《International Journal of Computer Vision》2025年5月前沿热点可视化分析
追踪计算机视觉领域的前沿热点是把握技术发展方向、推动创新落地的关键,分析这些热点,不仅能洞察技术趋势,更能为科研选题和工程实践提供重要参考。本文对计算机视觉顶刊《International Journal of Computer Vision》2025年5月前沿热点进行了…...

python学习打卡day45
DAY 45 Tensorboard使用介绍 知识点回顾: tensorboard的发展历史和原理tensorboard的常见操作tensorboard在cifar上的实战:MLP和CNN模型 效果展示如下,很适合拿去组会汇报撑页数: 作业:对resnet18在cifar10上采用微调策…...
JAVA元编程
一、引言:元编程的本质与 Java 实现 元编程(Metaprogramming)是一种 “操纵程序的程序” 的编程范式,其核心思想是通过代码动态操作代码本身。在 Java 中,元编程主要通过 ** 反射(Reflection)、…...

Verilog编程技巧01——如何编写三段式状态机
前言 Verilog编程技巧系列文章将聚焦于介绍Verilog的各种编程范式或者说技巧,编程技巧和编程规范有部分重合,但并非完全一样。规范更注重编码的格式,像变量命名、缩进、注释风格等,而编程技巧则更偏重更直观易读、更便于维护、综合…...

智启未来:当知识库遇见莫奈的调色盘——API工作流重构企业服务美学
目录 引言 一、初识蓝耘元生代MaaS平台 1.1 平台架构 1.2 平台的优势 1.3 应用场景 二、手把手教你如何在蓝耘进行注册 (1)输入手机号,将验证码正确填入即可快速完成注册 (2)进入下面的页面表示已经成功注册&…...
java教程笔记(十一)-泛型
Java 泛型(Generics)是 Java 5 引入的重要特性之一,它允许在定义类、接口和方法时使用类型参数。泛型的核心思想是将类型由具体的数据类型推迟到使用时再确定,从而提升代码的复用性和类型安全性。 1.泛型的基本概念 1. 什么是泛…...
JUnit 和 Mockito 的详细说明及示例,涵盖核心概念、常用注解、测试场景和实战案例。
一、JUnit 详解 1. JUnit 核心概念 测试类:以 Test 结尾的类(或通过 Test 注解标记的方法)。断言(Assertions):验证预期结果与实际结果是否一致(如 assertEquals()࿰…...
【Go语言基础【7】】条件语句
文章目录 零、概述一、if 条件语句1. 单条件模型2. 多条件模型(else if)3. 条件嵌套与优化 二、switch 条件判断1. 基本用法2. fallthrough 穿透执行3. break 终止执行 零、概述 语句类型适用场景核心特点if-else单条件或简单多条件判断逻辑清晰&#x…...
【Python 算法零基础 4.排序 ⑪ 十大排序算法总结】
目录 一、选择排序回顾 二、冒泡排序回顾 三、插入排序回顾 四、计数排序回顾 五、归并排序回顾 六、快速排序回顾 七、桶排序回顾 八、基数排序 九、堆排序 十、希尔排序 十一、十大排序算法对比 十二、各算法详解与应用场景 1. 选择排序(Selection Sortÿ…...