如何制作一个基于Tile的游戏(2) Cocos2d-x 3.0alpha0

在第一篇《如何制作一个基于Tile的游戏》基础上,增加碰撞和拾取功能,原文《Collisions and Collectables: How To Make a Tile-Based Game with Cocos2D Part 2》,在这里继续以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文件,添加如下声明:

    CC_SYNTHESIZE_RETAIN(TMXLayer*, _meta, Meta);
HelloWorldScene.cpp 文件构造函数里,添加代码:

    _meta = NULL;
init 函数里,添加背景之后,添加如下代码:

        this->setMeta(_tilemap->getLayer("Meta"));
        _meta->setVisible(false);
这里把Meta层隐藏起来了,因为这只是作为阻挡的,不是真实可见的。添加一个新的方法,代码如下:

Point HelloWorld::tileCoordForPosition(Point position)
{
    int x = position.x / _tilemap->getTileSize().width;
    int y = ((_tilemap->getMapSize().height * _tilemap->getTileSize().height) - position.y) / _tilemap->getTileSize().height;
    
    return Point(x, y);
}
这个方法将坐标转换成tile坐标,tile坐标系如下图所示:

修改 setPlayerPosition 函数,代码如下:

void HelloWorld::setPlayerPosition(Point position)
{
    Point tileCoord = this->tileCoordForPosition(position);
   
    int tileGid = _meta->getTileGIDAt(tileCoord);
    
    if (tileGid) {
        Dictionary* properties = _tilemap->getPropertiesForGID(tileGid);
        if (properties) {
            const String* collision = properties->valueForKey("Collidable");
            if (collision && collision->compare("true") == 0) {
                return;
            }
        }
        
    }
    _player->setPosition(position);
}
在这里,我们将坐标转成tile坐标,获得这个tile坐标上的GID,再根据GID得到的属性字典,查找是否" Collidable "属性为" true ",如果是则直接返回。
5.编译运行,可以看到忍者不能穿过红色区域了。如下图所示:

6.动态修改Tiled地图。我们为忍者增加可以吃的东西,比如这里的西瓜。创建一个可拾取的前景层,当忍者从tile拾取东西时,就把这个tile从前景层中移除。菜单栏→" 图层 "→" 添加图层 ",命名为" Foreground "。 注意 ,若是之前有在" Background "层绘制过西瓜的,需要用底图块,比如这里的沙漠块填充覆盖,以免达不到吃西瓜的效果。然后,选中" Foreground "层,选择西瓜tile块,在地图上进行绘制。如下图所示:

为西瓜标识可拾取。选择" Meta "层,图块切换到" meta _tiles "页,选择绿色tile,绘制到地图上西瓜tile区域。需要先把" Meta "层前置,点击菜单栏→" 图层 "→" 前置图层 ",确保" Meta "层在最上层。如下图所示:

在" 图块 "窗口,右键绿色tile块,选择"图块属性",新建一个属性,名称为" Collectable ",其值为" true "。点击" 确定 "。保存地图。
7.打开 HelloWorldScene.h 文件,添加如下声明:

    CC_SYNTHESIZE_RETAIN(TMXLayer*, _foreground, Foreground);
HelloWorldScene.cpp 文件构造函数里,添加代码:

    _foreground = NULL;
init 函数里,添加背景之后,添加如下代码:

        this->setForeground(_tilemap->getLayer("Foreground"));
setPlayerPosition 函数检测" Collidable "属性之后,添加检测" Collectable "属性,代码如下:

            const String* collectable = properties->valueForKey("Collectable");
            if (collectable && collectable->compare("true") == 0) {
                _meta->removeTileAt(tileCoord);
                _foreground->removeTileAt(tileCoord);
            }
8.编译运行,可以看到忍者把西瓜吃掉了,如下图所示:

9.创建计分器。为忍者记录所吃西瓜的数量。我们创建一个新层 HelloWorldHud 来显示分数。在 HelloWorldScene.h 文件中,添加如下代码:

#include "cocos2d.h"
USING_NS_CC;

class HelloWorldHud:public Layer {
    
public:
    virtual bool init();
    
    CREATE_FUNC(HelloWorldHud);
    
    void numCollectedChanged(int numCollected);
    LabelTTF* _label;
    
HelloWorldScene.cpp 文件中,进行实现,代码如下:

bool HelloWorldHud::init()
{
    bool bRet = false;
    do {
        CC_BREAK_IF(!Layer::init());
        
        Size winSize = Director::getInstance()->getWinSize();
        _label = LabelTTF::create("0", "Verdana-Bold", 18.0, Size(50, 20), TextHAlignment::RIGHT);
        _label->setColor(Color3B(0, 0, 0));
        int margin = 10;
        _label->setPosition(Point(winSize.width - (_label->getContentSize().width / 2) - margin, _label->getContentSize().height / 2 + margin));
        this->addChild(_label);
        
        bRet = true;
    } while (0);
    return bRet;
}

void HelloWorldHud::numCollectedChanged(int numCollected)
{
    _label->setString(String::createWithFormat("%d",numCollected)->getCString());
    
}
接下去在 HelloWorld 类,添加 HelloWorldHud 层指针,在 HelloWorldScene.h 文件中 HelloWorld 类里,添加如下代码:

    CC_SYNTHESIZE(int, _numCollected, NumCollected);
    CC_SYNTHESIZE_RETAIN(HelloWorldHud*, _hud, Hud);
HelloWorldScene.cpp 文件 HelloWorld 类构造函数里,添加代码:

    _numCollected = 0;
    _hud = NULL;
createScene() 函数里 ,添加如下代码:

    HelloWorldHud* hud = HelloWorldHud::create();
    scene->addChild(hud);
    layer->setHud(hud);
setPlayerPosition 函数,检测到" Collectable "属性为" true "时,添加如下代码:

                _numCollected++;
                _hud->numCollectedChanged(_numCollected);
10.编译运行,现在可以看到右下角有一个西瓜计分器,如下图所示:

参考资料:
1.Collisions and Collectables: How To Make a Tile-Based Game with Cocos2D Part 2 http://www.raywenderlich.com/1186/collisions-and-collectables-how-to-make-a-tile-based-game-with-cocos2d-part-2
2.碰撞与拾取:如何使用Cocos2D制作一款基于tile的游戏第2部分 http://www.raywenderlich.com/zh-hans/19250/%E7%A2%B0%E6%92%9E%E4%B8%8E%E6%8B%BE%E5%8F%96%EF%BC%9A%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8cocos2d%E5%88%B6%E4%BD%9C%E4%B8%80%E6%AC%BE%E5%9F%BA%E4%BA%8Etile%E7%9A%84%E6%B8%B8%E6%88%8F%E7%AC%AC2
3.(译)碰撞检测和收集物品:如何使用cocos2d制作基于tiled地图的游戏:第二部分 http://www.cnblogs.com/zilongshanren/archive/2011/05/03/2033620.html


iOS版下载地址: http://pan.baidu.com/share/link?shareid=2062648195&uk=3189484501



如文章存在错误之处,欢迎指出,以便改正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杜甲同学

感谢打赏,我会继续努力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值