2013-03-03 164 views
3

我有UITableView,它顯示在我的圖層`[[CCDirector sharedDirector] .view addSubview:myTableView]的前面,並佔據屏幕的某一部分。UITableView&UIScrollview停止cocos2d動畫

一切工作正常:它檢測到觸摸。 在tableView的滾動動畫期間所有的cocos2d凍結直到tableView結束這個滾動。 (在凍結下,我的意思是所有節點的動作暫停)。

問題是:這種凍結的原因是什麼,我該如何避免它?


-(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); 
} 
} 

回答

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如下(CCDirectorIOS有cocoaFriendlyRendering 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]; 
} 

這防止scrol l阻止cocos2d框架圖的視圖。我加入了cocoaFriendlyRendering BOOL(我假設你知道如何添加一個BOOL屬性),所以我可以把這種行爲只針對那些使用滾動視圖場景。我認爲這可能會更好的表現,並防止在遊戲過程中出現任何奇怪的問題,但可能沒有必要。

此代碼適用於cocos2d 1.0.1,可能需要稍微改編以使用cocos2d 2.x,例如EAGLView - > CCGLView,EAGLContext - > CCGLContext。

Other solutions revolve around timers和/或降低幀率(animationInterval)和/或改變顯示鏈接對象的運行循環模式。它們並不太好,滾動可能不順暢或滾動可能突然停止。我想所有這些解決方案,因爲我不想惹的cocos2d的渲染循環 - 但信號是唯一的工作完美無缺的解決方案,使滾動的UIKit與cocos2d中(反之亦然)的合作。

UPDATE:

我忘了說,我做的UIScrollView的子類,處理cocoaFriendlyRendering(YES上的init,NO在dealloc中),更重要的是,它將覆蓋觸摸事件轉發他們的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]; 
} 
+0

問這個問題不知道爲什麼,我確信你會回答它:) – 2013-03-03 13:20:18

+0

我試圖理解everythin你寫在這裏,取得所有替換,仍然有黑屏 – 2013-03-03 13:20:54

+0

我能說什麼更多。我設置useCocoaFriendlyRendering = NO,它適用於我!:)我看到tableView滾動不那麼定性,但猴子替換和複製粘貼爲我工作。現在我將嘗試瞭解我所做的所有更改:)謝謝! – 2013-03-03 13:25:06

2

走進了CCDirector.m或CCDirectorIOS.m文件,找到這一行:

[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 

它改成這樣:

[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];