Cocos2d-x不要随便在onEnter里面addChild

来源:互联网 发布:windows 系统错误 编辑:程序博客网 时间:2024/05/21 20:29

使用任何版本的Cocos2d-x(1.x,2.x,3.0),在onEnter中调用addChild,都要小心谨慎,因为它有可能导致两种莫名其妙的BUG,莫名其妙的BUG当然难以定位了!更何况这个BUG隐藏在引擎的底层。

接下来是场景还原:

在某个节点下,需要执行这样一段逻辑,在游戏场景中,添加几个节点,由于游戏场景就是该节点的父节点,于是就直接getParent然后调用父节点的addChild,在onEnter函数中添加看上去比较合适,因为这时候该节点的父节点可以访问,而在init函数中,还没有被添加到游戏场景中

神奇的事情发生了,在这之后添加的节点,都无法播放动画了,而把节点添加的位置,移到该节点之前进行添加,动画就可以正常播放,检查了一下代码,无果,先记下该问题

接下来又有一件神奇的事情发生了,我们的程序崩溃了!用排除法发现,是在onEnter下添加节点导致的崩溃,但是有趣的是,onEnter下的一个for循环添加5个节点,当我把节点数量该为4的时候,程序又可以正常执行了!而添加到5或者更多的时候,程序又崩溃了!

看到这里我仿佛明白了什么,打开2dx的CCNode::addChild的代码,在每次addChild的时候,会根据当前数组的容量,进行扩容

复制代码
void ccArrayDoubleCapacity(ccArray *arr){    arr->max *= 2;    CCObject** newArr = (CCObject**)realloc( arr->arr, arr->max * sizeof(CCObject*) );    // will fail when there's not enough memory    CCAssert(newArr != 0, "ccArrayDoubleCapacity failed. Not enough memory");    arr->arr = newArr;}
复制代码

上面的代码用realloc重新分配了内存,但是,在CCNode的onEnter中,是在遍历这个数组,执行所有子节点的onEnter

复制代码
void CCNode::onEnter(){    arrayMakeObjectsPerformSelector(m_pChildren, onEnter, CCNode*);        this->resumeSchedulerAndActions();    m_bIsRunning = true;    if (m_eScriptType != kScriptTypeNone)    {        CCScriptEngineManager::sharedManager()->getScriptEngine()->executeNodeEvent(this, kCCNodeOnEnter);    }}
复制代码

在arrayMakeObjectsPerformSelector中,调用到了2dx底层的一个宏,CCARRAY_FOREACH

复制代码
#define CCARRAY_FOREACH(__array__, __object__)                                                                \    if ((__array__) && (__array__)->data->num > 0)                                                            \    for(CCObject** arr = (__array__)->data->arr, **end = (__array__)->data->arr + (__array__)->data->num-1;    \    arr <= end && (((__object__) = *arr) != NULL/* || true*/);                                                \    arr++)
复制代码

这个宏用于遍历CCArray,它是用指针偏移的方式进行遍历,所以,当我们的数组扩容之后,指针的地址就变了,CCARRAY_FOREACH还在对原先的指针进行访问,当然崩溃了
其实这个BUG很好解决,只需要修改一下CCARRAY_FOREACH的遍历方式,改为下标访问即可,在CCNode::onEnter函数下,将代码调整为如下所示,BUG解决

复制代码
void CCNode::onEnter(){    //arrayMakeObjectsPerformSelector(m_pChildren, onEnter, CCNode*);    if (NULL != m_pChildren)    {        for (int i = 0; i < m_pChildren->count(); ++i)        {            ((CCNode*)(m_pChildren->data->arr[i]))->onEnter();        }    }        this->resumeSchedulerAndActions();    m_bIsRunning = true;    if (m_eScriptType != kScriptTypeNone)    {        CCScriptEngineManager::sharedManager()->getScriptEngine()->executeNodeEvent(this, kCCNodeOnEnter);    }}
复制代码

也许我不应该在onEnter里面addChild,但cocos2d-x更不应该让我在onEnter中添加节点之后崩溃

 

 

1 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 专升本学分不够怎么办 电脑连接无线网络网关禁用怎么办 背部毛孔粗大有黑头怎么办 毛孔变粗大长痘怎么办 皮肤粗糙暗黄毛孔大怎么办 毛孔粗大还有痘印怎么办 高一的不爱上数学怎么办 监狱系统需要体测怀孕怎么办 货运从业资格证年审过期了怎么办 科三线路记不住怎么办? 汽车大灯里面起雾水怎么办 二级重伤对方法庭拒绝赔偿怎么办? 在麦当劳工作收到假钞怎么办 东西湖小学分配太远怎么办 农行k令过期了怎么办 穿军训的鞋捂坏了怎么办 联通手机号销户话费怎么办 建行员工所持有的原始股怎么办 孕妇喝了午时茶怎么办 苹果6id被锁了怎么办 苹果手机app密码忘了怎么办 好哥们借钱手上没钱怎么办 武汉ca证书u盾怎么办 判了刑发现还有漏案没判怎么办 高铁旅客漏乘怎么办 水库里面要养殖小龙虾最好怎么办 点读机的笔丢了怎么办 皮肤晒的很黑怎么办 电脑wifi连接受限制怎么办 高中孩子班管理松怎么办 脱式计算有余数怎么办 手机被别人绑定微信怎么办 饿了么入职查不到学历怎么办 高中没考上家人让打工怎么办 一建证书丢了怎么办 自考大专证书丢了怎么办 护士学分卡丢了怎么办 公司电脑只能用内网怎么办 遇见素质低的人怎么办 被素质低的人骂怎么办 对素质差的人怎么办