在第一篇《》基础上,增加碰撞和拾取功能,原文《》,在这里继续以Cocos2d-x进行实现。有关源码、资源等在文章下面给出了地址。
步骤如下:
1.使用上一篇的工程;2.打开Tiled Map Editor工具,菜单栏→"图层"→"添加图层",命名为"Meta"。这个层,我们将放入一些假的tile来代表"特殊tile"。菜单栏→"地图"→"新图块",点击"浏览",选择"Resources"目录下的meta_tiles.png文件,边距和间距设置成1像素点,点击"确定"。可以看到在"图块"窗口新增了一页,里面有红色和绿色两种tile,如下图所示:3.确认"Meta"层被选中,选择工具栏上"图章刷",选择红色tile,绘制可碰撞区域,完成之后,大概如下图所示:需要给这个tile设置属性来标识它,这样才能知道该tile具有碰撞属性。在"图块"窗口,右键红色tile,选择"图块属性",新建一个属性,名称为"Collidable",其值为"true",如下图所示:点击"确定"。保存地图。4.打开HelloWorldScene.h文件,添加如下声明: 1 | CC_SYNTHESIZE_RETAIN(cocos2d::CCTMXLayer*, _meta, Meta); |
1 | _meta = NULL; |
1 2 | this->setMeta(_tileMap->layerNamed( "Meta")); _meta->setVisible( false); |
1 2 3 4 5 6 | CCPoint HelloWorld::tileCoordForPosition(CCPoint position) { int x = position.x / _tileMap->getTileSize().width; int y = ((_tileMap->getMapSize().height * _tileMap->getTileSize().height) - position.y) / _tileMap->getTileSize().height; return ccp(x, y); } |
修改 setPlayerPosition 函数,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | void HelloWorld::setPlayerPosition(CCPoint position) { CCPoint tileCoord = this->tileCoordForPosition(position); int tileGid = _meta->tileGIDAt(tileCoord); if (tileGid) { CCDictionary *properties = _tileMap->propertiesForGID(tileGid); if (properties) { const CCString *collision = properties->valueForKey( "Collidable"); if (collision && collision->compare( "true") == 0) { return; } } } _player->setPosition(position); } |
5.编译运行,可以看到忍者不能穿过红色区域了。如下图所示:
6.动态修改Tiled地图。我们为忍者增加可以吃的东西,比如这里的西瓜。创建一个可拾取的前景层,当忍者从tile拾取东西时,就把这个tile从前景层中移除。菜单栏→" 图层 "→" 添加图层 ",命名为" Foreground "。 注意 ,若是之前有在" Background "层绘制过西瓜的,需要用底图块,比如这里的沙漠块填充覆盖,以免达不到吃西瓜的效果。然后,选中" Foreground "层,选择西瓜tile块,在地图上进行绘制。如下图所示:
为西瓜标识可拾取。选择" Meta "层,图块切换到" meta _tiles "页,选择绿色tile,绘制到地图上西瓜tile区域。需要先把" Meta "层前置,点击菜单栏→" 图层 "→" 前置图层 ",确保" Meta "层在最上层。如下图所示:
在" 图块 "窗口,右键绿色tile块,选择"图块属性",新建一个属性,名称为" Collectable ",其值为" true "。点击" 确定 "。保存地图。
7.打开 HelloWorldScene.h 文件,添加如下声明:
1 | CC_SYNTHESIZE_RETAIN(cocos2d::CCTMXLayer*, _foreground, Foreground); |
1 | _foreground = NULL; |
1 | this->setForeground(_tileMap->layerNamed( "Foreground")); |
1 2 3 4 5 6 | const CCString *collectable = properties->valueForKey( "Collectable"); if (collectable && collectable->compare( "true") == 0) { _meta->removeTileAt(tileCoord); _foreground->removeTileAt(tileCoord); } |
9.创建计分器。为忍者记录所吃西瓜的数量。我们创建一个新层 HelloWorldHud 来显示分数。在 HelloWorldScene.h 文件中,添加如下代码:
1 2 3 4 5 6 7 8 | class HelloWorldHud : public cocos2d::CCLayer { public: virtual bool init(); CREATE_FUNC(HelloWorldHud); void numCollectedChanged( int numCollected); cocos2d::CCLabelTTF *lable; }; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | bool HelloWorldHud::init() { bool bRet = false; do { CC_BREAK_IF(! CCLayer::init()); CCSize winSize = CCDirector::sharedDirector()->getWinSize(); lable = CCLabelTTF::create( "0", "Verdana-Bold", 18. 0, CCSizeMake( 50, 20), kCCTextAlignmentRight); lable->setColor(ccc3( 0, 0, 0)); int margin = 10; lable->setPosition(ccp(winSize.width - (lable->getContentSize().width / 2) - margin, lable->getContentSize().height / 2 + margin)); this->addChild(lable); bRet = true; } while ( 0); return bRet; } void HelloWorldHud::numCollectedChanged( int numCollected) { lable->setString(CCString::createWithFormat( "%d", numCollected)->getCString()); } |
接下去在HelloWorld类,添加HelloWorldHud层指针,在HelloWorldScene.h文件中HelloWorld类里,添加如下代码:
1 2 | CC_SYNTHESIZE( int, _numCollected, NumCollected); CC_SYNTHESIZE_RETAIN(HelloWorldHud*, _hud, Hud); |
1 2 | _numCollected = 0; _hud = NULL; |
1 2 3 4 | HelloWorldHud *hud = HelloWorldHud::create(); scene->addChild(hud); layer->setHud(hud); |
在setPlayerPosition函数,检测到"Collectable"属性为"true"时,添加如下代码:
1 2 | _numCollected++; _hud->numCollectedChanged(_numCollected); |
11.增加音效和音乐。在 HelloWorldScene.cpp 文件 HelloWorld 类 init 函数里,添加如下代码:
1 2 3 4 | CocosDenshion::SimpleAudioEngine::sharedEngine()->preloadEffect( "pickup.wav"); CocosDenshion::SimpleAudioEngine::sharedEngine()->preloadEffect( "hit.wav"); CocosDenshion::SimpleAudioEngine::sharedEngine()->preloadEffect( "move.wav"); CocosDenshion::SimpleAudioEngine::sharedEngine()->playBackgroundMusic( "TileMap.wav"); |
1 | CocosDenshion::SimpleAudioEngine::sharedEngine()->playEffect( "hit.wav"); |
1 | CocosDenshion::SimpleAudioEngine::sharedEngine()->playEffect( "pickup.wav"); |
1 | CocosDenshion::SimpleAudioEngine::sharedEngine()->playEffect( "move.wav"); |
参考资料:
1.Collisions and Collectables: How To Make a Tile-Based Game with Cocos2D Part 2
2.碰撞与拾取:如何使用Cocos2D制作一款基于tile的游戏第2部分
3.(译)碰撞检测和收集物品:如何使用cocos2d制作基于tiled地图的游戏:第二部分
非常感谢以上资料,本例子源代码附加资源下载地址:
如文章存在错误之处,欢迎指出,以便改正。