2011-12-18 6 views
12

Jak mogę uruchamiać blok kodu w tle okresowo za pomocą GCD? Próbuję napisać silnik gry z kilkoma podsystemami, takimi jak rendering, fizyka, logika gry i tak dalej. Niektóre zadania powinny być sterowane zdarzeniami, ale niektóre (jak system fizyki) powinny być okresowo wywoływane w tle ze stałym czasem (na przykład po 1/100 s). Utworzono blok kodu, ale jak uruchomić ten blok okresowo w tle? Czy tutaj jest właściwe narzędzie GCD?Jak mogę uruchamiać blok kodu w tle okresowo za pomocą GCD?

Odpowiedz

6

Jak zaznacza @matt w komentarzach, możesz użyć do tego źródeł wysyłania timera. Zobacz odpowiedź dla właściwego podejścia.

dla potomności, oto mój oryginalny odpowiedź z kilku alternatyw:

  1. W swojej renderowania zwrotnego (powiedzmy, korzystając CADisplayLink), wystrzelić pracę GCD że Oblicza fizyki za ten (lub obok?) rama. Jeśli potrzebujesz więcej niż jedną aktualizację na ramkę do renderowania, po prostu uruchom pętlę roboczą kilka razy.

  2. Masz wątek fizyki, który śpi, dopóki nie będzie musiał wykonać pewnych obliczeń. Jeśli masz do tego osobny wątek, NSTimer może mieć wystarczającą rozdzielczość, aby obudzić twój wątek o 100 Hz. (W głównym wątku nie zadziałałoby to, ponieważ inne źródła wejściowe na runlerze zapobiegają tak szybkiemu uruchomieniu). Jeśli NSTimer nie działa, po prostu obliczyć ile czasu pozostało do następnej aktualizacji fizycznej, której potrzebujesz i spać swój wątek (przez, np. [NSThread sleepForTimeInterval:])

  3. Posiadać blok, który używa dispatch_after.

coś takiego:

dispatch_time_t next = dispatch_time(DISPATCH_TIME_NOW, 0); 
block = ^{ 
    next = dispatch_time(next, 10000000L); // increment by 10 ms 
    // do physics here 
    dispatch_after(next, queue, block); 
} 

Być może trzeba być trochę mądrzejszy o opuszczenie ramek (czyli wykryć, jeśli następnym razem, to w przeszłości przed wywołaniem dispatch_after go, etc.)

+0

Witam, dzięki za odpowiedź. Moim głównym celem jest odseparowanie podsystemu fizyki od renderowania, więc myślę, że druga odpowiedź jest dla mnie bardziej odpowiednia, jednak wciąż zastanawiam się, czy istnieją jakieś rozwiązania z blokami i GCD. – asdf

+0

OK. Dodałem trzecią opcję. –

+1

"Źródła czasowe liczników czasu generują zdarzenia w regularnych odstępach czasowych.Możesz używać liczników czasu do inicjowania określonych zadań, które muszą być wykonywane regularnie, na przykład gry i inne aplikacje intensywnie wykorzystujące grafikę mogą wykorzystywać liczniki czasu do inicjowania aktualizacji ekranu lub animacji. " Jeśli to nie GCD wspiera bezpośrednio zadania okresowe - i dokładnie w tym kontekście OP pyta - co to jest? – matt

3

w Swift można tworzyć za pomocą timera GCD:

func CreateTimerDispatchSource(interval: UInt64, leeway: UInt64, queue: dispatch_queue_t, block: dispatch_block_t) -> dispatch_source_t { 
    let timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue) 
    dispatch_source_set_timer(timer, dispatch_walltime(nil, 0), interval, leeway) 
    dispatch_source_set_event_handler(timer, block) 
    return timer; 
} 

var timer = CreateTimerDispatchSource(5*NSEC_PER_SEC, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { 
    // do some serious stuff 
} 

rozpocząć lub wznowić stoper:

dispatch_resume(timer) 

Zawiesić Timer:

dispatch_suspend(timer) 
Powiązane problemy