2011-10-31 60 views
3

我正在使用CCScrollLayer,我想在玩家选择阶段时准备图像。这很简单,但当我滚动舞台时,它执行时间(延迟加载图像)。我在线程中加载的图像没有出现

所以我决定使用NSThread。并且我收到了一条消息:“cocos2d:CCSpriteFrameCache:尝试从cocos2d使用文件'Level3.png'作为纹理”。那么它应该出现。但是我在线程上加载的这些图像不会按我的意思显示。根本不值一提。

-(void) moveToStagePage:(int)page 
{ 
    ... 
    [NSThread detachNewThreadSelector:@selector(prepareTexture:) toTarget:self withObject:[NSNumber numberWithInt:page]]; 
    ... 
} 

低于源是准备图像的代码。(线程)

-(void) prepareTexture:(NSNumber*)number 
{ 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 

    int _page = [number intValue]; 
    NSLog(@"%d Thread start", _page); 

    if(loadingTexNum != 0 && (_page + 1) != loadingTexNum) 
    { 
     [[CCSpriteFrameCache sharedSpriteFrameCache] removeSpriteFramesFromFile:[NSString stringWithFormat:@"Level%d.plist", loadingTexNum]]; 
     loadingTexNum = _page + 1; 
     [[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:[NSString stringWithFormat:@"Level%d.plist", loadingTexNum]]; 
    } 

    if(loadingTexNum == 0 && (_page + 1) != loadingTexNum) 
    { 
     loadingTexNum = _page + 1; 
     [[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:[NSString stringWithFormat:@"Level%d.plist", loadingTexNum]]; 
    } 

    [NSThread sleepForTimeInterval:10.0]; 
    NSLog(@"%d Thread release", _page); 
    [pool release]; 
} 

回答

1

除非您传递openGL上下文,否则OpenGL不支持在多个线程上加载。

Mac OS X进程中的每个线程都有一个当前的OpenGL渲染上下文。每当应用程序调用OpenGL函数时,OpenGL都会隐式地查找与当前线程关联的上下文,并修改与该上下文关联的状态或对象。

OpenGL不可重入。如果您同时从多个线程修改相同的上下文,结果是不可预测的。您的应用程序可能会崩溃,或者它可能会导致不正确。如果由于某种原因,您决定设置多个线程来定位相同的上下文,那么您必须通过在所有对上下文的OpenGL调用(例如gl *和CGL *)中放置一个互斥锁来同步线程。阻塞的OpenGL命令(如fence命令)不会同步线程。

Source

您可以在CCTextureCache类使用- (void) addImageAsync:(NSString *)filename target:(id) target selector:(SEL)selector;,调用这个在你的主线程。

或者你可以实现自己的,有效地像addImageAsync一样。

供您参考,这是CCTextureCache达到如何加载图像:

NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; 

     // textures will be created on the main OpenGL context 
     // it seems that in SDK 2.2.x there can't be 2 threads creating textures at the same time 
     // the lock is used for this purpose: issue #472 
     [contextLock lock]; 
     if(auxEAGLcontext == nil) { 
       auxEAGLcontext = [[EAGLContext alloc] 
                  initWithAPI:kEAGLRenderingAPIOpenGLES1 
                  sharegroup:[[[[CCDirector sharedDirector] openGLView] context] sharegroup]]; 

       if(! auxEAGLcontext) 
         CCLOG(@"cocos2d: TextureCache: Could not create EAGL context"); 
     } 

     if([EAGLContext setCurrentContext:auxEAGLcontext]) { 

       // load/create the texture 
       CCTexture2D *tex = [self addImage:async.data]; 

       // The callback will be executed on the main thread 
       [async.target performSelectorOnMainThread:async.selector withObject:tex waitUntilDone:NO]; 

       [EAGLContext setCurrentContext:nil]; 
     } else { 
       CCLOG(@"cocos2d: TetureCache: EAGLContext error"); 
     } 
     [contextLock unlock]; 

     [autoreleasepool release]; 
+0

非常感谢..我不知道如何欣赏。非常感谢。 –

0

我相信所发生的事情是,主线程试图使用图像prepareTexture线程有机会到前加载纹理。

如果您立即尝试使用新纹理创建精灵,例如在moveToStagePage方法中,则会失败。你的线程纹理加载方法将需要标记给已完成加载纹理的其他线程。最简单的方法是简单地切换BOOL变量。只有纹理加载线程发信号通知纹理已经加载时,你应该尝试使用这些纹理来创建精灵等。

+0

没有,moveToStagePage还准备只是下一个步骤。我检查了你在说什么。但事实并非如此。我等到足够的纹理加载。但是谢谢 –

+0

你在很多不同的问题上给了我很多帮助。我很感激。 –

+0

@ LearnCocos2D尽管您认为资产可能尚未准备就绪,但限制仅限于OpenGL上下文,并且在不改变上下文的情况下不能多线程化。看看[CCTextureCache addImageWithAsyncObject:]' –

0

当在一个单独的线程上加载纹理时,你需要使用[[CCTextureCache sharedTextureCache] addImageAsync:texture target:target selector:@selector(onTextureLoaded)];(否则GLContext会搞砸)。

+0

的执行情况非常感谢^^ –