首先看看cocos的主循环,这里以application.mm作为实例,相信window平台应该差不多:
while (!glview->windowShouldClose())
{
lastTime = getCurrentMillSecond();
director->mainLoop();
glview->pollEvents();
curTime = getCurrentMillSecond();
if (curTime - lastTime < _animationInterval)
{
usleep(static_cast<useconds_t>((_animationInterval - curTime + lastTime)*1000));
}
}
然后再看director->mainLoop();主要是调用了Director::drawScene();
高潮来了 我们看看Director::drawScene()这个方法:
// calculate “global” dt
calculateDeltaTime();
// skip one flame when _deltaTime equal to zero.
if(_deltaTime < FLT_EPSILON)
{
return;
}
if (_openGLView)
{
_openGLView->pollInputEvents();
}
前后都可以忽略了,关键是if(_deltaTime < FLT_EPSILON)这句判断要了老命,高端机上面的处理循环速度很快,结果反而造成了漏帧。
当然 最重要的还是 calculateDeltaTime();这个方法逻辑有问题:
void Director::calculateDeltaTime()
{
struct timeval now;
if (gettimeofday(&now, nullptr) != 0)
{
CCLOG(“error in gettimeofday”);
_deltaTime = 0;
return;
}
// new delta time. Re-fixed issue #1277
if (_nextDeltaTimeZero)
{
_deltaTime = 0;
_nextDeltaTimeZero = false;
}
else
{
_deltaTime = (now.tv_sec - _lastUpdate->tv_sec) + (now.tv_usec - _lastUpdate->tv_usec) / 1000000.0f;
_deltaTime = MAX(0, _deltaTime);
}
#if COCOS2D_DEBUG
// If we are debugging our code, prevent big delta time
if (_deltaTime > 0.2f)
{
_deltaTime = 1 / 60.0f;
}
#endif
*_lastUpdate = now;
}
可以看到在最后 *_lastUpdate = now;每次都把上次判断的时间更新了!!!!!!!
修改很简单,既然为了避免循环次数太多,造成手机发烫、耗电,那么再刷新时间的时候也需要判断一次:
*_lastUpdate = now;改为
if(_deltaTime >= FLT_EPSILON)
{
*_lastUpdate = now;
}
当然这样的改法还是会出现某些问题,但是至少不会因为高性能而掉帧。至于会出现的其他问题也可能只是我个人代码的问题,这里不表。