UITableView &UIScrollview 停止 cocos2d 动画 [英] UITableView & UIScrollview stop cocos2d animations

查看:19
本文介绍了UITableView &UIScrollview 停止 cocos2d 动画的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have UITableView, which is shown in front of my Layer `[[CCDirector sharedDirector].view addSubview:myTableView] and takes some part of the screen.

一切正常:它检测到触摸.但是 在 tableView 的滚动动画期间,所有 cocos2d 都会冻结,直到 tableView 结束这个滚动.(在冻结状态下,我的意思是所有节点的动作都暂停).

Everything works fine: it detects touches. But during the scroll animation of the tableView all cocos2d freezes untill tableView ends this scrolling. (Under freezing i mean all nodes actions pauses).

问题是:这种冻结的原因是什么,我该如何避免?

The question is : what is the reason of such freezing and how can i avoid it?

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

推荐答案

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

The reason is because UIKit views are not designed to be cooperative with other views. They're for user interaction, and so it usually doesn't matter if scrolling stops updating other views. In a user-interface driven app that makes a lot of sense because you want to give the best response and feel to the view that has the user's focus and needs a lot of resources to animate (ie scrolling).

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

The only way to fix this properly is to improve the cocos2d render loop in CCDirectorDisplayLink with a semaphore:

-(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 方法放在它自己的调度队列中.我曾经明白它做了什么,但我不记得了,所以与其错误地解释它的作用或它为什么起作用,我希望有人可以在评论中填写它.:)

This code puts the cocos2d drawscene method in its own dispatch queue. I once understood what it did but I can't remember it anymore, so instead of incorrectly explaining what it does or why it works I'm hoping someone can fill this in in a comment. :)

注意:可能不需要每次都调用最后一个调度信号量,但我这样做是因为切换 cocoaFriendlyRendering 标志可能会导致 semaphore_wait 无限期等待(冻结渲染).所以我只是每次都发出信号.

Note: the last dispatch semaphore may not need to be called every time, but I did because switching the cocoaFriendlyRendering flag might otherwise cause the semaphore_wait to wait indefinitely (freezes rendering). So I just signal it every time.

我更新了我的 CCDirectorDisplayLink 如下(CCDirectorIOS 有 cocoaFriendlyRendering BOOL):

I updated my CCDirectorDisplayLink as follows (CCDirectorIOS has the cocoaFriendlyRendering BOOL):

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

在 startAnimation 中创建信号量和调度队列:

In startAnimation the semaphore and dispatch queue are created:

- (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 中释放:

And released in dealloc:

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

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

This prevents the scroll view from blocking the cocos2d frame drawing. I added the cocoaFriendlyRendering BOOL (I assume you know how to add a BOOL property) so I could turn this behavior on only for scenes that do use scroll views. I thought this might be better for performance and to prevent any odd issues during gameplay, but it's probably not necessary.

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

This code is for cocos2d 1.0.1 and might need to be slightly adapted to work with cocos2d 2.x, for example EAGLView -> CCGLView, EAGLContext -> CCGLContext.

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

Other solutions revolve around timers and/or reducing the framerate (animationInterval) and/or changing the run loop mode of the display link object. They don't really work too well, scrolling might not be smooth or scrolling might suddenly stop. I tried all of those solutions because I didn't want to mess with cocos2d's render loop - but the semaphore was the only flawlessly working solution to make UIKit scrolling cooperative with cocos2d (and vice versa).

更新:

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

I forgot to mention, I made a subclass of UIScrollView that handles cocoaFriendlyRendering (YES on init, NO on dealloc) and more importantly, it overrides the touch events as to forward them to cocos2d as needed (whenever the scroll view isn't scrolling).

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

These are the overridden touch methods:

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

这篇关于UITableView &UIScrollview 停止 cocos2d 动画的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆