Unity3D A* 寻路算法

笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,国家专利发明人;已出版书籍:《手把手教你架构3D游戏引擎》电子工业出版社和《Unity3D实战核心技术详解》电子工业出版社等。

CSDN视频网址:http://edu.csdn.net/lecturer/144

A*寻路算法通常是应用于大型网络游戏中,A*算法通常应用在服务器中,在移动端游戏开发中,A*算法也可以在Unity端实现,下面给读者介绍一个插件A* PathFindingProject,它的下载地址:https://arongranberg.com/astar/download#,可以直接导入到Unity工程中,它目前支持直接寻路和网格寻路。在官网上有免费的版本和收费的版本,作为学习者可以下载免费的版本原理是一样的。下面通过它们提供的Demo,给读者介绍一下:

在导入到Unity工程后,使用时首选建立一个空的GameObject,然后将AstarPath脚本挂接上去。如下图所示:


这个AstarPath是整个A*寻路的核心组件,它计算了整个地面的寻路路径以及保存信息,它保存的是二进制文件格式,操作如下所示:

该类提供了保存,加载等函数,详情可以查看类AstarPathEditor,函数接口如下所示:

void DrawSerializationSettings () {
			serializationSettingsArea.Begin();
			GUILayout.BeginHorizontal();

			if (GUILayout.Button("Save & Load", level0LabelStyle)) {
				serializationSettingsArea.open = !serializationSettingsArea.open;
			}

			if (script.data.cacheStartup && script.data.file_cachedStartup != null) {
				GUIUtilityx.PushTint(Color.yellow);
				GUILayout.Label("Startup cached", thinHelpBox, GUILayout.Height(15));
				GUILayout.Space(20);
				GUIUtilityx.PopTint();
			}

			GUILayout.EndHorizontal();

			// This displays the serialization settings
			if (serializationSettingsArea.BeginFade()) {
				script.data.cacheStartup = EditorGUILayout.Toggle(new GUIContent("Cache startup", "If enabled, will cache the graphs so they don't have to be scanned at startup"), script.data.cacheStartup);

				script.data.file_cachedStartup = EditorGUILayout.ObjectField(script.data.file_cachedStartup, typeof(TextAsset), false) as TextAsset;

				if (script.data.cacheStartup && script.data.file_cachedStartup == null) {
					EditorGUILayout.HelpBox("No cache has been generated", MessageType.Error);
				}

				if (script.data.cacheStartup && script.data.file_cachedStartup != null) {
					EditorGUILayout.HelpBox("All graph settings will be replaced with the ones from the cache when the game starts", MessageType.Info);
				}

				GUILayout.BeginHorizontal();

				if (GUILayout.Button("Generate cache")) {
					var serializationSettings = new Pathfinding.Serialization.SerializeSettings();
					serializationSettings.nodes = true;

					if (EditorUtility.DisplayDialog("Scan before generating cache?", "Do you want to scan the graphs before saving the cache.\n" +
							"If the graphs have not been scanned then the cache may not contain node data and then the graphs will have to be scanned at startup anyway.", "Scan", "Don't scan")) {
						MenuScan();
					}

					// Save graphs
					var bytes = script.data.SerializeGraphs(serializationSettings);

					// Store it in a file
					script.data.file_cachedStartup = SaveGraphData(bytes, script.data.file_cachedStartup);
					script.data.cacheStartup = true;
				}

				if (GUILayout.Button("Load from cache")) {
					if (EditorUtility.DisplayDialog("Are you sure you want to load from cache?", "Are you sure you want to load graphs from the cache, this will replace your current graphs?", "Yes", "Cancel")) {
						script.data.LoadFromCache();
					}
				}

				GUILayout.EndHorizontal();

				if (script.data.data_cachedStartup != null && script.data.data_cachedStartup.Length > 0) {
					EditorGUILayout.HelpBox("Storing the cached starup data on the AstarPath object has been deprecated. It is now stored " +
						"in a separate file.", MessageType.Error);

					if (GUILayout.Button("Transfer cache data to separate file")) {
						script.data.file_cachedStartup = SaveGraphData(script.data.data_cachedStartup);
						script.data.data_cachedStartup = null;
					}
				}

				GUILayout.Space(5);

				GUILayout.BeginHorizontal();
				if (GUILayout.Button("Save to file")) {
					string path = EditorUtility.SaveFilePanel("Save Graphs", "", "graph.bytes", "bytes");

					if (path != "") {
						var serializationSettings = Pathfinding.Serialization.SerializeSettings.Settings;
						if (EditorUtility.DisplayDialog("Include node data?", "Do you want to include node data in the save file. " +
								"If node data is included the graph can be restored completely without having to scan it first.", "Include node data", "Only settings")) {
							serializationSettings.nodes = true;
						}

						if (serializationSettings.nodes && EditorUtility.DisplayDialog("Scan before saving?", "Do you want to scan the graphs before saving? " +
								"\nNot scanning can cause node data to be omitted from the file if the graph is not yet scanned.", "Scan", "Don't scan")) {
							MenuScan();
						}

						uint checksum;
						var bytes = SerializeGraphs(serializationSettings, out checksum);
						Pathfinding.Serialization.AstarSerializer.SaveToFile(path, bytes);

						EditorUtility.DisplayDialog("Done Saving", "Done saving graph data.", "Ok");
					}
				}

				if (GUILayout.Button("Load from file")) {
					string path = EditorUtility.OpenFilePanel("Load Graphs", "", "");

					if (path != "") {
						byte[] bytes;
						try {
							bytes = Pathfinding.Serialization.AstarSerializer.LoadFromFile(path);
						} catch (System.Exception e) {
							Debug.LogError("Could not load from file at '"+path+"'\n"+e);
							bytes = null;
						}

						if (bytes != null) DeserializeGraphs(bytes);
					}
				}

				GUILayout.EndHorizontal();
			}

			serializationSettingsArea.End();
		}

该函数调用了JsonSerializer类中的两个函数如下所示:

		public static void SaveToFile (string path, byte[] data) {
#if NETFX_CORE
			throw new System.NotSupportedException("Cannot save to file on this platform");
#else
			using (var stream = new FileStream(path, FileMode.Create)) {
				stream.Write(data, 0, data.Length);
			}
#endif
		}

		/** Load the specified data from the specified path */
		public static byte[] LoadFromFile (string path) {
#if NETFX_CORE
			throw new System.NotSupportedException("Cannot load from file on this platform");
#else
			using (var stream = new FileStream(path, FileMode.Open)) {
				var bytes = new byte[(int)stream.Length];
				stream.Read(bytes, 0, (int)stream.Length);
				return bytes;
			}
#endif
		}

场景通过AstarPath脚本布置完后,接下来开始寻路了,需要挂接如下的脚本:


其中AI脚本是用于查询物体的,它会调用Seeker脚本中的函数,同时Seeker会对场景做一些标识操作,这样AI寻路基本完成,其中AI脚本是继承AIPath类,非常方便我们自己编写,扩展功能,它是通过递归的方式进行路径查询,锁定目标的,它运行的效果如下所示:






已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页