3

CCScrollLayerを使用しており、プレーヤーがステージを選択するときに画像を準備したいと思います。シンプルですが、ステージをスクロールすると、時間(画像の読み込みの遅延)が発生します。

そこで、NSThreadを使用することにしました。cocos2dから「cocos2d:CCSpriteFrameCache:ファイル'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];
}
4

3 に答える 3

1

OpenGLは、openGLコンテキストを渡さない限り、複数のスレッドでのロードをサポートしていません。

Mac OS Xプロセスの各スレッドには、単一の現在のOpenGLレンダリングコンテキストがあります。アプリケーションがOpenGL関数を呼び出すたびに、OpenGLは現在のスレッドに関連付けられているコンテキストを暗黙的に検索し、そのコンテキストに関連付けられている状態またはオブジェクトを変更します。

OpenGLは再入可能ではありません。複数のスレッドから同時に同じコンテキストを変更すると、結果は予測できません。アプリケーションがクラッシュしたり、正しくレンダリングされなかったりする可能性があります。何らかの理由で同じコンテキストをターゲットにするように複数のスレッドを設定する場合は、gl*やCGL*などのコンテキストへのすべてのOpenGL呼び出しの周りにミューテックスを配置してスレッドを同期する必要があります。ブロックするOpenGLコマンド(フェンスコマンドなど)は、スレッドを同期しません。

ソース

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];
于 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 に答える