【Unity3D】学习笔记(第8记)游戏中的自动寻路算法

  最近两天刚好有空研究了下游戏中的自动寻路功能,收获颇丰,感觉用相应的算法去解决相应的问题真的非常重要啊!至少比自己想的流水账逻辑流程管用。看来以后得花多点时间研究下算法方面的知识了。
  游戏中的自动寻路,顾名思义就是找路,从地图找到从起点到终点的可行最短路径。既然是从地图找路,那么地图就应该是可数据化的,要不怎么找呢。
  所以自动寻路的有两个重点是分别是地图数据化和搜索算法。
  地图数据化,3D游戏地图有点复杂,还没研究,今天先看看2D游戏的。比如,搞一张九宫格式的地图,那么每个格子至少需要有这样的数据,格子的坐标、是路还是墙(根据具体情况格子还可以拓展其他属性)。然后有了这份数据化的地图后,寻路就变成了从一个格子移动到另一个格子的过程。
  搜索算法,深度优先搜索(DFS)和广度优先搜索(BFS)算法,通常我们说DFS用栈方式实现,BFS用队列方式实现,为什么呢,下面我们来看看。

  1. 队列:起点P,将邻接点A、B、C、D存入队列,标记P为已查找,然后A出队,得邻接点A1、A2、A3、A4, 队列变成B、C、D、A1、A2、A3、A4,继续B出队得新队列C、D、A1、A2、A3、A4、B1、B2、B3、B4…。
  2. 栈:起点P,将邻接点A、B、C、D存入栈,标记P为已查找,然后D出栈,得邻接点D1、D2、D3、D4, 栈变成B、C、D1、D2、D3、D4,继续D4出栈得新栈B、C、D1、D2、D3、d1、d2、d3、d4…。
    邻接点:不考虑斜角方向,有上下左右四个。

      粗糙理解讲下就是队列是从根节点开始,搜索所有子节点,然后搜索所有子节点的所有子节点;而栈是从根节点开始,搜索所有子节点,选择某个子节点搜索所有子节点,找不到则回溯父节点继续操作(参考二叉树辅助图理解)。其实从上面来看,无论是栈还是队列,对某个点都是只能访问一次的,访问后立即出栈或出队。如果没处理好,出现重复访问某个点的话,容易出现死循环。
      运用到游戏中,那么起点就是二叉树的根节点,终点就是某个子节点,自动寻路就是找到从根节点到子节点的一条连接线。根节点每连接一个子节点时就记录下长度,最后根据长度就可以求出最短路径了。

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

public class CPathFind : MonoBehaviour {
    // 自定义地图,1可行,0障碍
    private const int Row = 8, Col = 9;
    private int[,] MapDataArr = new int[Row, Col]
    {
        {1, 1, 1, 1, 1, 1, 1, 1, 1},
        {1, 1, 0, 0, 1, 0, 1, 1, 1},
        {1, 1, 1, 1, 1, 0, 0, 1, 1},
        {1, 1, 1, 0, 1, 1, 1, 1, 1},
        {1, 0, 0, 0, 1, 0, 1, 1, 1},
        {1, 1, 1, 1, 1, 1, 1, 1, 1},
        {1, 0, 0, 1, 1, 0, 0, 0, 1},
        {1, 1, 1, 1, 1, 1, 1, 1, 1},
    };
    // 每个地图点数据化
    private class CMapPoint
    { 
        public int x;
        public int y;
        public int abstacle;
        public bool isFind = false;
        public int moveDis = 0;
        public CMapPoint fatherPoint;

        public CMapPoint(int x, int y, CMapPoint fp = null)
        {
            this.x = x;
            this.y = y;
            fatherPoint = fp;
        }
    }

    public GameObject wBlockPrefab;
    public GameObject bBlockPrefab;
    public GameObject playerPrefab;
    public GameObject blockGroupObj;

    private bool isMove = false;
    private int leastDis = 10000;
    private int findCount = 0;

    private CMapPoint endTargetPoint = new CMapPoint(0, 0);
    private CMapPoint moveTargetPoint = new CMapPoint(0, 0);
    private CMapPoint playerPoint = new CMapPoint(0, 0);

    private List MapPointList = new List();
    private List MovePointList = new List();

    private List OpenList = new List();
    private List CloseList = new List();

    void Start () {
        CreateMap();
    }

    void Update () {
        PlayerMove();
    }

    void OnDestroy()
    {
        for (int i = 0; i < blockGroupObj.transform.childCount; i++)
        {
            GameObject.Destroy(blockGroupObj.transform.GetChild(i).gameObject);
        }
    }

    void CreateMap()
    {
        for (int r = 0; r < MapDataArr.GetLength(0); r++)
        {
            for (int c = 0; c < MapDataArr.GetLength(1); c++)
            {
                CMapPoint mp = new CMapPoint(c, r) {
                    abstacle = MapDataArr[r, c]
                };
                MapPointList.Add(mp);

                GameObject blockPrefab = null;
                if (MapDataArr[r, c] == 1)
                    blockPrefab = wBlockPrefab;
                else
                    blockPrefab = bBlockPrefab;

                GameObject blockObj = GameObject.Instantiate(blockPrefab, Vector3.zero, Quaternion.identity) as GameObject;
                blockObj.name = r + "," + c;
                blockObj.transform.SetParent(blockGroupObj.transform);
                blockObj.transform.localScale = Vector3.one;
                // 左下角为原点
                blockObj.transform.localPosition = new Vector3(c * 60, r * 60, 0);
                blockObj.SetActive(true);
                blockObj.GetComponent

》》》》戳我下载完整项目》》》》

你可能感兴趣的:(Unity3D学习笔记)