逻辑代码
using System.Collections.Generic;
using System.Text;
using UnityEngine; namespace Game
{
public enum NodeType
{
Movable, //可移动区域
Obstacle, //障碍物
Boundary, //边界
Route //路径
} public enum NodeState
{
None, //默认
Open, //开放列表
Close //封闭列表
} public class SearchPath
{
private readonly Dictionary<Vector2, Node> m_nodes = new Dictionary<Vector2, Node>(); private readonly List<Node> list_close = new List<Node>();
private readonly List<Node> list_open = new List<Node>(); private Vector2 position_target; private Node[,] t_nodes; /// <summary>
/// 初始化地图信息
/// </summary>
/// <param name="width">宽</param>
/// <param name="height">高</param>
/// <param name="slant">斜向关联</param>
/// <returns>地图数据</returns>
public void InitMap(int width, int height, bool slant = false)
{
t_nodes = new Node[width, height]; m_nodes.Clear(); for (int i = ; i < width; i++)
{
for (int j = ; j < height; j++)
{
t_nodes[i, j] = new Node(i, j); if (i == || i == width - ||
j == || j == height - )
{
t_nodes[i, j].type = NodeType.Boundary;
} m_nodes.Add(new Vector2(i, j), t_nodes[i, j]);
}
} Vector2 key; //关联周边节点
for (int i = ; i < width; i++)
{
for (int j = ; j < height; j++)
{
if (slant)
{
for (int h = -; h <= ; h++)
{
for (int v = -; v <= ; v++)
{
if (h != || v != )
{
key = new Vector2(i + h, j + v); if (m_nodes.ContainsKey(key))
{
t_nodes[i, j].neighbour.Add(m_nodes[key]);
}
}
}
}
}
else
{
for (int k = -; k <= ; k++)
{
if (k != )
{
key = new Vector2(i + k, j); if (m_nodes.ContainsKey(key))
{
t_nodes[i, j].neighbour.Add(m_nodes[key]);
} key = new Vector2(i, j + k); if (m_nodes.ContainsKey(key))
{
t_nodes[i, j].neighbour.Add(m_nodes[key]);
}
}
}
}
}
}
} /// <summary>
/// 设置障碍物
/// </summary>
/// <param name="points">位置</param>
public void Obstacle(params Vector2[] points)
{
foreach (var key in points)
{
if (m_nodes.ContainsKey(key))
{
m_nodes[key].type = NodeType.Obstacle;
}
}
} /// <summary>
/// 寻路
/// </summary>
/// <param name="nodes">地图信息</param>
/// <param name="start">起点</param>
/// <param name="end">终点</param>
/// <returns>路径是否存在</returns>
public bool Search(Vector2 start, Vector2 end)
{
bool result = false; if (!m_nodes.ContainsKey(start) || !m_nodes.ContainsKey(end))
{
return result;
}
if (m_nodes[start].type != NodeType.Movable || m_nodes[end].type != NodeType.Movable)
{
return result;
} //设置终点
position_target = end; //重置路径
for (int i = ; i < t_nodes.GetLength(); i++)
{
for (int j = ; j < t_nodes.GetLength(); j++)
{
t_nodes[i, j].Reset();
}
} list_close.Clear();
list_open.Clear(); Node A = t_nodes[(int)start.x, (int)start.y];
A.G = ;
A.H = Vector2.Distance(position_target, A.position);
A.F = A.G + A.H;
A.parent = null;
A.state = NodeState.Close; list_close.Add(A); do
{
if (list_open.Count > )
{
A = list_open[];
}
for (int i = ; i < list_open.Count; i++)
{
if (list_open[i].F < A.F)
{
A = list_open[i];
}
} if (A.Compare(position_target))
{
result = true;
} Node B = Search(A); if (B != null)
{
do
{
B.type = NodeType.Route;
B = B.parent;
}
while (B != null);
}
list_close.Add(A);
list_open.Remove(A);
A.state = NodeState.Close;
}
while (list_open.Count > ); return result;
} private Node Search(Node A)
{
Node B; for (int i = ; i < A.neighbour.Count; i++)
{
if (A.neighbour[i] != null &&
A.neighbour[i].type == NodeType.Movable)
{
B = A.neighbour[i]; if (B.state == NodeState.None)//更新B的父节点为A,并相应更新B.G; 计算B.F,B.H; B加入OpenList
{
B.parent = A;
B.G = Vector2.Distance(A.position, B.position) + A.G;
B.H = Vector2.Distance(B.position, position_target);
B.F = B.G + B.H;
B.state = NodeState.Open; list_open.Add(B); if (B.H < Mathf.Epsilon)//B的所有父节点既是路径
{
return B;
}
}
else if (B.state == NodeState.Open)
{
float curG = Vector2.Distance(A.position, B.position); if (B.G > curG + A.G)//更新B的父节点为A,并相应更新B.G,B.H
{
B.parent = A;
B.G = curG + A.G;
B.F = B.G + B.H;
}
}
}
} return null;
} /// <summary>
/// 路径数据
/// </summary>
public List<Vector2> Output
{
get
{
List<Vector2> route = new List<Vector2>(); if (m_nodes.ContainsKey(position_target))
{
Node node = m_nodes[position_target]; while (node != null)
{
route.Add(node.position);
node = node.parent;
}
} StringBuilder sb = new StringBuilder(); for (int i = ; i < route.Count; i++)
{
sb.Append(route[i].ToString());
sb.Append("&");
} Debug.LogFormat("<color=yellow>{0}</color>", sb.ToString()); return route;
}
} public Node[,] GetNodes()
{
return t_nodes;
}
} public class Node
{
public Vector2 position; public NodeState state; public NodeType type; public float F; // F = G + H
public float G; //从起点移动到指定方格的移动代价
public float H; //从指定方格移动到终点的移动代价 public Node parent; public List<Node> neighbour = new List<Node>(); public Node(int x, int y)
{
position = new Vector2(x, y);
} public void Reset()
{
F = G = H = ; parent = null; state = NodeState.None; if (type.Equals(NodeType.Route))
{
type = NodeType.Movable;
}
} public bool Compare(Vector2 position)
{
return this.position.x == position.x &&
this.position.y == position.y;
}
}
}
调用入口 Test
using Game;
using System.Collections.Generic;
using UnityEngine; public class Test : MonoBehaviour
{
private SearchPath path_ctr; private Dictionary<Vector2, Renderer> m_map = new Dictionary<Vector2, Renderer>(); private void Awake()
{
path_ctr = new SearchPath();
} private void Start()
{
path_ctr.InitMap(, , true); for (int i = ; i < ; i++)
{
path_ctr.Obstacle(new Vector2(, i));
} for (int i = ; i < ; i++)
{
path_ctr.Obstacle(new Vector2(i, ));
} for (int i = ; i < ; i++)
{
path_ctr.Obstacle(new Vector2(i, ));
} Node[,] nodes = path_ctr.GetNodes(); InitMap(nodes); Search(new Vector2(, ), new Vector2(, ));
} private void Update()
{
if (Input.GetKeyDown(KeyCode.P))
{
Vector2 start = new Vector2(Random.Range(, ), Random.Range(, )); Vector2 end = new Vector2(Random.Range(, ), Random.Range(, )); Search(start, end);
}
} private void Search(Vector2 start, Vector2 end)
{
bool result = path_ctr.Search(start, end); if (result)
{
Debug.Log("<color=green>成功寻找到路径!</color>" + path_ctr.Output.Count);
}
else
{
Debug.LogFormat("<color=red>未寻找到路径,起始点:{0} 结束点{1}</color>", start, end);
} Node[,] nodes = path_ctr.GetNodes(); RefreshMap(nodes);
} public void InitMap(Node[,] nodes)
{
for (int i = ; i < nodes.GetLength(); i++)
{
for (int j = ; j < nodes.GetLength(); j++)
{
GameObject curCube = GameObject.CreatePrimitive(PrimitiveType.Cube);
curCube.transform.position = new Vector3(i, j, );
m_map.Add(new Vector2(i, j), curCube.GetComponent<Renderer>());
}
}
} public void RefreshMap(Node[,] nodes)
{
for (int i = ; i < nodes.GetLength(); i++)
{
for (int j = ; j < nodes.GetLength(); j++)
{
Vector2 key = new Vector2(i, j); if (m_map.ContainsKey(key))
{
if (nodes[i, j].type == NodeType.Boundary)
{
m_map[key].material.SetColor("_Color", Color.black);
}
else if (nodes[i, j].type == NodeType.Obstacle)
{
m_map[key].material.SetColor("_Color", Color.red);
}
else if (nodes[i, j].type == NodeType.Route)
{
m_map[key].material.SetColor("_Color", Color.yellow);
}
else
{
m_map[key].material.SetColor("_Color", Color.white);
}
}
}
}
}
}

参考:https://blog.csdn.net/qq_36946274/article/details/81982691

A星寻路的更多相关文章

  1. A星寻路算法介绍

    你是否在做一款游戏的时候想创造一些怪兽或者游戏主角,让它们移动到特定的位置,避开墙壁和障碍物呢? 如果是的话,请看这篇教程,我们会展示如何使用A星寻路算法来实现它! 在网上已经有很多篇关于A星寻路算法 ...

  2. 用简单直白的方式讲解A星寻路算法原理

    很多游戏特别是rts,rpg类游戏,都需要用到寻路.寻路算法有深度优先搜索(DFS),广度优先搜索(BFS),A星算法等,而A星算法是一种具备启发性策略的算法,效率是几种算法中最高的,因此也成为游戏中 ...

  3. A星寻路算法

    A星寻路算法 1.准备一个close关闭列表(存放已被检索的点),一个open开启列表(存放未被检索的点),一个当前点的对象cur 2.将cur设成开始点 3.从cur起,将cur点放入close表中 ...

  4. cocos2d-x学习日志(13) --A星寻路算法demo

    你是否在做一款游戏的时候想创造一些怪兽或者游戏主角,让它们移动到特定的位置,避开墙壁和障碍物呢?如果是的话,请看这篇教程,我们会展示如何使用A星寻路算法来实现它! A星算法简介: A*搜寻算法俗称A星 ...

  5. 无递归 A星寻路算法

    整理硬盘的时候,发现我早些年写的A星寻路算法.特放上来,待有缘人拿去,无递归噢,性能那是杠杠的. 码上伺候 public class Node { public int X { get; set; } ...

  6. A星寻路算法(A* Search Algorithm)

    你是否在做一款游戏的时候想创造一些怪兽或者游戏主角,让它们移动到特定的位置,避开墙壁和障碍物呢? 如果是的话,请看这篇教程,我们会展示如何使用A星寻路算法来实现它! 在网上已经有很多篇关于A星寻路算法 ...

  7. A星寻路算法入门(Unity实现)

    最近简单学习了一下A星寻路算法,来记录一下.还是个萌新,如果写的不好,请谅解.Unity版本:2018.3.2f1 A星寻路算法是什么 游戏开发中往往有这样的需求,让玩家控制的角色自动寻路到目标地点, ...

  8. A星寻路算法-Mind&Hand(C++)

    //注1:Mind & Hand,MIT校训,这里指的理解与实现(动脑也动手) //注2:博文分为两部分:(1)理解部分,为参考其他优秀博文的摘要梳理:(2)代码部分,是C++代码实现的,源码 ...

  9. 【Android】基于A星寻路算法的简单迷宫应用

    简介 基于[漫画算法-小灰的算法之旅]上的A星寻路算法,开发的一个Demo.目前实现后退.重新载入.路径提示.地图刷新等功能.没有做太多的性能优化,算是深化对A星寻路算法的理解. 界面预览: 初始化: ...

  10. [转载]A星寻路算法介绍

    转载自:http://www.raywenderlich.com/zh-hans/21503/a%E6%98%9F%E5%AF%BB%E8%B7%AF%E7%AE%97%E6%B3%95%E4%BB% ...

随机推荐

  1. 动态新增删除tbody表格行与ajax请求完成后刷新父窗口问题

    获取tbody内的一行数据,包括hidden类型的数据$("#tbody_id").find("tr").each(function(){ var tdArr ...

  2. git 日常 常用命令

    初始化git git init 第一次拉代码: 方式1:git clone git clone https://git.oschina.net/*****.git (https远程仓库地址) 方式2: ...

  3. 定位公众号页面,跳转之后 vuejs 失效问题

    是第一个页面的. data () { }, 写成了这样,没写返回 {} 5555~. 网页中死活可以,微信中死活不行. data () { return {} },

  4. Vue的自定义滚动,我用el-scrollbar

    弄了一个持续更新的github笔记,可以去看看,诚意之作(本来就是写给自己看的--)链接地址:Front-End-Basics 此篇文章的地址:Vue的自定义滚动,我用el-scrollbar 基础笔 ...

  5. RMQ HelloWorld

    原创转载请注明出处:https://www.cnblogs.com/agilestyle/p/11791681.html Project Directory Maven Dependency < ...

  6. python实现Restful服务(基于flask)(2)

    参考:https://blog.csdn.net/yelena_11/article/details/53404892 最简单的post例子: from flask import Flask, req ...

  7. [CF959F]Mahmoud and Ehab and yet another xor task题解

    搞n个线性基,然后每次在上一次的基础上插入读入的数,前缀和线性基,或者说珂持久化线性基. 然后一个num数组记录当时线性基里有多少数 然后每次前缀操作一下就珂以了 代码 #include <cs ...

  8. 20180708-Java基本数据类型

    public class PrimitiveTypeTest{ public static void main(String[] args){ //byte System.out.println(&q ...

  9. ThreadLocal学习资料

    下面的这一段代码运行起来,就会发生线程安全问题: 启动两个线程,同时去修改 name 属性值. package com.liwei.thread; /** * 下面的代码演示了线程安全发生的由来 * ...

  10. wl

    <!DOCTYPE html> <html lang="en"> <head> <meta http-equiv="Conten ...