最近在研究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;
Rect.bottom = Rect.top + m_iGridHeigh;
if((Rect.left / m_iGridWidth % 2) == (Rect.top / m_iGridHeigh % 2))
{
pCenter.x = Rect.left, pCenter.y = Rect.top;
if(IsPtInDiamond(pt, Rect.left, Rect.top) == TRUE) return TRUE;
}
if((Rect.right / m_iGridWidth % 2) == (Rect.top / m_iGridHeigh % 2))
{
pCenter.x = Rect.right, pCenter.y = Rect.top;
if(IsPtInDiamond(pt, Rect.right, Rect.top) == TRUE) return TRUE;
}
if((Rect.left / m_iGridWidth % 2) == (Rect.bottom / m_iGridHeigh % 2))
{
pCenter.x = Rect.left, pCenter.y = Rect.bottom;
if(IsPtInDiamond(pt, Rect.left, Rect.bottom) == TRUE) return TRUE;
}
if((Rect.right / m_iGridWidth % 2) == (Rect.bottom / m_iGridHeigh % 2))
{
pCenter.x = Rect.right, pCenter.y = Rect.bottom;
if(IsPtInDiamond(pt, Rect.right, Rect.bottom)==TRUE) return TRUE;
}
return FALSE;
}

上面的代码就是生产tile的规则,下面是保存地图的代码:

BOOL CMy45MapEditorDoc::OnSaveDocument(LPCTSTR lpszPathName)
{
try
{
Blaze::ByteBuffer buff;
buff << (int)m_mapSize.cx << (int)m_mapSize.cy;     //地图尺寸
buff << m_iGridWidth << m_iGridHeigh;               //tile大小
buff << m_xTile << m_yTile;                         //tile尺寸
buff << m_xSplit << m_ySplit;                       //图元尺寸
std::string fileNameDif  = groundPath;
fileNameDif = fileNameDif.substr(fileNameDif.rfind(".") + 1, fileNameDif.size());
buff << fileNameDif;
buff << (int)(m_tiles.size());            //tile数量
for (TileMap::iterator it = m_tiles.begin(), ite = m_tiles.end(); it != ite; ++it)
{
int idx = it->first;
TileData* tileD = &it->second;
buff << idx << tileD->flag;
}
FILE* file = fopen(lpszPathName, "wb");
if (file)
{
fwrite(buff.contents(), 1, buff.size(), file);
fclose(file);
theApp.SpliteImage(groundPath, m_xSplit, m_ySplit, lpszPathName);
}
}
catch (CException* e)
{
AfxMessageBox("保存地图文件失败!");
return FALSE;
}
return TRUE;
}

最后是读取地图的代码:

BOOL CMy45MapEditorDoc::OnOpenDocument(LPCTSTR lpszPathName)
{
if (!CDocument::OnOpenDocument(lpszPathName))
return FALSE;
try
{
Blaze::ByteBuffer buff;
FILE* file = fopen(lpszPathName, "rb");
if (file)
{
while (!feof(file))
{
char buf[1024];
int size = fread(buf, 1, 1024, file);
buff.append((unsigned char*)buf, size);
}
int sx, sy;
buff >> sx >> sy;                           //地图尺寸
buff >> m_iGridWidth >> m_iGridHeigh;       //tile大小
buff >> m_xTile >> m_yTile;                 //tile尺寸
buff >> m_xSplit >> m_ySplit;               //图元尺寸
m_mapSize = CSize(sx, sy);
std::string fileNameDif;
buff >> fileNameDif;
std::string fileName(lpszPathName);
fileName = fileName.substr(0, fileName.rfind("."));
groundPath.Format("%s.%s", fileName.c_str(), fileNameDif.c_str());
if(m_pict.Load(groundPath))
{
int tileSize;
buff >> tileSize;
for (int i = 0; i < tileSize; ++i)
{
TileData td;
int tileIdx;
buff >> tileIdx >> td.flag;
td.tile.y = tileIdx % 1000;
td.tile.x = tileIdx / 1000;
m_tiles.insert(std::make_pair(tileIdx, td));
}
}
return TRUE;
}
}
catch (CException* e)
{
AfxMessageBox("打开地图文件失败!");
}
return FALSE;
}

配上原来实现的A*算法寻路效果相当好,在安卓上运行内存占用比用Tiled少了一半多,后面还可以加上底图视野管理,每次只加载9张底图,内存占用会更少。

下面给个测试版给大家试用一下,大家有什么意见可以反馈给我,暂时不开源,等完善之后再考虑开源吧!

45度地图编辑器DEMO

编写简易斜45度地图编辑器相关推荐

  1. cocos2dx使用TiledMap模拟3D地图场景----斜45度2D地图的靠墙直线移动

     基于cocos2dx引擎的第三人称射击游戏,角色使用3D模型,地图采用2.5D.  定制地图编辑系统抛开不谈,这里最大可能的挖掘现有工具TiledMap的潜力,完成超2.5D地图的实现.  使用2D ...

  2. Tiled实现斜45度瓦片地图

    首先是我最近在做的一个项目的需求,要做一个斜45度角的大地图,里面有很多的建筑,会有人在里面走来走去.一个手指按住滑动可以拖动地图,两个手指按下可以调整地图的放大和缩小. 1.tiled新建地图,加入 ...

  3. 斜45度瓦片地图(Staggered Tiled Map)里的简单数学

    瓦片地图(Tiled Map)系列文章: 斜45度瓦片地图(Staggered Tiled Map)里的简单数学 瓦片地图注意事项 前段时间在做游戏的地图编辑功能,我们是在一个斜45度视角的场景上,对 ...

  4. 45 度角地图-----斜45度角地图拼接

    45 度角地图, 可以分为 Staggered, slid 和 Diamond 三种类型 先看看地图元素: 可以看出来是个扁的菱形.这个地图元素的大小是64X32,你可以随意决定元素长宽,在设计程序时 ...

  5. 45度地图之整体旋转

    假设有如下一幅地图(左边为数组地图,右边为对应的位图地图),这幅地图对应的是一个一维数组int map[16],且我们知道总共有4行,4列,对于数组中的元素我们可以通过下面的公式求出它所在的行列, 第 ...

  6. 45度地图遮挡问题解决方案(cocos2d-x)

    最近一直在做45度斜视角游戏,也就是isometric等容地图,俗称2.5D.地图上物体的前后遮挡是我遇到的第一个问题,总结一下处理方法. 遮挡问题(不知道术语),就是比如一个角色站在树后面,那么树要 ...

  7. D3D游戏编程系列(二):自己动手编写即时战略游戏之地图编辑器的制作

    说起即时战略游戏,我第一时间想起魔兽争霸,这个不知道陪伴我多少个日日夜夜,让我哭让我笑的游戏,让我想起了sky,moon,grubby等人牵动心弦的战斗历程,让我想起了当年日日守在电脑前专注的欣赏着w ...

  8. Java中2.5D游戏(斜45度角)的设计与实现(1)

    通常的概念中,2D也就是所谓的二维,也就是平面图形--即由X与Y坐标构成的图形,其内容由水平的X轴向与垂直的Y轴描绘确定,也就是由长和高的形成所谓的二维平面. 而所谓3D,也称之为三维.其图形内容除了 ...

  9. COCOS2D-X中45度地图通过位置获得对应行列数中的三角变换理解

    晚上看COCOS2d-X的瓦片地图集这块,发现有2种地图,普通的和45度视角的.普通的通过位置获取所在行列数比较简单,大概就是具体的位置除以图素的宽高,而45度脚的方法则能够实现2.5D的效果,理解起 ...

最新文章

  1. Panabit安装测试小结
  2. dynamic_caast操作符
  3. uva5984(简单计算几何)
  4. 前端面试题(附上自己的回答)
  5. spring批量写入mysql数据库_MyBatis-spring和spring JDBC批量插入Mysql的效率比较
  6. Swift 编程语言
  7. Could not find class
  8. 树分解 tree decomposition
  9. 解决intellij idea卡顿的方法
  10. arduino交通灯编程代码_Arduino初初教程3 (交通灯)
  11. ubuntu linux ftp命令的使用
  12. OpenCV-Python教程:图像金字塔
  13. 比特客区块链 | 从A到Z速记区块链词汇表
  14. Python绘制箱形图全解
  15. 解析改变测试自动化的协作机器人
  16. 港科夜闻|香港科技大学参与共建「粤港水安全保障联合实验室」,开展水资源风险评估等方面交叉研究和成果转化...
  17. (九)统计学习方法 | 隐马尔可夫模型
  18. 计算机毕业设计ssm校园竞赛管理系统设计与实现hyr9b系统+程序+源码+lw+远程部署
  19. openEuler Meetup 南京站 | 麒麟信安加入南京用户组,分享《CentOS原地透明迁移方案技术实践》
  20. 《正面管教》思维导图图解,找对教育孩子好方法

热门文章

  1. 如何通过CRM进行客户来源统计与分析?
  2. python ide安装_python IDE Eric6安装
  3. VC++获取CPU的名称、主频和核数(附源码)
  4. 全国电子设计大赛2019年前历届优秀作品,肯定对你电赛之路有所帮助!
  5. 14 实例:自动轨迹绘制
  6. End-to-end Learning for Inter-Vehicle Distance and Relative Velocity Estimation in ADAS with a Monoc
  7. KEIL软件的Error: Flash Download failed - Could not load file ‘...axf‘解决思路
  8. 专访唐九洲:与开发者“在一起,梦飞扬”
  9. Mysql复习计划(一)- 字符集、文件系统和SQL执行流程
  10. 禁止navigationController左滑手势