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

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





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值