java动画迷宫寻路_[人工智能] 迷宫生成、寻路及可视化动画

前言数据结构准备迷宫生成算法迷宫寻路算法前言本次带来迷宫相关的算法,迷宫的算法涉及到不少经典的图论算法,在游戏中NPC这些算法被大量的运用,深入了解和学习这些算法是为开发游戏打下坚实的基础。除了纯算法以外,我还借用了OpenGL将这些算法的演算过程可视化出来,借用这些动画演算,可加深对算法的理解,枯燥的算法一下子有趣了起来呢!本工程全部源码及可执行程序可在github下载:https://gith...
摘要由CSDN通过智能技术生成

前言

数据结构准备

迷宫生成算法

迷宫寻路算法

前言

本次带来迷宫相关的算法,迷宫的算法涉及到不少经典的图论算法,在游戏中NPC这些算法被大量的运用,深入了解和学习这些算法是为开发游戏打下坚实的基础。除了纯算法以外,我还借用了OpenGL将这些算法的演算过程可视化出来,借用这些动画演算,可加深对算法的理解,枯燥的算法一下子有趣了起来呢!

本工程全部源码及可执行程序可在github下载:https://github.com/ZeusYang/Breakout。其中的Maze目录就是本次迷宫的项目文件了,可执行程序exe在Maze/x64/Release下,编译的64位程序,可直接运行。

程序操作说明:1、2、3数字键是生成迷宫指令,分别是深度优先、随机Prim、四叉树分割迷宫生成算法,A/a、B/b、C/c字符键是迷宫寻路指令,分别是深度优先、广度优先、A星算法迷宫寻路。按下之后再按Enter即自动开始对应的操作。注意先生成迷宫再进行寻路,否则没有意义,因为一开始都是封闭墙。

数据结构准备

迷宫本质上是一个二维平面,我们用一个二维数组表示,然后数组中的每个元素都是一个迷宫单元。定义迷宫单元[x,y],每个迷宫单元有上、下、左、右四面墙,初始时四面墙都存在。为了方面,我们定义下面的结构体:enum Neighbor { LEFT = 0, UP = 1, RIGHT = 2, DOWN = 3 };

struct Cell {//迷宫单元

int neighbors[4];//四个方向的邻居

int visited;//记录是否访问过了

//以下用于寻路算法

glm::ivec2 prev;//记录前驱

//用于A星算法的open表、closed表

bool inOpen, inClosed;

//启发式函数fn = gn + hn

//其中gn为起点到n的实际距离,hn为n到终点的哈密顿

int gn, hn;

Cell() :visited(0),inOpen(false),inClosed(false) {

neighbors[LEFT] = neighbors[UP] = neighbors[RIGHT] = neighbors[DOWN] = 0;

}

};

然后声明一个类–MazeAlgorithm,在这里我们将要实现六个算法,每个算法的数据结构如下:const int row, col;//迷宫单元的行、列数

static std::vector<:vector>> cells;//迷宫单元矩阵

//迷宫生成算法一数据结构:深度优先的栈

std::stack<:ivec2> record;

//迷宫生成算法二数据结构:随机Prim算法的链表

std::list<:ivec2> prim;

//迷宫生成算法三数据结构:四叉树广度优先的队列

std::queue<:pair glm::ivec2>> recursive;

//迷宫寻路算法一数据结构:深度优先的栈

std::stack<:ivec2> path_dfs;

//迷宫寻路算法一数据结构:广度优先的队列

std::queue<:ivec2> path_bfs;

//迷宫寻路算法一数据结构:A星算法的优先队列

std::priority_queue,Compare> path_astar;

以上仅仅是一部分,具体的细节请看源码。

迷宫生成算法

这里我实现的迷宫生成算法有三个,分别是:深度优先、随机Prim、四叉树分割。

深度优先

就是表面上的意思,深度优先的方法生成迷宫,当然跟普通的深度优先搜索有点差别,它加入了随机性,先看伪代码:将起点作为当前迷宫单元并标记为已访问

while 还存在未标记的迷宫单元

if 当前迷宫单元有未被访问过的的相邻的迷宫单元 then

随机选择一个未访问的相邻迷宫单元

将当前迷宫单元入栈

移除当前迷宫单元与相邻迷宫单元的墙

标记相邻迷宫单元并用它作为当前迷宫单元

else if 栈不空

栈顶的迷宫单元出栈

令其成为当前迷宫单元

算法的主要思想就是,每次在当前迷宫单元中寻找与其相邻的未访问过的迷宫单元,然后选择这些邻居其中的一个访问下去,直到所有的单元都被访问到。就是从起点开始随机走,走不通了就返回上一步,从下一个能走的地方再开始随机走。

那么如何实现呢,我们用一个栈来进行深度优先遍历,栈的元素是数组的下标。下面代码中的frame纯属用于演示动画,可去掉直接得结果,还有栈的初始化请在源代码中Generation_Init()函数查看。std::stack<:ivec2> record;

...

bool MazeAlgorithm::Generator_Dfs() {

frame = 5;//用于演示动画

while (!record.empty() && frame--) {//当队列或者frame不减到0时

cells[cur.x][cur.y].visited = 1;//标记当前的位置为访问过的了

bool hasNeigh = false;//是否有邻居未访问

std::vector<:pair>> tmp; //记录未访问的邻居, tmp.second代表它是哪个邻居

glm::ivec2 loc;

//寻找是否存在未访问的邻居

for (auto x = 0; x < 4; ++x) {

loc = glm::ivec2(cur.x + to[x][0], cur.y + to[x][1]);

if (CouldMove(loc) &

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值