• 【转】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()函数

    [cpp] view plaincopyprint?

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

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

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

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

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

    [cpp] view plaincopyprint?

    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.     }  

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

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

    比如我写Ship:

    [cpp] view plaincopyprint?

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

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

    [cpp] view plaincopyprint?

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

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

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

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

    [cpp] view plaincopyprint?

    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.     }else{ 
    8. delete bullet_a; 
    9.         bullet_a = 0; 
    10.     } 

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

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

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

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

    [cpp] view plaincopyprint?

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

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

    然后执行场景:

    [cpp] view plaincopyprint?

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

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

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

  • 相关阅读:
    顺序表的扩容
    顺序表的插入
    顺序表的构造
    C# ContentType: "application/json" 请求方式传json
    顺序表构造,插入,扩容操作
    顺序表
    线性表
    算法
    数据结构的分类
    什么是数据结构
  • 原文地址:https://www.cnblogs.com/yssgyw/p/3215329.html
Copyright © 2020-2023  润新知