Цыкл гульні з асобным таймерам для рэндэрынгу і гульнявой логікі

Я хачу, каб аддзяліць логіку гульні і рэндэрынгу ў двух розных завес, таму што я не хачу, каб ФПС кантраляваць хуткасць гульні. Я спрабаваў дамагчыся гэтага шляхам стварэння CADisplayLink для рэндэрынгу, і NSTimer для гульнявой логікі. Але затым адбылося нешта дзіўнае:

Часам (1 з 15 прыкладання працуе) гульня працуе на вельмі нізкай кадраў у секунду (каля 5-10), а астатняя частка часу гэта цалкам гладкай. Калі выдаліць NSTimer логікі гульні і аб'яднаць дзве завесы кадраў у секунду з'яўляецца стабільна высокім, але гэта, відавочна, не з'яўляецца прымальным рашэннем. Так што, падобна, што часам два таймера 'зацягваюць адзін аднаго ці нешта падобнае, але я не зусім разумею ўнутраную працу runloops.

Вось як я ствараю таймер і DisplayLink:

NSTimer *gameTimer = [[NSTimer alloc] initWithFireDate:[NSDate date] interval:1.0/60.0 target:self selector:@selector(gameTimerFired:) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:gameTimer forMode:NSDefaultRunLoopMode];
[gameTimer release];

CADisplayLink *aDisplayLink = [[UIScreen mainScreen] displayLinkWithTarget:self selector:@selector(drawFrame)];
[aDisplayLink setFrameInterval:animationFrameInterval];
[aDisplayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
self.displayLink = aDisplayLink;

Ці можаце вы сказаць мне, што выклікае праблему кадраў у секунду, і як гэта выправіць?

Ці вы можаце парэкамендаваць якія-небудзь іншыя рашэнні для падзелу рэндэрынгу і логікі гульні цыкла?

6
Вы не павінны ствараць дзве завесы, каб аддзяліць хуткасць гульні і кадраў у секунду ...
дададзена аўтар thedaian, крыніца
Тады як я магу зрабіць гэта з аднаго пятлёй?
дададзена аўтар mikabast, крыніца

3 адказы

Вы можаце зрабіць гэта з дапамогай аднаго цыкла з выкарыстаннем альбо gameTimer або CADisplayLink шляхам вымярэння часу, які прайшоў з моманту апошняга цыкла і выкарыстоўваць яго, каб павялічыць вашу логіку гульні.

Так ..

NSDate *oldTime = [[NSDate date] retain];

-(void)updateGame {
    NSDate *curTime = [NSDate date];
    NSTimeInterval timePassed_ms = [curTime timeIntervalSinceDate:oldTime] * 1000.0;

    [oldTime release];
    oldTime = curTime;
    [oldTime retain];

    //use the timePassed_ms to augment your game logic.  IE: Moving a ship
    [ship moveLength:ship.velocity * timePassed_ms/1000.0];
}

Гэта, як правіла, як я справіцца з такога роду рэчы. Я звычайна будаваць функцыі абнаўлення прама ў маіх гульнявых аб'ектаў. Так абнавіць карабель будзе на самой справе выглядаць наступным чынам:

[ship update:timePassed_mc];
3
дададзена
Дзякуй за прапанову. Гэта натхніла маё канчатковае рашэнне (глядзі ніжэй).
дададзена аўтар mikabast, крыніца

Так што я ў канчатковым выніку выкарыстаў тое, што прапанаваў Эндру Zimmer, з некаторымі малюсенькімі мадыфікацыямі, так як я магу абнавіць сваю гульню аб'екты разам паміж роўнымі інтэрваламі.

Таму я выкарыстоўваю толькі адзін цыкл, той, які запушчаны ў CADisplayLink. Вось канчатковы код:

- (void)drawFrame
{
    if (!isGameTimerPaused)
    {
        NSDate *newDate = [NSDate date];
        timeSinceLastUpdate += [newDate timeIntervalSinceDate:lastUpdateDate];

        while (timeSinceLastUpdate > 1.0/60.0) 
        {
            [self updateGame];//UPDATE GAME OBJECTS
            timeSinceLastUpdate -= 1.0/60.0;
        }

        [lastUpdateDate release];
        lastUpdateDate = [newDate retain];
    }


   //DRAWING CODE HERE
    (...)
    //
}
1
дададзена
Рады, што гэта працуе для вас! Майце на ўвазе, што вы можаце ўбачыць некаторае зніжэнне прадукцыйнасці, калі вы робіце шмат апрацоўкі ў функцыі updateGame (напрыклад, выяўленне сутыкненняў паміж вялікай колькасцю аб'ектаў). Ура!
дададзена аўтар Andrew Zimmer, крыніца

Майце на ўвазе, што NSTimer не збіраецца даць вам якой-небудзь надзейнай сінхранізацыі. Гэта блізка, але не гарантавана, і калі вы запусціце цыкл гульні ад яго, вы атрымаеце выпадковыя выпадзення кадраў.

Вы маглі б зрабіць вашу логіку гульні ў патоку, і спаць да наступнага кадра (гэта не будзе пастаянным колькасць часу).

0
дададзена
NSTimer не вельмі надзейна, але з пункту гледжання вопыту карыстальніка 56 абнаўленняў у секунду або 64 абнаўленняў у секунду на самай справе не робяць розніцы. Але калі я абнавіць гульнявыя аб'екты толькі тады, калі я малюю, ён можа зваліцца да 20 або 30 абнаўленняў у секунду на павольных прыладах, калі ён працуе ў два разы хутчэй на больш хуткіх прыладах.
дададзена аўтар mikabast, крыніца