unity3d 自动寻路算法怎么上台阶

Unity3D(1)
添加新物体,命名为Player,添加组件Nav Mesh Agent.同时添加Navigation,将
需要进行自动寻路的地方进行烘焙。创建脚本Follow:
using UnityE
using System.C
public class Follow : MonoBehaviour
&&& public T
&&& private NavMeshA
&&& void Start()
&&&&&&& agent = GetComponent&NavMeshAgent&();
&&& // Update is called once per frame
&&& void Update()
&&&&&&& if (target != null)
&&&&&&&&&&& agent.destination = target.
创建一个新物体Target,拖入脚本的变量中,可使Player自动找到Target。无论
Player如何变化,都可以找到。
新建Cube添加Nav Mesh Obstacle组件,将所有的障碍物都进行烘焙。此时Player
可绕过障碍物找到Target.
当Target突然移动时,为了让Player直接跳下来可设置Bake中的Drop Height的值
为4,Object中的选项都勾选上。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:95081次
积分:1401
积分:1401
排名:千里之外
原创:57篇
评论:31条
/GeniusVJR
/people/FrancisTao/activities
阅读:1961
(15)(7)(14)(5)(6)(3)(6)(1)(7)(2)使用Unity3D 自主实战开发的赛车游戏实例,关键点记录 (六)之自动寻路及优化 - 博客频道 - CSDN.NET
narutojzm1的博客
分类:游戏编程
赛车游戏的敌人赛车自动寻路一般有两种方式,一种是路点寻路,另外一种就是使用Unity自带组件NavMeshAgent进行寻路了,我介绍的是后者,另外后者在水平面上的汽车寻路导航还不错,但是一旦有Y方向的爬坡、下坡等,汽车就会因为角度依然保持水平显得很不自然,并且轮胎也不会旋转,我对此进行了优化
这个和NavMesh是一对,用来设置寻路的游戏对象。关于属性,我不再一一介绍,我就距我的设置来说一下:
1.AgentSize
如下图中,那个圆柱形就是NavMeshAgent了,其中AgentSize调整到更好适合车辆就可以了;
2.Stopping Distance
我将Stopping Distance设置为0,是因为,我每次都会将寻路目标设置为下一个道路监测点,如果Stopping Distance设置为大于0的话,就会看到车辆会不停地减速加速减速加速,不够连贯;
这个我最后查出来的它的尺寸是M/S,所以我设置的它的速度是47km/h,当然我的游戏赛道比较难跑,设置这个值比较合适。
4.Auto Traverse Off Mesh Link
这个指的是是否自动通过OffMeshLink,我这里没有什么特殊需求,不需要有些OffMeshLink需要设置才能通过,自然是自动通过最好了。
5.Obstacle Avoidance Quality
然后属性Obstacle Avoidance Quality是值的躲避障碍物的质量,对于我的游戏来说,障碍物只有一种,那就是封路用的,如下图中的导流牌,这个导流牌就添加了组件Nav Mesh Obstacle,它的作用就是动态的用作障碍物,如果隐藏掉这个组件或者直接隐藏掉组件所在的对象,障碍物效果就没有了,图中的道路就又通了
NavMesh就是NavMeshAgent就来赖以前行的寻路网格,将自己需要作为寻路路径的那部分游戏对象设置为NavMesh Static,然后再Navigation中进行Bake烘焙即可。
我将所有的道路到设置为了NavMesh Static,然后烘焙后蓝色区域就覆盖了整个道路。
需要注意的是道路有可能有不平整的地方,需要自己将道路检查一遍,如果哪些地方有断裂,需要铺平道路后重新烘焙
上图中也需要设置Agent信息,作用就是用来根据代理进行烘焙,因为代理Radius Height的不同都会导致烘焙结果的不同。
比如你将Agent Radius设置得较大,路面上的蓝色区域就会越窄,因为NavMesh会考虑给路两边留够距离。
然后Max Slope的设置就得考虑车辆最高爬坡角度了。
接下来就是对断裂地带实在没办法连接的地方进行处理了
四.Off Mesh Link
这个是专门对断裂地带进行连接的,如下图
由于坡度过大,无法贯通,于是使用Off Mesh Link。
1.首先在自动汽车对象上添加组件Off Mesh Link。
2.然后分别点击左边需要连接的木板和右边需要连接的木板,点击Navigation,选择Object选项卡,会出现Generate OffMeshLinks选项打钩,重新Bake,如下图
3.分别将左右木板对象拖曳到自动汽车的OffMeshLink组件的Start和End属性上,这样在两个木板间就会出现一个弧形的桥,连接两端。这样道路就导通了,车辆会飞跃过去。
直接设置自动寻路汽车的寻路目标是终点显然是不合适的。想要寻路汽车可以规规矩矩按照既定的路线前行,需要不断地更新目标点,到前方一个较近的位置。
我就使用的是当汽车碰到第一个道路监测点后,设置目标为下一个道路监测点,这样汽车就会不断地往前行进了。
注:我在开发时遇到一个问题,就是汽车到某个点后停止不动了。最后发现原因是,由于汽车身上的NavMeshAgent比较大,导致先接触到下一个道路监测点,这个时候,道路监测点还没有碰撞到汽车,导致没能再去设置下一个寻路目标,解决办法就是把车身上的Agent设置的较小一些,车的碰撞体靠前一些,这样每次都是先检测到碰撞,而还没有到达寻路目的地。
6.修正汽车上下坡时车辆未倾斜的问题
我发现使用NavMeshAgent给汽车做寻路导航,缺点就是汽车只会在水平面上转弯,上坡下坡的时候还是水平的,不会沿着坡道做倾斜,我想原因是因为这个Agent也可以给人用的缘故吧,因为人上下坡时身体不会沿着坡道做倾斜。
刚开始我试图直接修改汽车游戏对象的Rotation,发现一直受Agent的干扰。最后想到的解决办法就是:
由于汽车车体/轮胎其实都是汽车对象的子对象,我直接修改子对象的角度就好了。并不会受到Agent的干扰。
我的做法是每次设置自动寻路汽车的下一个寻路目标时,顺便设置汽车角度,如下:
private void SetEnemyCarDestionation(int index)
if (ConfigurationManager.Instance.CurrentGameModel == ConfigurationManager.GameModel.RacingModel) {
Vector3 vec = GetTheEnemyPlayerNextCollider(index).transform.
Transform currentEnemyTrans = _enemyPlayers[index].
Quaternion rotation = Quaternion.LookRotation(vec - currentEnemyTrans.position);
_enemyPlayersManager[index].TurnCarDirection(rotation);
7.修改自动寻路汽车,车轮不转动的问题
由于自动寻路汽车,并不是 物理意义上的汽车,WheelCollider并没有用。我看一个教程上使用的WayPoint方法,是可以实现物理意义上的寻路的。
所以我想给自动寻路汽车加上一个比较看起来真实的转动轮胎。
也就是说,随着汽车速度的加快,轮胎转动变快,速度变慢,轮胎转动变慢。
所以需要从速度转换出当前每秒转多少度:
设当前汽车速度为N m/s,
轮胎半径为R m
则汽车转速为 N / (2 * R * π)
汽车轮胎每秒转N / (2*R*π) * 360°
代码如下:
void FixedUpdate()
_angularSpeed = (_thisCarNavMesh.velocity.magnitude / _wheelCircle) * 360 * 0.2f
for (int i = 0
Wheels[i].Rotate(Vector3.right, _angularSpeed * Time.fixedDeltaTime)
其中参数0.2f,是我根据效果写的修正参数,不然轮胎转的角度太大,导致效果不好。
上面这个办法我目前实验的效果还不错,但是不知道其他人怎么认为,肯定还有很多别的好办法。
narutojzm1
排名:千里之外
(3)(6)(4)(7)(49)(14)(4)领导让做个动态寻路的效果,而不是简单的自动寻路。
意思是,首先Monster 检测hero的位置先自动寻路,如果hero位置不改变,说明刚才的寻路路径是正确的;如果hero位置改变,但是改变后的位置依然在旧的寻路路径上,也说明旧的寻路路径有用;但是如果hero的位置改变,而且已经不在刚才的寻路路径上,说明需要重新寻路。
ok,说清楚了效果,关键是如果得到旧的寻路路径,只要再遍历一下就好了。
问了一些群里的大神说,这是动态寻路,用一个插件,我给链接大家可以自己研究,
/club/forum.php?mod=viewthread&tid=328657&extra=page%3D%257Bprevpage%257D&page=3
不过,实际上我们自己也可以做。
我上一个Nav教程中写了很多关于NavMeshPath的属性,是别人翻译过来的,但是还是不全,需要自己去读原API,给链接
/ScriptReference/30_search.html?q=NavMeshAgent
ok,你会找到一个
它就是,自动寻路的路径。打开之后,看到它返回一个NavMeshPath类型的路径。再看NavMeshPath类
有个corners属性,再点开,人家给了个例子,是求自动寻路的路径长度
using UnityE
using System.C
public class ExampleClass : MonoBehaviour {
float PathLength(NavMeshPath path) {
if (path.corners.Length & 2)
Vector3 previousCorner = path.corners[0];
float lengthSoFar = 0.0F;
int i = 1;
while (i & path.corners.Length) {
Vector3 currentCorner = path.corners[i];
lengthSoFar += Vector3.Distance(previousCorner, currentCorner);
previousCorner = currentC
return lengthSoF
写到这,大家旧明白了,corners是一个数组,记录了路径上的几个关键的点(注意,路径不是线,是几个关键点构成,线段是由点构成的嘛)
ok。我稍加改进,在自己的脚本中,打印一下路径
using System.C
public class MonsterRun : MonoBehaviour {
private NavMeshA
private GameO
// Use this for initialization
void Start () {
agent = GetComponent&NavMeshAgent& ();
hero = GameObject.Find (&Hero&);
// Update is called once per frame
void Update () {
//Debug.Log (&Monster find hero's point :& + hero.transform.position.x + & & + hero.transform.position.z);
Vector3 vector=new Vector3 (hero.transform.position.x-1, transform.position.y, hero.transform.position.z-1);
//Vector3 vector = hero.transform.
transform.LookAt (vector);
agent.SetDestination(vector);
NavMeshPath path = agent.
Debug.Log (vector+& &+path.corners.Length+& &+path.status);
for (int i=0; i&path.corners.L i++) {
Debug.Log(i+&= &+path.corners[i]);
其中(29,1.2,29)是目标点,它画了8个点,8个点,大家可以看到,依次向目标点靠近。
OK了,最核心的一步:拿到路径已经做完了,下一步是,判断是否更新。
(ps:待会继续,我现在才理解到这!)Unity3D(15)
学了一段时间的寻路,在网上也学了挺多算法,今天整理了一下,使用到Unity的3D界面中用于寻路,首先是简单的寻路算法,以下是地图:
地图数组:
using UnityE
using System.C
public static class MapsArray {
public static int[,] MazeItem = new int[15, 10]
//初始化迷宫
{1,1,1,1,1,1,1,1,1,1},
{1,0,1,1,1,0,0,0,1,1},
{1,0,0,1,1,0,1,0,1,1},
{1,0,0,0,0,0,1,0,1,1},
{1,1,0,1,0,1,1,0,1,1},
{1,1,0,1,0,0,0,0,1,1},
{1,0,0,0,1,1,1,0,1,1},
{1,1,0,0,0,0,0,0,1,1},
{1,1,0,1,1,1,0,0,0,1},
{1,1,0,0,1,1,1,0,1,1},
{1,1,1,0,0,0,0,0,1,1},
{1,1,1,1,0,0,1,0,1,1},
{1,0,0,0,0,1,1,0,0,1},
{1,0,1,1,1,0,1,1,0,1},
{1,1,1,1,1,1,1,1,1,1}
然后是简单寻路的代码:
using UnityE
using System.C
using System.Collections.G
public class TestPathing : MonoBehaviour {
private int[,] MazeI
//初始化迷宫
private GameO
private List&Vector3&
private Vector3 target = Vector3.
private float speed = 4;
// npc移动速度
private int n = 0;
// 当前已经移动的路点
private const int xStart = 1;
private const int yStart = 1;
private const int xEnd = 8;
private const int yEnd = 8;
void Start () {
MazeItem = MapsArray.MazeI
// 初始化迷宫数组
path = new List&Vector3& ();
StartCoroutine (CreateMap());
void Update()
if (target != Vector3.zero)
if (path.Count & 0)
npc.transform.position = Vector3.MoveTowards(npc.transform.position, target, Time.deltaTime * speed);
if (npc.transform.position == target)
target = GetTarget();
// 创建地图
IEnumerator CreateMap () {
// 地图全局
GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
for (int i = 0; i & MazeItem.GetLength(0); i++) {
for (int j = 0; j & MazeItem.GetLength(1); j++) {
if(MazeItem[i, j] == 1) {
Instantiate(cube, new Vector3(i, j, 0), Quaternion.identity);
// 起始点标记
GameObject start = Instantiate(cube, new Vector3(xStart, yStart, 0), Quaternion.identity) as GameO
start.transform.localScale = Vector3.one * 0.3f;
start.renderer.material.color = Color.
GameObject end = Instantiate(cube, new Vector3(xEnd, yEnd, 0), Quaternion.identity) as GameO
end.transform.localScale = Vector3.one * 0.3f;
end.renderer.material.color = Color.
yield return new WaitForEndOfFrame();
StartCoroutine(CreateNPC());
// 创建NPC
IEnumerator CreateNPC()
GameObject npc_Prefab = GameObject.CreatePrimitive(PrimitiveType.Sphere);
yield return npc_P
if (MazeItem[1, 1] == 0)
npc = Instantiate(npc_Prefab, new Vector3(1, 1, 0), Quaternion.identity) as GameO
npc.renderer.material.color = Color.
target = npc.transform.
// 设置初始点
yield return new WaitForEndOfFrame();
StartCoroutine(Pathing());
// 开始寻路
IEnumerator Pathing() {
if (GoPathing(xStart, yStart, xEnd, yEnd))
print(&有路!!!&);
print(&没路!!!&);
yield return new WaitForEndOfFrame();
bool GoPathing(int startX, int startY, int endX, int endY)
if (startX & 0 || startX &= MazeItem.GetLength(0) || startY & 0 || startY &= MazeItem.GetLength(1) || MazeItem[startX, startY] == 1)
MazeItem[startX, startY] = 1;// 防止重复走
if ((startX == endX && startY == endY) ||
GoPathing(startX - 1, startY, endX, endY) || GoPathing(startX + 1, startY, endX, endY) ||
GoPathing(startX, startY - 1, endX, endY) || GoPathing(startX, startY + 1, endX, endY))
// 存储路径点
path.Add(new Vector3(startX, startY, 0));
print(&X:& + startX + &Y:& + startY);
// 获取路径
Vector3 GetTarget()
Vector3 point = npc.transform.
if (path.Count & 0 && n & path.Count)
point = path[path.Count - n - 1];
为了不让整个博客界面太长,请看下一篇《Unity3D之迷宫寻路_A*最短路径寻路》
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:23724次
排名:千里之外
原创:26篇
评论:10条
(1)(1)(2)(4)(6)(1)(1)(2)(1)(1)(1)(4)(1)(5)The page is temporarily unavailable
nginx error!
The page you are looking for is temporarily unavailable.
Please try again later.
Website Administrator
Something has triggered an error on your
This is the default error page for
nginx that is distributed with
It is located
/usr/share/nginx/html/50x.html
You should customize this error page for your own
site or edit the error_page directive in
the nginx configuration file
/etc/nginx/nginx.conf.

我要回帖

更多关于 unity3d 小地图寻路 的文章

 

随机推荐