[Unity插件]A* Pathfinding Project:简易教程(一)

原文链接:http://arongranberg.com/astar/docs/getstarted.php

插件下载地址:http://pan.baidu.com/s/1eROqaB4

题外话:最近想学习一下A*插件,由于在网上没有发现什么比较详细的教程,所以就只能上官网了。这是第一次看这么长的英语文章,翻译得不好,请见谅!


概述:

A*插件的核心脚本就是”astarpath.cs”,所以如果你想使用A*插件进行寻路,那么场景中一定要有一个”astarpath.cs”(并且一个场景仅有一个)。可以通过Component->Pathfinding->Pathfinder添加”astarpath.cs”。

第二重要的脚本就是”seeker.cs”,每一个需要寻路的物体最好要有这个脚本(不是一定要添加,但是有了可以让寻路更加简单)

然后就是一个名叫"SimpleSmoothModifier.cs"的脚本,它可以让路径更加圆滑、简单,它要跟"seeker"脚本一起添加到同一个物体上。


1.创建一个新场景,创建一个plane,位置(0,0,0),缩放(10,10,10)。创建一个新层(edit->project settings->tags and layers),命名为”Ground”,把plane设为”Ground”,创建一些cube作为障碍物,把这些cube设为新的层”Obstacles”。

 

2.创建一个新GameObject,命名为A*,添加"AstarPath"脚本。脚本中最重要的是两个东西是“Graphs”和下方的“Scan”按钮。“Graphs”包含了所有的寻路图,最多可以有16个,但是一般12个已经足够了。其中主要的两个是”Grid Graph”(以格子的方式生成节点)”Navmesh”(在可行走的区域生成mesh)“Scan”按钮用来更新寻路图。

 

3.点击”Grid Graph”,Grid graph会产生一系列的格子,大小为width * height,这个网格可以放在场景中的任何地方,也可以进行旋转。“Node Size”可以设置格子的大小,这里先设为1。注意有一个由5个点组成的正方形图标,点击它的左下方,此时图标那一行前面的文字会变为”Bottom-Left”,设为(-50,-0.1,-50)其中y方向设置为-0.1是为了避免产生浮点错误,因为地面planey向坐标是0,如果寻路图也是y向坐标也为0的话,在进行高度检测的raycast的时候,会产生问题。所以确保寻路图的y要略小于地面的y。为了网格可以适应我们的场景,调整WidthDepth,均为100。(在实际设置中好像有点问题,总之就是让网格跟plane大小适应就是了,可以通过"Scan"进行刷新)



高度检测

4.为了把寻路的node放置到场景中的正确高度,一般向下发射一束射线来进行检测,寻路node会被放置到碰撞点的位置。我们将mask设置为Ground,因为只希望寻路节点与Ground进行检测。如果射线没有发生碰撞,说明检测的物体没有设置为“Ground”,又或者上面的第三点中y设为了0

 


碰撞检测

5.当node被放置好后,它就会被用来检测是否可行走,一般可以使用sphere,capsuleray来进行碰撞检测(这里指的是用Physics.CapsuleCast或者Physics.SphereCast模拟AI对象)Capsule会使用和AI对象一样的半径和高度来进行碰撞。为了让AI对象和障碍物有一些边缘,这里将Capsule的半径设置为2.另外将碰撞检测的layer设置为Obstacles,因为不想让地面成为障碍。点击底部的Scan,我们就可以看到grid Graph的生成了。

 



添加AI

6.创建一个capsule,添加”Character Controller”部件,放到plane上。添加”Seeker”部件,Seeker脚本是一个帮助类的脚本,用来将其他脚本的寻路请求进行处理,它也可以处理Path modifier(一般是对寻路结果进行圆滑处理的脚本)。接下来将会写一个脚本用于寻路,当然你也可以用插件内置的脚本。A* 插件自带了两个AI脚本用于挂接到对象上进行寻路:AIPah可适用于任何类型的寻路图;而RichAI主要适用于NavMesh类型。

 

让物体寻路

7.seek脚本中有一个重要的方法:function StartPath (Vector3 start, Vector3 end, OnPathDelegate callback = null) : Path。参数是开始位置,结束位置,回调函数。其中OnPathDelegate是一个委托,被调用的函数类似于"void SomeFunction (Path p)"

脚本如下:

using UnityEngine;
using System.Collections;
//Note this line, if it is left out, the script won't know that the class 'Path' exists and it will throw compiler errors
//This line should always be present at the top of scripts which use pathfinding
using Pathfinding;
public class AstarAI : MonoBehaviour
{
    public Transform target;
    public void Start()
    {
        //Get a reference to the Seeker component we added earlier
        Seeker seeker = GetComponent<Seeker>();

        //Start a new path to the targetPosition, return the result to the OnPathComplete function
        seeker.StartPath(transform.position, target.position, OnPathComplete);
    }

    public void OnPathComplete(Path p)
    {
        Debug.Log("Yay, we got a path back. Did it have an error? " + p.error);
    }
}

把这个脚本添加到要寻路的物体上,给target赋值,点击"Play"后,你应该会看到一条绿色的线,这就是寻路的路径了,此时物体还不会动。

如果没有看到绿线,检查一下"Seek"的脚本的"Show Gizmos"有无勾上。又或者可能是unity版本的原因,使Gizmos画出来的线被隐藏在plane下面了。



可以看到画出来的线很不圆滑,后面会进行美化的。

设置回调的方式也可以是这样:

//OnPathComplete will be called every time a path is returned to this seeker
seeker.pathCallback += OnPathComplete;
//So now we can omit the callback parameter
seeker.StartPath (transform.position,targetPosition); 


注意上面的方法添加回调后,当你要移除或者摧毁该脚本,要:

 public void OnDisable () {
    seeker.pathCallback -= OnPathComplete;
}

回调后我们可以通过Path p得到计算后的路径,我们可以用它做什么呢?

计算后的路径有两个重要的list。

1.Path.vectorPath是一个Vector3的list,保存着每一个路径点的位置。

2.Path.path是一个node的list,保存着每一个路径点的node。


然后拓展一下上面的脚本:

using UnityEngine;
using System.Collections;
//Note this line, if it is left out, the script won't know that the class 'Path' exists and it will throw compiler errors
//This line should always be present at the top of scripts which use pathfinding
using Pathfinding;
public class AstarAI : MonoBehaviour
{
    //The point to move to
    public Transform target;

    private Seeker seeker;
    private CharacterController controller;

    //The calculated path
    public Path path;

    //The AI's speed per second
    public float speed = 100;

    //The max distance from the AI to a waypoint for it to continue to the next waypoint
    public float nextWaypointDistance = 3;

    //The waypoint we are currently moving towards
    private int currentWaypoint = 0;

    public void Start()
    {
        seeker = GetComponent<Seeker>();
        controller = GetComponent<CharacterController>();

        //Start a new path to the targetPosition, return the result to the OnPathComplete function
        seeker.StartPath(transform.position, target.position, OnPathComplete);
    }

    public void OnPathComplete(Path p)
    {
        Debug.Log("Yay, we got a path back. Did it have an error? " + p.error);
        if (!p.error)
        {
            path = p;
            //Reset the waypoint counter
            currentWaypoint = 0;
        }
    }

    public void FixedUpdate()
    {
        if (path == null)
        {
            //We have no path to move after yet
            return;
        }

        if (currentWaypoint >= path.vectorPath.Count)
        {
            Debug.Log("End Of Path Reached");
            return;
        }

        //Direction to the next waypoint
        Vector3 dir = (path.vectorPath[currentWaypoint] - transform.position).normalized;
        dir *= speed * Time.fixedDeltaTime;
        controller.SimpleMove(dir);

        //Check if we are close enough to the next waypoint
        //If we are, proceed to follow the next waypoint
        if (Vector3.Distance(transform.position, path.vectorPath[currentWaypoint]) < nextWaypointDistance)
        {
            currentWaypoint++;
            return;
        }
    }
}


然后运行游戏,物体就会移动了。注意路径点不是连续的,当物体离下一个路径点小于nextWaypointDistance时才会继续前进。最后物体会停在离目标前的一段距离,这是因为对于终点,我们需要进行特殊处理,但脚本还没有进行处理。


路径平滑

8.这时要用到内置的脚本"Path Modifiers",要加在有"seeker"脚本的物体上。(不过好像找不到这个名字的脚本,也可以通过Components–>Pathfinding–>Modifiers–>Simple Smooth添加脚本)。平滑的原理就是将一段段的小路径继续细分,让路径点之间的距离缩小。这里先将Max Segment Length设为1,Iterations设为5,Strength设为0.25。运行之后会发现绿线更加平滑了。




最后:因为使用上面的脚本进行寻路并不完美,而且每一次都要写脚本的话会很麻烦,所以直接为要寻路的物体添加"AIPath"脚本,赋值target,效果会更好!上面的脚本就当理解一下内部就好了!

  • 12
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
烘培桥是指将场景中的网格图(NavMesh)生成并保存在磁盘上,以便在运行时进行快速的路径计算。要在Unity中使用A*路径查找算法,需要使用Unity的NavMesh系统,并使用A*寻路插件来执行路径计算。 以下是在Unity中使用A*路径查找算法的步骤: 1. 安装A*寻路插件:从Unity Asset Store中下载并导入A* Pathfinding Project Pro插件。 2. 创建场景:在Unity中创建一个场景,并添加游戏对象和地形。 3. 创建NavMesh:使用Unity的NavMesh系统来创建场景的NavMesh。在场景中选择菜单栏的“Window”->“Navigation”,打开“Navigation”窗口,然后单击“Bake”按钮来烘焙NavMesh。 4. 添加A*路径查找组件:在场景中选择要使用A*路径查找算法的游戏对象,然后右键单击并选择“Add Component”->“A* Pathfinding”->“A* Pathfinding Component”。这将添加一个A*路径查找组件到游戏对象上。 5. 设置路径查找组件:在A*路径查找组件的属性窗口中,设置起点和终点,以及其他路径查找参数,例如搜索半径、移动速度和路径平滑等。 6. 执行路径查找:在游戏运行时,调用A*路径查找组件的路径查找函数来执行路径查找。例如,在脚本中调用“GetComponent<AstarPath>().Scan()”函数来执行路径查找。 7. 显示路径:在游戏运行时,使用A*路径查找组件的路径可视化功能来显示路径。例如,在脚本中调用“GetComponent<AstarPath>().DrawPath()”函数来显示路径。 以上是在Unity中使用A*路径查找算法的基本步骤。通过使用A*寻路插件Unity的NavMesh系统,可以轻松地实现高效的路径查找功能,从而为游戏开发带来更好的用户体验。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值