Iphone 创建NSThread游戏循环

Iphone 创建NSThread游戏循环,iphone,objective-c,ipad,game-loop,Iphone,Objective C,Ipad,Game Loop,我正在尝试创建一个NSThread游戏循环,我有一些时间能够获得57 FPS的成功 有时我的fps会上升到一些可笑的数字 我不明白这是怎么发生的 我检查距离最后一个循环有多长时间了,如果是快的话,让线程休眠那么长时间 这种情况并不总是发生,它有时会逃避对速度的if检查,并以循环方式加速 任何评论都意味着很多 还有,我应该在哪里打勾 - (void)gameLoop{ //gameIsRunning is set to TRUE in viewDidLoad while (gam

我正在尝试创建一个NSThread游戏循环,我有一些时间能够获得57 FPS的成功

有时我的fps会上升到一些可笑的数字

我不明白这是怎么发生的

我检查距离最后一个循环有多长时间了,如果是快的话,让线程休眠那么长时间

这种情况并不总是发生,它有时会逃避对速度的if检查,并以循环方式加速

任何评论都意味着很多

还有,我应该在哪里打勾

   - (void)gameLoop{
   //gameIsRunning is set to TRUE in viewDidLoad
   while (gameIsRunnning){
   NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    //Get Current date
    NSDate *curTime = [NSDate date];

    //Time since last loop and vurrent date;
    NSTimeInterval timePassed_ms = [curTime timeIntervalSinceDate:old_date];// * 1000.0;

    NSLog(@"***************");

    //Cout the time interval
    NSLog(@"Loop Time %f",timePassed_ms);

    //Check if the loop was to fast and sleep for long enough to make up for about 60 FPS
    if (timePassed_ms < 1.0/60) {
        double timeToSleep = timePassed_ms - (1.0/60);
        timeToSleep = timeToSleep*-1;
        NSLog(@"Sleep For %f",timeToSleep);
        [NSThread sleepForTimeInterval:timeToSleep];
    }

    //This new date is to try and check if after waiting the loop is taking the correct duration
    NSDate *newDate = [NSDate date];
    NSTimeInterval timePassed_after = [newDate timeIntervalSinceDate:curTime];// * 1000.0;

    //Make an fps out of this new time interval after wait
    double FPS = (1.0/timePassed_after);
    NSLog(@"FPS %f",FPS);
    NSLog(@"Adjusted Time %f",timePassed_after);

    NSLog(@"***************");

    //Reset olddate for next loop
    old_date = curTime;

    //Apparently this will capture touches and button events
    while(CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.002, TRUE) == kCFRunLoopRunHandledSource);

    //A test on moving a ball to see how smooth it will be
    [self performSelectorOnMainThread:@selector(moveBall) withObject:nil waitUntilDone:NO];

   [pool drain];

  } 

}
-(无效)游戏循环{
//游戏运行在viewDidLoad中设置为TRUE
while(游戏运行){
NSAutoreleasePool*池=[[NSAutoreleasePool alloc]init];
//获取当前日期
NSDate*curTime=[NSDate-date];
//自上次循环以来的时间和当前日期;
NSTimeInterval timePassed_ms=[curTime TimeIntervalsIncestate:old_date];//*1000.0;
NSLog(@“****************”);
//时间间隔
NSLog(@“循环时间%f”,时间通过\u ms);
//检查循环是否足够快,睡眠时间是否足够长,以弥补约60 FPS
如果(通过的时间小于1.0/60){
double timeToSleep=时间通过时间(1.0/60);
timeToSleep=timeToSleep*-1;
NSLog(@“为%f睡眠”,timeToSleep);
[NSThread sleepForTimeInterval:timeToSleep];
}
//此新日期用于尝试并检查循环等待后的持续时间是否正确
NSDate*newDate=[NSDate-date];
NSTimeInterval timePassed_after=[newDate TimeIntervalsIncestDate:curTime];//*1000.0;
//等待后,从新的时间间隔中进行fps
双FPS=(1.0/时间经过后);
NSLog(@“FPS%f”,FPS);
NSLog(@“调整后的时间%f”,时间经过\u之后);
NSLog(@“****************”);
//为下一个循环重置olddate
旧日期=短时间;
//显然,这将捕获触摸和按钮事件
而(CFRunLoopRunInMode(kCFRunLoopDefaultMode,0.002,TRUE)==kcfrunloopunhandledsource);
//一个关于移动一个球的测试,看看它有多平滑
[self-performSelectorOnMainThread:@selector(moveBall)with object:nil waitUntilDone:NO];
[泳池排水沟];
} 
}

您不应该依赖于睡眠线程,因为您永远无法确定它将花费相同的时间

因此,与其让线程睡眠,不如什么都不做,什么都不做(当然除了增加固定时间步长)

你会发现你会有一个更平滑的帧速率,然后

另请注意,不要将FPS用作性能指标。使用完成单个更新所需的时间量

如果你的目标是60帧/秒,你的目标处理时间应该是0.01666*秒。实际上,您应该能够将处理时间增加到0.02555*,即40fps,并且在游戏中没有明显的性能影响


编辑:我还注意到你正在创建一个新的池,并且每次更新被点击时都会耗尽,根据我的经验,自动释放池应该放在更高的级别,比如appDelegate。但是我不会把它降低到创建(create)/发布(drain)级别,将其进一步提高也会有助于提高性能。

我建议切换到
CADisplayLink
API()。它创建了一个计时器,在屏幕刷新时自动触发,而无需计算睡眠时间。这将解决在代码中传递“刷新”事件的问题,但不会解决所有问题

显然,如果您的代码不能在1/60秒内完成,那么您将无法获得60 fps。确保你的游戏逻辑和物理与视频刷新率无关。有些人不同意
CADisplayLink
是否是正确的做法。然而,商定的替代方案是在硬件允许的情况下尽快更新

去年,我在一个玩具游戏中切换了一个渲染循环,我不得不使用一个显示链接(Mac,而不是iOS)。我注意到游戏“流畅”的感觉有了显著的改善。您的结果可能会有所不同

下面是一种方法(半伪代码,简化):

-(无效)更新:(CADisplayLink*)链接{
现在=gettime();
同时(游戏时间<现在){
//物理总是以1/delta的速率更新
高级框架();
游戏时间+=增量;
}
draw();
}

timeIntervalSinceDate:
返回以秒为单位的间隔,而不是以毫秒为单位


(我想在一个小评论中写下这一点,不是在一个真实的答案中,但我不知道如何做到这一点…

计算机上的其他线程甚至进程可能会影响该线程的计时。你的应用程序中还发生了什么?只是移动球的方法。但是我如何在线程中均匀地增加我的固定时间步长?它将以最快的速度前进。我看不出增加时间戳的效果如何。它会不会立即达到数千?你不会均匀地增加它,你会增加它与上一场比赛结束时的时间差(完成所需的时间)。然后在您完成更新后(即使您什么也不做),计算这花费了多长时间,并且下一次更新将由此递增。这将导致更平滑的帧速率您确定向上移动池不会因为池中对象的数量增加而导致更大的延迟吗?我见过有人推动甚至刷新池,并在循环中多次创建新的池。如果你遵循正确的内存管理,这不会是一个问题。如果创建的对象太多,请查看设计或手动释放它们。自动释放池适用于使用自动释放标志创建的所有对象。排水管强制销毁所有这些对象(不再使用)和已释放的对象。基本上,你正在创建一个每秒60多次销毁各种对象的游戏。你认为你的游戏在任何时候都会有多少个对象?大约1000?对于游戏来说,使用固定的时间步长是被广泛接受的方法。它允许像physic这样的东西
- (void)update:(CADisplayLink *)link {
    now = gettime();
    while (gametime < now) {
        // Physics always updated at rate of 1/delta
        advanceframe();
        gametime += delta;
    }
    draw();
}
- (void) gameLoop 
{

    NSAutoreleasePool* loopPool = [NSAutoreleasePool new];

    int loopCnt = 0;

    while ( isRunning ) {

    while(CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.002f, TRUE) == kCFRunLoopRunHandledSource);

        [self draw];

        select(0, 0, 0, 0, &tm);

        if ( loopCnt > 20000 ) {      // 20000
            loopCnt = 0;
            [loopPool release];
            loopPool = [NSAutoreleasePool new];
        }
        ++loopCnt;

        while(CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.002f, TRUE) == kCFRunLoopRunHandledSource);

        }   

    [loopPool release];
}