本文展示了使用cocos2d-x来实现的一个迷宫探索演示程序,一种简单粗暴的寻路算法,算法来自经典的严蔚敏c语言数据结构里的迷宫探索算法,使用栈来实现。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AszjE6M5-1583604778767)(http://elloop.oss-cn-hangzhou.aliyuncs.com/blog_pic/stack-maze-explore.gif?OSSAccessKeyId=LTAI4FtWWR7eyV7ELYCixBe2&Expires=1584204324&Signature=QNO54jtAH1qUpeiKd7Rd6zs0WZU%3D)]
按钮功能:
Begin : 开始演示
Reset: 重新生成随机地图, 地图是可以编辑,点击每个掉块翻转状态(墙或者路)
State: 显示地图的数字状态,调试用。
Edit: 在进行过探索之后,可以通过Edit对地图进行微调,即可以不需要全部Reset。Edit之后再点Begin,重新进行探索。
下面给出代码实现, 算法和界面是分开的两部分,后面如果要集成新的寻路算法,界面部分是可以公用的,定义新的寻路算法仅需要继承类:,并实现寻路算法接口。
1. 算法基类:MazeStrategy.h
#pragma once
#include "cocos2d.h"
class MazeStrategy {
public:
typedef cocos2d::Vec2 MPoint;
typedef cocos2d::Size MSize;
struct MazeCell {
MPoint pos;
int state;
};
static const int kStateWall = 0;
static const int kStatePass = 1;
static const int kStateTryFail = 2;
static const int kStateInStack = 3;
typedef std::vector CellArray;
typedef std::vector Maze;
int _rows;
int _columns;
float _cellWidth;
Maze _maze;
MazeStrategy(int rows = 10, int columns = 10)
: _rows(rows)
, _columns(columns)
{
srand(time(0));
}
virtual ~MazeStrategy() {
}
virtual void clearState() {
for (auto &row : _maze) {
for (auto &column: row) {
column.state = (column.state > 0) ? kStatePass : kStateWall;
}
}
}
virtual void resetMaze(MSize winSize, MPoint origin) {
_cellWidth = std::min(winSize.width / _columns, winSize.height / _rows);
MPoint offsetForAnchorPoint(_cellWidth/2, _cellWidth/2);
_maze.resize(_rows);
int i, j;
i = j = 0;
for (auto &row : _maze) {
row.resize(_columns);
j = 0;
for (auto &column: row) {
column.pos.x = origin.x + j++ * _cellWidth + offsetForAnchorPoint.x;
column.pos.y = origin.y + i * _cellWidth + offsetForAnchorPoint.y;
column.state = (rand()*1.0 > RAND_MAX / 7.0 * 5) ? kStateWall : kStatePass;
}
++i;
}
_maze[0][0].state = kStatePass;
_maze[_rows-1][_columns-1].state = kStatePass;
}
void updateMazeCell(int i, int j, int val) {
_maze[i][j].state = val;
}
Maze& getMaze() {
return _maze;
}
struct TickResult {
MPoint pos;
int result;
};
virtual TickResult tickStep() {
return {MPoint(0, 0), 0};
}
};
2. 基于栈的解法:StackMazeStrategy.h
#pragma once
#include "MazeStrategy.h"
#include
#include
class StackMazeStrategy: public MazeStrategy {
public:
StackMazeStrategy(int row = 10, int col = 10) : MazeStrategy(row, col) {
}
struct Pos {
int _row;
int _col;
Pos(int row = -1, int col = -1) : _row(row), _col(col) { }
bool operator == (const Pos& rhs) const {
return (rhs._row == _row && rhs._col == _col);
}
bool operator != (const Pos& rhs) const {
return !(*this == rhs);
}
void makeValid(int size) {
_row = std::max(0, _row);
_col = std::max(0, _col);
_row = std::min(_row, size);
_col = std::min(_col, size);
}
};
std::stack _stack;
Pos _currentPos;
Pos getNextPos(const Pos& pos) {
std::array neigboors = {
Pos(pos._row + 1, pos._col),
Pos(pos._row, pos._col + 1),
Pos(pos._row - 1, pos._col),
Pos(pos._row, pos._col - 1),
};
Pos noWay = {-1, -1};
for (auto& posi : neigboors) {
posi.makeValid(_rows-1);
if ( (posi != pos) &&
(posi != noWay) &&
(_maze[posi._row][posi._col].state == MazeStrategy::kStatePass) ) {
return posi;
}
}
return noWay;
}
void markMaze(const Pos& pos, int t) {
_maze[pos._row][pos._col].state = t;
}
void clearState() override {
MazeStrategy::clearState();
std::stack stemp;
stemp.swap(_stack);
_stack.push({0, 0});
_currentPos = _stack.top();
markMaze(_currentPos, MazeStrategy::kStateInStack);
}
void resetMaze(MSize visibleSize, MPoint origin) override {
MazeStrategy::resetMaze(visibleSize, origin);
std::stack stemp;
stemp.swap(_stack);
_stack.push({0, 0});
_currentPos = _stack.top();
markMaze(_currentPos, MazeStrategy::kStateInStack);
}
TickResult tickStep() override {
int result(0);
if (_stack.empty()) {
return {_maze[_currentPos._row][_currentPos._col].pos, 0}; //fail
}
Pos outlet = {_rows - 1, _columns - 1};
if (_currentPos == outlet) {
// printSolution(st);
// break;
return {_maze[outlet._row][outlet._col].pos, 1}; // ok
}
Pos nextPos = getNextPos(_currentPos);
Pos noWay = {-1, -1};
if (nextPos == noWay) {
_stack.pop();
markMaze(_currentPos, MazeStrategy::kStateTryFail);
if (!_stack.empty()) {
_currentPos = _stack.top();
result = 2; // need next step
}
}
else {
_stack.push(nextPos);
markMaze(nextPos, MazeStrategy::kStateInStack);
_currentPos = nextPos;
result = 2;
}
return {_maze[_currentPos._row][_currentPos._col].pos, result};
}
};
#pragma once
#include "cocos2d.h"
#include
#include
class MazeStrategy;
class MatrixExplore : public cocos2d::Layer
{
public:
MatrixExplore() : _mazeStrategy(nullptr), _playing(false), _robot(nullptr), _door(nullptr), _showState(false){}
~MatrixExplore() {
CC_SAFE_DELETE(_mazeStrategy);
}
void onReset(cocos2d::Ref* target);
void onBegin(cocos2d::Ref* target);
void onShowState(cocos2d::Ref* target);
void onEdit(cocos2d::Ref* target);
void onMazeClicked(cocos2d::Ref* target);
void tick(float dt);
static cocos2d::Scene* createScene();
virtual bool init();
void reloadUI();
void loadMazeMap();
void reloadMazeStrategy();
void refreshState();
CREATE_FUNC(MatrixExplore);
private:
MazeStrategy* _mazeStrategy;
bool _playing;
bool _showState;
cocos2d::Sprite* _robot;
cocos2d::Sprite* _door;
};
MatrixExplore.cpp
#include "MatrixExplore.h"
#include "StackMazeStrategy.h"
USING_NS_CC;
Scene* MatrixExplore::createScene()
{
auto scene = Scene::create();
auto layer = MatrixExplore::create();
scene->addChild(layer);
return scene;
}
void MatrixExplore::loadMazeMap() {
auto& maze = _mazeStrategy->getMaze();
int rows = _mazeStrategy->_rows;
int columns = _mazeStrategy->_columns;
Vector
作者水平有限,对相关知识的理解和总结难免有错误,还望给予指正,非常感谢!
在这里也能看到这篇文章:github博客, CSDN博客, 欢迎访问