这里我就不解释A*算法

如果你还不知道A*算法

网上有很多简单易懂的例子

我发几个我看过的链接

http://www.cnblogs.com/lipan/archive/2010/07/01/1769420.html

https://zhuanlan.zhihu.com/p/24112879

我这里就当你会A*算法

三角网格的A*算法寻路

需要用到多边形方法

这里我引入了一个Polygon库

在一个工具类中调用这个库文件

如果你想自己写这些逻辑或者有更好的库 可以替换

using System.Collections.Generic;
using Polygon; namespace AStar
{
public class AStarTools
{
/// <summary>
/// 判断点在哪个三角形中
/// </summary>
/// <param name="point"></param>
/// <param name="allAStarTriangle"></param>
/// <returns></returns>
public static Triangle GetAStarTriangleByPoint(Ponit point, List<Triangle> allAStarTriangle)
{
if (allAStarTriangle == null)
{
return new Triangle();
} Point Point = new Point(point.x, point.z); for (int i = ; i < allAStarTriangle.Count; i++)
{
Triangle AStarTriangle = allAStarTriangle[i]; List<Point> pointList = new List<Point>();
pointList.Add(new Point(AStarTriangle.a.x, AStarTriangle.a.z));
pointList.Add(new Point(AStarTriangle.b.x, AStarTriangle.b.z));
pointList.Add(new Point(AStarTriangle.c.x, AStarTriangle.c.z)); if (Utility.CheckPointInPolygon(Point, new Polygon.Polygon(pointList)))
{
return AStarTriangle;
}
}
return new Triangle();
}
}
}

AStarTools

算法需要用到一些数据 起点 终点  导航网格信息 等等

我统一保存在一个类中

using UnityEngine;

namespace AStar
{
public class AStarData
{
/// <summary>
/// 开始.
/// </summary>
public Ponit start;
/// <summary>
/// 终点.
/// </summary>
public Ponit end;
/// <summary>
/// 导航网格信息
/// </summary>
public NavMeshInfo navMeshInfo; /// <summary>
/// 起点所在的三角形
/// </summary>
public Triangle startPlace;
/// <summary>
/// 终点所在的三角形
/// </summary>
public Triangle endPlace;
/// <summary>
/// 起点新建三角形
/// </summary>
public Triangle startAStarTriangle;
/// <summary>
/// 终点新建三角形
/// </summary>
public Triangle endAStarTriangle; public bool Init(Ponit start, Ponit end, NavMeshInfo navMeshInfo)
{
this.start = start;
this.end = end;
this.navMeshInfo = navMeshInfo; startAStarTriangle = new Triangle(start, start, start);
endAStarTriangle = new Triangle(end, end, end); startPlace = AStarTools.GetAStarTriangleByPoint(start, navMeshInfo.allTriangle);
endPlace = AStarTools.GetAStarTriangleByPoint(end, navMeshInfo.allTriangle); if (startPlace == new Triangle())
{
Debug.Log("起点不在导航网格信息中");
return false;
} if (endPlace == new Triangle())
{
Debug.Log("终点不在导航网格信息中");
return false;
} return true;
}
}
}

AStarData

最后是我写的A*算法

using System.Collections.Generic;
using System.Linq; namespace AStar
{
public delegate void AStarCallback(List<Ponit> list); public class Pathfinding
{
/// <summary>
/// 数据
/// </summary>
AStarData aStarData; /// <summary>
/// 待计算列表.
/// </summary>
List<Triangle> openList;
/// <summary>
/// 关闭列表.
/// </summary>
List<Triangle> closeList; /// <summary>
/// 父级索引.
/// </summary>
Dictionary<Triangle, Triangle> parentIndexes; /// <summary>
/// G值.
/// </summary>
Dictionary<Triangle, float> triangle_G;
/// <summary>
/// H值.
/// </summary>
Dictionary<Triangle, float> triangle_H;
/// <summary>
/// F值.
/// </summary>
Dictionary<Triangle, float> triangle_F; /// <summary>
/// 回调.
/// </summary>
AStarCallback callback; public void Start(Ponit start, Ponit end, NavMeshInfo navMeshInfo, AStarCallback callback)
{
if (callback == null)
{
return;
} aStarData = new AStarData(); if (aStarData.Init(start, end, navMeshInfo) == false)
{
return;
} this.callback = callback; openList = new List<Triangle>();
closeList = new List<Triangle>();
parentIndexes = new Dictionary<Triangle, Triangle>();
triangle_G = new Dictionary<Triangle, float>();
triangle_H = new Dictionary<Triangle, float>();
triangle_F = new Dictionary<Triangle, float>(); Core();
} /// <summary>
/// 核心
/// </summary>
void Core()
{
openList.Add(aStarData.startAStarTriangle); //开始寻路 寻路到终点结束
while (!openList.Contains(aStarData.endAStarTriangle) && openList.Count != )
{
Triangle AStarTriangle = GetOpenListMin(); openList.Remove(AStarTriangle); closeList.Add(AStarTriangle); Explore(AStarTriangle);
} List<Triangle> list = new List<Triangle>(); Triangle T = aStarData.endAStarTriangle;
while (parentIndexes.ContainsKey(T) && parentIndexes[T] != null)
{
list.Add(T); T = parentIndexes[T];
} Callback(list);
} /// <summary>
/// 获取待计算列表中F值最小的一个.
/// </summary>
/// <returns></returns>
Triangle GetOpenListMin()
{
Triangle AStarTriangle = openList[];
for (int i = ; i < openList.Count; i++)
{
if (GetDictionaryValue(triangle_F, AStarTriangle) > GetDictionaryValue(triangle_F, openList[i]))
{
AStarTriangle = openList[i];
}
} return AStarTriangle;
} /// <summary>
/// 获取当前三角形周围的三角形.
/// </summary>
/// <param name="current"></param>
/// <param name="end"></param>
/// <param name="map"></param>
void Explore(Triangle current)
{
//获取当前三角形所有的邻边三角形
List<Triangle> list = GetRuoundAStarTriangle(current, aStarData); for (int i = ; i < list.Count; i++)
{
Triangle AStarTriangle = list[i]; //去掉当前三角形
if (AStarTriangle == current)
{
continue;
} //去掉已经关闭的三角形
if (closeList.Contains(AStarTriangle))
{
continue;
} //如果不在待检测的集合 则加入待检测集合
if (!openList.Contains(AStarTriangle))
{
SetParentIndexes(AStarTriangle, current); SetDictionaryValue(triangle_G, AStarTriangle, GetG(AStarTriangle, current));
SetDictionaryValue(triangle_H, AStarTriangle, GetH(AStarTriangle)); openList.Add(AStarTriangle);
}
//如果在待检测的集合 则判断是否修改父级
else
{
float G = GetDictionaryValue(triangle_G, AStarTriangle);
float H = GetDictionaryValue(triangle_H, AStarTriangle);
float F = GetG(AStarTriangle, current) + GetH(AStarTriangle); if (G + H > F)
{
SetParentIndexes(AStarTriangle, current);
SetDictionaryValue(triangle_G, AStarTriangle, GetG(AStarTriangle, current));
SetDictionaryValue(triangle_H, AStarTriangle, GetH(AStarTriangle)); openList.Remove(AStarTriangle);
}
}
}
} /// <summary>
/// 获取G值.
/// </summary>
/// <param name="grid"></param>
/// <param name="parent"></param>
/// <returns></returns>
float GetG(Triangle grid, Triangle parent)
{
float distance = Ponit.Distance(grid.centroid, parent.centroid); distance += GetDictionaryValue(triangle_G, parent); return distance;
} /// <summary>
/// 获取H值.
/// </summary>
/// <param name="grid"></param>
/// <param name="end"></param>
/// <returns></returns>
float GetH(Triangle grid)
{
float distance = Ponit.Distance(grid.centroid, aStarData.end); return distance;
} /// <summary>
/// 添加父级索引.
/// </summary>
/// <param name="current"></param>
/// <param name="parent"></param>
void SetParentIndexes(Triangle current, Triangle parent)
{
if (parentIndexes.ContainsKey(current))
{
parentIndexes[current] = parent;
}
else
{
parentIndexes.Add(current, parent);
}
} /// <summary>
/// 回调
/// </summary>
/// <param name="listAStarTriangle"></param>
void Callback(List<Triangle> listAStarTriangle)
{
if (callback == null || listAStarTriangle == null)
{
return;
} listAStarTriangle.Reverse(); List<Ponit> list = new List<Ponit>(); //进距离移动 不超过一个三角形
if (listAStarTriangle.Count == )
{
list.Add(aStarData.end);
callback(list);
return;
} for (int i = ; i < listAStarTriangle.Count; i++)
{
list.Add(listAStarTriangle[i].centroid);
} callback(list); } /// <summary>
/// 获取周围的三角形
/// </summary>
/// <param name="current"></param>
/// <returns></returns>
public static List<Triangle> GetRuoundAStarTriangle(Triangle current, AStarData aStarData)
{
//该点为开始点 则获取该点三角重心来取值
if (current.a == aStarData.start && current.b == aStarData.start)
{
current = aStarData.startPlace;
} //获取三角形所有的邻边三角形
List<Triangle> list = new List<Triangle>(); list.AddRange(GetListAStarTriangle(current.a, aStarData.navMeshInfo.pointIndexes)); list.AddRange(GetListAStarTriangle(current.b, aStarData.navMeshInfo.pointIndexes)); list.AddRange(GetListAStarTriangle(current.c, aStarData.navMeshInfo.pointIndexes)); //去掉重复的三角形
list = list.Distinct().ToList(); if (list.Contains(aStarData.endPlace))
{
list.Add(aStarData.endAStarTriangle);
} return list;
} /// <summary>
/// 获取顶点对应的三角形列表.
/// </summary>
/// <param name="ponit</param>
/// <param name="map"></param>
/// <returns></returns>
public static List<Triangle> GetListAStarTriangle(Ponit ponit, Dictionary<Ponit, List<Triangle>> pointIndexes)
{
List<Triangle> list = null; if (pointIndexes == null)
{
return list;
} if (pointIndexes.ContainsKey(ponit))
{
list = pointIndexes[ponit];
} return list;
} /// <summary>
/// 设置字典的值.
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <param name="value"></param>
public static void SetDictionaryValue(Dictionary<Triangle, float> data, Triangle key, float value)
{
if (data == null)
{
return;
} if (data.ContainsKey(key))
{
data[key] = value;
}
else
{
data.Add(key, value);
}
} /// <summary>
/// 获取字典的值.
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <returns></returns>
public static float GetDictionaryValue(Dictionary<Triangle, float> data, Triangle key)
{
if (data == null)
{
return ;
} if (!data.ContainsKey(key))
{
data.Add(key, );
}
return data[key];
}
}
}

AStar

我们创建一个Capsule游戏对象 

让他成为我们需要移动的主角

挂上简单的移动代码

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using AStar; public delegate void CharacterMoveCallback(); /// <summary>
/// 角色移动
/// </summary>
public class CharacterMove : MonoBehaviour
{
/// <summary>
/// 目标
/// </summary>
public Vector3 target;
/// <summary>
/// 速度
/// </summary>
public float speed = ;
/// <summary>
/// 目标距离
/// </summary>
public float distance = 0.05f; /// <summary>
/// 移动经过的点
/// </summary>
List<Vector3> points;
/// <summary>
/// 回调
/// </summary>
CharacterMoveCallback callback; private void Awake()
{
target = transform.position;
} public void Move(Ponit vector3, CharacterMoveCallback callback = null)
{
target = Ponit.Convert(vector3);
this.callback = callback;
} public void Move(List<Ponit> points, CharacterMoveCallback callback = null)
{
this.points = new List<Vector3>(); for (int i = ; i < points.Count; i++)
{
this.points.Add(Ponit.Convert(points[i]));
}
this.callback = callback; GetTarget();
} void GetTarget()
{
if (points != null && points.Count >= )
{
target = points[];
points.Remove(points[]); Debug.Log("前进点 :" + target);
}
} void Callback()
{
if (callback != null)
{
callback();
callback = null;
}
} void Update()
{
//当前位置与目标距离小于间距 移动停止
if (Vector3.Distance(target, transform.position) < distance)
{
Callback();
return;
} //获取移动向量;
Vector3 vector = target - transform.position;
vector = vector.normalized; //移动
transform.position += vector * Time.deltaTime * speed; //如果到达目标点则替换下一个目标
if (Vector3.Distance(target, transform.position) < distance)
{
GetTarget();
} }
}

CharacterMove

再挂上一个简单的开始测试代码

using UnityEngine;
using AStar;
using System.Collections.Generic; public class test : MonoBehaviour
{
NavMeshInfo navMeshInfo; void Start()
{
NavMeshLoad navMeshLoad = new NavMeshLoad(); navMeshInfo = navMeshLoad.Load(Application.dataPath + "/AStar/obj/test.obj");
} private void Update()
{
if (Input.GetMouseButtonUp())
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); RaycastHit hit;//
if (Physics.Raycast(ray, out hit))//函数是对射线碰撞的检测
{
Vector3 Point = hit.point;//得到碰撞点的坐标 Debug.Log("开始点: " + transform.position);
Debug.Log("目标点: " + Point);
Debug.Log("目标点对象: " + hit.transform.name); Vector3 start = transform.position;
Vector3 end = Point; NavMeshHit tmpNavMeshHit; if (NavMesh.SamplePosition(start, out tmpNavMeshHit, 5.0f, NavMesh.AllAreas))
{
start = tmpNavMeshHit.position;
} Debug.Log("修改后 开始点: " + start); StartNavigation(start, end, navMeshInfo);
}
}
} public void StartNavigation(Vector3 start, Vector3 end, NavMeshInfo navMeshInfo)
{
if (navMeshInfo == null)
{
return;
} Pathfinding pathfinding = new Pathfinding(); Ponit startPonit = new Ponit(start);
Ponit endPonit = new Ponit(end); pathfinding.Start(startPonit, endPonit, navMeshInfo, (List<Ponit> list) =>
{
CharacterMove controller = GetComponent<CharacterMove>(); controller.Move(list, () =>
{
Debug.Log("寻路结束");
}); });
} }

test

运行 点击地面  就可以看到Capsule寻路自动行走了

工程下载:

链接: https://pan.baidu.com/s/1qY_zUrqIHB6W4K8wC3PxWQ 密码: iipb

unity A*寻路 (三)A*算法的更多相关文章

  1. FPGA加三移位算法:硬件逻辑实现二进制转BCD码

    本文设计方式采用明德扬至简设计法.利用FPGA来完成显示功能不是个很理想的方式,当显示任务比较复杂,要通过各种算法显示波形或者特定图形时,当然要用单片机通过C语言完成这类流程控制复杂,又对时序要求不高 ...

  2. 三目算法、if/else,switch/case运用

    //输入学生的成绩,判断考试是否及格,及格6大于等于0 //第一种写法:三目运算 大多用于单独判断是否满足某个条件 import java.util.Scanner; public class Hel ...

  3. K:找寻数组中第n大的数组元素的三个算法

    相关介绍:  给定一个数组,找出该数组中第n大的元素的值.其中,1<=n<=length.例如,给定一个数组A={2,3,6,5,7,9,8,1,4},当n=1时,返回9.解决该问题的算法 ...

  4. 最短路问题的三种算法&模板

    最短路算法&模板 最短路问题是图论的基础问题.本篇随笔就图论中最短路问题进行剖析,讲解常用的三种最短路算法:Floyd算法.Dijkstra算法及SPFA算法,并给出三种算法的模板.流畅阅读本 ...

  5. 分布式共识算法 (三) Raft算法

    系列目录 分布式共识算法 (一) 背景 分布式共识算法 (二) Paxos算法 分布式共识算法 (三) Raft算法 分布式共识算法 (四) BTF算法 一.引子 1.1 介绍 Raft 是一种为了管 ...

  6. PCL贪婪投影三角化算法

    贪婪投影三角化算法是一种对原始点云进行快速三角化的算法,该算法假设曲面光滑,点云密度变化均匀,不能在三角化的同时对曲面进行平滑和孔洞修复. 方法: (1)将三维点通过法线投影到某一平面 (2)对投影得 ...

  7. c语言求回文数的三种算法的描述

    c语言求回文数的三种算法的描述 题目描述 注意:(这些回文数都没有前导0) 1位的回文数有0,1,2,3,4,5,6,7,8,9 共10个: 2位的回文数有11,22,33,44,55,66,77,8 ...

  8. Java利用DES/3DES/AES这三种算法分别实现对称加密

    转载地址:http://blog.csdn.net/smartbetter/article/details/54017759 有两句话是这么说的: 1)算法和数据结构就是编程的一个重要部分,你若失掉了 ...

  9. unity A*寻路 (二)读取NavMesh数据

    上一章节我们已经看了怎么获得NavMesh数据保存为obj 这一章节我们来读取NavMesh数据 首先我们要定义两个结构体 点 和 三角形 为什么不用unity自带的Vector3呢? 相信你们应该已 ...

随机推荐

  1. 【转】UML的9种图例解析

    UML图中类之间的关系:依赖,泛化,关联,聚合,组合,实现 类与类图 1) 类(Class)封装了数据和行为,是面向对象的重要组成部分,它是具有相同属性.操作.关系的对象集合的总称. 2) 在系统中, ...

  2. 深度剖析PHP序列化和反序列化

    序列化 序列化格式 在PHP中,序列化用于存储或传递 PHP 的值的过程中,同时不丢失其类型和结构. 序列化函数原型如下: string serialize ( mixed $value ) 先看下面 ...

  3. Flume - Kafka日志平台整合

    1. Flume介绍 Flume是Cloudera提供的一个高可用的,高可靠的,分布式的海量日志采集.聚合和传输的系统,Flume支持在日志系统中定制各类数据发送方,用于收集数据:同时,Flume提供 ...

  4. canvas实现将文字变成颗粒

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  5. 面向服务的体系架构 SOA(三) --- Zookeeper API、zkClient API的使用

    zookeeper简单介绍及API使用 1.1 zookeeper简介 zookeeper是一个针对大型分布式系统的可靠的协调系统,提供的功能包括配置维护.名字服务.分布式同步.组服务等.zookee ...

  6. Java生成图片验证码

    在日常我们在登录或者注册的时候,网页上会出现验证码让我们填写,其实利用jdk提供给我们的工具类完全可以模拟出来一个生成验证码图片的功能. package util; import javax.imag ...

  7. 从分布式一致性到共识机制(一)Paxos算法

    从分布式系统的CAP理论出发,关注分布式一致性,以及区块链的共识问题及解决. 区块链首先是一个大规模分布式系统,共识问题本质就是分布式系统的一致性问题,但是又有很大的不同.工程开发中,认为系统中存在故 ...

  8. 连不上虚拟机中的Redis的原因分析、以及虚拟机网络配置

    1. 网络最好是桥接方式.我之前用的是"网络地址转换(NAT)",导致虚拟机里用命令ifconfig得到的ip是10.0.2.15,好奇怪的感觉,然后在真实机上一直连不上.有的说用 ...

  9. Spring MVC的handlermapping之RequestMappingHandlerMapping初始化

    RequestMappingHandlerMapping:这个handlerMapping是基于注解的同样,先上类图: 通过类图可以看到,同样是继承父类 AbstractHandlerMapping来 ...

  10. cocos对lua代码加密

    1.0 cocos luacompile 用法 我用的普通的cocos2d lua,没用quick,quick好像可以对整个资源包括图像和音频都加密,打包成zip.但我没用quick.看了下luaco ...