unity A*寻路 (三)A*算法
这里我就不解释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*算法的更多相关文章
- FPGA加三移位算法:硬件逻辑实现二进制转BCD码
本文设计方式采用明德扬至简设计法.利用FPGA来完成显示功能不是个很理想的方式,当显示任务比较复杂,要通过各种算法显示波形或者特定图形时,当然要用单片机通过C语言完成这类流程控制复杂,又对时序要求不高 ...
- 三目算法、if/else,switch/case运用
//输入学生的成绩,判断考试是否及格,及格6大于等于0 //第一种写法:三目运算 大多用于单独判断是否满足某个条件 import java.util.Scanner; public class Hel ...
- K:找寻数组中第n大的数组元素的三个算法
相关介绍: 给定一个数组,找出该数组中第n大的元素的值.其中,1<=n<=length.例如,给定一个数组A={2,3,6,5,7,9,8,1,4},当n=1时,返回9.解决该问题的算法 ...
- 最短路问题的三种算法&模板
最短路算法&模板 最短路问题是图论的基础问题.本篇随笔就图论中最短路问题进行剖析,讲解常用的三种最短路算法:Floyd算法.Dijkstra算法及SPFA算法,并给出三种算法的模板.流畅阅读本 ...
- 分布式共识算法 (三) Raft算法
系列目录 分布式共识算法 (一) 背景 分布式共识算法 (二) Paxos算法 分布式共识算法 (三) Raft算法 分布式共识算法 (四) BTF算法 一.引子 1.1 介绍 Raft 是一种为了管 ...
- PCL贪婪投影三角化算法
贪婪投影三角化算法是一种对原始点云进行快速三角化的算法,该算法假设曲面光滑,点云密度变化均匀,不能在三角化的同时对曲面进行平滑和孔洞修复. 方法: (1)将三维点通过法线投影到某一平面 (2)对投影得 ...
- c语言求回文数的三种算法的描述
c语言求回文数的三种算法的描述 题目描述 注意:(这些回文数都没有前导0) 1位的回文数有0,1,2,3,4,5,6,7,8,9 共10个: 2位的回文数有11,22,33,44,55,66,77,8 ...
- Java利用DES/3DES/AES这三种算法分别实现对称加密
转载地址:http://blog.csdn.net/smartbetter/article/details/54017759 有两句话是这么说的: 1)算法和数据结构就是编程的一个重要部分,你若失掉了 ...
- unity A*寻路 (二)读取NavMesh数据
上一章节我们已经看了怎么获得NavMesh数据保存为obj 这一章节我们来读取NavMesh数据 首先我们要定义两个结构体 点 和 三角形 为什么不用unity自带的Vector3呢? 相信你们应该已 ...
随机推荐
- Web项目生成详解
action 与用户控制层相关内容,来自用户的请求和页面跳转: dao 数据库进行增删改查操作,接口定义其中: dao.impl 将上述接口进行实现 domain 数据表都映射成java中的类,实现数 ...
- Ubuntu14.04安装pycharm用于Python开发环境部署,并且支持pycharm使用中文输入
一.目标 实现在Linux下用pycharm调试工具/Python开发 Linux使用vi/vim工具写Python,缺点:调试不方便,无代码提示.跳转等诸多功能. Windows使用idle/pyc ...
- Jersey+mybatis实现web项目第一篇
---恢复内容开始--- Jesery第一篇:实现Jesery前后台页面交互,Form表单提交,后台控制页面跳转 该项目中有实现的功能: Mybatis实现后台数据持久化 Jersey页面数据提交 后 ...
- 修改WordPress后台登录地址,提高安全性
大家都知道,WordPress默认的后台登陆地址是http://[你的域名]/wp-admin,今天就来讲讲怎么修改WordPress后台登录地址,首先要知道为什么要修改WordPress后台登录地址 ...
- 关于JDK和eclipse的安装和汉化
参考网址:http://jingyan.baidu.com/article/f96699bb8b38e0894e3c1bef.html http://titanseason.iteye.com/blo ...
- windows下大文件SQL导入问题
今天遇到了一个比较棘手的问题,SQL文件太大,导入数据库时太过于麻烦,超过1G以后nodpad.sublime等编辑器都打不开,这就有了一个比较尴尬的问题. 因为是本地测试所以环境是windows,最 ...
- c语言基础知识
进制: l 碾(nian)除法:十进制转为几进制则除几,从下往上看余数 (十进制转二进制,十进制转八进制,十进制转十六进制) l 几进制转化为十进制:直接乘以几的次方数: l binary: ...
- jmeter--简单的接口测试(GET/POST)
最近在学习接口测试,本文就简单的谈一谈对接口相关知识的理解. 一.什么是接口? 程序接口:由一套陈述.功能.选项.其它表达程序结构的形式.以及程序师使用的程序或者程序语言提供的数据组成(百度百科定义) ...
- windows下安装mongoDB以及配置启动
1.下载MongoDB的windows版本,有32位和64位版本,根据系统情况下载,下载地址:http://www.mongodb.org/downloads 2.解压缩至D:/mongodb即可 3 ...
- The based of tuning
调优目的: 1. 提高资源利用率 2. 找出性能瓶颈并缓解 3. 通过性能管理实现合理的资源分配,提升硬件性价比 调优分层及效率问题: 业务级调优 eg:1)网站使用的Apache—>业 ...