cocos2d-x游戏开发(八)各类构造器

欢迎转载:http://blog.csdn.net/fylz1125/article/details/8521997


这篇写cocos2d-x的构造器。

cocos2d-x引入自动释放机制后,创建的对象就不需要我们像C++编程那样自己delete了。但是怎么让自己的类也能保持cocos2d-x的风格呢?或者说怎么样才能让自己的类实例也能自动释放。

在cocos2d-x里面大量用到了一个叫create()方法(2.1.0版本)。几乎所有的实体类都会用这个create函数来产生实例而不是他们的构造函数。

看看CCSprite的create()函数

  1. CCSprite* CCSprite::create()  
  2. {  
  3.     CCSprite *pSprite = new CCSprite();//调用构造函数,产生对象  
  4.     if (pSprite && pSprite->init()) // 创建对象成功并且其init函数返回true则添加到自动释放池  
  5.     {  
  6.         pSprite->autorelease();  
  7.         return pSprite;  
  8.     }  
  9.     CC_SAFE_DELETE(pSprite); // 安全释放  
  10.     return NULL;  
  11. }  

看到了,create函数里面实质上做了两件事:1.调用构造函数 2.init()成功则添加到自动释放池。

然后看init()函数,就是自己的一些初始化工作了。

对于这个结构大家要非常熟悉,几乎可以说是一个套路。

这个二阶段构造用的很多,为了简化代码提高效率,cocos2d-x有个函数宏专门来干这个活:

  1. #define CREATE_FUNC(__TYPE__) \  
  2. static __TYPE__* create() \  
  3. { \  
  4.     __TYPE__ *pRet = new __TYPE__(); \  
  5.     if (pRet && pRet->init()) \  
  6.     { \  
  7.         pRet->autorelease(); \  
  8.         return pRet; \  
  9.     } \  
  10.     else \  
  11.     { \  
  12.         delete pRet; \  
  13.         pRet = NULL; \  
  14.         return NULL; \  
  15.     } \  
  16. }  

这个跟上面CCSprite的create函数很像啊。结构几乎是一样的。

所以我们自己的类只需要用这个宏定义,然后实现init()函数就可以了。用的时候直接调用create()函数。

比如我写Ship:

  1. #ifndef __MoonWarriorsx__Ship__  
  2. #define __MoonWarriorsx__Ship__  
  3.   
  4. #include "cocos2d.h"  
  5. #include "UnitSprite.h"  
  6. USING_NS_CC;  
  7.   
  8. class Ship : public UnitSprite{  
  9. private:  
  10.     // 速度  
  11.     int m_speed;  
  12.       
  13.     // 子弹速度  
  14.     int m_bulletSpeed;  
  15.       
  16.     // 生命值  
  17.     int m_HP;  
  18.       
  19.     // 子弹类型  
  20.     int m_bulletTypeValue;  
  21.       
  22.     // 子弹威力  
  23.     int m_bulletPowerValue;  
  24.       
  25.     // 是否在投掷炸弹  
  26.     bool m_throwBombing;  
  27.       
  28.     // 是否可被攻击  
  29.     bool m_canBeAttack;  
  30.       
  31.     bool m_isThrowBomb;  
  32.     int m_zOder;  
  33.       
  34.     // 最大子弹威力  
  35.     int m_maxBulletPowerValue;  
  36.       
  37.     // 出现的初始位置  
  38.     CCPoint m_appearPosition;  
  39.     int m_hurtColorLife;  
  40.     bool m_active;  
  41.       
  42. public:  
  43.     Ship();  
  44.     ~Ship();  
  45.       
  46.     // 被攻击使能  
  47.     void makeAttack(CCNode *pSender);  
  48.       
  49.     // 更新  
  50.     virtual void update(float dt);  
  51.       
  52.     // 射击  
  53.     void shoot(float dt);  
  54.       
  55.     // 初始化  
  56.     virtual bool init();  
  57.       
  58.     // 被攻击,受伤  
  59.     virtual void hurt();  
  60.       
  61.     // 销毁飞船  
  62.     virtual void destroy();  
  63.       
  64.     // 获取生存状态  
  65.     virtual bool isActive();  
  66.       
  67.     // 碰撞矩形  
  68.     virtual CCRect collideRect();  
  69.     int getZoder();  
  70.       
  71.     // 构造器  
  72.     CREATE_FUNC(Ship);  
  73. };  
  74.   
  75. #endif /* defined(__MoonWarriorsx__Ship__) */  

然后构造函数只带了一个初始化列表赋初值,没干别的事情。接着实现init()函数,所有初始化工作都在这里实现:

  1. bool Ship::init()  
  2. {  
  3.     // super init first  
  4.     if ( !CCSprite::init() )  
  5.     {  
  6.         return false;  
  7.     }  
  8.       
  9.       
  10.     // init life  
  11.     CCTexture2D * shipTextureCache = CCTextureCache::sharedTextureCache()->addImage(s_ship01);  
  12.     CCRect rec = CCRectMake(0, 0, 60, 38);  
  13.     this->initWithTexture(shipTextureCache,  rec);  
  14.       
  15.   
  16.     this->setPosition(m_appearPosition);  
  17.   
  18.       
  19.     // set frame  
  20.     CCSpriteFrame *frame0 = CCSpriteFrame::createWithTexture(shipTextureCache, CCRectMake(0, 0, 60, 38));  
  21.     CCSpriteFrame *frame1 = CCSpriteFrame::createWithTexture(shipTextureCache, CCRectMake(60, 0, 60, 38));  
  22.   
  23.     CCArray *animFrames = CCArray::create();  
  24.     animFrames->addObject(frame0);  
  25.     animFrames->addObject(frame1);  
  26.       
  27.     // ship animate  
  28.     // 这个方法有差异  
  29.     CCAnimation *animation = CCAnimation::createWithSpriteFrames(animFrames, 0.1);  
  30.     CCAnimate *animate = CCAnimate::create(animation);  
  31.     this->runAction(CCRepeatForever::create(animate));  
  32.       
  33.     // 子弹发射  
  34.     this->schedule(schedule_selector(Ship::shoot), 0.16);  
  35.       
  36.     // revive effect  
  37.     this->m_canBeAttack = false;  
  38.     CCSprite *ghostSprite = CCSprite::createWithTexture(shipTextureCache, CCRectMake(0, 45, 60, 38));  
  39.     ccBlendFunc cbl = {GL_SRC_ALPHA, GL_ONE};  
  40.     ghostSprite->setBlendFunc(cbl);  
  41.     ghostSprite->setScale(8);  
  42.     ghostSprite->setPosition(ccp(this->getContentSize().width / 2, 12));  
  43.     this->addChild(ghostSprite, 3000, 99999);  
  44.     ghostSprite->runAction(CCScaleTo::create(0.5, 1, 1));  
  45.       
  46.     // 闪烁动画  
  47.     CCBlink *blinks = CCBlink::create(3, 9);  
  48.       
  49.     // 回调,攻击使能  
  50.     // 带执行者回调,谁执行Action传谁。这里是this,所以传的就是this  
  51.     CCCallFuncN *makeBeAttack = CCCallFuncN::create(this, callfuncN_selector(Ship::makeAttack));  
  52.       
  53.     this->runAction(CCSequence::create(CCDelayTime::create(0.5), blinks, makeBeAttack, NULL));  
  54.     return true;  
  55. }  

init函数要先调用super的init(),然后写自己的东西。

这样的二阶段构造有个好处,就是将自动释放封装起来了。因为这个create函数是个static的,创建对象成功且初始化成功就将其添加到自动释放池,然后返回对象实例。你通过create获得对象后不用管它的释放问题。

当然,你也可以标新立异,不一定就按这个来。不过关键一点是,不管你怎么构造你的实例,要确保成功并将其加到自动释放池。比如我有个子弹类不是用create创建实例的,其使用如下:

  1. Bullet *bullet_a = new Bullet(m_bulletSpeed, "W1.png", 1);  
  2.     if (bullet_a) {  
  3.         bullet_a->autorelease();// 添加到自动释放池  
  4.         play_bullet->addObject(bullet_a);  
  5.         this->getParent()->addChild(bullet_a, bullet_a->m_zorder, 901);  
  6.         bullet_a->setPosition(ccp(position.x + offset, position.y + 3 + contentSize.height * 0.3));  
  7.   
  8.     }else{  
  9.         delete bullet_a;  
  10.         bullet_a = 0;  
  11.     }  

看,自己的构造函数,还要自己添加自动释放池。一看就很乱。其实这个也可以封装起来,自己实现create函数,不用那个宏定义,后续改下。


这里有一点不一样,就是CCScene的构造。

coco2d-x里面导演执行的单元是CCScene,就是场景。一个场景里面会添加很多CCLayer,即层。层里面又会添加很多元素,比如CCSprite,CCMenu等。那么场景如何构造呢?

demo里面是这一做的,在主Layer里面定义一个static的函数scene(),返回一个CCScene对象,例如:

  1. CCScene* HelloWorld::scene()  
  2. {  
  3.     // 'scene' is an autorelease object  
  4.     CCScene *scene = CCScene::create();  
  5.       
  6.     // 'layer' is an autorelease object  
  7.     HelloWorld *layer = HelloWorld::create();  
  8.   
  9.     // add layer as a child to scene  
  10.     scene->addChild(layer);  
  11.   
  12.     // return the scene  
  13.     return scene;  
  14. }  

他在这个函数里面将主Layer构造出来,然后添加到场景里面。注意,所有create函数构造的对象都是一个autorelease的对象。

然后执行场景:

  1. // create a scene. it's an autorelease object  
  2.    CCScene *pScene = HelloWorld::scene();  
  3.   
  4.    // run  
  5.    pDirector->runWithScene(pScene);  

看,封装好了,代码多清晰。


好了,就这么多,打完收工。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值