2011-10-31 51 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

的執行情況非常感謝^^ –