3

我正在使用 CCScrollLayer,我想在玩家选择阶段期间准备图像。这很简单,但是当我滚动阶段时,它会处理时间(延迟加载图像)。

所以我决定使用 NSThread。我从 cocos2d 收到一条消息“cocos2d: CCSpriteFrameCache: Trying to use file 'Level3.png' as texture”。那么它应该会出现。但是我在线程上加载的这些图像并没有像我想要的那样出现。根本不值一提。

-(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];
}
4

3 回答 3

1

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

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

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

资源

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

或者您可以实现自己的,实际上与 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];
于 2011-11-01T00:37:37.960 回答
0

我相信正在发生的事情是主线程在 prepareTexture 线程有机会加载纹理之前尝试使用图像。

如果您立即尝试使用新纹理创建精灵,例如在 moveToStagePage 方法中,那么这将失败。您的线程纹理加载方法将需要向另一个线程标记它已完成加载纹理。最简单的方法是简单地切换一个 BOOL 变量。只有当纹理加载线程发出已加载纹理的信号时,您才应尝试使用这些纹理创建精灵等。

于 2011-10-31T22:28:44.647 回答
0

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

于 2011-10-31T22:49:44.773 回答