在c#的winForm中写基于A*算法的简单路径规划
时间: 2024-03-23 11:38:58 浏览: 139
好的,以下是基于A*算法的简单路径规划的C# WinForm代码示例:
首先,我们需要定义一个节点类来表示地图上的每个点:
```csharp
public class Node
{
public int x; // 节点的横坐标
public int y; // 节点的纵坐标
public bool walkable; // 是否可以通行
public int gCost; // 起点到该节点的移动代价
public int hCost; // 该节点到终点的估算移动代价
public int fCost // 该节点的总移动代价(fCost = gCost + hCost)
public Node parent; // 该节点的父节点,用于记录路径
}
```
接下来,我们需要定义一个地图类来管理整个地图,包括节点的生成和路径规划:
```csharp
public class Map
{
private int width; // 地图宽度
private int height; // 地图高度
private Node[,] nodes; // 存储所有节点的二维数组
public Map(int width, int height)
{
this.width = width;
this.height = height;
// 初始化节点数组
nodes = new Node[width, height];
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
nodes[x, y] = new Node(x, y, true);
}
}
}
// 获取某个坐标上的节点
public Node GetNode(int x, int y)
{
if (x < 0 || x >= width || y < 0 || y >= height)
{
return null;
}
return nodes[x, y];
}
// A*算法路径规划
public List<Node> FindPath(int startX, int startY, int endX, int endY)
{
Node startNode = GetNode(startX, startY);
Node endNode = GetNode(endX, endY);
List<Node> openSet = new List<Node>(); // 存储待探索的节点
HashSet<Node> closedSet = new HashSet<Node>(); // 存储已探索的节点
openSet.Add(startNode);
while (openSet.Count > 0)
{
Node currentNode = openSet[0];
for (int i = 1; i < openSet.Count; i++)
{
if (openSet[i].fCost < currentNode.fCost || (openSet[i].fCost == currentNode.fCost && openSet[i].hCost < currentNode.hCost))
{
currentNode = openSet[i];
}
}
openSet.Remove(currentNode);
closedSet.Add(currentNode);
if (currentNode == endNode)
{
// 找到终点,回溯路径
List<Node> path = new List<Node>();
Node current = currentNode;
while (current != startNode)
{
path.Add(current);
current = current.parent;
}
path.Reverse();
return path;
}
// 遍历当前节点的所有邻居
foreach (Node neighbor in GetNeighbors(currentNode))
{
if (!neighbor.walkable || closedSet.Contains(neighbor))
{
continue;
}
int newCostToNeighbor = currentNode.gCost + GetDistance(currentNode, neighbor);
if (newCostToNeighbor < neighbor.gCost || !openSet.Contains(neighbor))
{
neighbor.gCost = newCostToNeighbor;
neighbor.hCost = GetDistance(neighbor, endNode);
neighbor.fCost = neighbor.gCost + neighbor.hCost;
neighbor.parent = currentNode;
if (!openSet.Contains(neighbor))
{
openSet.Add(neighbor);
}
}
}
}
// 没有找到路径,返回空
return null;
}
// 获取某个节点的邻居列表
private List<Node> GetNeighbors(Node node)
{
List<Node> neighbors = new List<Node>();
for (int x = -1; x <= 1; x++)
{
for (int y = -1; y <= 1; y++)
{
if (x == 0 && y == 0) continue;
int checkX = node.x + x;
int checkY = node.y + y;
Node neighbor = GetNode(checkX, checkY);
if (neighbor != null)
{
neighbors.Add(neighbor);
}
}
}
return neighbors;
}
// 获取两个节点之间的距离
private int GetDistance(Node nodeA, Node nodeB)
{
int distX = Mathf.Abs(nodeA.x - nodeB.x);
int distY = Mathf.Abs(nodeA.y - nodeB.y);
if (distX > distY)
{
return 14 * distY + 10 * (distX - distY);
}
else
{
return 14 * distX + 10 * (distY - distX);
}
}
}
```
最后,在WinForm的代码中,我们可以使用PictureBox来显示地图,使用鼠标事件来标记障碍物和起点终点,使用Graphics对象来绘制路径:
```csharp
public partial class Form1 : Form
{
private const int MAP_WIDTH = 50;
private const int MAP_HEIGHT = 50;
private const int NODE_SIZE = 10;
private Map map;
private Node startNode;
private Node endNode;
private List<Node> path;
private bool mouseDown = false;
private bool drawWall = false;
public Form1()
{
InitializeComponent();
map = new Map(MAP_WIDTH, MAP_HEIGHT);
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
// 绘制地图
for (int x = 0; x < MAP_WIDTH; x++)
{
for (int y = 0; y < MAP_HEIGHT; y++)
{
Node node = map.GetNode(x, y);
Brush brush = Brushes.White;
if (!node.walkable) brush = Brushes.Black;
if (node == startNode) brush = Brushes.Green;
if (node == endNode) brush = Brushes.Red;
g.FillRectangle(brush, x * NODE_SIZE, y * NODE_SIZE, NODE_SIZE, NODE_SIZE);
}
}
// 绘制路径
if (path != null)
{
Pen pen = new Pen(Color.Blue, NODE_SIZE / 2);
for (int i = 0; i < path.Count - 1; i++)
{
Node nodeA = path[i];
Node nodeB = path[i + 1];
g.DrawLine(pen, nodeA.x * NODE_SIZE + NODE_SIZE / 2, nodeA.y * NODE_SIZE + NODE_SIZE / 2, nodeB.x * NODE_SIZE + NODE_SIZE / 2, nodeB.y * NODE_SIZE + NODE_SIZE / 2);
}
}
}
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
int x = e.X / NODE_SIZE;
int y = e.Y / NODE_SIZE;
Node node = map.GetNode(x, y);
if (node == startNode || node == endNode) return;
mouseDown = true;
drawWall = !node.walkable;
node.walkable = drawWall;
pictureBox1.Invalidate();
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (!mouseDown) return;
int x = e.X / NODE_SIZE;
int y = e.Y / NODE_SIZE;
Node node = map.GetNode(x, y);
if (node == startNode || node == endNode) return;
node.walkable = drawWall;
pictureBox1.Invalidate();
}
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
mouseDown = false;
}
private void button1_Click(object sender, EventArgs e)
{
// 找到起点和终点
for (int x = 0; x < MAP_WIDTH; x++)
{
for (int y = 0; y < MAP_HEIGHT; y++)
{
Node node = map.GetNode(x, y);
if (node.walkable)
{
if (startNode == null)
{
startNode = node;
}
else if (endNode == null)
{
endNode = node;
break;
}
}
}
if (endNode != null) break;
}
// 进行路径规划
path = map.FindPath(startNode.x, startNode.y, endNode.x, endNode.y);
pictureBox1.Invalidate();
}
}
```
这样,我们就完成了一个简单的基于A*算法的路径规划程序。
阅读全文