广度优先搜索算法在Unity网格地图中实现最短路径

广度优先搜索算法在Unity网格地图中实现最短路径

内容学习取自于B站BeaverJoeUP主

最终效果展示图 鼠标点击方块 然后球向那个方块移动
效果展示图
方块的设置 以及位置点 都在上述视频中有展示
大体是分为三个脚本

  1. WayPoint 这是挂载在每个方块上的
  2. PathFinding 这是负责寻找最佳路径的类
  3. EnemyMovement 球挂载的脚本 负责根据寻找到的最佳路径移动至目标点

WayPoint

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;

public class WayPoint : MonoBehaviour
{  
    EnemyMovement enm;
    public   WayPoint WayPointParent;//储存找到这个点的父级
    public bool IsSerach=false;
    public TMP_Text tex;
    // Start is called before the first frame update
    void Start()
    {
        tex = transform.GetChild(0).GetChild(0).GetComponent<TMP_Text>();
        enm = FindObjectOfType<EnemyMovement>();
        // Debug.Log(gameObject.name + ":" + GetPosition());
        tex.text = GetPosition().ToString();
        tex.overflowMode = TextOverflowModes.Overflow;
        tex.enableWordWrapping = false;
        tex.fontSize = 24;
        
    }

    public Vector2Int GetPosition()//获取这个点的位置  将自身左边转换成位置坐标
    {
        return new Vector2Int(Mathf.RoundToInt(transform.localPosition.z/1.5f), Mathf.RoundToInt(transform.localPosition.x / 1.5f));
    }


    private void OnMouseDown()
    {
        PathFinding pf = FindObjectOfType<PathFinding>();
        pf.EndPoint = gameObject;
        pf.isRunning = true;
        enm.OnStop();
        enm.Onstart();
    }




}

PathFinding

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PathFinding : MonoBehaviour
{
    [SerializeField] private GameObject startPoint, endPoint;//记录起始点和目标点
    Queue<WayPoint> queue = new Queue<WayPoint>();//队列 用于存放每次检索到的点
   public  bool isRunning = true;//用于找到最佳路径后取消寻找

    WayPoint tempPoint;
    public List<WayPoint> waylist;//获得所有路径点

    public GameObject EndPoint
    {
        get {

            return endPoint;

        }
        set { endPoint = value; }

    }
    public GameObject StartPoint
    {
        get
        {

            return startPoint;

        }
        set { startPoint = value; }

    }

    private void Start()
    {
        LoadAllWayPoints();//获取所有路径点
        startPoint.GetComponent<MeshRenderer>().material.color = new Color(0, 1, 0, 1);
        endPoint.GetComponent<MeshRenderer>().material.color = new Color(1, 0, 0, 1);
        //  ExploreAround();
        
    }
    public Dictionary<Vector2Int, WayPoint> waypoint = new Dictionary<Vector2Int, WayPoint>();//存放场景瓦片,通过瓦片位置标记每一个瓦片
    private Vector2Int[] directions =
        {
           Vector2Int.up,
           Vector2Int.right,
           Vector2Int.down,
           Vector2Int.left
        };
    private void ExploreAround()
    {   if (!isRunning)
            return;
        foreach (var item in directions)
        {

           // Debug.Log("Exploring" +(tempPoint.GetPosition() + item));
            if (!waypoint.ContainsKey(tempPoint.GetPosition() + item))
               continue;
            if (waypoint[tempPoint.GetPosition() + item].IsSerach == true)
                continue;
         // waypoint[tempPoint.GetPosition() + item].GetComponent<MeshRenderer>().material.color = new Color(0, 0, 1, 1);
            var tempWayPoint = waypoint[tempPoint.GetPosition() + item];
            tempWayPoint.IsSerach = true;
            tempWayPoint.WayPointParent = tempPoint;
          queue.Enqueue(tempWayPoint);
        }
    }
    //将场景中的瓦片,存放在字典wayPointDict中,在游戏一开始时
    private void LoadAllWayPoints()
    {
        var wayPoints = FindObjectsOfType<WayPoint>();
        foreach (var item in wayPoints)
        {
            var tempWayPoint = item.GetPosition();
            if (waypoint.ContainsKey(tempWayPoint))
            {
                Debug.Log("skip overlap block" + item);
            }
            else
            {
                waypoint.Add(item.GetPosition(), item);
            }
        }
    }
    // 判断当前点是否为最终点
    public void BFS()
    {

        for (int i = 0; i < waylist.Count; i++)
        {
            waylist[i].GetComponent<MeshRenderer>().material.color = new Color(1, 1, 1, 1);
        }

        startPoint.GetComponent<MeshRenderer>().material.color = new Color(0, 1, 0, 1);
        endPoint.GetComponent<MeshRenderer>().material.color = new Color(1, 0, 0, 1);
        queue.Clear();
        queue.Enqueue(startPoint.GetComponent<WayPoint>());
        while (queue.Count > 0&&isRunning)
        {
           tempPoint = queue.Dequeue();
          //  Debug.Log("Search From:" + tempPoint.GetPosition());
            ExploreAround();
            StopIfSerchEnd();
        }
    }
    private void StopIfSerchEnd()//用于判断是否找到最佳路径
    {
        if (tempPoint == endPoint.GetComponent<WayPoint>())
        {
            //那么意味着我们已经找到终点,停止继续搜索路径
            isRunning = false;
            Debug.Log("serach is finish");
              waylist=new List<WayPoint>();
            waylist.Add(tempPoint);
            while (tempPoint.WayPointParent!=startPoint.GetComponent<WayPoint>())
            {
                waylist.Add(tempPoint.WayPointParent);
                tempPoint = tempPoint.WayPointParent;
                tempPoint.GetComponent<MeshRenderer>().material.color = new Color(0, 1, 0, 1);//将最佳路径的每个点赋值为绿色
            }
            waylist.Add(startPoint.GetComponent<WayPoint>());
            startPoint.GetComponent<MeshRenderer>().material.color = new Color(0, 0, 1, 1);
            waylist.Reverse();
            startPoint = endPoint;
            
        }
        else
        {
            Debug.Log("没有找到路径");
            

        }


    }

    public List<WayPoint> ReturnPath()//刷新路径
    {

        BFS();
        return waylist;
    }

    

}

EnemyMovement

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class EnemyMovement : MonoBehaviour
{
    [SerializeField] private List<GameObject> pathWayPoints = new List<GameObject>();
    PathFinding pf;
    WayPoint _point;
    private void Start()
    {
        pf = FindObjectOfType<PathFinding>();
    }
    IEnumerator FindWayPoint(List<WayPoint> _WayPoint)
    {
        foreach (var item in _WayPoint)
        {
            //transform.position = item.transform.position+ new Vector3(0, 1f, 0);
            _point = item;
            yield return StartCoroutine(ToPoint(_point));
        }
    }

    IEnumerator ToPoint(WayPoint _Point)
    {
        while (transform.position != (_Point.transform.position + new Vector3(0, 1f, 0)))
        {
            transform.position = Vector3.MoveTowards(transform.position, _Point.transform.position + new Vector3(0, 1f, 0), 3 * Time.deltaTime);

            yield return null;

        }
    }

    public void Onstart()//开启寻找路线
    {
        WayPoint[] way = FindObjectsOfType<WayPoint>();
        for (int i = 0; i < way.Length; i++)
        {
            way[i].IsSerach = false;
        }
        StartCoroutine(FindWayPoint(pf.ReturnPath()));
    }
    public void OnStop()//停止寻找路线
    {
        StopAllCoroutines();
        if (_point != null)
            pf.StartPoint = _point.gameObject;
    }
}

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值