Autor Wątek: "Migające" sprajty dla zachowania framerate  (Przeczytany 19620 razy)

ssr86

  • *
  • Wiadomości: 37
  • Miejsce pobytu:
    Bydgoszcz
"Migające" sprajty dla zachowania framerate
« dnia: 2016.01.20, 13:44:28 »
Ma ktoś jakieś doświadczenie lub zna gry, które, dla zachowania pewnego ustalonego framerate, ograniczają liczbę rysowanych sprajtów w klatce? Sprajt nierysowany w poprzedniej klatce miałby mieć priorytet w kolejnej. Przy 50fps tworzy to efekt migania tych sprajtów. W sumie technika ta ma jako-tako sens dla zachowania 50fps (miganie jak na pegazusie)... Pytam raczej ogólnie w odniesieniu do sprajtów programowych na z80. Jedyny mój pomysł to LUT z czasami poszczególnych procedur i zliczanie aktualnego czasu/czasu pozostałego do końca ramki i decydowanie na bieżąco czy sprajt ma być rysowany, czy nie. Ewentualnie gdy przerwania można włączyć w dowolnej linii, to można by dodać "wajchę" w przerwaniu...
Może jakieś lepsze pomysły? Ktoś używał takiej techniki?
"Kto zawsze tylko żył w pustyni..."

Tygrys

  • Administrator
  • *****
  • Wiadomości: 4540
  • Miejsce pobytu:
    Warszawa
  • mistrz ceremonii
Odp: "Migające" sprajty dla zachowania framerate
« Odpowiedź #1 dnia: 2016.01.20, 13:49:32 »
Najprostsza metoda to w tablicy sprite dodać parametr delay. Co ramkę przeglądasz tabele sprite, zmniejszasz wartość delay, a jeżeli jest równa 0 to odrysowujesz sprite, a następnie ustawiasz wartość delay na dowolną nie mniejszą niż 1.

ssr86

  • *
  • Wiadomości: 37
  • Miejsce pobytu:
    Bydgoszcz
Odp: "Migające" sprajty dla zachowania framerate
« Odpowiedź #2 dnia: 2016.01.20, 15:41:26 »
Nie jestem pewien czy rozumiem, ale chyba to nie na mój przypadek.

Chodzi o to, że mam bardzo (?) zmienny czas wykonania ramek ze względu na animację, ruchy sprajtów - rysowanych sprajtów jest 3-12 takich 16x16, jeden duży 32x40, ale do wykonania są też jakieś inne rzeczy (np. muzyka, czy jakaś logika, a także są pewne dodatkowe graficzne elementy dodawane opcjonalnie - np. deszcz). Bez dodatkowych "bajerów" i muzyki gra chodzi w 50fps, gdy sprajtów jest chyba 10 i mniej. Chciałbym się zmieścić w jednej ramce i chcę rezygnować z rysowania tylu z mniejszych sprajtów ile pozwoli mi zachować 50fps (tym bardziej, że przynajmniej muzyka powinna być). Jak mógłbym tu zastosować opisaną przez ciebie metodę?

Muszę jakoś w trakcie wykonania dowiedzieć się na narysowanie ilu sprajtów będę mógł sobie pozwolić.
"Kto zawsze tylko żył w pustyni..."

matofesi

  • *****
  • Wiadomości: 2049
  • Miejsce pobytu:
    Toruń/Poland
Odp: "Migające" sprajty dla zachowania framerate
« Odpowiedź #3 dnia: 2016.01.20, 15:57:23 »
Miałem wrażenie, że rozwiązanie proponowane przez Tygrysa nie zadziała w twoim przypadku. Nie jestem pewien, czy jest jakieś jedno dobre rozwiązanie tego problemu, ale ja bym próbował przenieść całą logikę do obsługi przerwań i tam modyfikować pozycję i stan sprite'ów a w głównym ciągu wyświetlania "omiatał" tablicę spriteów i rysował nie zwracając uwagi na to w którym jestem miejscu. Przerwanie musiałoby tylko pilnować, żeby nie zmieniać (albo buforować w jakiś sposób) tego sprite'a, który był akurat wyświetlany. W efekcie tracisz całkowicie kontrolę nad frameratem wyświetlania sprite'ów, ale zachowujesz pełne "logiczne" 50 Hz.

Natomiast nic ci tu nie będzie "migać" jak przy multipleksowniu zbyt dużej liczby sprzętowych sprite'ów - po prostu ruch nie będzie całkowicie płynny.

No i oczywiście musisz się liczyć z tym, że raster będzie ci zrywał sprite'y.

Tygrys

  • Administrator
  • *****
  • Wiadomości: 4540
  • Miejsce pobytu:
    Warszawa
  • mistrz ceremonii
Odp: "Migające" sprajty dla zachowania framerate
« Odpowiedź #4 dnia: 2016.01.20, 16:08:06 »
To co Mat proponuje ma sens.

Innym rozwiązaniem jakie mi przychodzi do głowy to zapisanie gdzieś w tablicy sprite dodatkową informacje - 'waga' sprite - im większy sprite tym większa waga. Przy wyświetlaniu sprite dodajesz wagę sprite do jakiegoś licznika, sprawdzasz czy licznik przekroczył jakąś krytyczną wartość - jeżeli nie to wyświetlasz sprite, jeżeli tak - kończysz wyświetlanie. Do tego warto by było zrobić jakieś sortowanie lub oddzielne listy zależne od wielkości sprite.  Równie ważne jest zapamiętanie informacji czy dany sprite ma być w ogóle wyświetlany.

RafalM

  • *****
  • Wiadomości: 1133
  • Miejsce pobytu:
    Sulejówek
Odp: "Migające" sprajty dla zachowania framerate
« Odpowiedź #5 dnia: 2016.01.20, 17:31:26 »
Zacznijmy od banału - to ile będziesz mógl wyświetlić sprajtów zależy od tego ile czasu zajdzie ci na inne rzeczy.

Niestety np. muzyka jest tutaj bardzo nieprzewidywalna. Zakładam że nie napisałeś własnego playera tylko używasz coś stworzone w jakimś trackerze. Z mojego doświadczenia:

-  ilość czasu pracy procesora zużywana przez te trackery jest niestety spora, nawet np. 25% ramki

- czas ten jest bardzo zmienny i nie masz na to żadnego wpływu. Zagra nagle jakaś perkusja i jest skok o 100%

W tej sytuacji masz dwa wyjścia:

1) dostosować się do najgorszego przypadku (który możesz ustalić eksperymentalnie) i cały czas wyświetlać tyle sprajów ile da radę w tym najgorszym przypadku

2) wyświetlać więcej i przyjąć do wiadomości że co jakiś czas gra będzie zwalniać a sprajty mrugać. Jeśli to będzie odpowienio rzadko to gracze wybaczą ;)

Oczywiście możesz też użyć bufora ekranu jak robi większość późniejszych gier. Albo rysować tuż za rastrem co da ci 25 fps ale i więcej czasu (mogę wyjaśnić szczegóły jakbyś chciał). Tylko to by była zmiana koncepcji a tym chyba nie jesteś zainteresowany.

Dr Piotr

  • ***
  • Wiadomości: 196
Odp: "Migające" sprajty dla zachowania framerate
« Odpowiedź #6 dnia: 2016.01.20, 17:42:39 »
To co Mat proponuje ma sens.

Innym rozwiązaniem jakie mi przychodzi do głowy to zapisanie gdzieś w tablicy sprite dodatkową informacje - 'waga' sprite - im większy sprite tym większa waga. Przy wyświetlaniu sprite dodajesz wagę sprite do jakiegoś licznika, sprawdzasz czy licznik przekroczył jakąś krytyczną wartość - jeżeli nie to wyświetlasz sprite, jeżeli tak - kończysz wyświetlanie. Do tego warto by było zrobić jakieś sortowanie lub oddzielne listy zależne od wielkości sprite.  Równie ważne jest zapamiętanie informacji czy dany sprite ma być w ogóle wyświetlany.
Najepiej od razu zrobic tablice sprajtow, posortowanych wg wagi i wyswietlac w kolejnosci w zaleznosci od wolnego czasu.
Ja bym podzielil sprajty na 2 grupy - te, ktore musza byc wyswietlane co ramke I te, ktore moga byc wyswietlane rzadziej. Logika powinna byc wykonywana osobno dla wszystkich sprajtow co ramke, a wyswietlanie calej pierwszej grupy i czesci sprajtow z 2 grupy. Dla kazdego sprajta przechowywalbym dodatkowy paramatr, okreslajacy ile czasu trzeba na jego wyswietlenie. Potem prosta operacja typu
 while wolny czas ramki<czas_wyswietlania sprajta then wyswietl_i_oznacz_jako_wyswietlony
Oznaczenie wyswietlonego sprajta to moze byc bajt>0, ktory przy kazdej iteracji jest zmniejszany - w momencie, gdy =0 sprajt bedzie zakolejkowany do wyswietlenia w nastepnej iteracji. W ten sposob bedzie mozna ustawiac priorytety sprajtow i np. rozkladac ich wyswietlanie na kolejne iteracje.


ssr86

  • *
  • Wiadomości: 37
  • Miejsce pobytu:
    Bydgoszcz
Odp: "Migające" sprajty dla zachowania framerate
« Odpowiedź #7 dnia: 2016.01.20, 23:10:29 »
O takim rozwiązaniu w sumie właśnie myślałem. Tylko ciągle nie wiem jak załatwić kwestię zliczania dostępnego/pozostałego czasu jaki mam gdy zaczynam rysować te sprajty...
Dodanie wagi(=czasu potrzebnego na rysowanie) - ok. Oznaczenie wyświetlonych sprajtów już mam w silniku, ze względu na podwójne buforowanie (kontroluję, na których ekranach jest narysowany).
@RafalM a czy złym pomysłem byłoby przechowywanie zbliżonych czasów wykonania głównych procedur? (z uwzględnieniem skrajnych przypadków). Nie chciałbym się dostosowywać do "najgorszego przypadku", a zwalnianie z 50hz na 25hz jest trochę zbyt wyraźne. "Chciałbym" wyciskać ile się da z dostępnego czasu w ramce...;p Jendak jak się nie uda to się nie uda i chyba dodam dodatkowe ustawienia w menu - czy "force 50hz" i wtedy rysować dla najgorszego przypadku, "mixed" albo jakoś tak i po prostu "force 25hz" bo w tylu na razie chodzi bez problemów przy wszystkich opcjach... 

Ogólnie to silnik sprajtów działa na 3 bufory (gra na 128kb, więc "co mi tam"). Jeden jest "czysty" używany do mazania sprajtów, dwa pozostałe jak w standardowym podwójnym buforowaniu. Chodzi o tę "grę", której wipa prezentowałem już jakiś czas temu https://www.youtube.com/watch?v=5Qb3tiWqjtU . Co prawda wip już stary i trochę się zmieniło, bo udało się znacznie przyspieszyć silnik sprajtów przez niestandardowy układ pamięci i użycie sprajtów kompresowanych/kompilowanych. Pojawiła się szansa aby to działało w 50hz, a "gra" przy typie jaki reprezentuje dużo by zyskała przez to na "gameplayu"... (Tylko czy warto to dłużej męczyć?...), ale przede wszystkim jest to jakieś "wyzwanie".

Mógłbym jeszcze trochę zoptymalizować sprajty tych płomieni wyłączając częściowe maskowanie (tylko bajty w pełni przezroczyste lub całkowicie nieoprzezroczyste - każdy "częsciowy" traktowany jako nieprzezroczysty)... innych możliwości chyba nie mam... No może jeszcze zobaczyć czy mazanie stosem nie byłoby szybsze niż obecnie użyte...
Nie bardzo mam szansę podzielić sprajty na 2 grupy, o których pisał Dr Piotr... a przynajmniej na razie tak mi się wydaje...

Widzę, że przy np. deszczu i muzyce to nawet miganie wszystkich sprajtów (tj. rysowanie połowy sprajtów w każdej klatce) nie daje zawsze 50fps, ale z samą muzyką powinno być ok.
"Kto zawsze tylko żył w pustyni..."

RafalM

  • *****
  • Wiadomości: 1133
  • Miejsce pobytu:
    Sulejówek
Odp: "Migające" sprajty dla zachowania framerate
« Odpowiedź #8 dnia: 2016.01.21, 10:44:21 »
Ale zaraz, to mówimy o grze na Spectrum czy na Enterprise ?

ssr86

  • *
  • Wiadomości: 37
  • Miejsce pobytu:
    Bydgoszcz
Odp: "Migające" sprajty dla zachowania framerate
« Odpowiedź #9 dnia: 2016.01.21, 11:09:47 »
Docelowo o Enterprise, ale pytanie miało być ogólne o techniki dla sprajtów programowych na z80, które by realizowały cel...  :-[
Różnica, która ma jakiś wpływ na rozwiązanie to system przerwań - na ep128 przerwania można ustawiać w prawie dowolnej linii (min. co 2 linie ekranowe).
Na spectrumie chyba jest jedno na początku ramki, tak?
Ale reszta jest przenośna...
« Ostatnia zmiana: 2016.01.21, 11:34:20 wysłana przez ssr86 »
"Kto zawsze tylko żył w pustyni..."

RafalM

  • *****
  • Wiadomości: 1133
  • Miejsce pobytu:
    Sulejówek
Odp: "Migające" sprajty dla zachowania framerate
« Odpowiedź #10 dnia: 2016.01.21, 12:46:04 »
Wiesz, diabeł siedzi w szczegółach... Z góry zaznaczam więc że moje wypowiedzi dotyczyły Zx Spectrum ;)

Na Spectrum przerwanie jest zawsze na początku ramki.

Istotnym elementem ekranu Spectrum jest border. Wysłanie linii bordera przez układ ULA na telewizor zajmuje tyle samo czasu co wysłanie linii z zasadniczym obszarem gry. Czyli można spokojnie odświeżać ekran podczas gdy ULA rysuje border.

A o programowaniu Enterprise zasadniczo nic nie wiem  :P

ssr86

  • *
  • Wiadomości: 37
  • Miejsce pobytu:
    Bydgoszcz
Odp: "Migające" sprajty dla zachowania framerate
« Odpowiedź #11 dnia: 2016.01.21, 12:57:09 »
Wiesz, diabeł siedzi w szczegółach... Z góry zaznaczam więc że moje wypowiedzi dotyczyły Zx Spectrum ;)
Domyśliłem się po "Albo rysować tuż za rastrem co da ci 25 fps ale i więcej czasu (mogę wyjaśnić szczegóły jakbyś chciał)." ;P
Ale na moje wszystkie pozostałe uwagi były ogólnie stosowalne czy to do cpc, zx czy ep.
"Kto zawsze tylko żył w pustyni..."

Dr Piotr

  • ***
  • Wiadomości: 196
Odp: "Migające" sprajty dla zachowania framerate
« Odpowiedź #12 dnia: 2016.01.21, 13:06:29 »
... No może jeszcze zobaczyć czy mazanie stosem nie byłoby szybsze niż obecnie użyte...
Bedzie szybsze od kazdej innej metody

ssr86

  • *
  • Wiadomości: 37
  • Miejsce pobytu:
    Bydgoszcz
Odp: "Migające" sprajty dla zachowania framerate
« Odpowiedź #13 dnia: 2016.01.21, 13:57:25 »
... No może jeszcze zobaczyć czy mazanie stosem nie byłoby szybsze niż obecnie użyte...
Bedzie szybsze od kazdej innej metody
Ponieważ mazanie sprajtów obecnie odbywa się metodą "hybrydową". Używam ldi, ale tylko dla bajtów, które rzeczywiście tego wymagają - resztę omijam. Wydaje mi się, że mazanie na push/pop wymagałoby skomplikowania przełączania sp z czystego bufora na bufor ekranu... Musiałbym sprawdzić jak by to wyszło - nawet porównać z mazaniem całego prostokąta ekranu zamiast tylko nieprzezroczystych bajtów...

Obecnie mazanie używa listy adresów, na której początek ustawiam adres stosu - w ten sposób ret wykonuje skok do procedury obsługi mazania linii. Każda taka procedura składa się z dostosowanego ciągu ldi i inkrementów i kończy się uaktualnieniem adresów buforów o wartości pobrane ze stosu aby przejść do kolejnej linii ekranowej. Jest to połączenie sprajtów kompresowanych z kompilowanymi i działa w miarę szybko - pomysł "pożyczony" skądś z  cpcwiki.
Jednak może rzeczywiście z push/pop wyjdzie lepiej. Martwi mnie konieczność częstej zmiany sp...
"Kto zawsze tylko żył w pustyni..."

Tygrys

  • Administrator
  • *****
  • Wiadomości: 4540
  • Miejsce pobytu:
    Warszawa
  • mistrz ceremonii
Odp: "Migające" sprajty dla zachowania framerate
« Odpowiedź #14 dnia: 2016.01.21, 14:55:24 »
Używanie stosu do sprite jest mocno nieefektywne, co już sam zauważyłeś. Stosem można szybko wypełniać duże obszary pamięci identyczną wartością, maksymalnie 16 powtarzającymi się bajtami. No i tu nie ma mowy o maskach dla sprite.