编写简易斜45度地图编辑器
最近在研究cocos2dx的地图,最开始使用的是Tiled,这个编辑器做比较小的地图还是比较强大的,不过做大地图的时候,有一些功能不太方便并且有缺陷(包括刷图繁琐以及坐标体系过于复杂,导致寻路比较看起来很不平滑)。于是就酝酿着自己写一个斜45度的地图编辑器。
现在的自己老是不能集中注意力,经常出现思考着思考着就想睡觉的情况,所以导致这个工具写了2周,汗颜啊!使用MFC+GDI实现,目前已经完成的功能有:
1、tile坐标系设计和转换,右下X轴,右上Y轴。这是实现45度地图的关键呀。
2、拆分合并图片功能,我的这个地编需要在编辑时传入一张大图(贴小图的方式没有实现,自己太懒),在导出的时候在拆成小图。
3、刷阻挡位,刷透明位,批量刷阻挡以及清除阻挡和透明等。
4、一些显示和隐藏等状态设置的小功能。
目前基本能用了,后期准备加入配置NPC和热区的功能,暂时没有时间来实现。还有就是当前的合并图片和拆分图片使用的是CImage的功能,感觉拆出来的图比原图质量差一些,以后有时间再优化完善吧。
先上一个图吧,看看成果:
再上关键算法:
tile编码的算法:
enum OCC_FLAG
{
F_BLOCK = 0x01,
F_ALPHA = 0x02,
};
struct TileData
{
CPoint tile;
BYTE flag;
TileData() : flag(0) {}
}
for(int j = 0; j < m_yTile * 2 - 1; j++)
{
for(int i = 0; i < m_xTile * 2 - 1; i++)
{
if(i % 2 == j % 2)
{
CPoint ct = CPoint((i+1) * m_iGridWidth, m_iGridHeigh * (j + 1));
TileData td;
td.tile = Space2Tile(ct);
int idx = td.tile.x * 1000 + td.tile.y;
m_tiles.insert(std::make_pair(idx, td));
}
}
}
CPoint CMy45MapEditorDoc::Space2Tile(CPoint& screen)
{
CPoint center;
GetCursorDiamond(screen, center);
int x=(center.x/(m_iGridWidth * 2)+(center.y+m_iGridHeigh)/(m_iGridHeigh*2));
int y=center.x/(m_iGridWidth * 2)-center.y/(m_iGridHeigh*2)+m_yTile;
return CPoint(x, y);
}
//参数:
// POINT p 指定的某个点
// LPPOINT ptPolygon 多边形的各个顶点坐标(首末点可以不一致)
// int nCount 多边形定点的个数
BOOL PtInPolygon(POINT p, LPPOINT ptPolygon, int nCount)
{
int nCross = 0;
for (int i = 0; i < nCount; i++)
{
POINT p1 = ptPolygon[i];
POINT p2 = ptPolygon[(i + 1) % nCount];
// 求解 y=p.y 与 p1p2 的交点
if ( p1.y == p2.y ) // p1p2 与 y=p0.y平行
continue;
if ( p.y < min(p1.y, p2.y) ) // 交点在p1p2延长线上
continue;
if ( p.y >= max(p1.y, p2.y) ) // 交点在p1p2延长线上
continue;
// 求交点的 X 坐标 --------------------------------------------------------------
double x = (double)(p.y - p1.y) * (double)(p2.x - p1.x) / (double)(p2.y - p1.y) + p1.x;
if ( x > p.x )
nCross++; // 只统计单边交点
}
// 单边交点为偶数,点在多边形之外 ---
return (nCross % 2 == 1);
}
//判断点在不在菱形中
//pt-点指针
//x--菱形中心点横坐标
//y--菱形中心点纵坐标
BOOL CMy45MapEditorDoc::IsPtInDiamond(CPoint& pt, int x, int y)
{
POINT point4[4];
point4[0].x = x - m_iGridWidth;
point4[0].y = y;
point4[1].x = x;
point4[1].y = y - m_iGridHeigh;
point4[2].x = x + m_iGridWidth;
point4[2].y = y;
point4[3].x = x;
point4[3].y = y + m_iGridHeigh;
return PtInPolygon(pt, point4, 4);
}
//获取鼠标点中的那个菱形的中心点
//pt-------鼠标位置
//pCenter--返回中心点坐标
BOOL CMy45MapEditorDoc::GetCursorDiamond(CPoint& pt, CPoint& pCenter)
{
RECT Rect;
CRgn diamond;
Rect.left = pt.x / m_iGridWidth * m_iGridWidth;
Rect.top = pt.y / m_iGridHeigh * m_iGridHeigh;
Rect.right = Rect.left + m_iGridWidth