cocos2d-x 游戏 之 Tiled Map Editor(地图编辑)
转载于:http://blog.csdn.net/zhy_cheng/article/details/8308609
Tiled Map Editor是Cocos2d-x支持的地图编辑器,使用Tiled编辑出的地图可以很方便的被Cocos2d-x使用Tiled的官网是Tiled Map Editor。我使用的地图编辑器是QT版本。
好了,下面就试一试吧。
1.编辑地图
选择文件----->新文件
然后选择地图----->新图块,选择Tiled安装目录下的examples里的图片
在这里图片中间和最左边最上边都有黑线,所以绘制偏移1个像素,边距和间距都为一。
下面将图层的名字改为floor,作为地板。
把地板铺上砖。
新建一个图层,改名为wall,在上面摆上自己喜欢的东西吧。我设计成如下:
下一步是设置主角,这也比较难的一步。
选择图层------>添加对象层,改对象层为hero。
现在在对象层中添加对象。点击工具栏上的添加对象,在地图上话按住鼠标拖出一块。右击该块,改成如下
我们看到,下面可以添加名称和值,其实这就是键值对。今后会用对,现在还没有必要用到。
好了,地图编辑好了,先设置参数 ,点击编辑----->参数,设置为下
保存地图。
2.使用地图
使用文本编辑器打开刚才编辑好的地图,将
<image source="D:/application/Tiled/examples/tmw_desert_spacing.png" width="265" height="199"/>
改为
<image source="tmw_desert_spacing.png" width="265" height="199"/>
新建一个Cocos2d-x的项目,将地图文件和打开的图块文件复制到resource文件夹下。
在头文件中加入
- cocos2d::CCTMXTiledMap *_tileMap;
cocos2d::CCTMXTiledMap *_tileMap;
将init函数中的菜单,精灵,文字的代码删除,加入下面的代码:
- _tileMap=CCTMXTiledMap::create("theMap.tmx");
- addChild(_tileMap);
_tileMap=CCTMXTiledMap::create("theMap.tmx");
addChild(_tileMap);
编译运行,效果如下
下面从地图中获得精灵的位置,在头文件中加入精灵的声明
- cocos2d::CCSprite *_player;
cocos2d::CCSprite *_player;
在源文件中添加如下代码
- CCTMXObjectGroup *objects=_tileMap->objectGroupNamed("hero");//获取对象层
- CCDictionary *spawnPoint=objects->objectNamed("pa");//获取对象
- const CCString *x=spawnPoint->valueForKey("x");//获取对象的坐标
- const CCString *y=spawnPoint->valueForKey("y");
- /
- char *tempx=new char[30];//这里的代码将CCString转换为int
- char *tempy=new char[30];
- memset(tempx,0,30);
- memset(tempy,0,30);
- sprintf(tempx,x->getCString());
- sprintf(tempy,y->getCString());
- int px=atoi(tempx);
- int py=atoi(tempy);
- delete tempx;
- delete tempy;
- //
- _player=CCSprite::create("www.png");
- _player->setPosition(ccp(px,py));
- addChild(_player);
CCTMXObjectGroup *objects=_tileMap->objectGroupNamed("hero");//获取对象层
CCDictionary *spawnPoint=objects->objectNamed("pa");//获取对象
const CCString *x=spawnPoint->valueForKey("x");//获取对象的坐标
const CCString *y=spawnPoint->valueForKey("y");
/
char *tempx=new char[30];//这里的代码将CCString转换为int
char *tempy=new char[30];
memset(tempx,0,30);
memset(tempy,0,30);
sprintf(tempx,x->getCString());
sprintf(tempy,y->getCString());
int px=atoi(tempx);
int py=atoi(tempy);
delete tempx;
delete tempy;
///
_player=CCSprite::create("www.png");
_player->setPosition(ccp(px,py));
addChild(_player);
这里创建精灵,并且从地图中获得精灵的位置,从而设置精灵的位置。下面是效果图
下面接着让这个hero可以移动,先添加鼠标响应,在init中添加如下代码
- CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this,0,false);
CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this,0,false);
接着覆盖父类的鼠标响应消息
- bool HelloWorld::ccTouchBegan(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent)
- {
- return 1;
- }
- void HelloWorld::ccTouchEnded(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent)
- {
- cocos2d::CCPoint pp=pTouch->getLocation();
- if(fabs(pp.x-_player->getPosition().x)>=fabs(pp.y-_player->getPosition().y))
- {
- if(pp.x>=_player->getPosition().x)
- {
- _player->setPosition(ccp(_player->getPosition().x+32,_player->getPosition().y));
- }
- else
- {
- _player->setPosition(ccp(_player->getPosition().x-32,_player->getPosition().y));
- }
- }
- else
- {
- if(pp.y>=_player->getPosition().y)
- {
- _player->setPosition(ccp(_player->getPosition().x,_player->getPosition().y+32));
- }
- else
- {
- _player->setPosition(ccp(_player->getPosition().x,_player->getPosition().y-32));
- }
- }
- }
bool HelloWorld::ccTouchBegan(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent)
{
return 1;
}
void HelloWorld::ccTouchEnded(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent)
{
cocos2d::CCPoint pp=pTouch->getLocation();
if(fabs(pp.x-_player->getPosition().x)>=fabs(pp.y-_player->getPosition().y))
{
if(pp.x>=_player->getPosition().x)
{
_player->setPosition(ccp(_player->getPosition().x+32,_player->getPosition().y));
}
else
{
_player->setPosition(ccp(_player->getPosition().x-32,_player->getPosition().y));
}
}
else
{
if(pp.y>=_player->getPosition().y)
{
_player->setPosition(ccp(_player->getPosition().x,_player->getPosition().y+32));
}
else
{
_player->setPosition(ccp(_player->getPosition().x,_player->getPosition().y-32));
}
}
}
在这里,先在ccTouchBegan中返回true,以便在ccTouchEnded中处理事件。
原理是先判断鼠标点击的点与hero现在的点是在x方向还是在y方向上的距离大,若在x方向上距离大,则改变x左边,若在y方向上距离大,则改变y的坐标。然后使hero向着点击点移动。
下面是效果图
对上面的一些代码进行优化,一个是从对象获取对象的坐标。上次使用的代码有点麻烦,现在改为下面的代码:
- CCTMXObjectGroup *objects=_tileMap->objectGroupNamed("hero");//获取对象层
- CCDictionary *spawnPoint=objects->objectNamed("pa");//获取对象
- heroPoint.x=spawnPoint->valueForKey("x")->floatValue();//获取对象的坐标
- heroPoint.y=spawnPoint->valueForKey("y")->floatValue();
- CCLog("x=%f,y=%f",heroPoint.x,heroPoint.y);
CCTMXObjectGroup *objects=_tileMap->objectGroupNamed("hero");//获取对象层
CCDictionary *spawnPoint=objects->objectNamed("pa");//获取对象
heroPoint.x=spawnPoint->valueForKey("x")->floatValue();//获取对象的坐标
heroPoint.y=spawnPoint->valueForKey("y")->floatValue();
CCLog("x=%f,y=%f",heroPoint.x,heroPoint.y);
这是因为我找到了一个函数,直接获得float值。
将hero放到地图中,随地图一起移动。
- _player=CCSprite::create("www.png");
- _player->setAnchorPoint(CCPoint(0,0));
- _player->setPosition(heroPoint);
- _tileMap->addChild(_player,0);
_player=CCSprite::create("www.png");
_player->setAnchorPoint(CCPoint(0,0));
_player->setPosition(heroPoint);
_tileMap->addChild(_player,0);
还有一个地方就是,要严格判断用户是点击还是拖动,在头文件中声明beginPoint,在ccTouchBegan函数中赋值,在ccTouchEnded中判断,只要这个点与beginPoint相同,则为点击。
对于判断地图的拖动,则放到了ccTouchMoved中,这样用户体验更好。
- void HelloWorld::ccTouchMoved(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent)
- {
- CCPoint pp=pTouch->getPreviousLocation();//获取之前的点
- CCPoint np=pTouch->getLocation();//获取现在的点
- CCPoint dp=ccpSub(np,pp);//获取差
- if(_tileMap->getPosition().x+dp.x>-480&&_tileMap->getPosition().x+dp.x<0)
- {
- mapPoint=ccp(_tileMap->getPosition().x+dp.x,0);
- _tileMap->setPosition(mapPoint);//移动地图
- }
- }
void HelloWorld::ccTouchMoved(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent)
{
CCPoint pp=pTouch->getPreviousLocation();//获取之前的点
CCPoint np=pTouch->getLocation();//获取现在的点
CCPoint dp=ccpSub(np,pp);//获取差
if(_tileMap->getPosition().x+dp.x>-480&&_tileMap->getPosition().x+dp.x<0)
{
mapPoint=ccp(_tileMap->getPosition().x+dp.x,0);
_tileMap->setPosition(mapPoint);//移动地图
}
}
好了,优化都做完了,现在开始新的知识。
3.碰撞检测
获取建筑层,在hero移动的时候,检测该层是否有建筑,有则不让hero移动。wall->tileGIDAt()这个函数获得在某一个Tile的块是那一块,图块都被编号了,从1开始,如果wall没有图块的话则为0.
- if(9-_player->getPosition().y/32<10&&9-_player->getPosition().y/32>=0&&_player->getPosition().x/32-1<50&&_player->getPosition().x/32-1>=0&&!(wall->tileGIDAt(ccp(_player->getPosition().x/32-1,9-_player->getPosition().y/32))))
- {
- _player->setPosition(ccp(_player->getPosition().x-32,_player->getPosition().y));}
if(9-_player->getPosition().y/32<10&&9-_player->getPosition().y/32>=0&&_player->getPosition().x/32-1<50&&_player->getPosition().x/32-1>=0&&!(wall->tileGIDAt(ccp(_player->getPosition().x/32-1,9-_player->getPosition().y/32))))
{
_player->setPosition(ccp(_player->getPosition().x-32,_player->getPosition().y));}
这行代码就是先判断将要去的位置是否在地图中,然后判断是否有建筑,没有建筑则让hero移动。
4.动态修改地图
这原来的地图上再建一个图层,改为foreground,在这个图层中添加一些西瓜,用于沙漠中的hero解渴。
做好之后地图为
然后判断hero所在的位置是否有西瓜,若有,则在foreground中移除西瓜,表示hero吃了西瓜。
- if(9-_player->getPosition().y/32<10&&9-_player->getPosition().y/32>=0&&
- _player->getPosition().x/32-1<50&&_player->getPosition().x/32-1>=0&&
- !(wall->tileGIDAt(ccp(_player->getPosition().x/32-1,9-_player->getPosition().y/32))))
- {
- _player->setPosition(ccp(_player->getPosition().x-32,_player->getPosition().y));
- if(foreground->tileGIDAt(ccp(_player->getPosition().x/32,9-_player->getPosition().y/32)))
- {
- foreground->removeTileAt(ccp(_player->getPosition().x/32,9-_player->getPosition().y/32));
- }
- }
if(9-_player->getPosition().y/32<10&&9-_player->getPosition().y/32>=0&&
_player->getPosition().x/32-1<50&&_player->getPosition().x/32-1>=0&&
!(wall->tileGIDAt(ccp(_player->getPosition().x/32-1,9-_player->getPosition().y/32))))
{
_player->setPosition(ccp(_player->getPosition().x-32,_player->getPosition().y));
if(foreground->tileGIDAt(ccp(_player->getPosition().x/32,9-_player->getPosition().y/32)))
{
foreground->removeTileAt(ccp(_player->getPosition().x/32,9-_player->getPosition().y/32));
}
}
使用foreground->removeTileAt(CCPoint &pt)这个函数移除图块。
5.创建一个积分器
创建一个积分器,显示hero吃了多少西瓜,在头文件中声明一个int的count,每当hero吃了一个西瓜,就加一。然后创建一个CCLabelTTF显示出来。
- if(foreground->tileGIDAt(ccp(_player->getPosition().x/32,9-_player->getPosition().y/32)))
- {
- foreground->removeTileAt(ccp(_player->getPosition().x/32,9-_player->getPosition().y/32));
- count++;
- CCString *temp=CCString::stringWithFormat("%d",count);
- label->setString(temp->getCString());
- }
if(foreground->tileGIDAt(ccp(_player->getPosition().x/32,9-_player->getPosition().y/32)))
{
foreground->removeTileAt(ccp(_player->getPosition().x/32,9-_player->getPosition().y/32));
count++;
CCString *temp=CCString::stringWithFormat("%d",count);
label->setString(temp->getCString());
}
吃了西瓜后,计数加一,改变CCLabelTTF的值。
最后还应该加入一些音效,前面讲过,就不多说了。
下面来几张截图:
这张图吃了3个西瓜
6.添加敌人
在对象层中加入敌人,
- for(int i=0;i<int(objects->getObjects()->count());i++)
- {
- CCDictionary *enemy=(CCDictionary *)objects->getObjects()->objectAtIndex(i);
- if(enemy->valueForKey("n")->intValue()==1)
- {
- CCSprite *s=CCSprite::create("enemy1.png");
- float x=enemy->valueForKey("x")->floatValue();
- float y=enemy->valueForKey("y")->floatValue();
- s->setPosition(ccp(x,y));
- s->setAnchorPoint(CCPoint(0,0));
- _tileMap->addChild(s,4);
- CCActionInterval *move=CCMoveBy::create(2,CCPoint(_player->getPosition().x-s->getPosition().x>0?10:-10,_player->getPosition().y-s->getPosition().y>0?10:-10));//
- CCFiniteTimeAction *func=CCCallFuncN::create(this,callfuncN_selector(HelloWorld::goon));
- s->runAction(CCSequence::create(move,func,NULL));
- }
- }
for(int i=0;i<int(objects->getObjects()->count());i++)
{
CCDictionary *enemy=(CCDictionary *)objects->getObjects()->objectAtIndex(i);
if(enemy->valueForKey("n")->intValue()==1)
{
CCSprite *s=CCSprite::create("enemy1.png");
float x=enemy->valueForKey("x")->floatValue();
float y=enemy->valueForKey("y")->floatValue();
s->setPosition(ccp(x,y));
s->setAnchorPoint(CCPoint(0,0));
_tileMap->addChild(s,4);
CCActionInterval *move=CCMoveBy::create(2,CCPoint(_player->getPosition().x-s->getPosition().x>0?10:-10,_player->getPosition().y-s->getPosition().y>0?10:-10));//
CCFiniteTimeAction *func=CCCallFuncN::create(this,callfuncN_selector(HelloWorld::goon));
s->runAction(CCSequence::create(move,func,NULL));
}
}
这段代码从对象层中获得所有对象,判断键为n的是否为1,有则为敌人,加入到地图中,并且让敌人运动。
- void HelloWorld::goon(CCNode *pSender)
- {
- CCSprite *s=(CCSprite *)pSender;
- CCActionInterval *move=CCMoveBy::actionWithDuration(2,CCPoint(_player->getPosition().x-s->getPosition().x>0?10:-10,_player->getPosition().y-s->getPosition().y>0?10:-10));//
- CCFiniteTimeAction *func=CCCallFuncN::actionWithTarget(this,callfuncN_selector(HelloWorld::goon));
- s->runAction(CCSequence::actions(move,func,NULL));
- }
void HelloWorld::goon(CCNode *pSender)
{
CCSprite *s=(CCSprite *)pSender;
CCActionInterval *move=CCMoveBy::actionWithDuration(2,CCPoint(_player->getPosition().x-s->getPosition().x>0?10:-10,_player->getPosition().y-s->getPosition().y>0?10:-10));//
CCFiniteTimeAction *func=CCCallFuncN::actionWithTarget(this,callfuncN_selector(HelloWorld::goon));
s->runAction(CCSequence::actions(move,func,NULL));
}
在goon函数中继续调用自己,这样敌人就一直向英雄运动。
7.使英雄可以攻击
- bool mode;
bool mode;
在屏幕上添加菜单
- CCMenuItem *oon,*ooff;
- oon=CCMenuItemImage::create("projectile-button-on.png","projectile-button-on.png");
- ooff=CCMenuItemImage::create("projectile-button-off.png","projectile-button-off.png");
- CCMenuItemToggle *toggle=CCMenuItemToggle::createWithTarget(this,//回调函数所在的类
- menu_selector(HelloWorld::toggleGame),//回调函数
- ooff,oon,NULL //添加的菜单
- );
- CCMenu *menu=CCMenu::create(toggle,NULL);
- menu->setPosition(ccp(oon->getContentSize().width/2,oon->getContentSize().height/2));
- addChild(menu);
CCMenuItem *oon,*ooff;
oon=CCMenuItemImage::create("projectile-button-on.png","projectile-button-on.png");
ooff=CCMenuItemImage::create("projectile-button-off.png","projectile-button-off.png");
CCMenuItemToggle *toggle=CCMenuItemToggle::createWithTarget(this,//回调函数所在的类
menu_selector(HelloWorld::toggleGame),//回调函数
ooff,oon,NULL //添加的菜单
);
CCMenu *menu=CCMenu::create(toggle,NULL);
menu->setPosition(ccp(oon->getContentSize().width/2,oon->getContentSize().height/2));
addChild(menu);
在toggleGame函数中添加控制状态改变的代码:
- void HelloWorld::toggleGame(CCObject *pSender)
- {
- mode=mode?false:true;
- }
void HelloWorld::toggleGame(CCObject *pSender)
{
mode=mode?false:true;
}
当状态为false的时候,hero发射子弹:
- else
- {
- CCSprite *s=CCSprite::create("Projectile.png");
- s->setPosition(_player->getPosition());
- _tileMap->addChild(s,4);
- float dx=pp.x-_player->getPosition().x;
- float dy=pp.y-_player->getPosition().y;
- if(dx>0)
- {
- float lx=32*30-_player->getPosition().x;
- float ly=dy/dx*lx;
- CCActionInterval *move=CCMoveBy::create(3,ccp(lx+s->getContentSize().width,ly));
- CCFiniteTimeAction *ff=CCCallFuncN::create(this,callfuncN_selector(HelloWorld::targetFinish));
- s->runAction(CCSequence::actions(move,ff,NULL));
- }
- else
- {
- float lx=0-_player->getPosition().x;
- float ly=dy/dx*lx;
- CCActionInterval *move=CCMoveBy::actionWithDuration(3,ccp(lx-s->getContentSize().width,ly);
- CCFiniteTimeAction *ff=CCCallFuncN::create(this,callfuncN_selector(HelloWorld::targetFinish));
- s->runAction(CCSequence::actions(move,ff,NULL));
- }
else
{
CCSprite *s=CCSprite::create("Projectile.png");
s->setPosition(_player->getPosition());
_tileMap->addChild(s,4);
float dx=pp.x-_player->getPosition().x;
float dy=pp.y-_player->getPosition().y;
if(dx>0)
{
float lx=32*30-_player->getPosition().x;
float ly=dy/dx*lx;
CCActionInterval *move=CCMoveBy::create(3,ccp(lx+s->getContentSize().width,ly));
CCFiniteTimeAction *ff=CCCallFuncN::create(this,callfuncN_selector(HelloWorld::targetFinish));
s->runAction(CCSequence::actions(move,ff,NULL));
}
else
{
float lx=0-_player->getPosition().x;
float ly=dy/dx*lx;
CCActionInterval *move=CCMoveBy::actionWithDuration(3,ccp(lx-s->getContentSize().width,ly);
CCFiniteTimeAction *ff=CCCallFuncN::create(this,callfuncN_selector(HelloWorld::targetFinish));
s->runAction(CCSequence::actions(move,ff,NULL));
}
发射完子弹后,让子弹移动到地图外,通过hero的位置和点击的位置,可以知道发射子弹的角度,然后通过相似三角形对应边成比例的原理,可以知道x超出地图的位置。这样让子弹移出地图。
8.后期工作
- bool intersectsRect (const CCRect & rect) const
bool intersectsRect (const CCRect & rect) const
来判断碰撞。
cocos2d-x 游戏 之 Tiled Map Editor(地图编辑)相关推荐
- 【Cocos2d-x游戏引擎开发笔记(13)】Tiled Map Editor(一)
原创文章,转载请注明出处:http://blog.csdn.net/zhy_cheng/article/details/8308609 Tiled Map Editor是Cocos2d-x支持的地图编 ...
- 【日常点滴016】python游戏库arcade结合Tiled map editor地图编辑器和Pymunk物理引擎制作游戏过程记录,并最终打包为exe文件
独此一家,建议收藏 前言 一.创建一个空白窗口 step001.py代码示例 二.创建很多全局能用的常量 step002.py代码示例 三.创建实例变量即代表各种精灵等的变量 step003.py代码 ...
- Tiled Map Editor(一)
出处:http://blog.csdn.net/zhy_cheng/article/details/8308609 Tiled Map Editor是Cocos2d-x支持的地图编辑器,使用Tiled ...
- html5地图编辑器,Tiled地图编辑器 Tiled Map Editor 的使用(一)基础功能+地形功能...
看了很久关于 Tiled Map Editor 相关资料,但是网上的东西相对太少了,多日整理之后重新写一份吧 一方面是对自己学习的总结 另外也是和想入门的人做个分享. 首先是官网下载地址 http:/ ...
- Tiled Map Editor(瓦片地图编辑器)的Java和QT版本区别
尊重作者劳动,转载时请标明文章出处. 作者: Bugs Bunny 地址: http://www.cnblogs.com/cocos2d-x/archive/2012/05/03/2479469.ht ...
- Tiled地图编辑器 Tiled Map Editor 的使用(一)基础功能+地形功能
看了很久关于 Tiled Map Editor 相关资料,但是网上的东西相对太少了,多日整理之后重新写一份吧 一方面是对自己学习的总结 另外也是和想入门的人做个分享. 首先是官网下载地址 http ...
- Tiled Map Editor libgdx 讲解
Tiled Map Editor 主页为:http://www.mapeditor.org/,中文基本都翻译为瓦片编辑器,原因便是此工具是将小的碎片拼接在一起,形成一个个地图,因此叫做瓦片编辑器. 工 ...
- Tiled Map Editor 地图编辑器(一)基础功能+地形功能
看了很久关于 Tiled Map Editor 相关资料,但是网上的东西相对太少了,多日整理之后重新写一份吧 一方面是对自己学习的总结 另外也是和想入门的人做个分享. 本文链接地址: [url]htt ...
- How to Make Terrains in Tiled Map Editor
Published July 13th, 2015 by Stephen Gygi How to Make Terrains in Tiled Map Editor http://www.binary ...
最新文章
- 分布式平台下的HS(High-Security) --Apache Shiro API(介绍)
- oc中在控件上显示图片
- 计算机专业接本应用心理学,专接本接应用心理学但遇到阻挠?
- 一个优秀的软件测试工程师需具备的技能
- ext2.0 主体皮肤 (xtheme-black)
- html怎么给表格加a链接地址,html基础02-图片标签、绝/相对地址、表格的属性、链接的属性及链接的分类、name定义锚点的名称、编码...
- 全民小视频 无水印下载教程 (三步完成)
- 【富文本】解决会声会影、PR、AE处理视频后过大的问题(三款工具)专业视频压制软件|专业视频压制神器下载
- Python利用selenium实现自动登录网页qq
- 用HTML语言编写一个课程表,html做课程表
- JimuReport积木报表 — SQL数据源报表制作
- php 倒计时 考试,php实现倒计时
- Android中使用apk-parser解析apk
- Collections集合
- 【云原生学习3】Pod及K8S
- DLT645-2007 规约 电表 报文解析
- 【附源码】计算机毕业设计SSM校园二手商品交易系统
- 如何完全利用Win7
- unity 消融效果
- 软件开发软件开发,到底怎么开发出来的?