现在的位置: 首页 > 综合 > 正文

box2d再遇新问题(其实是cocos2d的问题,+_+)

2018年05月18日 ⁄ 综合 ⁄ 共 6575字 ⁄ 字号 评论关闭

在项目进行的路程上,总会遇到各种各样的问题,而解决这些问题所要花费的时间,

对于我这种连门都还只跨进了半步的小小菜鸟,真的是要看人品了~

想当初夸下海口说一个月就把目前策划的这款游戏搞出来,看来希望不怎么大了

现实往往是如此的残酷,吼一声,老天你能否少给我出一些难题?!

发泄归发泄,不过问题总算是解决了,还是很可喜可贺的!!

今天遇到的这个问题,是在cocos2d切换场景的时候出现的,

切换场景以后,单例中持有的GameScene中的b2World对象的引用竟然变成了NULL?!!

相当的蛋疼,刚开始的时候,报错出现在b2World->CreateBody()方法上面,

说什么 m_freelist[index] (b2World还是b2Body的成员变量) 有问题,总之,报出的错误又是可恶的EXEC_BAD_ACCESS!!

妈的objective-c的报错系统可真是先进,不管什么都能归结到 EXEC_BAD_ACCESS上面来~

怎么就不发扬一下java的优点呢?!我后来测了下,发现就是调用CreateBody()方法的b2World对象为NULL

他妈的不就是Java里面的nullPointer么,蛋疼不蛋疼,害我暴力调试了好一会儿才发现从单例中取出来的这个鸟原来是NULL大哥~

我检查了一遍又一遍,GameScene里面的几百行代码我看了一遍又一遍,我不烦代码代码都烦我了~

没办法,拿出看家本领,到处NSLog(),其实我也知道,如果这个时候懂的下断点的技巧的话,是根本用不着这么麻烦的,

到时候这些NSLog还得一个个找出来删除或注释掉,真是他妈的麻烦~

我想到了一个好办法,我直接在tick方法里面加入了一行nSLog语句,什么时候单例中持有的GameScene中的b2World对象的指针变为NULL了

立马就输出一条 “怎么为NULL了?”的语句,果然是大有进展,以下贴出控制台的输出:

*****************************************************************************************

[Switching to process 1353 thread 0x10f0b]

2011-09-27 23:59:48.835 GoldMine0.4[1353:c503] Retina Display Not supported

2011-09-27 23:59:48.839 GoldMine0.4[1353:c503] cocos2d: surface size: 480x320

2011-09-27 23:59:48.849 GoldMine0.4[1353:c503] Screen width 480.00 screen height 320.00

2011-09-27 23:59:48.857 GoldMine0.4[1353:c503]地图的大小为:480.000000,
320.000000

2011-09-27 23:59:48.869 GoldMine0.4[1353:c503] Denshion::CDAudioManager - Audio session set category AVAudioSessionCategorySoloAmbient failed with error Error Domain=NSOSStatusErrorDomain
Code=-50 "The operation couldn’t be completed. (OSStatus error -50.)"

AudioStreamBasicDescription:  2 ch,  44100 Hz, 'lpcm' (0x00000C2C) 8.24-bit little-endian signed integer, deinterleaved

[Switching to process 1353 thread 0xc503]

2011-09-27 23:59:49.826 GoldMine0.4[1353:c503] GameScene init

2011-09-27 23:59:49.826 GoldMine0.4[1353:c503] cocos2d: Frame interval: 1

2011-09-27 23:59:49.829 GoldMine0.4[1353:c503] XMLParserdealloc方法被调用~

2011-09-27 23:59:54.877 GoldMine0.4[1353:c503] Screen width 480.00 screen height 320.00

2011-09-27 23:59:54.878 GoldMine0.4[1353:c503]地图的大小为:480.000000,
320.000000

2011-09-27 23:59:54.882 GoldMine0.4[1353:c503] GameScene init

2011-09-27 23:59:54.882 GoldMine0.4[1353:c503] GoldMineScene dealloc begins!

2011-09-27 23:59:54.883 GoldMine0.4[1353:c503] GoldMineScene dealloc finished!

2011-09-27 23:59:54.888 GoldMine0.4[1353:c503] XMLParserdealloc方法被调用~

2011-09-27 23:59:54.894 GoldMine0.4[1353:c503]怎么世界竟然为NULL了?

2011-09-27 23:59:54.910 GoldMine0.4[1353:c503]怎么世界竟然为NULL了?

2011-09-27 23:59:54.927 GoldMine0.4[1353:c503]怎么世界竟然为NULL了?

2011-09-27 23:59:54.945 GoldMine0.4[1353:c503]怎么世界竟然为NULL了?

2011-09-27 23:59:54.961 GoldMine0.4[1353:c503]怎么世界竟然为NULL了?

2011-09-27 23:59:54.978 GoldMine0.4[1353:c503]怎么世界竟然为NULL了?

2011-09-27 23:59:54.994 GoldMine0.4[1353:c503]怎么世界竟然为NULL了?

2011-09-27 23:59:55.010 GoldMine0.4[1353:c503]怎么世界竟然为NULL了?

2011-09-27 23:59:55.027 GoldMine0.4[1353:c503]怎么世界竟然为NULL了?

2011-09-27 23:59:55.044 GoldMine0.4[1353:c503]怎么世界竟然为NULL了?

................

*******************************************************************

我的默认设定是一个场景开始之后过5秒马上切换到下一幅场景,红色开始的地方是一个分界线~

再来一段更有说服力的控制台输出,之后我将下结论

*******************************************************************

[Switching to process 1460 thread 0xc503]

2011-09-28 00:10:32.203 GoldMine0.4[1460:c503] Retina Display Not supported

2011-09-28 00:10:32.220 GoldMine0.4[1460:c503] cocos2d: surface size: 480x320

2011-09-28 00:10:32.235 GoldMine0.4[1460:c503]GameScene init starts!!

2011-09-28 00:10:32.283 GoldMine0.4[1460:c503] Screen width 480.00 screen height 320.00

2011-09-28 00:10:32.284 GoldMine0.4[1460:c503]地图的大小为:480.000000, 320.000000

2011-09-28 00:10:32.303 GoldMine0.4[1460:c503] Denshion::CDAudioManager - Audio session set category AVAudioSessionCategorySoloAmbient failed with error Error Domain=NSOSStatusErrorDomain
Code=-50 "The operation couldn’t be completed. (OSStatus error -50.)"

AudioStreamBasicDescription:  2 ch,  44100 Hz, 'lpcm' (0x00000C2C) 8.24-bit little-endian signed integer, deinterleaved

2011-09-28 00:10:33.309 GoldMine0.4[1460:c503]GameScene init finished!

2011-09-28 00:10:33.320 GoldMine0.4[1460:c503] cocos2d: Frame interval: 1

2011-09-28 00:10:33.331 GoldMine0.4[1460:c503] XMLParserdealloc方法被调用~

2011-09-28 00:10:39.147 GoldMine0.4[1460:c503]GameScene init starts!!

2011-09-28 00:10:39.148 GoldMine0.4[1460:c503] Screen width 480.00 screen height 320.00

2011-09-28 00:10:39.150 GoldMine0.4[1460:c503]地图的大小为:480.000000, 320.000000

2011-09-28 00:10:39.165 GoldMine0.4[1460:c503]GameScene init finished!

2011-09-28 00:10:39.166 GoldMine0.4[1460:c503] XMLParserdealloc方法被调用~

2011-09-28 00:10:39.167 GoldMine0.4[1460:c503]GameScene dealloc begins!

2011-09-28 00:10:39.167 GoldMine0.4[1460:c503]GameScene dealloc is finished!

Assertion failed: (r.LengthSquared() > 0.0f),已自动忽略!!

Assertion failed: (r.LengthSquared() > 0.0f),已自动忽略!!

2011-09-28 00:10:53.040 GoldMine0.4[1460:c503]GameScene init starts!!

2011-09-28 00:10:53.041 GoldMine0.4[1460:c503] Screen width 480.00 screen height 320.00

2011-09-28 00:10:53.042 GoldMine0.4[1460:c503]地图的大小为:480.000000, 320.000000

2011-09-28 00:10:53.053 GoldMine0.4[1460:c503]GameScene init finished!

2011-09-28 00:10:53.053 GoldMine0.4[1460:c503] XMLParserdealloc方法被调用~

2011-09-28 00:10:53.054 GoldMine0.4[1460:c503]GameScene dealloc begins!

2011-09-28 00:10:53.055 GoldMine0.4[1460:c503]GameScene dealloc is finished!

Assertion failed: (r.LengthSquared() > 0.0f),已自动忽略!!

Assertion failed: (r.LengthSquared() > 0.0f),已自动忽略!!

*******************************************************************
从上面可以清楚的看到,GameScene的构造方法执行了两次之后才开始第一次执行GameScene的dealloc方法!!
这就说明:GameScene在切换场景的时候,是
先将新场景的init方法执行完毕之后再执行的上一个场景的 dealloc方法!!

这么做我一开始真的没想到,其实仔细想一下一个优秀的引擎确实应该如此设计

对游戏感兴趣的一般都听说过双缓冲这个处理吧?

刚开始在程序编写入门的时候,做的第一个东西就是游戏,是一个联网版的java中国象棋

也是在做那个游戏的过程中,我第一次认识到了什么是双缓冲处理。。

双缓冲其实很简单,就是在游戏画面切换到下一帧之前,提前在内存中将下一副将要显示的画面绘制完毕,

之后就可以直接从内存中提取到窗口中来了,这样的话玩家的眼睛不会觉得累~

如果是跑到那一帧就即时画那一帧的话,眼睛肯定是受不了的,对马士兵尚学堂的坦克大战还有深刻印象~

那种犀利的绿色背景+红色坦克车身,现在想起来眼睛还止不住地想流水,丫的,看的眼睛太累了~

okay,到这里问题就算是圆满结束了~

其实我还想说一句,我是在GameScene的init方法中产生b2World对象并用单例中的指针指向这个对象的~

由于过于害怕出现内存泄露的情况而我在这方面又很没有经验,所以,

我便自作聪明的在GameScene的dealloc方法中加入了一句将单例中指向b2World对象的指针置为NULL的代码~

不巧的是,就是这行代码让我费尽心机,睁大眼睛足足找了4个小时!!蛋疼!!

贴出GameScene的dealloc方法杀鸡给猴看,哈哈~

- (void) dealloc {
    NSLog(@"GoldMineScene dealloc begins!");
    // C++ part
	delete _world;
	_world = NULL;
	delete _m_debugDraw;
	_m_debugDraw = NULL;
    
	
    // Objective-c part
//    [_laserSegment dealloc];  // 详见 GoldMineScene 的 tick 方法(已经dealloc了)~
    [_eleBallContainer dealloc];
	[_spriteContainer dealloc];
    
    /** 
     * - -,我错了,这是必须要注释掉的!! 场景切换时,先调用新场景的init方法
     * 新场景的init方法调用完之后,才会调用上一个场景的 dealloc 方法,这么一来的话这行代码反而帮倒忙了~
     */
//    [[BYSingle getInstance] setGameSceneWorld:NULL];
    
//    [_level dealloc]; // 详见 GoldMineScene头文件,XMLParser的mm文件~
	[super dealloc];
    NSLog(@"GoldMineScene dealloc finished!");
}
@end

还有一件事情,之所以这么个小问题花了我这么长的时间,还是在于我被误导了,贴出连接

http://www.box2d.org/forum/viewtopic.php?f=3&t=4070

erin catto的回复我理解为如果world是在回调函数中创建的话,此时的b2World调用isLocked()方法将为返回true

这样就无法通过断言:Assert(isLocked()!=true),于是便会抛出错误

如上所述,其实问题本不是在这里的,暴汗,今后,还是得严谨一点儿啊,这次的乱猜确实给我带来了不小的麻烦~

抱歉!评论已关闭.