android a*算法寻路,简易的A*算法 自动寻路

该博客详细介绍了如何使用A*算法实现一个简单的寻路系统。文章首先定义了曼哈顿距离和欧几里得距离的概念,然后展示了A*算法的核心代码,包括开放列表、关闭列表的管理,以及如何寻找最短路径。算法考虑了节点的周围四个方向(不包括对角线),并计算了节点间的距离。最后,博主还提供了路径折点的计算方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

参考:

曼哈顿距离,横向和纵向直线距离,仅限于横向纵向移动

对角线距离,对角线 + 直线,可以横向、纵向、对角线方向移动

欧几里得距离,任意角度直线,任意方向移动using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using System.Linq;

public class AStartTest

{

AStarNode[,] nodeMap = new AStarNode[10, 10];

void CheckAndFindPath(AStarNode startNode, AStarNode endNode)

{

//计算路径

List pathNodes = FindNodePath(startNode, endNode, nodeMap);

if (pathNodes == null || pathNodes.Count == 0)

return;

//计算路径折点

List pathPoints = GetPathPoint(pathNodes);

}

//计算路径折点

List GetPathPoint(List path)

{

List tmpPointList = new List();

//无折点

if (path.Count <= 2)

return tmpPointList;

//当前节点与前一节点的位置关系(X坐标相同或Y坐标相同)

bool lastDirIsX = path[1].pos.x == path[0].pos.x;

//计算折点

for (int i = 2; i < path.Count; i++)

{

//若与前一节点X坐标相同

if (path[i].pos.x == path[i - 1].pos.x)

{

//前两个节点时Y坐标相同,即为折点

if (!lastDirIsX)

{

//记录折点,记录当前节点关系

tmpPointList.Add(path[i - 1]);

lastDirIsX = true;

}

}

else

{

if (lastDirIsX)

{

tmpPointList.Add(path[i - 1]);

lastDirIsX = false;

}

}

}

//路径最后节点也视为折点

tmpPointList.Add(path[path.Count - 1]);

//

return tmpPointList;

}

#region --- A*算法 ---

//计算最短有效路径

List openList = new List();

List closeList = new List();

List aroundNodes;

List FindNodePath(AStarNode startNode, AStarNode endNode, AStarNode[,] allNodes)

{

//计算范围内的节点

openList.Clear();

//不在计算范围内的节点

closeList.Clear();

//添加起点

openList.Add(startNode);

AStarNode curNode;

//从起点开始循环判断

while (openList.Count > 0)

{

//初始当前位置

curNode = openList[0];

//计算最优当前位置

for (int i = 0; i < openList.Count; i++)

{

//F:从起点到目标点的移动步数

//H:从当前位置到目标位置的移动步数

if (openList[i].CostF < curNode.CostF && openList[i].costH < curNode.costH)

{

curNode = openList[i];

}

}

//锁定当前位置节点

openList.Remove(curNode);

closeList.Add(curNode);

已经计算到目标点

//if (curNode.Equals(endNode))

//{

// //返回最优路径

// return GetPathWithNode(startNode, endNode);

//}

//未计算到目标点, 继续

//获取当前点的周围节点, 在周围节点中查找下一步的最优节点

aroundNodes = GetAroundNodes(curNode, allNodes);

for (int i = 0; i < aroundNodes.Count; i++)

{

//计算到目标点

if (aroundNodes[i].Equals(endNode))

{

//设置上一节点

aroundNodes[i].lastNode = curNode;

//返回最优路径

return GetPathWithNode(startNode, endNode);

}

//不是目标点, 继续计算, 剔除周围节点不可通过、在不可计算范围内的节点

if (!aroundNodes[i].isWall && !closeList.Contains(aroundNodes[i]))

{

//计算 G H F

//F:从起点到目标点的移动步数

//G:从起点到当前位置的移动步数

int newCostG = curNode.costG + GetNodesDistance(curNode, aroundNodes[i]);

if (newCostG <= aroundNodes[i].costG || !openList.Contains(aroundNodes[i]))

{

//刷新赋值

aroundNodes[i].costG = newCostG;

//H:从当前位置到目标位置的移动步数

aroundNodes[i].costH = GetNodesDistance(aroundNodes[i], endNode);

//设置上级节点

aroundNodes[i].lastNode = curNode;

//添加到计算范围内

if (!openList.Contains(aroundNodes[i]))

{

openList.Add(aroundNodes[i]);

}

}

}

}

}

return null;

}

//计算距离

int GetNodesDistance(AStarNode startNode, AStarNode endNode)

{

return Mathf.Abs(startNode.pos.x - endNode.pos.x) + Mathf.Abs(startNode.pos.y - endNode.pos.y);

}

//周围节点只取上下左右四个, 不取对角线(根据实际需求设置周围节点)

Vector2Int[] aroundPos = { new Vector2Int(0, 1), new Vector2Int(0, -1), new Vector2Int(1, 0), new Vector2Int(-1, 0) };

//获取周围Node

List tmpAroundList = new List();

List GetAroundNodes(AStarNode curNode, AStarNode[,] allNodes)

{

tmpAroundList.Clear();

for (int i = 0; i < aroundPos.Length; i++)

{

//计算周围节点坐标

int x = curNode.pos.x + aroundPos[i].x;

int y = curNode.pos.y + aroundPos[i].y;

//剔除不在取值范围内的数据

if (x >= 0 && x < allNodes.GetLength(0) && y >= 0 && y < allNodes.GetLength(1))

{

if (allNodes[x, y] != null)

tmpAroundList.Add(allNodes[x, y]);

}

}

return tmpAroundList;

}

//获取路径(包含起点)

List tmpNodePath = new List();

List GetPathWithNode(AStarNode startNode, AStarNode endNode)

{

tmpNodePath.Clear();

if (endNode != null)

{

//逆向查找路径

AStarNode temp = endNode;

while (temp != startNode)

{

tmpNodePath.Add(temp);

temp = temp.lastNode;

}

tmpNodePath.Add(startNode);

//路径数据反向

tmpNodePath.Reverse();

}

return tmpNodePath;

}

#endregion

}

// A*数据节点类

public class AStarNode

{

//A*算法节点类

//是否能通过

public bool isWall;

//位置坐标

public Vector2Int pos;

//上个节点

public AStarNode lastNode;

//从起点到当前位置的移动步数

public int costG;

//从当前位置到目标位置的移动步数

public int costH;

//从起点到目标点的移动步数

public int CostF

{

get { return costG + costH; }

}

public AStarNode(bool _isWall, Vector2Int _pos)

{

isWall = _isWall;

pos = _pos;

}

//重写Equals

public override bool Equals(object obj)

{

if (obj is AStarNode)

{

AStarNode objNode = (AStarNode)obj;

return objNode.pos == pos;

}

return false;

}

public override int GetHashCode()

{

return base.GetHashCode();

}

}

标签:int,openList,AStarNode,List,public,简易,算法,寻路,curNode

来源: https://blog.youkuaiyun.com/qq_39108767/article/details/89039911

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值