地图在游戏中是我们经常用到的,在地图上我么可以设置一些物体,添加一些属性,利用这些属性在程序中编写我们的逻辑。今天我们来学习使用Tiled Map Editor软件来生成TMX格式的地图,以及用到的一些和tiled地图相关的类的使用方法。先来看看都用到哪些类和方法,有个大体的了解。CCTMXTiledMap这个类对应瓦片地图,里边传入的参数就是我们将用到的软件生成的,关于这个软件大家可以去下载。CCTMXlayer对应的是图层类,在软件的使用过程中我会说明,CCTMXObjectGroup对应的是对象层,同样在软件使用过程中说明。

Tiled地图

首先说明一下如何使用Tiled Map Editor这个软件,用的时候注意和上边的这些类相对照。在软件的菜单栏点击地图->新图块,出现下图。

Tiled地图

在浏览中选择我们要添加的图片,这里使用的是引擎自带的资源,在如下的路径E:\cocos2d-x-2.2\cocos2d-x-2.2\samples\Cpp\TestCpp\Resources\TileMaps\tmw_desert_spacing.png大家将这个PNG文件拷贝到我们的资源文件夹下,然后选择图片。其他的值按照图示添加就可以。添加好了以后在软件的右下角有图示的样子。

Tiled地图

这些就是我们用到的资源,在右上角建立一个图层(原来有一个图层,这里给它改个名字就行)和一个对象层(单击鼠标右键点击新建对象层)。这里用到的图层和对象层就是上边的那俩个类。

Tiled地图

点击工具栏的图章按钮,然后选择右下角的资源,就可以在中间自由作图了,关于工具栏其他工具的使用大家可以自己研究(在右上角的图层区域中选择mapLayer图层才可以画图)。

Tiled地图

这个就是我做出的图。接下来在右上角选择objLayer对象层,我们在这个地图上添加几个对象。工具都在工具栏的后边。可以添加矩形对象和图块对象,单击右键为它们添加属性,我添加的几个属性如下。

Tiled地图 Tiled地图 Tiled地图

有关该软件的具体操作,这里没法详细说明,这里列出关键步骤只是为了以后便于在程序中说明。其中最主要的一点是tiled地图的坐标系统,是以地图块为单位的。我放上一张图片,大家就看清楚了,这个坐标一定要看清楚,后边程序中还要转化,而且理解它的坐标系统一些东西你才会理解的透彻。

Tiled地图

下面我们就在程序中看看具体的怎么使用上边的三个类做一些事情。

Tiled地图

//头文件中声明三个变量,分别是tiled地图,图层,对象层
public:
	CCTMXTiledMap * tiledMap;
	CCTMXLayer * mapLayer;
	CCTMXObjectGroup * objectGroup;
bool HelloWorld::init()
{
    bool bRet = false;
    do
    {
        CC_BREAK_IF(! CCLayer::init());
		//参数就是我们通过tiled map editor获得的文件
        tiledMap = CCTMXTiledMap::create("map.tmx");
		//添加tiledMap的时候不需要设置坐标和锚点
		this->addChild(tiledMap);
		//通过tiledMap调用layerNamed()函数获得图层,参数就是我们在软件中设置的那个图层名称啊
		mapLayer = tiledMap->layerNamed("mapLayer");
		//通过tiledMap调用objectGroupNamed()获得对象层,参数同样是我么在软件中设置的那个对象层的名称
		objectGroup = tiledMap->objectGroupNamed("objLayer");

		//开启屏幕触摸
		this->setTouchEnabled(true);

        bRet = true;
    } while (0);

    return bRet;
}

//为屏幕注册触摸事件
void HelloWorld::registerWithTouchDispatcher()
{
	CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this,0,true);
}

//实现ccTouchBegan()协议方法
bool HelloWorld::ccTouchBegan(CCTouch * touch,CCEvent * pEvent)
{
	CCPoint touchPoint = touch->getLocation();
	//将opengl坐标转化为tiledMap坐标,getMapPoint函数是我么自己实现的
	CCPoint mapPoint = this->getMapPoint(touchPoint);

	//以下代码的功能是为了获得图层的属性
	//获得tiledMap坐标的目的就是获得在这个坐标位置的图块的GID(全球标识),传入的参数就是tiledMap坐标
	//图块的GID是从1开始的(对应软件右下角的第一个图块),大家可以看一下自己右下角的图块,数一数你地图上的图块对应的GID
	int gid = mapLayer->tileGIDAt(mapPoint);
	CCLog("x = %.0f,y = %.0f,gid = %d",mapPoint.x,mapPoint.y,gid);
	//根据图块的gid我们可以得到图块的属性字典,前提是这个图块有属性,否则字典是空的
	//这里的属性是在选中mapLayer图层的时候为图块整体添加的,在右下角处添加的(选中一个图块,单击右键),和对象层没有关系
	CCDictionary * dic = tiledMap->propertiesForGID(gid);
	if(dic)
	{
		CCString * string = (CCString *)dic->objectForKey("key1");
		CCLog("%s",string->getCString());
	}

	return false;
}

//将触摸点(opengl坐标)转换为tiled地图上的坐标,单位是块
CCPoint HelloWorld::getMapPoint(CCPoint touchPoint)
{
	//用tiledMap调用getTileSize()函数获得的是每个图块的尺寸大小,以本例为例的话就是32*32
	//调用getMapSize()获得的是tiled地图的大小,单位是块,在本例中是(15,10)
	//opengl坐标是以左下角为原点,x轴向右增加,y轴向上增加,而tiled地图的坐标是以左上角为原点,y轴向下增加
	//所以转化方法就是用touchPoint除以地图块的宽度,而高度需要先减一下,方法如下
	int x = touchPoint.x/tiledMap->getTileSize().width;
	int y = ((tiledMap->getTileSize().height)*(tiledMap->getMapSize().height)-touchPoint.y)/tiledMap->getTileSize().height;
	return ccp(x,y);
}

接下来看看我们如何使用对象层。这里只是修改了ccTouchBegan的方法。
Tiled地图

bool HelloWorld::ccTouchBegan(CCTouch * touch,CCEvent * pEvent)
{
	//以下代码实现的功能是当鼠标点击对象所在的区域时,会产生一个精灵
	//获得对象层的对象属性,传入的就是对象的名字
	CCDictionary * objDic = objectGroup->objectNamed("objTest");
	//不需要对objDic进行判断,因为它至少有x,y,width,height属性
	//以下的x,y是转化后的opengl坐标下的x,y
	int x = ((CCString *)objDic->objectForKey("x"))->intValue();
	int y = ((CCString *)objDic->objectForKey("y"))->intValue();
	int w = ((CCString *)objDic->objectForKey("width"))->intValue();
	int h = ((CCString *)objDic->objectForKey("height"))->intValue();
	CCRect rect = CCRect(x,y,w,h);
	if(rect.containsPoint(touchPoint))
	{
		CCSprite * sprite = CCSprite::create("image.png");
		sprite->setPosition(touchPoint);
		this->addChild(sprite);
		return true;
	}

	return false;
}