我有一个cocos2d v2.x应用程序,它有一个场景,有很多精灵,节点,配置,数据等......加载非常昂贵,以至于当将场景添加到导演时,有一个暂停1/2到1秒,导致当前运行的动画冻结,直到加载场景.我描述了最慢的方法,并尝试在后台线程中异步执行它们,并在加载时显示进度微调器.
我的实现是这样的:
-(void)performAsyncLoad { self.progressSpinner.visible = YES; self.containerForLoadedStuff.visible = NO; self.mainContext = [EAGLContext currentContext]; NSOperationQueue *queue = [NSOperationQueue new]; NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(loadDependencies) object:nil]; [queue addOperation:operation]; } -(void)loadDependencies { @autoreleasepool { glFlush(); EAGLSharegroup *shareGroup = [[(CCGLView*)[[CCDirector sharedDirector] view] context] sharegroup]; EAGLContext *context = [[EAGLContext alloc] initWithAPI:[[EAGLContext currentContext] API] sharegroup:shareGroup]; [EAGLContext setCurrentContext:context]; // ... expensive stuff here // [self.containerForLoadedStuff addChild:sprites, etc...] [self performSelectorOnMainThread:@selector(done) withObject:nil waitUntilDone:NO]; } } -(void)done { glFlush(); [EAGLContext setCurrentContext:self.mainContext]; self.progressSpinner.visible = NO; self.containerForLoadedStuff.visible = YES; }
不幸的是,这不起作用,一旦调用该操作,它就会在CCTextureAtlas的第523行与EXC_BAD_ACCESS崩溃
glDrawElements(GL_TRIANGLES, (GLsizei) n*6, GL_UNSIGNED_SHORT, (GLvoid*) (start*6*sizeof(_indices[0])) );
并且控制台日志显示数十亿:
OpenGL错误0x0502 in - [CCSprite draw] 530
我究竟做错了什么?
UPDATE
我改变了我的代码:
dispatch_queue_t queue = dispatch_queue_create("myqueue", NULL); CCGLView *view = (CCGLView*)[[Director sharedDirector] view]; EAGLContext *context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2 sharegroup:[[view context] sharegroup]]; dispatch_async(queue, ^{ [EAGLContext setCurrentContext:context]; // expensive calls glFlush(); [self performSelector:@selector(done) onThread:[[CCDirector sharedDirector] runningThread] withObject:nil waitUntilDone:NO]; [EAGLContext setCurrentContext:nil]; });
它停止了崩溃,一切正常,但我仍然得到十亿:
OpenGL error 0x0502 in -[CCSprite draw] 530 OpenGL error 0x0502 in -[CCSprite draw] 530 OpenGL error 0x0502 in -[CCSprite draw] 530 OpenGL error 0x0502 in -[CCSprite draw] 530 OpenGL error 0x0502 in -[CCSprite draw] 530 OpenGL error 0x0502 in -[CCSprite draw] 530 OpenGL error 0x0502 in -[CCSprite draw] 530 OpenGL error 0x0502 in -[CCSprite draw] 530 OpenGL error 0x0502 in -[CCSprite draw] 530 OpenGL error 0x0502 in -[CCSprite draw] 530 OpenGL error 0x0502 in -[CCSprite draw] 530 OpenGL error 0x0502 in -[CCSprite draw] 530 OpenGL error 0x0502 in -[CCSprite draw] 530 OpenGL error 0x0502 in -[CCSprite draw] 530
任何想法为什么会发生这些错误以及如何阻止它们?
再来一次更新
这没有任何意义......显然这些错误来自于向CCSpriteBatchNode添加精灵.如果我将它们放在常规CCNode上,那么一切正常.搞什么鬼!?!?!?!?!
和最后一次最终更新*
看来我只是听不到很多废话.我设法让这些错误消失了98%,但它们似乎仍然间歇性地随机发生.我做了大量的调试器和试错测试,发现这段代码:
-(void)loadDependencies { dispatch_queue_t queue = dispatch_queue_create("myqueue", NULL); CCGLView *view = (CCGLView*)[[Director sharedDirector] view]; EAGLContext *context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2 sharegroup:[[view context] sharegroup]]; dispatch_async(queue, ^{ [EAGLContext setCurrentContext:context]; [self.myObject doExpensiveStuff]; glFlush(); [self performSelector:@selector(done) onThread:[[CCDirector sharedDirector] runningThread] withObject:nil waitUntilDone:NO]; [EAGLContext setCurrentContext:nil]; }); } -(void)done { [self.delegate completedAsyncStuff]; }
导致随机崩溃 - 通常是cocos removeFromParent尝试删除无效索引处的四元组...所以然后我尝试暂停对象之前对它进行操作..
//... background thread stuff: [self.myObject pauseSchedulerAndActions]; [self.myObject doExpensiveStuff]; [self.myObject resumeSchedulerAndActions];
然后它不再崩溃,但在日志中放置了那些OpenGL错误0x0502 - [CCSprite draw] 530 ......
那么我做了一些极端的日志记录,试图找出这些错误发生的地方......
... // previous code above... etc NSLog(@"gl flush..."); glFlush(); NSLog(@"after gl flush..."); [self performSelector:@selector(done) onThread:[[CCDirector sharedDirector] runningThread] withObject:nil waitUntilDone:NO]; [EAGLContext setCurrentContext:nil]; }); } -(void)done { NSLog(@"done scheduling notify delegate"); [self scheduleOnce:@selector(notifyDelegate) delay:1]; } -(void)notifyDelegate { NSLog(@"about to notify delegate"); [self.delegate completedAsyncStuff]; }
在我的日志中,我看到:
gl flush after gl flush done scheduling notify delegate OpenGL error 0x0502 in -[CCSprite draw] 530 OpenGL error 0x0502 in -[CCSprite draw] 530 OpenGL error 0x0502 in -[CCSprite draw] 530 OpenGL error 0x0502 in -[CCSprite draw] 530 OpenGL error 0x0502 in -[CCSprite draw] 530 OpenGL error 0x0502 in -[CCSprite draw] 530 OpenGL error 0x0502 in -[CCSprite draw] 530 about to notify delegate
所以这些错误发生在cocos等待计划选择器的触发时???? 我勒个去!?我再也受不了了,没有人能够帮助我,所以现在是赏金的时候了.
我是这样做的:
LoadingScene
-(void) onEnterTransitionDidFinish { [super onEnterTransitionDidFinish]; [NSThread detachNewThreadSelector:@selector(loadGameSceneInAnotherThread) toTarget:self withObject:nil]; } - (void) loadGameSceneInAnotherThread { NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; CCGLView *view = (CCGLView*)[[CCDirector sharedDirector] view]; EAGLContext *auxGLcontext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2 sharegroup:[[view context] sharegroup]]; if( [EAGLContext setCurrentContext:auxGLcontext] ) { self.gameScene = [GameScene sceneWithLevelName:levelName]; self.gameLoadingDone = YES; glFlush(); [EAGLContext setCurrentContext:nil]; } [auxGLcontext release]; [autoreleasepool release]; } //this method ticks every 0.5sec -(void) checkIfGameSceneLoaded { if (self.gameLoadingDone) { [self unschedule:@selector(checkIfGameSceneLoaded)]; [[CCDirector sharedDirector] replaceScene:[CCTransitionFade transitionWithDuration:0.75 scene:self.gameScene]]; } }
但是,我不建议为场景加载背景..因为cocos2d并没有真正设计这样做...