【问题标题】:UITableView & UIScrollview stop cocos2d animationsUITableView & UIScrollview 停止 cocos2d 动画
【发布时间】:2013-03-03 12:35:57
【问题描述】:

我有UITableView,它显示在我的图层 `[[CCDirector sharedDirector].view addSubview:myTableView] 前面并占据了屏幕的一部分。

一切正常:它检测到触摸。 但是 在 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);
}
}

【问题讨论】:

    标签: iphone ios objective-c uitableview cocos2d-iphone


    【解决方案1】:

    原因是因为 UIKit 视图没有设计为与其他视图协作。它们用于用户交互,因此滚动停止更新其他视图通常无关紧要。在用户界面驱动的应用程序中,这很有意义,因为您希望对具有用户焦点并需要大量资源来制作动画(即滚动)的视图提供最佳响应和感觉。

    正确解决此问题的唯一方法是使用信号量改进 CCDirectorDisplayLink 中的 cocos2d 渲染循环:

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

    这可以防止滚动视图阻塞 cocos2d 框架绘制。我添加了cocoaFriendlyRendering BOOL(我假设您知道如何添加 BOOL 属性),所以我可以只为使用滚动视图的场景启用此行为。我认为这可能会更好地提高性能并防止游戏过程中出现任何奇怪的问题,但可能没有必要。

    此代码适用于 cocos2d 1.0.1,可能需要稍作调整才能与 cocos2d 2.x 一起使用,例如 EAGLView -> CCGLView、EAGLContext -> CCGLContext。

    Other solutions revolve around timers 和/或降低帧率 (animationInterval) 和/或更改显示链接对象的运行循环模式。它们并不能很好地工作,滚动可能不流畅或滚动可能突然停止。我尝试了所有这些解决方案,因为我不想弄乱 cocos2d 的渲染循环 - 但是信号量是唯一可以使 UIKit 滚动与 cocos2d 协作的完美工作解决方案(反之亦然)。

    更新:

    我忘了提一下,我创建了一个 UIScrollView 的子类来处理 cocoaFriendlyRendering(初始化时是,dealloc 时否),更重要的是,它会覆盖触摸事件,以便根据需要将它们转发到 cocos2d(只要滚动视图不是t 滚动)。

    这些是被覆盖的触摸方法:

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

    【讨论】:

    • 问这个问题不知道为什么,我相信你会回答的:)
    • 我试图理解你在这里写的一切,做了所有的替换,仍然有黑屏
    • 我还能说什么。我设置 useCocoaFriendlyRendering = NO,它对我有用!:) 我发现 tableView 滚动质量较差,但猴子替换和复制粘贴对我有用。现在我将尝试了解我所做的所有更改:) 谢谢!
    • 你能解释一下如何使用 cocoaFriendlyRendering(我在 CCDirectorIOS 中添加了这个属性),因为如果它是 NO,它会对性能产生可怕的影响,如果是,我就会黑屏。
    • 这是cocos2d 2.x 的吗?我没试过。我没有测量性能,因为没有显着差异,但当然这是在没有物理或其他性能密集型任务的菜单屏幕中。我只在添加滚动视图(更改场景)之前启用 cocoaFriendlyRendering,并在滚动视图消失时禁用它。就是这样。
    【解决方案2】:

    进入 CCDirector.m OR CCDirectorIOS.m 文件并找到这一行:

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

    改成这样:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-05-16
      • 2011-11-15
      • 1970-01-01
      • 1970-01-01
      • 2015-12-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多