引擎初始化的时候,会获取应用状态是否在前台,有时候会发生应用状态获取错误的情况,导致引擎初始化设置isAppActive的值为false,所以不执行mainLoop。
源码分析
CCDirectorCaller-ios.mm是引擎对ios平台的适配。
看init方法可以发现,引擎初始化的时候会根据当前应用是否在前台来设置isAppActive的值。并且监听了应用前后台切换的事件来更新isAppActive的值。
在startMainLoop里面可以看到,引擎通过监听ios的屏幕刷新事件来调用doCaller方法,在doCaller中会判断isAppActive的值来决定是否执行director的mainLoop方法。
问题就出现在ios初始化引擎的时候,应用处于前台状态[UIApplication sharedApplication].applicationState == UIApplicationStateActive也偶尔会得到false。这点跟ios开发联调发现,确实会有状态判断错误的情况(可能是ios系统的问题)。
#include <mach/mach_time.h>
#import "platform/ios/CCDirectorCaller-ios.h"
#include "platform/CCDevice.h"
#import <Foundation/Foundation.h>
#import <OpenGLES/EAGL.h>
#import "base/CCDirector.h"
#import "platform/ios/CCEAGLView-ios.h"
static id s_sharedDirectorCaller;
@interface NSObject(CADisplayLink)
+(id) displayLinkWithTarget: (id)arg1 selector:(SEL)arg2;
-(void) addToRunLoop: (id)arg1 forMode: (id)arg2;
-(void) setFrameInterval: (NSInteger)interval;
-(void) invalidate;
@end
@implementation CCDirectorCaller
@synthesize interval;
+(id) sharedDirectorCaller
{
if (s_sharedDirectorCaller == nil)
{
s_sharedDirectorCaller = [[CCDirectorCaller alloc] init];
}
return s_sharedDirectorCaller;
}
+(void) destroy
{
[s_sharedDirectorCaller stopMainLoop];
[s_sharedDirectorCaller release];
s_sharedDirectorCaller = nil;
}
- (instancetype)init
{
if (self = [super init])
{
isAppActive = [UIApplication sharedApplication].applicationState == UIApplicationStateActive;
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:@selector(appDidBecomeActive) name:UIApplicationDidBecomeActiveNotification object:nil];
[nc addObserver:self selector:@selector(appDidBecomeInactive) name:UIApplicationWillResignActiveNotification object:nil];
self.interval = 1;
}
return self;
}
-(void) dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[displayLink release];
[super dealloc];
}
- (void)appDidBecomeActive
{
// initialize initLastDisplayTime, or the dt will be invalid when
// - the app is lauched
// - the app resumes from background
[self initLastDisplayTime];
isAppActive = YES;
}
- (void)appDidBecomeInactive
{
isAppActive = NO;
}
-(void) startMainLoop
{
// Director::setAnimationInterval() is called, we should invalidate it first
[self stopMainLoop];
displayLink = [NSClassFromString(@"CADisplayLink") displayLinkWithTarget:self selector:@selector(doCaller:)];
[displayLink setFrameInterval: self.interval];
[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}
-(void) stopMainLoop
{
[displayLink invalidate];
displayLink = nil;
}
-(void) setAnimationInterval:(double)intervalNew
{
// Director::setAnimationInterval() is called, we should invalidate it first
[self stopMainLoop];
self.interval = 60.0 * intervalNew;
displayLink = [NSClassFromString(@"CADisplayLink") displayLinkWithTarget:self selector:@selector(doCaller:)];
[displayLink setFrameInterval: self.interval];
[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}
-(void) doCaller: (id) sender
{
if (isAppActive) {
cocos2d::Director* director = cocos2d::Director::getInstance();
if(!CC_USE_METAL) {
EAGLContext* cocos2dxContext = [(CCEAGLView*)director->getOpenGLView()->getEAGLView() context];
if (cocos2dxContext != [EAGLContext currentContext])
glFlush();
[EAGLContext setCurrentContext: cocos2dxContext];
}
CFTimeInterval dt = ((CADisplayLink*)displayLink).timestamp - lastDisplayTime;
lastDisplayTime = ((CADisplayLink*)displayLink).timestamp;
director->mainLoop(dt);
}
}
-(void)initLastDisplayTime
{
struct mach_timebase_info timeBaseInfo;
mach_timebase_info(&timeBaseInfo);
CGFloat clockFrequency = (CGFloat)timeBaseInfo.denom / (CGFloat)timeBaseInfo.numer;
clockFrequency *= 1000000000.0;
// convert absolute time to seconds and should minus one frame time interval
lastDisplayTime = (mach_absolute_time() / clockFrequency) - ((1.0 / 60) * self.interval);
}
@end
解决方案
在引擎中添加了一个额外设置isAppActive的方法,在ios初始化引擎的时候主动设置isAppActive为true。
2528

被折叠的 条评论
为什么被折叠?



