Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [JS] sposób składowania danych
Forum PHP.pl > Forum > Przedszkole
CuteOne
Tytuł tematu zapewne nie mówi za wiele, więc postaram pokrótce opisać mój mały problem. Otóż za pomocą JS chcę utworzyć krótkie animacje np. poruszających się piłeczek. Problem w tym, że każda akcja (np. ruch, kolizja itp.) musi być gdzieś "składowana" na początku rozsądnym rozwiązaniem wydał mi się JSON :
[JAVASCRIPT] pobierz, plaintext
  1. var objects = [
  2. {name: "kulka-1", x: 12, y:13},
  3. {name: "kulka-2", x: 11, y:13},
  4. {name: "kulka-3", x: 10, y:13}
  5. ];
  6.  
  7. var action = [
  8. [{x:15, y:25}, {x:15, y:20},{x:10, y:25}], //każda akacja zapisana w ten sposób gdzie index odpowiada objects[indeks]
  9. [{x:45, y:25}, {"type": "colison", x:15, y:23},{x:11, y:25}],
  10. [{x:95, y:25}, {x:15, y:28},{x:15, y:25}]
  11. ];
[JAVASCRIPT] pobierz, plaintext


Niestety tego typu zapis jest mało wydajny:
- dla 100 obiektów 10 sekundowa animacja zajmuje grubo ponad 500kb
- JS strasznie zamula podczas odczytywania tak składowanych wartości (chociaż nie powinien :/)

Stąd moje pytanie czy istnieje jakiś format zapisu, który pozwoli na łatwy odczyt zawartości + minimalną wielkość tworzonego pliku
?
croc
JavaScript krztusi się już przy średnich rozmiarów tablicach, więc to chyba nie jest problem JSON-a. Musisz zapisywać pozycję piłeczek dla każdej klatki? Piłeczki nie poruszają się po liniach?
CuteOne
Po liniach tylko dla 100 piłeczek w jednej klatce na pewno znajdzie się kilkanaście akcji dotyczących zmiany położenia, kolizji, zmiany koloru itp. itd. Kurcze HTML5 daje takie możliwości a mimo to nie mogę ich w pełni wykorzystać sad.gif

rozmiar plików mógłbym ograniczyć przez kompaktowanie + gzip ale na zamulanie JS przy (tylko) 10sek animacji nie znam lekarstwa
darko
Ogólnie ciężko będzie znaleźć jakieś alternatywne rozwiązanie problemu pozostając w języku javascript, który, w przypadku animacji, mistrzem wydajności nie jest. Może jednak warto próbować pójść w stronę canvasa albo flasha? Jeżeli ta zmiana nie wchodzi w grę, to można jeszcze szukać rozwiązania w postaci użycia innych algorytmów, np. zamiast zapisywać współrzędne wszystkich obiektów - cyklicznie wywoływać (np. co sekundę) jakąś funkcję, która uwzględniając rozmaite parametry, jak np. prędkość ruchu, przyspieszenie, aktualną pozycję - wyliczy aktualne współrzędne i sprawdzi czy ma miejsce kolizja.
croc
Wydaje mi się, że canvas jeszcze pogorszy sprawę. Kompresja pliku kompletnie nic nie poprawi.
darko
Canvas jest w powijakach jeszcze, ale jest rozwojowe i krojone na miarę takich potrzeb.
croc
W najnowszych wersjach FF canvas działa nie najgorzej, w najnowszym Chrome wciąż tragedia smile.gif Dobry dla grafiki, animacje pociągnie tylko i wyłącznie bardzo ubogie.
everth
A ja dalej nie rozumiem co kolega miał na myśli. Zapisuje osobno każdą klatkę czy też tworzy dla każdego obiektu listy wcześniej wyliczonych zdarzeń? Patrzę i nie wiem.
Pawel_W
Cytat(croc @ 23.10.2011, 23:51:51 ) *
w najnowszym Chrome wciąż tragedia

testowałem kilka gier i, przynajmniej u mnie, wszystko normalnie działało, a różnica w fps pomiędzy chrome a firefox wynosiła jakieś 5%
CuteOne
Animację tworzę właśnie w canvas (dlatego wspomniałem o HTML5) wink.gif

everth:
Tworzę każdą klatkę:
klatka 1. ruch piłeczki A do 10,10 (współrzędne XY), B do 11,12
klatka 2. ruch piłeczki C do 1, 1
klatka 3. kolizja piłeczki A i C, ruch piłeczki B do 9,9 (piłeczka osiągnęła 11,12)
klatka 4. kolizja piłeczki B i C
itd..

Taki zapis wydaje mi się najbardziej optymalny - nie muszę sprawdzać warunków w każdej klatce np. czy dany obiekt osiągnął położenie X,Y / ma kolizję z innym obiektem itp.

darko:
Flash to dinozaur, który wydajnością nie dorasta do pięt JS smile.gif

Hmmm właśnie oglądam mecz z cs-manager.com i tam za pomocą Javy zrobiono pokaz rozegranych meczów, więc tym bardziej w JS musi się dać zrobić coś podobnego (chodzi o animację nie mecze ;p)
everth
Cytat
Taki zapis wydaje mi się najbardziej optymalny - nie muszę sprawdzać warunków w każdej klatce np. czy dany obiekt osiągnął położenie X,Y / ma kolizję z innym obiektem

Można to ugryźć inaczej tak jak @darko powiedział. Na początku tworzysz zestaw funkcji określających przyszłe położenie (np. przesuń się pixel w prawo/lewo/góra/dół/kombinacja), jeśli ruch idzie tylko po liniach prostych. Przyporządkowujesz te funkcje poszczególnym obiektom (jako właściwość). Zakładam że animacja jest wcześniej wyliczona więc wiemy kiedy (nr klatki) i między kim nastąpią ewentualne kolizje lub zdarzenia modyfikujące ruch obiektów.

Więc najprostszy algorytm sprowadza się do zmiany funkcji ruchu u konkretnych obiektów (wiemy u których bo mamy to już wyliczone) na inne i następnie aktualizacji pozycji obiektów na planszy (co klatkę). Nawet jeśli tych zdarzeń jest kilkadziesiąt na klatkę to zmieniany tylko referencje do funkcji. A zapisujemy tylko ewentualne zmiany w ruchu obiektów (czyli klatki puste w których nic nie zachodzi wylatują z końcowego "zapisu")

PS: To wszystko przy założeniu wcześniejszego wyliczenia kolizji i zdarzeń - ale ja rozumiem że tobie chodzi raczej o zapis animacji a nie jej żywą symulację.
CuteOne
Dzięki za odpowiedź.

Chyba nie bardzo wiem jak by to miało wyglądać.. Powiedzmy, że mam odgórne funkcje animujące obiekty tak jak opisałeś. Teraz każdy obiekt we właściowościach miałby posiadać referencję:
[JAVASCRIPT] pobierz, plaintext
  1. function lewo(x) { }
  2. function prawo(x) { }
  3. function dol(x) { }
  4.  
  5. var obj = {
  6. 'kulka-1': [lewo(1),lewo(2),prawo(2)],
  7. 'kulka-2': [dol(1),lewo(2),prawo(2)],
  8. 'kulka-3': [lewo(1),lewo(2),dol(2)]
  9. };
[JAVASCRIPT] pobierz, plaintext


Czy o to ci chodziło? Bo jeśli tak to jest mały problem - skąd skrypt ma wiedzieć kiedy odpalać te funkcje?

ps. chodzi mi o odtworzenie animacji stworzonej gdzieś kiedyś wcześniej smile.gif
everth
Bardziej cosik takiego
[JAVASCRIPT] pobierz, plaintext
  1. predictFunctions = [
  2. function(x,y) { return [x, y+1]; },
  3. function(x,y) { return [x, y-1]; }
  4. // itd.
  5. ]
  6.  
  7. someObject = {
  8. var coord = [x,y]; // koordynaty
  9. this.updateFunction; // tu będzie nasza funkcja
  10.  
  11. this.update = function() {
  12. coord = this.updateFunction(coord[0],coord[1]);
  13. }
  14. }
  15.  
  16. obj = new someObject();
  17. obj.updateFunction = predictFunctions[0]; //przypisujemy naszą funkcję, później można ją zmienić
  18. obj.update(); // to będzie wykonywane dla każdego obiektu na każdą klatkę
[JAVASCRIPT] pobierz, plaintext

Skrypt nie wie jakie funkcje odpalać. On w każdej klatce nakazuje tylko obiektom uaktualnić pozycję. Wcześniej może przeprowadzić podmianę funkcji wyznaczających pozycje bazując na jakimś zapisie. Załóżmy że chcemy użyć tutaj tablic tylko klasy Array() - nie wiem czy nie będą one mniejsze i szybsze niż standardowy zapis właściwość-wartość w JS.

Jedna tablica trzyma więc obiekty, wartość numeryczna jest identyfikatorem. Druga trzyma po kolei opisane kolejne klatki, każda klatka zawiera również obiekt typu Array składający się listy obiektów które w danej klatce ulegają zmianie oraz nr powiązanej funkcji
[JAVASCRIPT] pobierz, plaintext
  1. moveChanges = [
  2. [ [0,3],[3,2],[2,1] ], // to jest klatka nr 1, zawiera listę obiektów w powiązaniu z funkcjami które muszą się zmienić
  3. [ [45,1],[23,1] ]
  4. ]
[JAVASCRIPT] pobierz, plaintext

W każdej klatce przed wykonaniem na object.update() skrypt sprawdza taką listę i ewentualnie nanosi zmiany. Wszystkie dane są liczbowe więc nie powinno być chyba dużego narzutu na pamięć.
wNogachSpisz
http://en.wikipedia.org/wiki/Web_Workers
CuteOne
Dzięki evereth ! Twój sposób zapisu wydaje się być o niebo lepszy (jutro go wypróbuję wink.gif).

@wNogachSpisz: heh całkiem zapomniałem, że JS mogę wykonywać w ten sposób smile.gif Tobie również dziękuję
zegarek84
nie wiem jak dokładnie ustawiasz własności poszczególnych obiektów ale zapewne każdego z osobna - zmiana pojedynczej własności w zasadzie niemal zawsze powoduje renderowanie - przeliczanie... i to właśnie tutaj jest problem - niektóre przeglądarki nie renderują nawet dom'u jeśli stale są robione zmiany (ale to te nowsze i nie wszystkie - już nie jestem w temacie)... ale najlepiej jeśli byś ustawiał wszystkie właściwości obiektów tylko raz - możesz to zrobić np. przez utworzenie dynamicznego elementu style w drzewie dom - wcześniej każdemu elementowi np. przypisując jakieś id, i w tym style możesz określać sytuację końcową - poczytaj na stronie opery o modyfikacjach dom i o ustawianiu kilku styli na raz (już wspomniałem jak to można zrobić zamiast podmiany klasy to po prostu podmieniasz zawartość elementu style z przygotowanym wcześniej opisem styli dla poszczególnych id na raz):
Efficient JavaScript -> DOM (page 3)

lub o ile dobrze pamiętam przed ustawianiem styli w następnej klatce mógłbyś na całą animację dać display:none; ustawiać pojedynczo style tak jak robisz i zmiana chyba też przy renderowaniu dokona się raz - no 2 razy - display:none i display block - to też powinno przyśpieszyć...

animacje by były płynne dla ludzkiego oka to odstęp między klatkami musi wynosić około 40ms (25fps -> co 40ms klatka), fakt, niektóre filmy mają chyba delikatniej mniejszy fsp i chyba wynosi on 23,7 fps ale to szczegół...

mógłbyś jeszcze poczytać o transition (czy jakoś tak się zwie) i ustawić go na liniowy - jeśli przez np. 3s coś się przemieszcza stale po tej samej linii to na początku mógłbyś zmienić wartość na końcową, czas zmiany ustawić na te 3s i w kolejnych klatkach masz np. null co znaczy, że nie wprowadzasz żadnych zmian w stylach...
CuteOne
Wszystko było by pięknie gdyby nie to że animację tworzę w canvas "a tam nie ma CSS" smile.gif Mimo wszystko ciekawe podejście do problemu aż sobie zapisze gdzieś w zeszycie biggrin.gif
everth
Cytat(zegarek84 @ 25.10.2011, 14:46:20 ) *
animacje by były płynne dla ludzkiego oka to odstęp między klatkami musi wynosić około 40ms (25fps -> co 40ms klatka), fakt, niektóre filmy mają chyba delikatniej mniejszy fsp i chyba wynosi on 23,7 fps ale to szczegół...

To nie do końca tak. Dla ludzkiego ruch oka jest płynny chyba już od granicy 15-16 fps - tyle chyba miały najstarsze filmy. Rozdziałkę zmieniono by zgrać ją z odświeżaniem obrazu (50-60Hz). Tylko że ten zabieg chyba ma sens tylko dla technik wyświetlania w których następuje wygaszenie obrazu pomiędzy kolejnymi odświeżeniami (kino tradycyjne, telewizory kineskopowe). W LCD o ile wiadomo wygaszenie nie następuje dlatego możesz tu kombinować już od najniższej granicy (chyba że będzie rwało).
CuteOne
Po delikatnych przeróbkach Twojego kodu (everth, dałem ci podwójne pomógł za twój kod wink.gif dał bym jeszcze 10 ale pewnie bym bana wyłapał biggrin.gif) i rozdzieleniu tablicy na kilka mniejszych (po 500 klatek) wszystko działa znacznie płynniej niż w moim poprzednim kodzie a zużycie pamięci jest o 20-30% mniejsze.

Mimo wszystko jestem ciekaw czy istnieje inny sposób zapisu takiej animacji lub inny (lepszy) format składowania danych niż JSON ?
wNogachSpisz
Cytat(CuteOne @ 25.10.2011, 18:11:43 ) *
animację tworzę w canvas

Koniecznie do workerów, przy 2-4 workerach program wykona się 10-15 razy szybciej.
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.