A*寻路

在很多游戏中我们需要让角色用最快的速度到达目标地点,于是我们需要找到一条最短的路径或是比较短的路径,于是出现很多寻路算法,在此介绍较为高效的A* 算法。

原理:把一个2D或者3D的场景解析成由很多方块或者方体组成,给每个方块赋予坐标值,则可以出现起始点的坐标值。        

依托公式F=H+G; 靠谱指数=预计耗费+移动到当前已经耗费

关键集合:openList<point> 用来储存将要判断F值的点,closeList<point>用来储蓄已经判断过F值得点;

实现思路:

  1. 自定义起始点和终点(point start = map[2, 3]; point end = map[6, 3];)  
  2. 新建openList<point>往里添加起始点。
  3. 用while判断如果openlist>0; 寻找openlist里最小F的点,把这点移除openlist,添加closelist. 
  4. 新建sorroundList用来储存最小点周围的点;
  5. 过滤是否在closeList
  6. 遍历这些点是否在openList里面,如果是则判断周围的点和openlist里的点的G值,因为H知同一点一样(新建判断G值函数);如果当前点G值比opnelist的这一点G值小,则把这一点的父点改为最小F的点;
  7. 如果不在openlist则添加
  8. 再一次判断openlist里最小F的点,重复4.5.6.7
  9. 知道结束点在openlist里面打破循环;


point类

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

public class point  {

    public point Parent { get; set; }
    public float F { get; set; }
    public float G { get; set; }
    public float H { get; set; }

    public int X { get; set; }
    public int Y { get; set; }
    public bool IsWall { get; set; }                //

    public point(int x,int y,point parent=null)
    {
        this.X = x;
        this.Y = y;
        this.Parent = parent;
        IsWall = false;
    }
	
    public void UpDateParent(point parent,float g)
    {
        this.Parent = parent;
        this.G = g;
        this.F = G + H;
    }

}

逻辑类

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

public class AStart : MonoBehaviour {                           //在开集合中找最小值,创建这一点的周围集合
                                                                //这个周围集合是否有点在开集合,有就比较,替换
    public float width = 8;
    public float height = 6;
    private point[,] map = new point[8, 6];

	// Use this for initialization
	void Start () {
        InitMap();
        point start = map[2, 3];
        point end = map[6, 3];
        FindPath(start,end);
        ShowPath(start,end);

        //List<point> li = GetSurroundPoint(map[3, 3]);
        //foreach (point p in li)
        //{
        //    Debug.Log(p.X+"-"+p.Y);
            
        //}

		
	}
    public void InitMap()                                   //初始化
    {
        for (int i=0;i<8;i++)
        {
            for (int j=0;j<6;j++)
            {
                map[i, j] = new point(i,j);
            }
        }
        map[4, 2].IsWall = true;
        map[4, 3].IsWall = true;
        map[4, 4].IsWall = true;


    }

    public void ShowPath(point start,point end)
    {
        point temp = end;
        while (true)
        {
            Debug.Log(temp.X+","+temp.Y);
            temp = temp.Parent;
            if (temp.Parent==null)
            {
                Debug.Log(temp.X + "," + temp.Y);
                break;
            }
        }

    }

    public void FindPath(point start,point end)             //寻找路径(起点,终点)
    {
        List<point> openList = new List<point>();
        List<point> closeList = new List<point>();
        openList.Add(start);                                //
        while (openList.Count>0)
        {
            point point1 = FindMinF(openList);
            openList.Remove(point1);
            closeList.Add(point1);
            List<point> surroundPointd = GetSurroundPoint(point1);                  //获得附近的点
            PointsFilter(surroundPointd,closeList);                                 //过滤这些点是否在闭集合

            foreach (point surroundPoint in surroundPointd)
            {
                if (openList.IndexOf(surroundPoint)>-1)                             //周围的点是否在开集合中出现过
                {
                    float nowG = CalcG(surroundPoint,point1);                       //当前G值==当前到父类距离+父类G
                    if (nowG < surroundPoint.G)                                     //原本在开集合这点的G值
                    {
                        surroundPoint.UpDateParent(point1,nowG);
                    }
                }
                else                                                                //如果开集合没有则添加,并赋值
                {
                    surroundPoint.Parent = point1;
                    CalcF(surroundPoint,end);                                       //
                    openList.Add(surroundPoint);
                }
            }
            if (openList.IndexOf(end)>-1)
            {
                break;
            }

        }
    }

    public void PointsFilter(List<point> surroundPointd,List<point> closeList)      //过滤周围在闭集合的点
    {
        foreach (point p in closeList)
        {
            if (surroundPointd.IndexOf(p)>-1)                                       //闭集合存在则移除
            {
                surroundPointd.Remove(p);
            }
        }
    }

    public List<point> GetSurroundPoint(point point)        //获得周围的点
    {
        point up = null, down = null, left = null, right = null;
        point upLeft = null, upRight = null, downLeft = null, downRight = null;
        List<point> list = new List<point>();


        //先判断上下左右是否为边界,在判断是否为为空,不为墙
        if (point.Y<(6-1))
        {
            up = map[point.X, point.Y + 1];
            if (up!=null&&up.IsWall==false)
            {
                list.Add(up);
            }
        }
        if (point.Y > (0))
        {
            down = map[point.X, point.Y - 1];
            if (down != null && down.IsWall == false)
            {
                list.Add(down);
            }
        }
        if (point.X < (8 - 1))
        {
            right = map[point.X+1, point.Y];
            if (right != null && right.IsWall == false)
            {
                list.Add(right);
            }
        }
        if (point.X > (0))
        {
            left = map[point.X-1, point.Y];
            if (left != null && left.IsWall == false)
            {
                list.Add(left);
            }
        }


        /左上存在时,左和上必须不为空,不为墙,自己也不能为空不能为墙
        if (up!=null&&left!=null)
        {
            upLeft = map[point.X - 1, point.Y + 1];
            if (up.IsWall==false&&left.IsWall==false&&upLeft!=null&&upLeft.IsWall==false)
            {
                list.Add(upLeft);
            }
        }
        if (up != null && right != null)
        {
            upRight = map[point.X + 1, point.Y + 1];
            if (up.IsWall == false && right.IsWall == false && upRight != null && upRight.IsWall == false)
            {
                list.Add(upRight);
            }
        }
        if (down != null && left != null)
        {
            downLeft = map[point.X - 1, point.Y - 1];
            if (down.IsWall == false && left.IsWall == false && downLeft != null && downLeft.IsWall == false)
            {
                list.Add(downLeft);
            }
        }
        if (down != null && right != null)
        {
            downRight = map[point.X + 1, point.Y - 1];
            if (down.IsWall == false && right.IsWall == false && downRight != null && downRight.IsWall == false)
            {
                list.Add(downRight);
            }
        }

        return list;
    }

    private point FindMinF(List<point> openList)            //寻找最小的的F
    {
        float f = float.MaxValue;
        point temp = null;
        foreach (point p in openList)
        {
            if (p.F<f)
            {
                temp = p;
                f = p.F;
            }
        }
        return temp;
    }

    private void CalcF(point now,point end)                     //当前点和终点,给F,G,H赋值
    {
        //F=G+H
        float h = Mathf.Abs(end.X - now.X) + Mathf.Abs(end.Y-now.Y);
        float g = 0;
        if (now.Parent==null)
        {
            g = 0;
        }
        else
        {
            g = Vector2.Distance(new Vector2(now.X, now.Y), new Vector2(now.Parent.X, now.Parent.Y))+now.Parent.G;
        }
        float f = g + h;
        now.F = f;
        now.G = g;
        now.H = h;
    }

    private float CalcG(point now,point parent)
    {
        return Vector2.Distance(new Vector2(now.X, now.Y), new Vector2(parent.X, parent.Y))+parent.G;
    }

    // Update is called once per frame
    void Update () {
		
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值