大白话说一下几个点:

通俗的来说,其实就是以一个规则来 从A点走到B点。
怎么来判断我们走的格子是一个合适的格子?
就是靠一个规则来计算,这个规则就是估价函数。

估价函数:
常用:曼哈顿算法
F = G + H
G:表示从起点 A 移动到网格上指定方格的移动耗费 (可沿斜方向移动).
H:表示从指定的方格移动到终点 B 的预计耗费

G值的计算:
假定:左右上下方向的移动产生的耗费是10
那么在斜方向的移动耗费 就是 左右上下方向耗费的 根号2 倍,就是14咯

H值的计算:
(H 有很多计算方法, 这里我们设定只可以上下左右移动).
就是算是指定格子 到 终点格子的 横方向上的耗费+竖方向上的耗费。

开启列表:就是一个等待检查方格的列表.
关闭列表:存放不需要再次检查的方格的列表

伪代码:
把起始格添加到 “开启列表”
do
{
寻找开启列表中F值最低的格子, 我们称它为当前格.
把它切换到关闭列表.
对当前格相邻的8格中的每一个
if (它不可通过 || 已经在 “关闭列表” 中)
{
什么也不做.
}
if (它不在开启列表中)
{
把它添加进 “开启列表”, 把当前格作为这一格的父节点, 计算这一格的 FGH
}
if (它已经在开启列表中)
{
if (用G值为参考检查新的路径是否更好, 更低的G值意味着更好的路径)
{
把这一格的父节点改成当前格, 并且重新计算这一格的 GF 值.
}
}
} while( 目标格已经在 “开启列表”, 这时候路径被找到)
如果开启列表已经空了, 说明路径不存在.
最后从终点开始, 沿着每一格的父节点移动直到回到起始格, 这就是路径。

地图信息:
1,不可走
0,可走

在Unity里效果如下:

节点:

using UnityEngine;
using System.Collections; public class Node
{
public bool canWalk;//是否可以行走
public Vector3 worldPos;//节点的位置
public int gridX, gridY;//地形网格的下标 public int gCost;//离起始点的耗费
public int hCost;//离目标点的耗费
public int fCost { get { return gCost + hCost; } } public Node parent;//父对象 public Node(bool _canWalk, Vector3 _pos, int _x, int _y)
{
canWalk = _canWalk;
worldPos = _pos;
gridX = _x;
gridY = _y;
}
}

地图网格:

using UnityEngine;
using System.Collections;
using System.Collections.Generic; public class Grid : MonoBehaviour
{
public Node[,] grid;//网格,是Node节点的二维数组
public Vector2 gridSize;//网格的大小
public float nodeRadius;//节点的半径
private float nodeDiameter;//节点的直径 public LayerMask whatLayer;//是可走层还是不可走层 public int gridCountX, gridCountY;//每一行、列有几个Node public List<List<Node>> AllPath = new List<List<Node>>();//所有人的路径 void Start()
{
nodeDiameter = nodeRadius * ;
gridCountX = Mathf.RoundToInt(gridSize.x / nodeDiameter);
gridCountY = Mathf.RoundToInt(gridSize.y / nodeDiameter); grid = new Node[gridCountX, gridCountY]; CreateGrid();
} void CreateGrid()
{
//左下角
Vector3 startPoint = this.transform.position - gridSize.x / * Vector3.right - gridSize.y / * Vector3.forward; for (int i = ; i < gridCountX; i++)
{
for (int j = ; j < gridCountY; j++)
{
Vector3 worldPoint = startPoint + Vector3.right * (i * nodeDiameter + nodeRadius) + Vector3.forward * (j * nodeDiameter + nodeRadius);
bool walkable = !Physics.CheckSphere(worldPoint, nodeRadius *, whatLayer);//检测半径(直径)范围内是否可行走,发射球形射线检测层
grid[i, j] = new Node(walkable, worldPoint, i, j);
}
}
} void OnDrawGizmos()
{
//画地形网格边缘
Gizmos.DrawWireCube(transform.position, new Vector3(gridSize.x, , gridSize.y)); //画节点Node
if (grid == null) return;
foreach (var node in grid)
{
Gizmos.color = node.canWalk ? Color.white : Color.red;
Gizmos.DrawCube(node.worldPos, Vector3.one * (nodeDiameter - .1f));
}
//画角色
/* Node playerNode = GetFromPositon(player.position);
if (playerNode != null && playerNode.canWalk)
{
Gizmos.color = Color.yellow;
Gizmos.DrawCube(playerNode.worldPos, Vector3.one * (nodeDiameter - .1f));
}*/ //画路径
//if (path != null)
//{
// foreach (var node in path)
// {
// Gizmos.color = Color.black;
// Gizmos.DrawCube(node.worldPos, Vector3.one * (nodeDiameter - .1f));
// }
//} if (AllPath.Count > )
{
for (int i = ; i < AllPath.Count; i++)
{
if (AllPath[i].Count > )
{
foreach (var node in AllPath[i])
{
Gizmos.color = Color.black;
Gizmos.DrawCube(node.worldPos, Vector3.one * (nodeDiameter - .1f));
}
}
}
}
}
}

寻路:

using UnityEngine;
using System.Collections;
using System.Collections.Generic; public class FindPath
{
public Grid mapGrid;
private GameObject npc, target;
private List<Node> FinalPath = new List<Node>(); public List<Node> GetFinalPath(GameObject self, GameObject target)
{
FindingPath(self.transform.position, target.transform.position);
return FinalPath;
} public void FindingPath(Vector3 _startPos, Vector3 _endPos)
{
//Node startNode = mapGrid.GetFromPositon(_startPos);
//Node endNode = mapGrid.GetFromPositon(_endPos); Node startNode = GetFromPositon(_startPos);
Node endNode = GetFromPositon(_endPos); //开启列表
List<Node> openSet = new List<Node>(); //关闭列表
HashSet<Node> closeSet = new HashSet<Node>(); openSet.Add(startNode); while (openSet.Count > )
{
Node currentNode = openSet[]; for (int i = ; i < openSet.Count; i++)
{
if (openSet[i].fCost < currentNode.fCost && openSet[i].hCost < currentNode.hCost)
{
currentNode = openSet[i];
}
} openSet.Remove(currentNode);
closeSet.Add(currentNode); if (currentNode == endNode)
{
GeneratePath(startNode,endNode);
return;
} foreach (var node in GetNeibourhood(currentNode))
{
if (!node.canWalk || closeSet.Contains(node)) continue;
int newCost = currentNode.gCost + GetNodesDistance(currentNode,node);
if (newCost < node.gCost || !openSet.Contains(node))
{
node.gCost = newCost;
node.hCost = GetNodesDistance(node,endNode);
node.parent = currentNode;
if (!openSet.Contains(node))
{
openSet.Add(node);
}
}
}
}
}
private void GeneratePath(Node startNode,Node endNode)
{
List<Node> path = new List<Node>();
Node temp = endNode;
while (temp != startNode)
{
path.Add(temp);
temp = temp.parent;
}
path.Reverse();
FinalPath = path; mapGrid.AllPath.Add(FinalPath);
}
public int GetNodesDistance(Node a, Node b)
{
int countX = Mathf.Abs(a.gridX - b.gridX);
int countY = Mathf.Abs(a.gridY - b.gridY);
if (countX > countY)
{
return * countY + * (countX - countY);
}
else
{
return * countX + * (countY - countX);
}
} //角色在哪个节点之上
public Node GetFromPositon(Vector3 _PlayerPos)
{
float percentX = (_PlayerPos.x + mapGrid.gridSize.x / ) / mapGrid.gridSize.x;
float percentY = (_PlayerPos.z + mapGrid.gridSize.y / ) / mapGrid.gridSize.y; percentX = Mathf.Clamp01(percentX);
percentY = Mathf.Clamp01(percentY); int x = Mathf.RoundToInt((mapGrid.gridCountX - ) * percentX);
int y = Mathf.RoundToInt((mapGrid.gridCountY - ) * percentY); return mapGrid.grid[x, y];
} //获取节点周围的节点
public List<Node> GetNeibourhood(Node node)
{
List<Node> neribourhood = new List<Node>();
for (int i = -; i <= ; i++)
{
for (int j = -; j <= ; j++)
{
if (i == && j == )
{
continue;
}
int tempX = node.gridX + i;
int tempY = node.gridY + j;
if (tempX > && tempY > && tempX < mapGrid.gridCountX && tempY < mapGrid.gridCountY)
{
neribourhood.Add(mapGrid.grid[tempX, tempY]);
}
}
}
return neribourhood;
}
}

还有许多优化的地方:
1.多单位寻路
2.动态障碍

A star 寻路的更多相关文章

  1. 数据结构和算法总结(三):A* 寻路算法

    前言 复习下寻路相关的东西,而且A star寻路在游戏开发中应用挺多的,故记录下. 正文 迪杰斯特拉算法 说起A*得先谈谈Dijkstra算法,它是在BFS基础上的一种带权值的两点最短寻路贪心算法. ...

  2. atc游戏bot

    游戏玩起来太虐心了,就写了个bot来玩, 代码在此: git clone https://github.com/chenfengyuan/atc-bot-new.gitgit clone https: ...

  3. RCP:gef智能寻路算法(A star)

    本路由继承自AbstactRouter,参数只有EditPart(编辑器内容控制器),gridLength(寻路用单元格大小),style(FLOYD,FLOYD_FLAT,FOUR_DIR). 字符 ...

  4. A*(也叫A star, A星)寻路算法Java版

    寻路算法有非常多种,A*寻路算法被公觉得最好的寻路算法. 首先要理解什么是A*寻路算法,能够參考这三篇文章: http://www.gamedev.net/page/resources/_/techn ...

  5. 算法:Astar寻路算法改进

    早前写了一篇<RCP:gef智能寻路算法(A star)> 出现了一点问题. 在AStar算法中,默认寻路起点和终点都是N x N的方格,但如果用在路由上,就会出现问题. 如果,需要连线的 ...

  6. 无递归 A星寻路算法

    整理硬盘的时候,发现我早些年写的A星寻路算法.特放上来,待有缘人拿去,无递归噢,性能那是杠杠的. 码上伺候 public class Node { public int X { get; set; } ...

  7. 一种高效的寻路算法 - B*寻路算法

    在此把这个算法称作B* 寻路算法(Branch Star 分支寻路算法,且与A*对应),本算法适用于游戏中怪物的自动寻路,其效率远远超过A*算法,经过测试,效率是普通A*算法的几十上百倍. 通过引入该 ...

  8. CritterAI与Recast Navigation寻路

    版权声明:本文为博主吴欣伟原创文章,未经博主允许不得转载. 前言 这篇文章写于去年,由于工作需要,故写出这个研究文档,发现网上有关此寻路库的中文资源十分稀少,故发布出来与诸位共享交流,如文中有不对之处 ...

  9. A* Pathfinding Project (Unity A*寻路插件) 使用教程

    Unity4.6 兴许版本号都已经内置了寻路AI了.之前的文章有介绍 Unity3d 寻路功能 介绍及项目演示 然而两年来项目中一直使用的是 A* Pathfinding 这个插件的.所以抽时间来写下 ...

随机推荐

  1. PHP session

    PHP Session PHP session 变量用于存储关于用户会话(session)的信息,或者更改用户会话(session)的设置.Session 变量存储单一用户的信息,并且对于应用程序中的 ...

  2. glusterFS系统中文管理手册(转载)

    GlusterFS系统中文管理手册       1文档说明 该文档主要内容出自 www.gluster.org 官方提供的英文系统管理手册<Gluster File System 3.3.0 A ...

  3. 签名、BOM头、编码、Windows记事本编码、java编码解码的那些事

    对于Windows记事本: ANSI :GB2312 java中应使用GBK解码 Unicode :有签名的UTF-16LE java中应使用UTF-16解码 Unicode big endian : ...

  4. Hydra用户手册

    Hydra 参数: -R继续从上一次进度接着破解 -S大写,采用SSL链接 -s <PORT>小写,可通过这个参数指定非默认端口 -l <LOGIN>指定破解的用户,对特定用户 ...

  5. windows系统和ubuntu虚拟机之间文件共享——samba

    参考:http://www.cnblogs.com/phinecos/archive/2009/06/06/1497717.html 一. samba的安装: sudo apt-get insall  ...

  6. 用 nssm 把 Nginx 安装成 Windows 服务方法

    总之:用 nssm 比 srvany.exe 简便多了.1. 下载nginx windows版本:http://nginx.org/ 2. 下载 nssm :http://nssm.cc/3. 安装N ...

  7. webstormkey

    webStorm : UserName:William ===== LICENSE BEGIN ===== 45550-12042010 00001SzFN0n1bPII7FnAxnt0DDOPJA  ...

  8. 调用webservice 总结

    最近做一个项目,由于是在别人框架里开发app,导致了很多限制,其中一个就是不能直接引用webservice . 我们都知道,调用webserivice 最简单的方法就是在 "引用" ...

  9. 关于NotePad一些功能的实现方法

    NotePad功能:1.向上查找,大小写,全字匹配,利用CFindDlg的基类的成员函数实现:switch casePreTranslateMessage()函数http://blog.sina.co ...

  10. mac 安装nginx

    首先准备工作,打开mac终端 1.安装brew  输入命令 curl -LsSf http://github.com/mxcl/homebrew/tarball/master | sudo tar x ...