转载请注明,原文地址: http://www.benmutou.com/archives/944
文章来源:笨木头与游戏开发
 

 

上一篇我们已经制作好tg1.tmx文件了,现在就要使用它了。

 
笨木头花心贡献,啥?花心?不呢,是用心~

转载请注明,原文地址:  http://www.benmutou.com/archives/944

文章来源:笨木头与游戏开发
 

很抱歉,我们又要新建2个类了,我已经尽力少新建类了,毕竟是教程,类越多越容易混乱。

 

我们要新建一个Monster类,以及一个MonsterLayer类,专门添加Monster对象。

 

Monster类

来看看Monster.h文件:
[cce_cpp]
#ifndef Monster_H

#define Monster_H

 

#include "cocos2d.h"

USING_NS_CC;

 

class Monster : public Node 

{

public:

Monster();

~Monster();

    static Monster* create(int ID);

    bool init(int ID);

 

    /* 加入到当前场景的物理世界 */

    void joinToWorld(Node* parent);

 

    CC_SYNTHESIZE(int, m_ID, ID);

    CC_SYNTHESIZE(float, m_fShowTime, fShowTime);

    CC_SYNTHESIZE(int, m_iPosX, iPosX);

CC_SYNTHESIZE(int, m_iPosY, iPosY);

CC_SYNTHESIZE(int, m_iAtk, iAtk);

CC_SYNTHESIZE(Value, m_sModelPath, sModelPath);

};

 

#endif [/cce_cpp]

很简单,有几个成员变量:

1. m_ID

2. m_fShowTime就是记录什么时候出场

3. m_sModelPath就是怪物的图片资源名称,Value是3.0的新特性,可以理解为CCString、CCInteger等的合体

4. m_iPosX和m_iPosY是坐标不解释(小若:已经解释了~)~

5. m_iAtk就是怪物的攻击力

 

主要关注一下joinToWorld函数,这个函数是让Monster加入到物理世界的,为什么不创建Monster对象的时候就让它加入到物理世界呢?

原因很简单,因为我们的怪物不是一开始就出现的,是随着游戏时间慢慢出现的,所以不能一开始就加入到世界中。

 

然后,来看看Monster.cpp文件:
[cce_cpp]
#include "Monster.h"

#include "scene\ObjectTag.h"

Monster::Monster()

{

}

 

Monster::~Monster()

{

}

 

Monster* Monster::create(int ID)

{

    auto monster = new Monster();

    

    if(monster && monster->init(ID)) 

    {

    monster->autorelease();

    }

    else

    {

    CC_SAFE_DELETE(monster);

    }

    

    return monster;

}

 

bool Monster::init(int ID)

{

    this->m_ID = ID;

 

    /* 这里以后要改成读取Json配置文件,暂时写死 */

    if (ID == 1)

    {

        m_sModelPath = Value("item2.png");

m_iAtk = 1;

    }

    else if (ID == 2)

    {

        m_sModelPath = Value("heart_red.png");

m_iAtk = -1;

    }

    return true;

} [/cce_cpp]
 

为了别一下子太复杂,joinToWorld函数我暂时没有贴出来。

这里主要看看init函数,Monster对象是根据ID来创建的,不同的ID代表不同的怪物类型,目前我们只有两种类型。

 

因为还没讲解到Json的部分,所以init函数暂时写死,但是大概意思是一样的:根据怪物ID加载不同的配置。

 

好,再来看看joinToWorld函数:
[cce_cpp]
void Monster::joinToWorld(Node* parent)

{

    Sprite* sp = Sprite::createWithSpriteFrameName(m_sModelPath.asString().c_str());

 

    /* 创建刚体 */

    PhysicsBody* body = PhysicsBody::createBox(sp->getContentSize());

    body->setCategoryBitmask(1);    // 0001

    body->setCollisionBitmask(1);   // 0001

    body->setContactTestBitmask(1); // 0001

 

    /* 精灵居中 */

    sp->setPosition(Point(sp->getContentSize().width * 0.5f, sp->getContentSize().height * 0.5f));

 

    /* 精灵作为Monster的表现,添加到Monster身上 */

    this->addChild(sp);

 

    /* 设置怪物Tag类型 */

    this->setTag(ObjectTag_Monster);

 

    /* 精灵作为Monster的表现,Monster本身没有大小,所以要设置一下大小 */

    this->setContentSize(sp->getContentSize());

 

    /* 刚体添加到Monster本身,而不是精灵身上 */

    this->setPhysicsBody(body);

 

    /* 设置坐标 */

    this->setPosition(Point(getiPosX(), getiPosY()));

 

    /* Monster加入到物理世界 */

    parent->addChild(this);

 

} [/cce_cpp]

代码注释已经够详细的了,大概的意思就是:

1. 创建一个Sprite对象,用于表现Monster的样子

2. 创建一个刚体,用于做物理碰撞

3. 设置怪物Tag类型

4. 将刚体添加到Monster上

5. Monster根据自身属性进行设置(比如设置坐标,完整版还有出场音效、颜色之类的)

6. 将Monster添加到物理世界

 

MonsterLayer 怪物层

为了不要让TollgateScene的代码太过臃肿(虽然它已经很臃肿了),我不得不再创建一个MonsterLayer类。

 

看看MonsterLayer.h文件:
[cce_cpp]
#ifndef MonsterLayer_H

#define MonsterLayer_H

 

#include "cocos2d.h"

USING_NS_CC;

 

class Monster;

class MonsterLayer : public Layer 

{

public:

MonsterLayer();

~MonsterLayer();

CREATE_FUNC(MonsterLayer);

virtual bool init();

 

    void logic(float dt);

private:

    /* 从配置文件中加载怪物数据 */

    void loadMonstersFromTmxConf();

 

    /* 存放所有即将要出场的怪物对象 */

    Vector<Monster*> m_monsterVec;

 

    /* 计时器 */

    float m_fTimeCounter;

};

 

#endif [/cce_cpp]

噗,好简单,你不用解释了~

哦,好吧,既然如此,我就不解释了。

(小若:喂,别在那里自己表演对白好吗?!谁说不用解释的?)

 

好吧,大概的意思的是:

1. loadMonstersFromTmxConf函数,很明显就是从我们生成的TiledMap关卡文件里读取数据,然后创建Monster对象了

2. m_monsterVec,这就是一个列表,用来保存读取到的所有怪物对象。而Vector也是3.0的新特性,封装了C++的Vector容器

3. m_fTimeCounter是计时器,因为怪物是达到某个时间才会出现的~

 

然后再来看看MonsterLayer.cpp文件:
[cce_cpp]
#include "MonsterLayer.h"

#include "entity\Monster.h"

 

MonsterLayer::MonsterLayer()

{

    m_fTimeCounter = 0;

}

 

MonsterLayer::~MonsterLayer()

{ SpriteFrameCache::getInstance()->removeSpriteFramesFromFile("monster.plist"); }

 

bool MonsterLayer::init()

{

    if (!Layer::init())

    {

        return false;

    } SpriteFrameCache::getInstance()->addSpriteFramesWithFile("monster.plist");  

    /* 加载关卡的怪物配置 */

    loadMonstersFromTmxConf();

    return true;

} [/cce_cpp]

好,好简单~

(小若:啊才怪啊,少了两个函数别以为我不知道)

 

OK,刚刚贴出来的一看就知道什么意思了,我就不说了,我们来看看loadMonstersFromTmxConf函数是怎么实现的:
[cce_cpp]
void MonsterLayer::loadMonstersFromTmxConf()

{

    /* 加载地图 */

    TMXTiledMap* map = TMXTiledMap::create("tg1.tmx");

    this->addChild(map);

 

    /* 加载怪物对象层的所有对象 */

    TMXObjectGroup* objGroup = map->getObjectGroup("monster");

    ValueVector objects = objGroup->getObjects();

 

    /* 遍历所有对象 */

    for (const auto v : objects)

    {

        const ValueMap dict = v.asValueMap();

 

        int id = dict.at("id").asInt();

        float fShowTime = dict.at("showTime").asFloat();

        int iPosX = dict.at("x").asInt();

        int iPosY = dict.at("y").asInt();

 

        /* 创建怪物对象,并保存起来 */

        Monster* monster = Monster::create(id);

        monster->setID(id);

        monster->setfShowTime(fShowTime);

        monster->setiPosX(iPosX);

        monster->setiPosY(iPosY);

 

        /* 保存怪物对象 */

        m_monsterVec.pushBack(monster);

    }

} [/cce_cpp]

我对自己的注释还是比较有信心的,所以,我再讲解一下(小若:好有自信= =)

1. 首先,加载TiledMap地图对象(TMXTiledMap)

2. 然后获取对象层(TMXObjectGroup)也就是我们之前一直大做文章的monster对象层了

3. 从monster对象层中获取所有的对象列表,也就是我们之前画的那一堆矩形

4. 每一个矩形对象取出来之后就是一个ValueMap,这也是3.0封装好的,功能和map一样(当然,用法有点点区别)

5. 从ValueMap中取出所有的属性,然后创建一个Monter对象,给Monster对象赋值

6. 把Monster对象添加到m_monsterVec列表,保存好

7. 大功告成

 

这个函数完成之后,我们就得到了所有的怪物对象,这些怪物对象都已经跟进关卡配置文件赋值好了。

怎么样,很简单吧~

 

最后,我们看看MonsterLayer的logic函数,重点中的重点(小若:算了吧你,重点这个词被你用烂了好吧)
[cce_cpp]
void MonsterLayer::logic(float dt)

{

    /* 计时 */

    m_fTimeCounter += dt;

 

    /* 记录本次出场的怪物 */

    Vector<Monster*> deleteVec;

 

    /* 让达到出场时间的怪物添加到物理世界 */

    for (auto monster : m_monsterVec)

    {

        /* 达到时间,可以出场了 */

        if (m_fTimeCounter >= monster->getfShowTime())

        {

            monster->joinToWorld(this);

 

            /* 记录本次出场的怪物,然后删除掉 */

            deleteVec.pushBack(monster);

        }

    }

 

    /* 删除已经添加到物理世界的怪物,避免重复出场 */

    for (auto monster : deleteVec)

    {

        m_monsterVec.eraseObject(monster, false);

    }

} [/cce_cpp]

虽然我对自己的注释很有自信,但是,我还是解释一下:

1. m_fTimeCounter计时器累计时间

2. 遍历怪物列表,判断有没有哪只怪物已经达到出场时间,可以出场的

3. 调用可出场怪物的joinToWorld函数,这样怪物就会出现在游戏中了

4. 把已经出场过的怪物对象从m_monsterVec中删除,避免下次又重复出场

 

完成喇~

木了个头的,真是没想到,就这么简单的几个类,竟然要花这么长时间讲解。

而且,本篇竟然还不是最后一篇~!(小若:那你在这么发表什么获奖感言啊)

 

我们来试试加载怪物有没有成功吧~

 

同样的,给TollgateScene添加一个成员变量(我就不贴详细的代码了):
[cce_cpp]MonsterLayer* m_monsterLayer;[/cce_cpp]
 

然后修改TollgateScene的scene函数,把MonsterLayer添加到scene里:
[cce_cpp]
Scene* TollgateScene::scene()

{

    auto scene = Scene::createWithPhysics();

 

    /* 这里省略了很多代码 */

 

    /* 背景层 */

    auto backgroundLayer = BackgroundLayer::create();

    scene->addChild(backgroundLayer, 0);

 

    /* 怪物层 */

    auto monsterLayer = MonsterLayer::create();

    scene->addChild(monsterLayer, 1);

 

    auto layer = TollgateScene::create();

    scene->addChild(layer, 10);

 

    layer->m_backgroundLayer = backgroundLayer;

    layer->m_monsterLayer = monsterLayer;

    return scene;

} [/cce_cpp]
 

最后,别忘了在TollgateScene的logic里调用MonsterLayer的logic函数:
[cce_cpp]
void TollgateScene::logic(float dt)

{

    m_backgroundLayer->logic(dt);

    m_monsterLayer->logic(dt);

} [/cce_cpp]
 

OK,运行游戏,我们看看怪物出现没?

 

[caption id="attachment_946" align="aligncenter" width="317"]Cocos2d-x3.0游戏实例之《别救我》第九篇 Cocos2d-x3.0游戏实例之《别救我》第九篇[/caption]

怪物会根据我们配置的时间出现。

 

OK,到此,《别救我》的核心功能算是完成了,但是它完全还不能算是一个游戏。

 

下一篇,我们再介绍一个核心功能——读取Json配置文件

 

 
72 条评论
  • 乜亻八一 2015-12-04 18:22:28

    木头还在吗 运行时中断了 提示
    0x0016C425 处的第一机会异常(在 Myproj.exe 中): 0xC0000005: 读取位置 0xCDCDCFD9 时发生访问冲突。
    0x0016C425 处有未经处理的异常(在 Myproj.exe 中): 0xC0000005: 读取位置 0xCDCDCFD9 时发生访问冲突。
    也就是
    /* 计时 */
    m_fTimeCounter += dt;
    这里有问题指针
    0回复
    • 博主 糟糕_树叶的mut 2015-12-05 16:52:43

      还活着。。。
      应该不是这里, 这句不会引起这个错误,估计你是某个变量没有赋值或者被释放了
      0回复
      • 乜亻八一 2015-12-07 15:42:37

        解决了 自己大意 少写了一句。。。 坑死了自己
        0回复
        • 乜亻八一 2015-12-07 15:42:50

          谢谢木头啦
          0回复
    • QZBYSZYK改变 2016-09-24 23:34:41

      这个错误是TollgateScene创建场景最后没加下面这句
      layer->m_monsterLayer=monsterLayer;
      0回复
  • 见人不会飞 2015-08-25 11:07:56

    suffix = csbtextureSize = 0classname = Nodesize = 3classname = Buttoncocos2d: fullPathForFilename: No file found at Default/Button_Press.png. Possible missing file.cocos2d: fullPathForFilename: No file found at Default/Button_Disable.png. Possible missing file.callBackName cannot be foundsize = 0child = 050CDA48classname = Buttoncocos2d: fullPathForFilename: No file found at Default/Button_Press.png. Possible missing file.cocos2d: fullPathForFilename: No file found at Default/Button_Disable.png. Possible missing file.callBackName cannot be foundsize = 0child = 050F8E40classname = Buttoncocos2d: fullPathForFilename: No file found at Default/Button_Press.png. Possible missing file.cocos2d: fullPathForFilename: No file found at Default/Button_Disable.png. Possible missing file.callBackName cannot be foundsize = 0child = 050E7498“SaveME.exe”(Win32): 已卸载“C:WindowsSysWOW64igdusc32.dll”“SaveME.exe”(Win32): 已加载“C:WindowsSysWOW64igdusc32.dll”。无法查找或打开 PDB 文件。0x00FEDC15 处的第一机会异常(在 SaveME.exe 中): 0xC0000005: 读取位置 0xCDCDD085 时发生访问冲突。0x00FEDC15 处有未经处理的异常(在 SaveME.exe 中): 0xC0000005: 读取位置 0xCDCDD085 时发生访问冲突。
    0回复
    • 博主 糟糕_树叶的mut 2015-08-26 07:44:44

      只丢个错误信息什么都不说的,一律不回答。
      0回复
  • free skype download 2015-03-11 09:16:33

    download skype

    free skype download
    0回复
  • java version 2015-03-10 05:40:56

    java test

    download java
    0回复
  • firefox free download 2015-03-09 12:35:30

    download firefox

    mozilla firefox free download
    0回复
  • google chrome download 2015-03-09 05:23:43

    Download Google Chrome

    Download Chrome
    0回复
  • Vanessa Smith 2015-03-08 05:29:56

    I liked your blog very much.

    I want to thank you for the contribution.
    0回复
  • 李宗杰 2014-09-22 13:29:47

    大神,请问在这class MonsterLayer :public Layerda上面哪句class Monster; 和 #include "Monster.h" 有什么区别? 为什么这样引用呢
    0回复
    • 博主 糟糕_树叶的mut 2014-09-22 16:51:07

      这个两句话解释不清,主要是避免多余的重新编译,以及解决相互include产生的编译混乱~具体情况可以百度一下~比较多资料
      0回复
      • 李宗杰 2014-09-22 18:02:09

        刚才买的你的这个整个源码!!! 教程里一共也就5,6个类…… 源码里翻了十倍不止啊!!! 瞬间就慌了
        0回复
        • 博主 糟糕_树叶的mut 2014-09-22 19:25:58

          原来是你吖~完整版当然要多很多,哈哈,不然怎么能叫做完整版呢,我可不会坑人 其实不用慌的,核心就是这10篇教程,只是在此基础上加了很多界面而已,其他的那些逻辑都不会复杂的~至于广告部分,就可以忽略了
          0回复
          • 螺丝 2016-03-02 11:37:20

            问一下,完整版教程里面注释多么?新人能自己学明白不?
            0回复
            • 博主 糟糕_树叶的mut 2016-03-02 13:37:39

              如果你能看懂Demo版的话,应该没问题吧。
              注释的话,是我的爱好,哈哈哈,但也不会很多,该注释的注释,不该注释的就没了。
              0回复
  • 11电信张强 2014-09-11 23:39:19

    MonsterLayer.obj : error LNK2019: 无法解析的外部符号 "public: static class Monster * __cdecl Monster::create(int)" (?create@Monster@@SAPAV1@H@Z),该符号在函数 "private: void __thiscall MonsterLayer::loadMonstersFromTmxConf(void)" (?loadMonstersFromTmxConf@MonsterLayer@@AAEXXZ) 中被引用为什么无法解析呢? 找不出哪里错了 求解
    0回复
    • 博主 糟糕_树叶的mut 2014-09-12 08:36:20

      确定一下你的create(int)函数有没有实现,可能只是声明了
      0回复
      • 11电信张强 2014-09-13 17:38:53

        好了 能运行了 一切正常 谢谢
        0回复
  • 查水表哦也 2014-09-09 19:05:48

    你好 我使用xcode 学习您的教程 float fShowTime = dict.at("showTime").asFloat(); //libc++abi.dylib: terminating with uncaught exception of type std::out_of_range: unordered_map::at: key not found每次老卡在 这里 百度了一下 说是c++异常 但是也没有个解决办法 libc++abi.dylib:自己也尝试了添加了这个libc++abi.dylib:文件 但还是没有解决问题。博主见多识广 能否在百忙之中指点一二 不胜感激
    0回复
    • 博主 糟糕_树叶的mut 2014-09-09 21:19:33

      你看看是不是你的关卡配置文件错了,对象的showTime属性是不是漏掉了?
      0回复
      • 查水表哦也 2014-09-10 11:42:10

        谢谢 我在重新配置一下 话说 今天我们主程走了 日子好难过
        0回复
        • 博主 糟糕_树叶的mut 2014-09-10 13:09:31

          正好,你去补上,哈哈
          0回复
          • 查水表哦也 2014-09-10 13:11:14

            我是小白 刚学cocosdx 我来了一个月他就走了 心里有一种失落的感觉
            0回复
            • 查水表哦也 2014-09-10 14:18:50

              搞定还真是那个问题
              0回复
            • 博主 糟糕_树叶的mut 2014-09-10 14:23:36

              没什么好失落的~加油
              0回复
发表评论
粤ICP备16043700号

本博客基于 BlazorAnt Design Blazor 开发