正六边形:寻路优化

参考资料:https://www.redblobgames.com/grids/hexagons/

处理正六边形网格数据【纵坐标优化,引入Z坐标】:

const double sqrt3 = 1.732051;
const int sideLen = 50;
const int rowGridNum = 14;
const int colGridNum = 16;

void HelloWorld::addSixSideGrid()
{
	char buff[32] = { 0 };
	std::vector<AStar::MapData> childVec;
	AStar::MapData tmpData;
	for (int i = 0; i <= rowGridNum; i++)
	{
		childVec.clear();
		for (int j = 0; j < colGridNum; ++j) {
			tmpData.grid.x = i;
			tmpData.grid.y = j - i;
			tmpData.grid.z = -1 * (tmpData.grid.x + tmpData.grid.y);

			auto sp = Sprite::create("six_side.png");
			auto pos = this->getPosByGrid(i, j);
			sp->setPosition(pos);
			this->addChild(sp);

			auto txt = ui::Text::create();
			sprintf(buff, "%d,%d,%d", tmpData.grid.x, tmpData.grid.y, tmpData.grid.z);
			txt->setString(buff);
			txt->setTextColor(Color4B::BLACK);
			txt->setFontSize(24);
			sp->addChild(txt);
			txt->setPosition(sp->getContentSize() * 0.5);

			tmpData.grid.posX = pos.x;
			tmpData.grid.posY = pos.y;
			childVec.push_back(tmpData);
		}

		mapVec.push_back(childVec);
	}
}

//根据网格信息计算坐标
Vec2 HelloWorld::getPosByGrid(const int& gridX, const int& gridY)
{
	int y = gridY - gridX / 2;

	Vec2 pos = Vec2::ZERO;
	pos.x = gridX * sideLen * 1.5 + sideLen;
	if (gridX % 2 == 0)
	{
		pos.y = sideLen * sqrt3 * y;
	}
	else
	{
		pos.y = sideLen * sqrt3 * (y - 0.5);
	}
	return pos;
}

//根据坐标计算网格信息
Vec2 HelloWorld::getGridByPos(const Vec2& pos)
{
	int girdX = (pos.x- sideLen) / (1.5 * sideLen) + 0.5;
	int girdY = 0;
	if (girdX % 2 == 0)
	{
		girdY = pos.y / (sideLen * sqrt3) + 0.5;
	}
	else
	{
		girdY = pos.y / (sideLen * sqrt3)+1;
	}
	girdY -= (girdX+1)/2;
	return Vec2(girdX, girdY);
}

AStar.h



#ifndef __AStar__
#define __AStar__

#include <algorithm>
#include <vector>
#include <string>

struct Grid
{
	Grid() {}
	Grid(int x, int y,int z) {
		this->x = x;
		this->y = y;
		this->z = z;
	}

	int x = 0;
	int y = 0;
	int z = 0;

	double posX = 0;
	double posY = 0;

	double distance(const Grid& grid) {
		double dis = abs(grid.x - x) + abs(grid.y - y)+abs(grid.z-z);
        //需要除以2
		return dis/2;
	}

	bool operator==(const Grid& grid) const {
		return this->x == grid.x && this->y == grid.y;
	}

	void operator+=(const Grid& grid) {
		this->x += grid.x;
		this->y += grid.y;
		this->z += grid.z;
	}
};

class AStar
{
public:
	AStar();
	~AStar();

	struct MapData
	{
		Grid grid;
		bool visited = false;
		bool isSpace = true;
		void reset() {
			visited = false;
		}
	};

	MapData* getMapDataByGrid(const Grid& grid, std::vector<std::vector<MapData>>& arr);
	void findPath(const Grid & startPos,const Grid &endPos, std::vector<std::vector<MapData>> &arr,std::vector<Grid> &pathVec);
};

#endif /* defined(__AStar__) */

AStar.cpp


#include "AStar.h"
#include <iostream>
#include <map>

struct Data
{
	Data() {}
	Data(Grid pos, double h, double g, Data* parent) {
		this->grid = pos;
		this->h = h;
		this->g = g;
		this->parent = parent;
	}

	Grid grid = Grid(0, 0, 0);
	double h = 0;
	double g = 0;
	Data* parent = nullptr;

	double f() {
		return this->g + this->h;
	}
};

struct MinHeap
{
	std::vector<Data*> m_vec;
	std::map<std::string, Data*> m_map;
	int index = 0;

	Data* getMinAndRemove() {
		if (isEmpty()) {
			return nullptr;
		}
		sort();
		auto first = m_vec.at(0);
		auto last = m_vec.at(index - 1);
		m_vec[0] = last;

		--index;
		return first;
	}

	bool isEmpty() {
		return index <= 0;
	}

	std::string getKey(const Grid& grid) {
		char buff[32] = { 0 };
		sprintf(buff, "%d-%d", grid.x, grid.y);
		return buff;
	}

	Data* find(const Grid& grid) {
		auto it = m_map.find(getKey(grid));
		if (it != m_map.end())
		{
			return it->second;
		}
		return nullptr;
	}

	void add(Data* data) {
		if (index < m_vec.size())
		{
			m_vec[index] = data;
		}
		else
		{
			m_vec.push_back(data);
		}
		index = m_vec.size();
		m_map[getKey(data->grid)] = data;
	}

	void sort() {
		std::sort(m_vec.begin(), m_vec.end(), [](Data* a, Data* b) {return a->f() < b->f(); });
	}

	void release() {
		for (auto it = m_map.begin(); it != m_map.end();)
		{
			Data* tmp = it->second;
			it = m_map.erase(it);
			delete tmp;
		}
	}
};



AStar::AStar()
{}

AStar::~AStar()
{
}


AStar::MapData* AStar::getMapDataByGrid(const Grid& grid, std::vector<std::vector<MapData>>& arr)
{
	auto& vec = arr[grid.x];
	for (auto &a:vec)
	{
		if (a.grid.y==grid.y)
		{
			return &a;
		}
	}
	return nullptr;
}

void AStar::findPath(const Grid& startPos, const Grid& endPos, std::vector<std::vector<MapData>>& arr, std::vector<Grid>& pathVec)
{
	//------可以拓展的六个方向
	std::vector<Grid> directs = {
		Grid( 1,-1, 0),
		Grid(-1, 1, 0),
		Grid( 1, 0,-1),
		Grid(-1, 0, 1),
		Grid( 0, 1,-1),
		Grid( 0,-1, 1)
	};
	MinHeap heap;
	heap.add(new Data(startPos, 0, 0, nullptr));
	bool finish = false;
	Data* lastData = nullptr;// 记录最后一个点的数据,用来反推路径 若为空则无路径可到达

	int max_l = 0;
	while (!finish && !heap.isEmpty())
	{
		Data* data = heap.getMinAndRemove();// 取出f值最小的点
		auto mapData = getMapDataByGrid(data->grid, arr);
		if (mapData->isSpace)
		{
			mapData->visited = true;// 将取出的点标识为已访问点
		}

		max_l = arr[data->grid.x].size();
		for (auto dir : directs)// 遍历六个方向的点
		{
			Grid pos = mapData->grid;
			pos += dir;
			if (pos.x >= 0 && pos.x < arr.size()
				&& pos.y < max_l)
			{
				auto c = getMapDataByGrid(pos,arr);
				if (!c)
				{
					continue;
				}
				if (endPos==pos)// 如果是终点,则跳出循环,不用再找
				{
					finish = true;
					lastData = data;
					break;
				}
				if (!c->isSpace||c->visited)// 如果不是空地,就不需要再扩展
				{
					continue;
				}

				auto nn = heap.find(pos);
				if (nn)
				{
					if (nn->g > data->g + 1)
					{
						nn->g = data->g + 1;
						nn->parent = data;
					}
				}
				else
				{
					heap.add(new Data(pos, pos.distance(endPos), data->g + 1, data));
				}
			}
		}
	}

	if (lastData)
	{
		// 反向找出路径
		pathVec.clear();
		auto mapData = getMapDataByGrid(lastData->grid, arr);
		if (mapData)
		{
			pathVec.push_back(mapData->grid);
		}
		while (lastData->parent)
		{
			lastData = lastData->parent;
			mapData = getMapDataByGrid(lastData->grid, arr);
			pathVec.push_back(mapData->grid);
		}
	}
	else
	{
		std::cout << "no path" << std::endl;
	}
	heap.release();
}

 实现效果:

猜你喜欢

转载自blog.csdn.net/auccy/article/details/115621229