Cocos2dx CrazyTetris 自定义精灵类 继承精灵

制作完主菜单场景,紧接着就是要制作游戏场景GameView。游戏场景的创建和主菜单是一样的,其中的布景、UI都可以参照主菜单场景做出来,难度较低。

游戏中的主要元素,我们要操作的方块也可以看成一个Sprite。同时,明显的,方块我们可以把它抽象成一个类,他们的基本操作和性质都是一样的,只是在表现上有些不同(直线、田字块什么的)。

因此,这一次主要就是分享一下继承Sprite制作自定义Sprite类的方法

其实像继承Layer或者Scene,这都很简单,但是如果不注意可能会在调试的时候断言错误,主要就是一个空指针异常。因此,这里,我主要分享一下如何避免继承时的简单错误以及发生该错误的原因。

废话不多说,继承Sprite主要关注create。先上一段代码

BaseBlock * BaseBlock::create(const std::string & filename)
{
	BaseBlock * sprite = new BaseBlock();

	 if (sprite && sprite->initWithFile(filename)) 
    {
        sprite->autorelease(); return sprite; 
    }
    CC_SAFE_DELETE(sprite); 
    return nullptr;
}

BaseBlock是我自定义的方块类,他继承自SpritecreateSprite类中的一个静态方法,用来创建Sprite。该函数返回Sprite*,但是我们需要的是创建BaseBlock,因此需要重写此方法

当然,Spritecreate方法大概有5种。但不一定都用,因此可以用到哪个create方法就重写对应的方法。例如:

BaseBlock * BaseBlock::createWithTexture(cocos2d::Texture2D * texture)
{
	BaseBlock * sprite = new BaseBlock();

	 if (sprite && sprite->initWithTexture(texture)) 
    {
        sprite->autorelease(); return sprite; 
    }
    CC_SAFE_DELETE(sprite); 
    return nullptr;
}

只要比照着写即可。

这里容易忽略的就是sprite->autorelease()。如果缺少他,便会在结束时报空指针异常。

原因其实也很容易想明白。

首先,我们重载这个create方法,返回的是一个Sprite为基类的自定义BaseBlock的指针。在C++中,指针操作需要非常注意。原则上,当有new操作申请指针时,一定要有delete操作与之对应,释放该指针。如果缺少delete就会形成野指针,关闭程序后导致内存泄露。

但是,delete在什么地方与new形成对应有时很难控制。程序短当然没什么,但如果程序够长,并且参与编程的人多,就很有可能在newdelete中间做了些什么操作,直接跳过了delete。因此,最好的解决方案就是智能指针,他可以自动释放自己。

而在cocos2dx中,应该也采用了类似的思想。他里面有一个全局的自析池(自己析构自己的池)。在创建Sprite的指针时,需要令其自动释放(autorelease),其实就是将其添加至自析池中。

同时,为了避免使用cocos2dx开发的开发人员不仔细,产生了像Sprite这个类的野指针,里面应该添加了断言。因此,如果Sprite缺少自析操作,断言会中断程序,报出类似空指针的异常。



附加一些cocos2dx中的这一部分的源码:

<pre name="code" class="cpp">Ref* Ref::autorelease()
{
    PoolManager::getInstance()->getCurrentPool()->addobject(this);
    return this;
}

PoolManager应该就是自析池管理器,是个单例模式。


PoolManager* PoolManager::getInstance()
{
    if (s_singleInstance == nullptr)
    {
        s_singleInstance = new PoolManager();
        // Add the first auto release pool
        new AutoreleasePool("cocos2d autorelease pool");
    }
    return s_singleInstance;
}

获取自析池单例。


PoolManager::PoolManager()
{
    _releasePoolStack.reserve(10);
}

PoolManager::~PoolManager()
{
    cclOGINFO("dealLocing PoolManager: %p",this);
    
    while (!_releasePoolStack.empty())
    {
        AutoreleasePool* pool = _releasePoolStack.back();
        
        delete pool;
    }
}

创建自析池以及最终释放自析池中所有资源。

相关文章

    本文实践自 RayWenderlich、Ali Hafizji 的文章《...
Cocos-code-ide使用入门学习地点:杭州滨江邮箱:appdevzw@1...
第一次開始用手游引擎挺激动!!!进入正题。下载资源1:从C...
    Cocos2d-x是一款强大的基于OpenGLES的跨平台游戏开发...
1.  来源 QuickV3sample项目中的2048样例游戏,以及最近《...
   Cocos2d-x3.x已经支持使用CMake来进行构建了,这里尝试...