Petle Gry - rozwiazania dla gier realtime

Transkrypt

Petle Gry - rozwiazania dla gier realtime
Pętle Gry
rozwiązania dla gier realtime
Jan Darowski
14 maja 2014
Jan Darowski
Pętle Gry
Problemy
1
Utrzymanie płynności gry
2
Różny charakter obiektów gry (budynek, gracz, system
osiągnięć)
3
Rózne akcje wykonywane na poszczególnych obiektach
(animowanie, wybieranie przeciwnika)
4
Synchronizacja ze światem zewnętrznym (użytkownik, inne
instancje gry)
5
Sprawiedliwe aktualizowanie wszystkich obiektów (niezależnie
od obciążenia)
6
Utrzymanie kolejności aktualizowania obiektów
Jan Darowski
Pętle Gry
Najprostsze rozwiązania
while (1) {
foreach ( GameObject & go , gameObjects )
go . update () ;
}
Zależne od sprzętu
Zależne od obciążenia
Brak podziału wykonywanych akcji według częstotliwości
Jan Darowski
Pętle Gry
Najprostsze rozwiązania
while (1) {
wait ( lastUpdate + INTERVAL - time () ) ;
lastUpdate = time () ;
foreach ( GameObject & go , gameObjects )
go . update () ;
}
Zależne od obciążenia
Brak podziału wykonywanych akcji według częstotliwości
Jan Darowski
Pętle Gry
Zmienny czas wywołania
while (1) {
foreach ( GameObject & go , gameObjects )
go . update ( time () - lastUpdate ) ;
lastUpdate = time () ;
}
Niezależne od obciążenia lub sprzętu
100% wykorzystanie procesora
Konieczność implementacji obsługi czasu wewnątrz update()
Dobre przy liczeniu fizyki i animacji - brak lagów
Jan Darowski
Pętle Gry
Wiele niezależnych pętli gry
while (1) {
wait ( lastUpdate1 + INTERVAL - time () ) ;
lastUpdate1 = time () ;
foreach ( GameObject & go , gameObjects )
go . update11 () ;
foreach ( GameObject & go , gameObjects )
go . update12 () ;
if ( lastUpdate2 + INTERVAL2 > time () ) {
lastUpdate2 = time () ;
foreach ( GameObject & go , gameObjects )
go . update2 () ;
}
}
Ponownie - zależność od obciążenia
Możliwość rzadszego wykonywania ciężkich akcji
Jan Darowski
Pętle Gry
Rozwiązanie
Ale w końcu mamy Qt i sensowne timery.
Jan Darowski
Pętle Gry
Rozwiązanie
Ale w końcu mamy Qt i sensowne timery.
Niezależność od sprzętu
Pasuje do kodu sterowanego zdarzeniami
Częściowa niezależność od obciążenia
Możliwość updateowania różnych rzeczy co różny czas
Dodatkowe nakłady na timery (wywoływane systemowo)
Możliwość wykonywania ciężkich działań gdy procesor jest
wolny (QtConcurrent)
Brak kontroli nad kolejnością wykonywania działań
Jan Darowski
Pętle Gry
Predykcja zachowań
Co zrobić kiedy obiektów gry jest zbyt dużo i nie nadążamy z ich
aktualizacją? Udawać że aktualizujemy
Koniecznie aktualizować grafikę
Aktualizować fizykę (a przynajmniej część, np bez detekcji
kolizji)
Pomijać część informacji o zmianach, być może nie są już
potrzebne (małe bufory na zdarzenia jednego typu)
Jan Darowski
Pętle Gry
Update()
Do tej pory skupialiśmy się na samej strukturze pętli gry. Trzeba
jednak zintegrować ją z odpowiednią implementacją obiektów.
Możliwe podejścia:
Jan Darowski
Pętle Gry
Update()
Do tej pory skupialiśmy się na samej strukturze pętli gry. Trzeba
jednak zintegrować ją z odpowiednią implementacją obiektów.
Możliwe podejścia:
Obiekty zawierają tylko dane, aktualizuje je główna funkcja w
pętli gry.
Każda klasa opisująca jakiś obiekt zawiera osobną
implementację update()
Dziedziczenie funkcji update(). Być może wielodziedziczenie
Strategie (Brainzzzz)
Strategia na dekoratorach
Animatory
Jan Darowski
Pętle Gry
Dziedziczenie update()
1
Problemy z wielodziedziczeniem
2
Możliwe nieintuicyjne dziedziczenia (budynek - statek matka)
3
Spora nadmiarowość kodu - niektóre akcje mogą mieć duże
części wspólne
4
Długie ścieżki dziedziczenia - problemy w utrzymaniu kodu
5
Mnożenie liczby klas posiadających te same atrybuty przez
niewielkie różnice w zachowaniu (żołnierz, żołnierz z super
umiejętnościami)
Jan Darowski
Pętle Gry
Strategie - Brainzzzz
Każdy obiekt posiada wskaźnik na swój mózg - obiekt opisujący
działanie głównego obiektu
1
Możliwość oddzielenia opisu atrybutów od logiki
2
Znowu - dużo klas i wielodziedziczenie
3
Redundancja kodu
4
Możliwość zmiany zachowań obiektu w trakcie gry (uśpiony
guardian, patrolujący, ścigający)
Jan Darowski
Pętle Gry
Dekoratory
Sposób na zastąpienie dziedziczenia, można użyć zarówno na
samym obiekcie jak i na jego mózgu.
Jan Darowski
Pętle Gry
Wady i zalety
1
Możliwość tworzenia dowolnych kombinacji obiekt zachowanie
2
Brak dziedziczenia
3
Mała redundancja kodu
4
Brak sposobu na łatwe podzielenie akcji według okresu
wykonywania
5
Możliwość pomyłki przy kolejności inicjowania dekoratora (złe
zagnieżdżenie)
Jan Darowski
Pętle Gry
Animatory - pochodzenie
Niektóre silniki, takie jak Irrlicht wykorzystują Animatory,
rozwiązanie pozwalające szybko dodawać logikę typowych
zachowań do dowolnego obiektu gry.
Jan Darowski
Pętle Gry
Animatory - pochodzenie
Niektóre silniki, takie jak Irrlicht wykorzystują Animatory,
rozwiązanie pozwalające szybko dodawać logikę typowych
zachowań do dowolnego obiektu gry.
1
Animowanie kolejnych klatek
2
Zatrzymywanie się przy zderzeniu
3
„Wchodzenie” na niewielkie podwyższenia
4
Grawitacja
Dodawanie animatora jest realizowane przez wywołanie metody
silnika samej gry, na węźle danego obiektu.
Jan Darowski
Pętle Gry
Animatory - podstawowe założenia
1
Obiekty gry jedynie przechowują dane - nie zawierają logiki
zachowań
2
Animatory są częścią silnika, nie obiektów
3
Każdy animator może działać na potencjalnie dowolnym
obiekcie gry
4
Każdy obiekt może być obsługiwany przez wiele animatorów
5
Animatory mogą mieć różny czas aktualizacji
6
Animatory mają łatwy dostęp do danych zawartych w silniku
(Gameplay)
7
Każdy animator dba o kolejność aktualizowanych przez siebie
obiektów
Jan Darowski
Pętle Gry
Animatory - architektura
Każdy animator posiada częstotliwość aktualizacji, priorytet,
listę aktualizowanych obiektów i wskaźnik do Gameplay
Gameplay inicjalizuje wszystkie animatory
Dla każdego występującego czasu aktualizacji tworzy osobną
warstwę
Warstwa składa się z posortowanych po priorytecie
animatorów i timera o odpowiednim okresie aktualizacji
Timer co określony czas wywołuje update() wszystkich
animatorów należących do danej warstwy
Update() animatora polega na wykonaniu tej samej akcji na
wszystkich obiektach z listy, zawsze w tej samej kolejności
Animatory mogą korzystać ze swoich wyników zapisywanych w
mapie QString - QVariant
Jan Darowski
Pętle Gry
Animatory - zady i walety
Relatywnie mało timerów
Dowolne mieszanie obiektów z zachowaniami
Dopuszczalne różne czasy aktualizacji
Stała kolejność aktualizowania obiektów
Bezpieczeństwo wywołania animatorów gwarantowane
globalnie, nie osobno dla każdego obiektu
Krótki kod dodający nowy obiekt o typowym zachowaniu
Brak pewności czy obiekt posiada parametry wymagane przez
dany animator
Niewygodne wczytywanie obiektów - konieczność niezależnego
pamiętania animatorów dla każdego obiektu
Łatwość debugowania - można dowolny, mały fragment
działania obiektów testować niezależnie
Brak redundancji kodu
Jan Darowski
Pętle Gry
Skryptowanie - Po co?
Czemu dobrze jest skryptować fragmenty logiki gry?
Brak konieczności rekompilacji przy niewielkich zmianach
Możliwość szybszej pracy przy szlifowaniu zachowań i
sprawdzaniu różnych wariantów
Mniejsze wymagania dot. osoby pracującej nad logiką
Ułatwia pisania kodu łatwego w dostosowaniu do innych
projektów
Jan Darowski
Pętle Gry
Skryptowanie -Jak to robić poprawnie
Skryptować jedynie najwyższą warstwę logiki
Skrypty powinny być możliwie proste
Skomplikowane fragmenty trzymać w kodzie - są od razu
sprawdzane przez kompilator, są szybsze
Skryptowane powinny być fragmenty, które wynikają z
mechaniki opisywalnej graczowi
Przekazywać minimum danych, z maksymalną wartością
Jan Darowski
Pętle Gry
Skryptowanie -Bridge Pattern
Pozwala na niezależne łączenie rodzajów obiektów ze sposobami
implementacji.
Przykład: Animatory, Warunki zwycięstwa, Menu HUD
Przykład Inkscape: Narzędzia rysowania, konwertery, filtry
Jan Darowski
Pętle Gry
Skryptowanie w Qt
QScriptEngine engine ;
QObject * someObject = new MyObject ;
QScriptValue objectValue = engine . newQObject ( someObject ) ;
engine . globalObject () . setProperty ( " myObject " , objectValue ) ;
engine . globalObject () . setProperty ( " foo " , 123) ;
qDebug () << engine . evaluate ( " foo * 2 + myObject . scale " ) .
toNumber () ;
Jan Darowski
Pętle Gry
Skryptowanie w Qt
QScriptEngine engine ;
QObject * someObject = new MyObject ;
QScriptValue objectValue = engine . newQObject ( someObject ) ;
engine . globalObject () . setProperty ( " myObject " , objectValue ) ;
engine . globalObject () . setProperty ( " foo " , 123) ;
qDebug () << engine . evaluate ( " foo * 2 + myObject . scale " ) .
toNumber () ;
Connect:
QScriptEngine eng ;
QLineEdit * edit = new QLineEdit (...) ;
QScriptValue handler = eng . evaluate (
" ( function ( text ) { print ( ’ text was changed to ’,
text ) ; }) " ) ;
q ScriptConnect ( edit , SIGNAL ( textChanged ( const QString &) ) ,
QScriptValue () , handler ) ;
Jan Darowski
Pętle Gry
Dziękuję za uwagę.
Jan Darowski
Pętle Gry

Podobne dokumenty