迷宫生成算法和迷宫寻路算法
大学二年级的时候,作为对栈这个数据结构的复习,我制作了一个迷宫生成算法的小程序,当时反响十分好,过了几天我又用自己已经学的DirectX技术制作了DirectX版的程序。这几天回过头看自己的文章,感觉温故而知不足。温故是因为唤醒了我对迷宫算法的回忆,知不足是因为我那个程序一点儿也没有按照面向对象的思路去做。还是那一套C的思想。
我打算重新制作迷宫程序。这次和以前不同,我学习了C++、STL、Lua、OpenGL,还有很多很多对游戏开发很实用的知识。因此我打算将自己的迷宫重新写一遍,使用面向对象的思想。
大家先看看演示程序吧。演示程序的下载地址在这里。
放几张截图出来,给大家一点视觉冲击!
怎么样?眼花缭乱了吧。其实这些都归功于我写的Maze类。
这个Maze类负责所有与迷宫有关的操作,包括自动产生迷宫和迷宫自动寻路算法都是它的方法。一般来说,迷宫的属性有多少行和多少列,以及各个小格子的属性等等。下面是Maze类的声明:
class Maze { public: Maze( void ); ~Maze( void ); Maze( unsigned short column, unsigned short row ); void Init( unsigned short column = 12, unsigned short row = 12 ); void SetCallback( IMazeCallback* pCallback ); void Draw( void ); void DrawPath( void ); void RandomCreate( void ); void SetStartPoint( unsigned short row, unsigned short col ); void SetEndPoint( unsigned short row, unsigned short col ); void AutoFindPath( void ); void ClearPoints( void ); private: IMazeCallback* m_pCallback; unsigned long* m_pMap; unsigned short m_MaxColumn; unsigned short m_MaxRow; };
这里最重要的算法算是自动迷宫生成算法和迷宫自动寻路算法了。上面的声明是RandomCreate()和AutoFindPath(),为了实现该算法,我使用了一个辅助的类MazeStep,它用来标记迷宫中的每一步。也就是说这一“步”既可以开辟天地形成迷宫,也可以聪明地从迷宫的一端到达另外一端。
不要担心一个点到达不了另外一个点,因为我们前前后后只使用了一条栈。如果你使用两条栈生成迷宫或者你在一个迷宫中生成了两次,那么可能真的存在不可达路径了。
下面是RandomCreate()和AutoFindPath()的关键代码。
void Maze::RandomCreate( void ) { …… MazeStep newStep( 1, 1 ); MazeStep dummyStep( 0, 0 );// 无效的,用来压栈底 // 新式迷宫生成方法 stepStack.push( dummyStep );// 压入一个无效的步 while ( !stepStack.empty( ) ) { newStep.RandomState( );// 自动产生状态 bool statement1 = dummyStep == stepStack.top( );// 栈中元素个数是否为1 bool statement2 = newStep.CheckBoundary( );// 检测边界 if ( statement1 && statement2 || statement2 && newStep.CheckPrevious( stepStack.top( ) ) &&// 检测是否走回头路 newStep.CheckTraveled( ) )// 检测该路是否走过了 { newStep.SetCell( ); newStep.SetTraveled( ); stepStack.push( newStep ); newStep.Init( ); newStep.SetPrevious( stepStack.top( ) ); continue; } newStep.DisableCurrentState( ); if ( newStep.IsDead( ) )// 是死路一条 { newStep.SetTraveled( ); newStep = stepStack.top( ); stepStack.pop( ); if ( dummyStep == stepStack.top( ) ) stepStack.pop( );// 把无效的步也弹出吧 } }// 新式迷宫生成方法 …… }
void Maze::AutoFindPath( void ) { …… MazeStep newStep = s_StartStep; MazeStep dummyStep( 0, 0 );// 无效的,用来压栈底 pathStack.push( dummyStep ); while ( s_EndStep != pathStack.top( ) ) { newStep.RandomState( ); bool statement1 = dummyStep == pathStack.top( );// 栈底是否为无效 bool statement2 = newStep.CheckBoundary( );// 检测边界 bool statement3 = newStep.PathCheckAccessible( );// 检测路径是否可达 if ( statement1 && statement2 && statement3 || statement2 && statement3 && newStep.CheckPrevious( pathStack.top( ) ) &&// 检测是否走回头路 newStep.CheckTraveled( ) )// 检测是否已经走过了 { newStep.SetPath( ); newStep.SetTraveled( ); pathStack.push( newStep ); newStep.Init( ); newStep.SetPrevious( pathStack.top( ) ); continue; } newStep.DisableCurrentState( ); if ( newStep.IsDead( ) )// 是死路一条 { newStep.SetTraveled( ); if ( s_EndStep == newStep ) break;// 死路也是终点啊 newStep = pathStack.top( ); pathStack.pop( ); newStep.ClearPath( ); if ( dummyStep == pathStack.top( ) ) { newStep = s_StartStep; } else { newStep.SetPrevious( pathStack.top( ) ); } } } SetStartEndPoint( ); …… }
在我的演示程序中使用了Lua脚本语言,因此你可以修改Config.lua中的变量,看看不同效果。
如果你想和我一样顺利地编译运行程序或者是想深入地了解我是怎样制作这个演示程序的,那么可以先看看我写的另外一篇博客:用QtCreator开发OpenGL游戏,然后可以下载我的程序源代码。另外还有什么问题的话可以留言给我。