3

UITableViewあり、レイヤー `[[CCDirector sharedDirector].view addSubview:myTableView] の前に表示され、画面の一部を占めています。

すべて正常に動作します。タッチを検出します。ただし、tableView のスクロール アニメーション中は、tableView がこのスクロールを終了するまで、すべての cocos2d がフリーズします。(凍結中は、すべてのノードのアクションが一時停止することを意味します)。

問題は、このような凍結の理由は何ですか?どうすれば回避できますか?


-(void) mainLoop:(id)sender
{
if (dispatch_semaphore_wait(frameRenderingSemaphore, DISPATCH_TIME_NOW) != 0)
{
    return;
}

if (self.useCocoaFriendlyRendering)
{
    dispatch_sync(frameRenderingDispatchQueue, ^{ // HERE dispatch_async make black screen, i shows everything but still bad performance.
        CCGLView *openGLview = (CCGLView*)[self view];
        [EAGLContext setCurrentContext:openGLview.context];
        [self drawScene];
        dispatch_semaphore_signal(frameRenderingSemaphore);
    });
}
else
{
    CCGLView *openGLview = (CCGLView*)[self view];
    [EAGLContext setCurrentContext:openGLview.context];
    [self drawScene];
    dispatch_semaphore_signal(frameRenderingSemaphore);
}
}
4

2 に答える 2

7

その理由は、UIKit ビューが他のビューと連携するように設計されていないためです。これらはユーザーの操作のためのものであるため、通常、スクロールが他のビューの更新を停止しても問題ありません。ユーザーのフォーカスがあり、アニメーション (スクロールなど) に多くのリソースを必要とするビューに最高の応答と感触を与えたいため、非常に理にかなっているユーザー インターフェイス駆動型アプリで。

これを適切に修正する唯一の方法は、cocos2d レンダリング ループをCCDirectorDisplayLinkセマフォで改善することです。

-(void) mainLoop:(id)sender
{
    if (dispatch_semaphore_wait(frameRenderingSemaphore, DISPATCH_TIME_NOW) != 0)
    {
        return;
    }

    if (useCocoaFriendlyRendering)
    {
        dispatch_async(frameRenderingDispatchQueue, ^{
            [EAGLContext setCurrentContext:openGLView_.context];
            [self drawScene];
            dispatch_semaphore_signal(frameRenderingSemaphore);
        });
    }
    else
    {
        [EAGLContext setCurrentContext:openGLView_.context];
        [self drawScene];
        dispatch_semaphore_signal(frameRenderingSemaphore);
    }
}

このコードは、cocos2d drawscene メソッドを独自のディスパッチ キューに配置します。私はかつてそれが何をしたかを理解していましたが、もう思い出せません. :)

注: 最後のディスパッチ セマフォは毎回呼び出す必要はないかもしれませんが、cocoaFriendlyRendering フラグを切り替えると semaphore_wait が無期限に待機する (レンダリングがフリーズする) 可能性があるため、そうしました。だから私は毎回それを知らせるだけです。

次のように更新CCDirectorDisplayLinkしました(CCDirectorIOScocoaFriendlyRendering BOOLを持っています):

@interface CCDirectorDisplayLink : CCDirectorIOS
{
    id displayLink;
    dispatch_semaphore_t frameRenderingSemaphore;
    dispatch_queue_t frameRenderingDispatchQueue;
}
-(void) mainLoop:(id)sender;
@end

startAnimation では、セマフォとディスパッチ キューが作成されます。

- (void) startAnimation
{
        ...
    displayLink = [NSClassFromString(@"CADisplayLink") displayLinkWithTarget:self selector:@selector(mainLoop:)];
    [displayLink setFrameInterval:frameInterval];
    [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];

    frameRenderingSemaphore = dispatch_semaphore_create(1);
    frameRenderingDispatchQueue = dispatch_queue_create("render", DISPATCH_QUEUE_SERIAL);
}

そしてdeallocでリリース:

-(void) dealloc
{
    dispatch_release(frameRenderingDispatchQueue);
    dispatch_release(frameRenderingSemaphore);
    [displayLink release];
    [super dealloc];
}

これにより、スクロール ビューが cocos2d フレームの描画をブロックするのを防ぎます。BOOL を追加cocoaFriendlyRenderingしたので (BOOL プロパティの追加方法はご存知だと思います)、スクロール ビューを使用するシーンでのみこの動作をオンにできるようにしました。これは、パフォーマンスとゲームプレイ中の奇妙な問題を防ぐために良いかもしれないと思いましたが、おそらく必要ではありません.

このコードは cocos2d 1.0.1 用であり、cocos2d 2.x で動作するように少し調整する必要がある場合があります。たとえば、EAGLView -> CCGLView、EAGLContext -> CCGLContext です。

他の解決策は、タイマーやフレームレート (animationInterval) の削減、および/または表示リンク オブジェクトの実行ループ モードの変更を中心に展開します。スクロールがスムーズにいかなかったり、スクロールが突然止まったりすることがあります。cocos2d のレンダリング ループを台無しにしたくなかったので、これらのソリューションをすべて試しましたが、セマフォは、UIKit のスクロールを cocos2d と連携させる (およびその逆) ための唯一の完璧に動作するソリューションでした。

アップデート:

言い忘れていましたが、cocoaFriendlyRendering (init では YES、dealloc では NO) を処理する UIScrollView のサブクラスを作成しました。さらに重要なことに、タッチ イベントをオーバーライドして、必要に応じて cocos2d に転送します (スクロール ビューがスクロールしていないときはいつでも)。 .

オーバーライドされたタッチ メソッドは次のとおりです。

-(void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event
{
    if (self.dragging)
        [super touchesBegan:touches withEvent:event];
    else
        [[CCDirector sharedDirector].openGLView touchesBegan:touches withEvent:event];
}

-(void) touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
{
    if (self.dragging)
        [super touchesMoved:touches withEvent:event];
    else
        [[CCDirector sharedDirector].openGLView touchesMoved:touches withEvent:event];
}

-(void) touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event
{
    [super touchesCancelled:touches withEvent:event];
    [[CCDirector sharedDirector].openGLView touchesCancelled:touches withEvent:event];
}

-(void) touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event
{
    [super touchesEnded:touches withEvent:event];
    [[CCDirector sharedDirector].openGLView touchesEnded:touches withEvent:event];
}
于 2013-03-03T12:51:09.467 に答える