如何使用A*插件实现移动以及网格的动态生成

在学习Unity Behavior插件和AStarPathFinding(即A*)插件的时候,遇到了一个小的问题。因为系统自带的Nevigation组件地形需要事先烘培,没办法对随机生成的地图和障碍进行动态Bake,在尝试了很久之后,还是决定放弃自带的,而把眼光瞄上了A*插件。从网上下载了一个学习使用。在网上参考了很多大神的学习笔记,然后开始了自己的尝试。
首先简单讲一下A*使用(网上已经很多资源,不多废话):我们先打开项目,导入A*插件,在项目中加一个Plane,将位置reset为(0,0,0)不妨把Scale设置为10,1,10,顺便可以为它设置一个layer,如Ground;再添加一个空物体,改名为A*,在Project栏搜索AstarPath脚本,给这个空物体挂上。 点击Add New Graph,这里我选择了GridGraph,然后我们来修改网格信息。如下:Width表示宽的这个方向有多少Node,Depth表示长的这个方向有多少个Node,Nodesize则表示每一个Node占了多大的面积,这里刚才设置地板Scale为10乘10,也就是长宽都是100米,所以我们网格大小设置为1,长宽都设置100个节点。往下把Center设置为(0,0,0),Connections这里是设置网格之间怎么连通的,可以选择Four 或者Six 或者 Eight,这个牵扯到人物寻路可以怎么从一个网格到另一个网格,我这里选择Eight。
这里写图片描述

再往下,我们在Collision testing中选择一些层作为障碍物,比如Wall等。因为A*是通过层来区别障碍物的。下面是表示高度的一个 参考平面,用来做高度检测,有时候我们需要多层的网格。(类似于海拔的基准平面吧,不知道是不是,只是感觉),我们这里选择Ground。这时候我们可以不用去管其他的了,直接拉到最底下点击Scan按钮,或者是按快捷键Ctrl+Alt+S键生成网格(也是更新网格),我们可以看到平面上覆盖了一层网格了,如果看不到,把AstarPath下面的Show Graphs勾选上。

这里写图片描述

好啦,我们初始工作已经做好了,接下来开始我们的正事,让Player动起来。这里先给Player加上Seeker组件和CharacterController组件(我是通过这个实现移动的),来编写我们的第一段代码吧!
新建一个C#脚本AStar.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Pathfinding;
public class AStar : MonoBehaviour {
  //  public Transform target;
    private Seeker seeker;
    private CharacterController characterController;
    public Path path;
    private float speed = 100;
    private float angularSpeed = 10;
    private float nextWaypointDistance = 1.5f;
    private int currentWaypoint = 0;
    private AstarPath aStarPath;

    void Start () {
        aStarPath = GameObject.Find("A*").GetComponent<AstarPath>();
        seeker = GetComponent<Seeker>();
        characterController = GetComponent<CharacterController>();
        seeker.pathCallback += OnPathComplete; //寻路的一个回调
    }
    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            RaycastHit hit;
            if (!Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out hit, 100))
            {
                return;
            }
            if (!hit.transform)
            {
                return;
            }           
            seeker.StartPath(transform.position, hit.point, OnPathComplete);    //寻路并移动到鼠标点击位置
        }
        if (Input.GetMouseButtonDown(1))    //按鼠标右键,更新网格,实现了动态障碍物网格生成 嘻嘻
        {
            aStarPath.Scan();
        }
    }

    public void StarPath(Transform target)
    {
        seeker = GetComponent<Seeker>();
        characterController = GetComponent<CharacterController>();
        seeker.pathCallback += OnPathComplete; //寻路的一个回调
        seeker.StartPath(transform.position, target.position, OnPathComplete);
    }
    private void FixedUpdate()
    {
        Move();
    }
    public void Move()
    {
        if (path == null)   //如果路径为空,直接返回
        {
            return;
        }
        if (currentWaypoint >= path.vectorPath.Count)
        {
            return;
        }
        if (characterController != null && characterController.enabled == true)
        {
            Vector3 dir = (path.vectorPath[currentWaypoint] - transform.position).normalized;
            dir *= speed * Time.deltaTime;
            characterController.SimpleMove(dir);
            Quaternion targetRotation = Quaternion.LookRotation(dir);
            transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.fixedDeltaTime * angularSpeed);
            if (Vector3.Distance(transform.position, path.vectorPath[currentWaypoint]) < nextWaypointDistance)
            {
                currentWaypoint++;
                return;
            }
        }
    }
    public void OnPathComplete(Path p)
    {
        if (!p.error)
        {
            path = p;   //如果不发生错误,把p传给path
            currentWaypoint = 0;
        }
    }
    private void OnDisable()
    {
        seeker.pathCallback -= OnPathComplete;
    }
    //提供get set方法供其他脚本使用
    #region GetSet      
    public float Speed
    {
        get { return speed; }
        set { speed = value; }
    }
    public float AngularSpeed
    {
        get { return angularSpeed; }
        set { angularSpeed = value; }
    }
    public float ArriveDistance
    {
        get { return nextWaypointDistance; }
        set { nextWaypointDistance = value; }
    }
    #endregion

}

运行后点击地面,Player便会寻路,并移动到点击位置,这时候也可以加一些障碍物,按鼠标右键可以在障碍物周围设置障碍网格,通过Scan这个方法可以更新网格信息,实现了网格动态更新。注意:

seeker.StartPath(transform.position, hit.point, OnPathComplete);

这个不能再UpDate中一直执行,否则不会移动。Move函数不做解释,也是参考了别人的一些做法。下一篇博文我将把这个寻路与行为树结合起来,实现一个简单的巡逻任务。

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
烘培桥是指将场景中的网格图(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系统,可以轻松地实现高效的路径查找功能,从而为游戏开发带来更好的用户体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值