正六边形:以指定位置为原点平铺

正六边形:平铺一文中,平铺是以左下角为中心进行平铺,项目需要以指定点为中心进行平铺,因此对平铺逻辑做了调整,在此记录下,以备后查。

核心代码如下:



#ifndef __TKHexagonGrid__
#define __TKHexagonGrid__

#include <vector>

const double cubeSideLen = 50;
const double mathSqrt3 = 1.732051;
const double cubeSideLen_X_mathSqrt3 = cubeSideLen * mathSqrt3;
const double halfSideLen = cubeSideLen * 0.5;
const double halfSideLen_X_mathSqrt3 = halfSideLen * mathSqrt3;
const double oneAndAHalfSideLen = cubeSideLen * 1.5;

class Grid
{
public:
	Grid() {}
	Grid(int x, int y,int z=0) {
		this->x = x;
		this->y = y;
		this->z = z;
	}

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

	double posX = 0;
	double posY = 0;

	void updateZ();
	int getYIdx() const;

	double distance(const Grid& grid);

	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;
	}

	Grid operator+(const Grid& grid) {
		return add(grid);
	}

	Grid scale(int k) {
		return Grid(this->x*k,this->y*k,this->z*k);
	}

	Grid add(const Grid& grid) {
		return Grid(this->x + grid.x, this->y + grid.y, this->z + grid.z);
	}

	Grid neighbor(int direction);
	bool posInGrid(const double& posX, const double& posY, bool& xMoreThanHalf);
};


class GridHelper
{
public:
	static Grid direction(unsigned idx);
	/*
		centenrGrid:中心六边形网格
		radius:距离centenrGrid的步长
		ringsVec:距离centenrGrid步长为radius的所有网格信息
	*/
	static void getGridRingsByRadius(const Grid& centenrGrid,const int radius, std::vector<Grid>& ringsVec);
	static void getPosByGrid(const int gridX, const int gridY, Grid& pos);
	static void getGridByPos(const double posX, const double posY, Grid& grid);
	static int getTwoGridDistance(const double startPosX, const double startPosY, const double endPosX, const double endPosY,double &distance);
	//设置平铺的中心坐标
	static void setCenterPos(const double posX, const double posY);
protected:
	static void getGridY(const int gridX, const double posX,const double posY,int &gridY);
	//平铺中心的世界坐标
	static double m_centerPosX;
	static double m_centerPosY;
};

#endif /* defined(__TKHexagonGrid__) */

#include "TKHexagonGrid.h"
#include <algorithm>

void Grid::updateZ()
{
	this->z = -(this->x + this->y);
}

int Grid::getYIdx() const
{
	//y is an offset data,equal row sub col
	return this->y + this->x;
}

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

Grid Grid::neighbor(int direction)
{
	return this->add(GridHelper::direction(direction));
}

bool Grid::posInGrid(const double& posX, const double& posY, bool& xMoreThanHalf)
{
	const double dx = std::abs(this->posX - posX);
	const double dy = std::abs(this->posY - posY);
	if (dx <= halfSideLen)
	{
		return dy <= halfSideLen_X_mathSqrt3;
	}
	else
	{
		xMoreThanHalf = true;
		const double maxY = -mathSqrt3 * (dx - halfSideLen) + halfSideLen_X_mathSqrt3;
		return dy < maxY;
	}
}

/********************************/
/********************************/
/********************************/

double GridHelper::m_centerPosX = 0.0;
double GridHelper::m_centerPosY = 0.0;

const std::vector<Grid> _neighbourVec = {
	Grid( 1, 0,-1),
	Grid( 1,-1, 0),
	Grid( 0,-1, 1),
	Grid(-1, 0, 1),
	Grid(-1, 1, 0),
	Grid( 0, 1,-1),
};

Grid GridHelper::direction(unsigned idx)
{
	return _neighbourVec[idx];
}

void GridHelper::getGridRingsByRadius(const Grid& centenrGrid, const int radius, std::vector<Grid>& ringsVec)
{
	ringsVec.clear();
	Grid grid = GridHelper::direction(4).scale(radius);
	for (int side = 0; side < 6; side++) {
		for (int step = 0; step < radius; step++) {
			ringsVec.push_back(grid + centenrGrid);
			grid = grid.neighbor(side);
		}
	}
}

void GridHelper::getPosByGrid(const int gridX, const int gridY, Grid& pos)
{
	const int y = gridY - gridX / 2;
	pos.x = gridX;
	pos.y = gridY - gridX;
	pos.posX = gridX * oneAndAHalfSideLen;
	if (gridX % 2 == 0)
	{
		pos.posY = cubeSideLen_X_mathSqrt3 * y;
	}
	else
	{
		if (gridX>=0)
		{
			pos.posY = cubeSideLen_X_mathSqrt3 * (y - 0.5);
		}
		else
		{
			pos.posY = cubeSideLen_X_mathSqrt3 * (y + 0.5);
		}
	}
	pos.posX += m_centerPosX;
	pos.posY += m_centerPosY;
}

void GridHelper::getGridY(const int gridX, const double posX,const double posY, int& gridY)
{
	const bool xGreatThanZero = posX >= 0;
	const bool yGreatThanZero = posY >= 0;
	gridY = 0;
	if (gridX % 2 == 0)
	{
		if (yGreatThanZero)
		{
			gridY = posY / cubeSideLen_X_mathSqrt3 + 0.5;
		}
		else 
		{
			gridY = posY / cubeSideLen_X_mathSqrt3 - 0.5;
		}
	}
	else
	{
		if (yGreatThanZero)
		{
			gridY = posY / cubeSideLen_X_mathSqrt3 + 1;
		}
		else
		{
			gridY = posY / cubeSideLen_X_mathSqrt3;
		}
	}
	
	if (xGreatThanZero)
	{
		gridY -= (gridX + 1) / 2;
	}
	else 
	{
		gridY -= gridX / 2;
	}
}

void GridHelper::getGridByPos(const double px, const double py, Grid& grid)
{
	//获得相对地图中心点的坐标
	const double posX = px - m_centerPosX;
	const double posY = py - m_centerPosY;

	const bool xGreatThanZero = posX >= 0;

	const double gridD = posX/ oneAndAHalfSideLen + (xGreatThanZero ? 0.5 : -0.5);
	int gridX = gridD;
	int gridY = 0;
	GridHelper::getGridY(gridX, posX,posY, gridY);

	grid.x = gridX;
	grid.y = gridY;

	GridHelper::getPosByGrid(gridX, grid.getYIdx(), grid);
	bool xMoreThanHalf = false;
	if (!grid.posInGrid(px, py, xMoreThanHalf))
	{
		if (xMoreThanHalf)
		{
			if (xGreatThanZero)
			{
				if (gridD > gridX + 0.5)
				{
					gridX += 1;
				}
				else
				{
					gridX -= 1;
				}
			}
			else
			{
				if (gridD > gridX - 0.5)
				{
					gridX += 1;
				}
				else
				{
					gridX -= 1;
				}
			}
			GridHelper::getGridY(gridX, posX, posY, gridY);
		}
		else
		{
			if (grid.posY > py)
			{
				gridY -= 1;
			}
			else
			{
				gridY += 1;
			}
		}
	}

	grid.x = gridX;
	grid.y = gridY;
	grid.updateZ();
	//posX/posY 需要记录传入的坐标
	grid.posX = px;
	grid.posY = py;;
}

int GridHelper::getTwoGridDistance(const double startPosX, const double startPosY, const double endPosX, const double endPosY, double& distance)
{
	Grid startGrid, endGrid;
	GridHelper::getGridByPos(startPosX, startPosY, startGrid);
	GridHelper::getGridByPos(endPosX, endPosY, endGrid);
	const int dx = std::abs(startGrid.x - endGrid.x);
	const int dy = std::abs(startGrid.y - endGrid.y);
	const int dz = std::abs(startGrid.z - endGrid.z);
	int radius = std::max(dx, std::max(dy, dz));

	//两个网格间的距离【移动消耗】【无阻挡点有效】
	//对角线消耗2,对边消耗1.73,边界消耗1
	//通过对角线必然经过边界
	distance = 0;
	int diagonalStep = std::min(dx, std::min(dy, dz));
	distance = diagonalStep * (2/*对角线消耗*/+1/*边界消耗*/) + (radius - diagonalStep*2) * mathSqrt3;
	return radius;
}

void GridHelper::setCenterPos(const double posX, const double posY)
{
	m_centerPosX = posX;
	m_centerPosY = posY;
}

寻路效果图:

demo地址:https://github.com/jjinglover/MyCocosDemo/tree/main/%E6%AD%A3%E5%85%AD%E8%BE%B9%E5%BD%A2%E5%AF%BB%E8%B7%AF 

猜你喜欢

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