【Unity】A*算法的GUI实现

前言

A*算法是常用的游戏算法之一,也是初学者比较难掌握的一个算法。

本文在Unity中以GUI的方式形象的再现了A*算法的详细步骤,

包括地图的搜索、FGH的计算以及开启关闭列表的变化等。

博文首发地址:http://blog.csdn.net/duzixi

步骤一:

创建Unity新工程新场景

步骤二:

创建AStar.cs脚本,将以下代码内容粘贴覆盖后,保存运行即可

<span style="font-size:14px;">/// <summary>
/// A*算法 Unity GUI实现
/// Created by 杜子兮(duzixi.com) 2015.2.19
/// www.lanou3g.com All Rights Reserved
/// </summary>

using UnityEngine;
using System.Collections;
using System; // 用到排序接口

// 枚举:定义格子类型
public enum GridType {
	Normal,    // 常规
	Obstacle,  // 障碍
	Start,     // 起点
	End        // 终点
}

// 定义格子类(继承可比较接口 IComparable)
public class Grid : IComparable{
	public int x;		// x 坐标
	public int y;       // y 坐标
	public int F;       // 总评分
	public int G;       // 从起点到当前点的消耗值
	public int H;       // 从当前点到终点的估算值(直走10,斜走14)
	public GridType gridType;  // 格子类型
	public Grid fatherNode;

	// 可比较接口的实现(用于排序)
	public int CompareTo (object obj)
	{
		Grid g1 = (Grid) obj; // 强制类型转换
		if (this.F < g1.F)    // 升序
			return -1;
		if (this.F > g1.F)    // 降序
			return 1;
		return 0;             // 相等
	}
}

// A*算法
public class AStar : MonoBehaviour {
	private const int col = 7;          // 列数
	private const int row = 5;          // 行数
	private int size = 70;              // 大小

	private Grid[,] map;                // 地图(格子二维数组)
	private const int xStart = 2;
	private const int yStart = 1;
	private const int xEnd = 2;
	private const int yEnd = 5;        

	ArrayList openList;                 // 开启列表(重要!!)
	ArrayList closeList;                // 关闭列表(重要!!)

	// 初始化
	void Start () {
		map = new Grid[row, col];       // 创建地图
		for (int i = 0; i < row; i++) {
			for (int j = 0; j < col; j++) {
				map[i,j] = new Grid();  // 实例化格子
				map[i,j].x = i;			// x坐标赋值
				map[i,j].y = j;			// y坐标赋值
			}
		}

		map[xStart, yStart].gridType = GridType.Start; // 确定开始位置
		map[xStart, yStart].H = Manhattan(xEnd, yEnd); // 初始化开始位置的H值
		map[xEnd, yEnd].gridType = GridType.End;	   // 确定结束位置
		for (int i = 1; i <= 3; i++) {		           // 确定障碍位置
			map[i, 3].gridType = GridType.Obstacle;
		}

		openList = new ArrayList();		               // 初始化开启列表
		openList.Add(map[xStart, yStart]);  		   // 将开始节点放入开放列表中
		closeList = new ArrayList();	               // 初始化关闭列表
	}

	void OnGUI() {
		// 绘制地图
		for (int i = 0; i < row; i++) {
			for (int j = 0; j < col; j++) {
				// 根据格子类型设置背景颜色
				Color bgColor;
				if (map [i, j].gridType == GridType.Start) {
					bgColor = Color.green;
				} else if (map [i, j].gridType == GridType.End) {
					bgColor = Color.red;
				} else if (map [i, j].gridType == GridType.Obstacle) {
					bgColor = Color.blue;
				} else if (closeList.Contains (map [i, j])) {
					bgColor = Color.black;
				} else {
					bgColor = Color.gray;
				}
				GUI.backgroundColor = bgColor;
				// 用按钮表示格子
				GUI.Button(new Rect(j * size, i * size, size, size), FGH (map[i, j]));
			}
		}

		if (GUI.Button(new Rect(col * size, 0 , size, size), "Go Next")) {
			NextStep();
		}

		// 绘制开启列表
		for (int j = 0; j < openList.Count; j++) {
			GUI.Button(new Rect(j * size, (row + 1) * size, size, size), FGH((Grid)openList[j]));
		}

		// 绘制关闭列表
		for (int j = 0; j < closeList.Count; j++) {
			GUI.Button(new Rect(j * size, (row + 2) * size, size, size), FGH((Grid)closeList[j]));
		}
	}

	// 通过逆向追溯找到路径
	void showFatherNode(Grid grid) {
		if (grid.fatherNode != null) {
			print (grid.fatherNode.x + "," + grid.fatherNode.y);
			showFatherNode(grid.fatherNode);
		}
	}

	// 走下一步
	void NextStep() {
		//  0. 只要开启列表有节点, 就进行下一个过程
		if (openList.Count == 0) {
			print ("Over !");
			return;
		}

		//	1. 从开放列表中选择第一个节点并将其作为当前节点
		Grid grid = (Grid)openList[0];
		if (grid.gridType == GridType.End) {
			showFatherNode(grid);
			print ("Over !");
			return;
		}

		//	2. 获得这个当前节点不是障碍物的邻近节点
		for (int m = -1; m <= 1; m++) {
			for (int n = -1; n <= 1; n++) {
				if ( !( m == 0 && n == 0 )) {
					int x = grid.x + m;
					int y = grid.y + n;
					//	3. 对于每一个邻近节点,查看是否已在关闭列表中.
					if (x >= 0 && x < row && y >= 0 && y < col &&
					    map[x,y].gridType != GridType.Obstacle &&
					    !closeList.Contains(map[x, y]) ) {
						// 4.如果不在, 计算所有F、H、G
						int g = grid.G + (int)(Mathf.Sqrt(Mathf.Abs(m) + Mathf.Abs(n)) * 10);
						if (map[x, y].G == 0 || g < map[x, y].G) {
							map [x, y].G = g;
						}
						map[x, y].H = Manhattan(x, y);
						map[x, y].F = map[x, y].G + map[x, y].H;
						//	5.将代价数据存储在邻近节点中,并且将当前节点保存为该邻近节点的父节点.
						//    最后我们将使用这个父节点数据来追踪实际路径.
						map[x, y].fatherNode = grid;
						//	6.将邻近节点存储在开放列表中.
						if (!openList.Contains(map[x, y])) {
							openList.Add(map[x, y]);
						}
						//  7.根据F,以升序排列开放列表.
						openList.Sort();
					}
				}
			}
		}
		//	8. 如果没有邻近节点需要处理, 将当前节点放入关闭列表并将其从开放列表中移除.
		closeList.Add(grid);
		openList.Remove(grid);
	}

	// H值(曼哈顿估算法)
	int Manhattan(int x, int y) {
		return (int)(Mathf.Abs(xEnd - x) + Mathf.Abs(yEnd - y)) * 10;
	}

	// 将格子FGH 以字符串形式显示
	string FGH(Grid grid) {
		string fgh = "F:" + grid.F + "\n";
		fgh += "G:" + grid.G + "\n";
		fgh += "H:" + grid.H + "\n";
		fgh += "(" + grid.x + "," + grid.y + ")";
		return fgh;
	}
}
</span>

步骤三:

点击画面上的“Go Next”按钮,即可观察每部计算详情

(注:最终找到的路径在控制台里可看到,这个部分没有可视化)

后语

A*算法的具体实现细节有很多,本文脚本只是给出了其中一种。

另外,按照这个算法障碍墙是可以斜穿的,若要避免斜穿还需进一步修改。

时间: 2024-10-03 15:01:27

【Unity】A*算法的GUI实现的相关文章

【Unity】8.2 GUI Style和GUISkin

分类:Unity.C#.VS2015 创建日期:2016-04-27 一.自定义GUI Control 功能控件 (Functional Control) 是游戏必要的,而这些控件的外观对游戏的美感非常重要.在 UnityGUI 中,可以微调控件 (Control) 外观的很多细节. 默认情况下,当你在未定义 GUIStyle 时创建一个控件 (Control),将应用 Unity 的默认 GUIStyle.这种样式内置于 Unity 中,且可用于对已发布的游戏进行快速原型设计,你也可以选择不对

unity导弹算法 预计目标点

关于导弹的飞行算法,网上有很多教程.简单算法无非是获取目标点的当前位置,然后导弹朝目标方向移动.高深点的,就是通过计算获取碰撞点然后朝着目标移动.如果你能看懂这个高深算法的话,可以去看原帖:http://game.ceeger.com/forum/read.php?tid=3919 需要注意的是,原帖存在错误.而且一些方法使用的不合理.下面是我整合后的代码,欢迎大家提出不同见解. 想要实现导弹的“拦截”功能,首先需要根据目标物体的速度,位置,导弹的速度,位置,计算出两者相交的预计点.然后导弹朝碰

Unity的Editor的GUI的样式

public class GUIStyleViewer : EditorWindow { Vector2 scrollPosition = new Vector2(0, 0); string search = ""; GUIStyle textStyle; private static GUIStyleViewer window; [MenuItem("Tools/GUIStyleViewer", false, 100)] private static void O

【Unity】第8章 GUI开发

分类:Unity.C#.VS2015 创建日期:2016-04-27 一.简介 前面的章节中实际上已经多次使用了GUI,只不过用法都比较简单,这一章系统地介绍Unity 5.x自带的GUI(称为UnityGUI)开发相关的知识. 二.本章要点 对于Unity的早期版本来说,由于其自身提供的GUI设计功能较弱,所以一般还需要借助其他GUI插件(例如:NGUI)来实现.但是,对于Unity 5.x来说,由于其自身已经包含了非常棒的功能,所以直接使用Unity自带的GUI(称为UnityGUI)就行了

2015年5月27日 Unity学习疑问记录之新GUI

学习Unity 4.6新GUI系统 http://segmentfault.com/a/1190000000642686

【Unity】4.1 创建组件

分类:Unity.C#.VS2015 创建日期:2016-04-05 一.简介 组件(Component)在Unity游戏开发工作中非常重要,可以说是实现一切功能所必需的. 1.游戏对象(Game Object) 游戏对象(Game Object)包括空物体.基本几何体.外部导入的模型.摄像机.GUI.粒子.灯光.树木等各类元素. 凡是出现在层次视图中的元素都是游戏对象. 2.组件(Component) 组件是在游戏对象(Game Object)中的实现某些功能的集合.无论是模型.GUI.灯光还

unity 编辑器和插件制作(五)

接着前面的继续前行,默默的fighting. 前面讲了,怎么使用摄像机发射线到物体,来触发事件.今天我们 来讲述下怎么去实现一个label. 这个就相对比较简单了,其实我们可以直接使用unity自带得textmesh来实现一个字体,但大多数时候,需要改一些设置,字体大小,材质等等 一些得问题所以我们,最好还是自己写一个脚本来实现一些简单的操作,方便简洁嘛.其实很简单 ,下面我们就开始来实现这些方法. 代码 : using UnityEngine; using System.Collections

类似Unity的全新游戏引擎Godot

http://www.godotengine.org/wp/ Godot是一个全新开发的游戏引擎,其功能集类似知名的跨平台游戏引擎Unity,可用于开发PC.主机.移动和Web游戏.开发者声称引 擎的2D和动画支持要强于Unity,表示在功能和特性上没有其它开源游戏引擎能相媲美.Godot引擎内置了类似Unity的编辑器,GUI工具 包,2D/3D物理支持,支持OpenGL ES 2.0 功能集的3D渲染器,易于学习的语言和API,支持用ASM.js或Google Native Client输出

Unity Web前端研究

原地址:http://blog.csdn.net/libeifs/article/details/7200630 开发环境 Window7 Unity3D  3.4.1 MB525defy Android 2.2.1 羽化的第二十五篇博客,明天就要启程回家了,所以这应该是本月的最后一篇博客.最近工作还算顺利,只是临近春节放假,大家貌似都很轻松,春节过后杰哥就要离职到别的公司,是羽化在公司唯一的机友,生活方面得到很多照顾,希望杰哥新的一年能工作顺利,万事开心~ ~前几天突然翻起了<灌篮高手>漫画