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

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

问题描述

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

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



问题是:这种冻结的原因是什么,
$ b




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

if(self.useCocoaFriendlyRendering)
{
dispatch_sync(frameRenderingDispatchQueue,^ {//这里dispatch_async使黑屏,我显示一切,但仍然表现不佳。
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视图不是设计为与其他视图协作。它们用于用户交互,因此,如果滚动停止更新其他视图通常没有关系。在一个用户界面驱动的应用程序,这是很有道理,因为你想给予最好的反应和感觉的视图有用户的焦点,需要很多资源动画(即滚动)。



正确修复此问题的唯一方法是使用信号量改进 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 有可可的FriendlyRendering 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。



/ question / 5133731 / how-to-make-ui-responsive-all-the-time-and-do-background-updating>其他解决方案围绕定时器和/或减少帧率(animationInterval)或改变显示链接对象的运行循环模式。他们不是真的工作得很好,滚动可能不顺利或滚动可能突然停止。我尝试所有这些解决方案,因为我不想混乱cocos2d的渲染循环 - 但信号量是唯一完美的工作解决方案,使UIKit滚动与cocos2d合作(反之亦然)。



UPDATE:



我忘了提及,我做了一个UIScrollView的子类处理cocoaFriendlyRendering on 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];
}


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

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

解决方案

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).

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

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. :)

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.

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

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

And released in dealloc:

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

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.

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.

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).

UPDATE:

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天全站免登陆