Forum dyskusyjne  |  Kanał IRC | Użytkownicy | Hosting
[Omega] Animacje warstw- Izometria w świecie prostokatnym część 3
załącznik
2007-12-02 16:18:16, wyświetleń: 4758 [ historia ]


ANIMACJE WARSTW- IZOMETRIA W ŚWIECIE PROSTOKĄTNYM- CZEŚĆ 3



Witam wszystkich czytających ten artykuł. Powiedzmy, że jest to część trzecia cyklu o izomerii w świecie prostokątnym, choć temat poruszany w tym artykule można zastosować w dowolnie innym modelu świta 2D. Poniższy zrzut ekranu z działającego kodu dołączonego do artykułu wprowadzi w temat.

0112205608cz3_rys1.PNG

Na obrazie nie widać animacji, ale po uruchomieniu dema i po dojściu w to miejsce świata powinieneś Czytelniku zobaczyć:
-animację wody
-animację rosnącego zboża
-animację wirnika wiatraka
-animację koła młyńskiego

Sposób realizacji animacji nie jest trudny. Przebiega on dokładnie tak samo jak animacja ruchu postaci. Kolejne klatki są przerzucane przez zegar gry. W tym tekście chciałbym zwrócić uwagę na pewien problem:

Kiedy animować?

Świat gry można podzielić na warstwy, w których mogą się znaleźć: obiekty żywe, obiekty statyczne animowane lub nieanimowane.


0112205734cz3_rys2.PNG


Każdy obiekt dla stanu gry reprezentowany jest przez układ liczb- parametrów. Dla człowieka- gracza wystarczy tylko grafika. Stąd można dokonać kolejnego podziału obiektów, który prawidłowo przemyślany będzie decydować o prędkości gry. Mam nadzieję, że poniższym rysunkiem uda mi się lepiej wprowadzić w omawiane zagadnienie.

0112205816cz3_rys3.PNG


Niebieski obszar to kafle widoczne. Jednocześnie są to warstwy utworzone na zasadach opisanych w cyklu artykułówGiganty świata 2D. Do kafli tych warstw są ładowane dane przechowywane w szarych kaflach mapy świata na zasadzie taśmociągu. Idea też jest opisana w Gigantach… Taki układ organizacji podsuwa pewien pomysł na animację. Otóż animowane klatki warstw można podzielić na animację wpływającą na zachowanie poza częścią widoczną lub nie wpływającą. To znaczy: na przykład animacja wody nie ma żadnego wpływu na to, co się dzieje poza częścią widoczną. To samo dotyczy ruchu wirnika wiatraków czy koła młyńskiego. Przykładów można mnożyć. Ale może wystąpić taka animacja, która stanem swych klatek będzie o czymś decydować i poza częścią widoczną. Może to być zboże lub inne uprawy. Chodzi mi o to, że żniwa będą w tedy, gdy zboże dojrzeje. Czyli jest to na przykład dziesiąta klatka animacji. Tak więc, życie poza częścią widoczną musi się toczyć na tych samych zasadach co w części widocznej. Jedynie rezygnuje się z wyświetlania klatek. Ze zliczania nie. Mając to na uwadze należy wprowadzić podział animowanych obiektów.
W kodzie programu utworzyłem do tego zarys klasy TCykl, zapisanej w unit UnitCyklSwiata. Rozbudowując tą klasę można obsłużyć wiele zdarzeń. Na przykład produkcja jednostek, szkolenie itp. Procedura zliczająca klatki dla obiektów dopisanych do TList tej klasy wywoływana jest w zegarze gry
Kod:

procedure TForm1.OmegaTimer1Timer(Sender: TObject);
var
 x:integer;
begin
 Cykl.deltaSeconds:=OmegaTimer1.DeltaSecs;
 OmegaInput1.Update;
 if oisbutton28 in OmegaInput1.keyboard.statesclicked then
  OmegaScreen1.ToggleFullScreen;
 if not omegascreen1.CanDraw then exit;

 OmegaScreen1.BeginRender;
 OmegaScreen1.ClearScreen(0,0,0,0);
 if fZaladowanoPlik then
 begin
Cykl.Animacja;
...
 



Wynik zliczeń animacji jest pamiętany w wybranych kaflach świata gry. Jest to ten rekord danych

Kod:
tAnimacja=record
       fIdObAnim:Word;//indeks odpowiadajacy pozycji typu ob. animacji w  tObiektyAnimacji=(oWoda,oWoda1,...
       fAnimPos1,
       fAnimPos2  :single;//Liczniki animacji
     end;
 

Dla elementów typu woda, wiatrak, młyn itp. Takie zliczanie odbywa się w kaflach warstwach widocznych. Takich kafli jest dużo mniej niż wszystkich kafli świata 2D. Wynik zliczeń jest zapisywany tym samym rekordzie pojedynczego kafla i przerzucany podczas przesuwania świata na tych samych zasadach co obrazy. W kodzie programu wykonuje to nowa procedura dopisana w tej części

procedure Animacja;

Procedura ta występuje w klasie TKostkaMapy oraz TKostkaGruntuMapy Jedynie należy podczas ładowania świat zdecydować, co mam być animowane. Konkretnie wybrać kafle.

Wybór kafli do animacji

Jest to ważny element struktury organizacji zapisu świata gry. Ja ze swojego rozwiązania nie jestem w pełni zadowolony. Otóż świat buduję w swoim edytorze, który ma być uniwersalnym edytorem. No i do końca nie jestem zdecydowany jak tą uniwersalność zapewnić. Tak wiec w kodzie dołączonym do artykułu dopisałem pewną stałą tablicę przechowującą dane o animowanych obiektach

Kod:
DaneObiektu:array [0..9]of tDaneAnimacji=(
                      (fAnimacja1:false;fAnimacja2:false)  ,//oBrak
                      (fAnimacja1:true;fdV1:2 ;L1:4 ;P1:12),//oWoda
                      (fAnimacja2:true;fdV2:2 ;L2:4 ;P2:12),//oWoda1
                      (fAnimacja1:true;fdV1:45;L1:0 ;P1:11),//oZboze1
                      (fN:'lopatyS';fAnimacja1:true;fdV1:5 ;L1:0 ;P1:23), //wiatrakS-wirnik animowany w pierwszym obrazie,
                      (fN:'lopatySW';fAnimacja1:true;fdV1:5 ;L1:0 ;P1:23), //wiatrakSW-wirnik animowany w pierwszym obrazie,
                      (fN:'lopatySE';fAnimacja1:true;fdV1:5 ;L1:0 ;P1:23), //wiatrakSE-wirnik animowany w pierwszym obrazie,
                      (fN:'koloS' ;fAnimacja2:true;fdV2:4 ;L2:0 ;P2:31),//oMlynS-koło animowane w drugim obrazie
                      (fN:'koloSW';fAnimacja2:true;fdV2:4 ;L2:0 ;P2:31),//oMlynSW-koło animowane w drugim obrazie
                      (fN:'koloSE';fAnimacja2:true;fdV2:4 ;L2:0 ;P2:31) //oMlynSE-koło animowane w drugim obrazie
                      );
 

Teraz jedynie podczas ładowania gry sprawdzam czy danej klatce warstwy istnieje wybrany obiekt. Jeżeli tak to na taką klatkę ustawiam flagę animacji. Patrz kod

Kod:
UstawAnimacjeWKaflu(PMapa(Lista.Items[0])^[aI]);// animacja Wody
     UstawAnimacjeWKaflu(PMapa(Lista.Items[1])^[aI]);//animacja Wiatrak, Młyn


Takie podejście wydłuża czas ładowania pliku.A plik jest duży bo zawiera 512x384 kafli w trzech warstwach. Co daje 589824 kafli. Taki mały gigant. Lepszym rozwiązaniem byłoby ustalenie tego w momencie tworzenia świata. Czyli edytorze.

Animacja w pojedynczym kaflu

W tej części do kodu wprowadziłem do wszystkich warstw możliwość wyświetlania dwóch obrazów w jednym kaflu. W poprzedniej części było to zastosowane do płynnych przejść terenu. Teraz taką właściwość posiada każdy kafel. Praktycznie daje to nam aż sześć warstw rysunku. Dużo. Można, więc zrezygnować z trzeciej warstwy. Na pewno wydatnie przyspieszy to grę. Aby to sprawdzić należy wyrzucić z kodu te linie zaznaczone czerwoną czcionką

Kod:
procedure TForm1.CzysteMapy;
var
  AMapa:PMapa;
  a,b,
  i:LongInt;

begin
…..
  for b:=0 to DaneMapy.YSwiataEkranu-1 do
   for a:=0 to DAneMapy.XSwiataEkranu-1 do
   begin
     //warstwa ZERO- nowy pomysł
      SwiatProstokatnyGrunt[a,b]:=TKostkaGruntuMapy.Kreacja(
                               DAneMapy,
                               0,0,0,a,b);
     //warstwa 1
      SwiatProstokatnyWarstwy[1,a,b]:=TKostkaMapy.Kreacja(DaneMapy.OmegaSprite,
                          DAneMapy,
                          0,0,1,a,b,b{czyli z});
      [kolor=red]SwiatProstokatnyWarstwy[2,a,b]:=TKostkaMapy.Kreacja(DaneMapy.OmegaSprite,
                          DAneMapy,
                          0,0,2,a,b,b+3{czyli z});[/kolor]
   end;

end;
 

oraz

Kod:
procedure TForm1.OdswiezEkran;
var
  a,b:byte;
begin
     //odswiez ekran
     for b:=0 to DaneMapy.YSwiataEkranu-1 do
         for a:=0 to DAneMapy.XSwiataEkranu-1 do
             begin
              SwiatProstokatnyGrunt[a,b].ZmianaKlatki;       
              SwiatProstokatnyWarstwy[1,a,b].ZmianaKlatki;
              [kolor=red]SwiatProstokatnyWarstwy[2,a,b].ZmianaKlatki;[/kolor]
            end;
end;


 


Ale nie o tym chcę tu napisać. Na stronie grafika 2D z której pobrałem grafikę klatki do animacji na przykład młyna są tak zorganizowane

0112210955cz3_rys4.PNG

0112211027cz3_rys5.PNG

Co prowadzi do takiego rozwiązania: wyświetl budynek a potem animowane klatki koła w odpowiednich współrzędnych. Cały proces animacji przebiega w tej procedurze

Kod:
procedure TKostkaMapy.Animacja;
begin
  with PMapa(Lista.Items[idWskMApy])^[IDKafla] do begin
          //animacja pierwszego obrazu
          if DaneObiektu[Animacja.fIdObAnim].fAnimacja1 then begin
             Animacja.fAnimPos1:=Animacja.fAnimPos1+Form1.OmegaTimer1.DeltaSecs;
             if Animacja.fAnimPos1>Form1.OmegaTimer1.DeltaSecs*DaneObiektu[Animacja.fIdObAnim].fdV1 then
                begin
                inc(IdKlatka,1);
                Animacja.fAnimPos1:=0;
                end;
             if IdKlatka>DaneObiektu[Animacja.fIdObAnim].P1 then IdKlatka:=DaneObiektu[Animacja.fIdObAnim].L1;
          end;
          //animacja drugiego obrazu
          if DaneObiektu[Animacja.fIdObAnim].fAnimacja2 then begin
             Animacja.fAnimPos2:=Animacja.fAnimPos2+Form1.OmegaTimer1.DeltaSecs;
             if Animacja.fAnimPos2>Form1.OmegaTimer1.DeltaSecs*DaneObiektu[Animacja.fIdObAnim].fdV2 then
                begin
                inc(RGBA.idKlatka2,1);
                Animacja.fAnimPos2:=0;
                end;
             if RGBA.idKlatka2>DaneObiektu[Animacja.fIdObAnim].P2 then RGBA.idKlatka2:=DaneObiektu[Animacja.fIdObAnim].L2;
          end;
  end;
end;


Dla warstwy gruntu jest bardzo podobnie. Jedynie nie ma tam możliwości nakładania klatek z poza obrazu innego niż rysunek wyświetlany na pierwszym obrazie. Ponieważ zakładam ze cały grunt i wszystkie jego klatki animacji można, zapisać w jednym obrazie. Tak jak poniżej

0112211230cz3_rys6.png

Można teraz sobie wyobrazić, że dodajemy tu klatki animacji błota, lawy, ruchomych pisaków itp. Jednym obrazem załatwiamy cały grunt świata 2D. Wyświetlanie obu obrazów w jednym kaflu wykonuje procedura

Kod:
procedure TKostkaMapy.Draw;
begin
 if (ImageIndex=-1)or(fIDKafla=-1)then exit;
 Animacja;
 OdswiezKlatke;
 Image.Draw(Round(x+left),Round(y+top),0,0.5,0.5,1,1,Red,Green,Blue,Alpha,ImageIndex,0);
 if (idKlatka2=-1)then exit;
fOmegaImageList.ImageList.Items[idObrazka2].Draw(Round(x+left+left2),Round(y+top+top2),
0,0.5,0.5,1,1,Red,Green,Blue,Alpha,idKlatka2,0);
end;


I to by było na tyle w tej części.

Pozdrawiam Adam Lasko (oksal) Zbylitowska Góra 1 XII 2007

PS
Do prawidłowego działania przykładu wymagane są te pliki

swiat_512x384.mue2D
teren_rosliny.oil
swiatynie.oil
zamki.oil
pierwotny001.oil
wiatrak.oil
mlyn.oil
D3DX81AB.DLL
MPPSDK.DLL



Plik swiat_512x384.mue2D został zmieniony co do organizacji zapisu. Nie będzie prawidłowo czytany dla poprzednich części i na odwrót.



Pobierz załącznik załącznik

Autor: oksal

Komentarze
Artykuły mogą być komentowane wyłącznie przez zarejestrowanych użytkowników.

Zaloguj się | Załóż nowe konto

Redakcja zastrzega sobie prawo do skracania, usuwania komentarzy o treściach wulgarnych, obraźliwych oraz niezgodnych z polskim i miedzynarodowym prawem. Unit1.pl Team nie ponosi odpowiedzialności za treść komentarza.