Poradniki

 
 
 
Kurs RGSS - cz. 1
(Sabikku)

Hejka. W tym trzyczęściowym kursie postaram się wyjaśnić podstawy działania rgss - systemu gry stworzonego na potrzeby Rpg Makera. Będę posługiwał się XPkiem, ale różnice są na tyle małe, że używając VXa nie powinniście mieć problemów. Nie polecam jednak wersji pl, ze względu na niezrozumiałe komentarze (w języku japońskim). W pierwszej części znajdziecie małe wprowadzenie do rgss i scen.

Ruby, ruby, ruby.

Niniejszy kurs piszę z myślą o osobach, które przestudiowały już dostępne w sieci materiały. Jest ich sporo, ale prawie wszystkie przedstawiają jedynie składnie języka - na temat rgss trudno znaleźć cokolwiek przydatnego. Powód? Po co, skoro jest dokładna dokumentacja, a dzięki przejrzystości kodu wszystko widać jak na dłoni. Mimo wszystko właśnie z opanowaniem rgss sporo ludzi ma problem, więc postaram się przybliżyć jego podstawy. Od razu zaznaczę, ze niektóre kwestie upraszczam i uogólniam, starając się wspominać tylko o tym, co ważne.

Chyba nie muszę wspominać, że znajomość języka angielskiego kilkakrotnie ułatwi naukę.
Dla tych, którzy mają problemy z samą składnią czy podstawami programowania przytoczę trzy przydatne linki:

http://www.ruby-lang.org/pl/dokumentacja/ - spora dawka krótszych/dłuższych tutków na temat składni Ruby'ego. Szczególnie polecam tryruby, w którym na bierząco możemy próbować swoich sił.
http://www.rmxp.pl/index.php?topic=476.0 - krótki, wprowadzający do rgss kurs autorstwa areva. http://www.ruby-doc.org/core/ - dokumentacja Ruby'ego. Spośród setek klas w środkowej rameczce najbardziej przydatne okazują się te, których używamy na każdym kroku, czyli m.in.: Integer, String, Array. Przykład.
Mamy napis "Marek lubi pieski" zapisany w zmiennej @moj_napis (@moj_napis = "Marek lubi pieski"). Potrzebujemy dodać do niego w odpowiednim momencie dopisek " i kotki.". Wchodzimy więc do wspomnianej dokumentacji Ruby, klikamy w środkowej rameczce odnośnik 'String' i wyszukujemy, jak dopisać do stringa tekst. Znajdujemy krótki schemat z przykładem: str + other_str => new_str; czyli napis + inny_napis = nowy_napis. Możemy z tego wywnioskować, że wystarczy zapisać to w ten sposób: @moj_napis = @moj_napis + " i kotki." , czyli w skrócie: @moj_napis += " i kotki".
Może i brzmi skomplikowanie, ale wystarczy dokładnie studiować przykłady z dokumentacji, by osiągnąć wszystko, co w standardzie można robić z daną klasą / typem danych.
Um, kończymy przydługawą dygresję i wracamy do kursu.

Mały schemat.

Po pierwszym otwarciu edytora skryptów można się nieco pogubić. Mamy listę klas z dziwnymi dopiskami (Game, Scene, Window itp), setki niezrozumiałych metod i zmiennych. W większości można jednak znaleźć taką część wspólną:

class Nazwa_Klasy
  def initialize
    (...)
  end
  def update
    (...)
  end
  (Inne metody.)
end


To teraz objaśnimy:
- initialize - metoda ta uruchamiana jest jednorazowo, przy tworzeniu obiektu. Na przykład w Window_Gold metoda initialize (a konkretniej wszystko między def initialize a end) uruchamiana jest tylko w momencie wchodzenia do menu (esc) - to wtedy tworzone jest okienko z ilością złota.
- update - metoda ta uruchamiana jest w każdej klatce gry (teoretycznie kilkadziesiąt razy na sekundę), tak długo, jak obiekt istnieje. Na przykład w Sprite_Character metoda update uruchamiana jest co klatkę tak długo, jak widzimy postać na mapie - gracza lub zdarzenie.
- inne metody - wszystko inne, co robi klasa. Funkcje zwracające jakieś wartości czy wykonujące dane czynności. Na przykład funkcja width w klasie Game_Map - po wywołaniu zwraca szerokośc aktualnej mapy.

To tyle. Powyższe zasady sprawdzają się w większości klas, na których będziecie pracować.

Sceny!

Czego nauczymy się w tym punkcie:
 + zmienianie scen;
 + tworzenie własnych scen.

Po uruchomieniu gry widzimy różne sceny - raz jest to ekran tytułowy, kiedy indziej eksploracja mapy, czasem walka z potworami. Każdą z tych scen obsługuje osobna klasa, umownie każda z nich posiada dopisek - "Scene_". Przykładowo Scene_Shop odpowiada za kontrolowanie przebiegu zakupów w grze, Scene_Gameover za wyświetlenie ekranu końcowego, a Scene_Menu - obsługę menu (esc).

No dobrze, ale jak zmienić aktualnie wykonywaną scenę? Jak przejść z mapy do menu, czy z walki do ekranu końcowego? Otóż wyczytywane jest to ze zmiennej globalnej $scene. Jeśli w $scene schowamy obiekt klasy Scene_Map - komputer pokaże mapę, jeśli w $scene schowamy obiekt klasy Scene_Battle - komputer pokaże walkę, itp. Robimy to następująco:
  $scene = Scene_Battle.new # W tym momencie (tak jakby) rozpocznie się walka.

Dalej. Łatwo zauważyć, że sceny nie posiadają wspomnianej metody 'initialize', mają za to inną - 'main'. Właściwie zasada jest taka sama: def main wywoływane jest tylko raz. Main jednak ma w środku pętlę, która wykonuje się tak długo, aż zmienimy scenę. Na przykład.
Ustawiamy $scene = Scene_Title.new (czyli odpalamy ekran tytułowy). W tym momencie uruchomi się def main z zakładki Scene_Title, a pętla w jego wnętrzu zacznie się wykonywać. Wybieramy strzałkami 'Nowa Gra', wciskamy enter. Teraz $scene ustawi się na Scene_Map.new - pętla ze Scene_Title przestanie działać, po czym uruchomi się def main z zakładki Scene_Map, a pętla w jego wnętrzu zacznie się wykonywać...
Może brzmieć niezrozumiale, ale wystarczy zapamiętać, że w $scene schowany jest obiekt aktualnej sceny.

Oto schemat przedstawiający budowę przykładowej sceny, wraz z krótkimi objaśnieniami:

class Scene_Nazwa
  # Main.
  def main
    (...) # utworzenie obiektów - mapy, okienek itp,
          # czyli wszystkiego, co będzie potrzebne w danej scenie
          # i uruchomi się po jej rozpoczeciu
    Graphics.transition # płynne, graficzne 'przejście' z poprzedniej sceny,
                        # coś jak 'execute transition'
    loop do # rozpoczęcie kodu pętli
      Graphics.update # odświeżenie grafiki
      Input.update # odświeżenie informacji o klawiaturze
      update # patrz do --> def update, nieco niżej
      if $scene != self
        break # zatrzymanie pętli, jeśli scena się zmieniła
        end
      end # zakończenie kodu pętli
      Graphics.freeze # zarzymanie grafiki na ekranie,
                        # coś jak 'prepare transition'
      (...) # usunięcie, zniszczenie obiektów - mapy, okienek itp,
          # czyli wszystkiego, czego komputer nie będzie już potrzebował
          # i uruchomi po zakonczeniu sceny
  end

  def update # Tutaj odsyłany jest komputer w każdym obiegu pętli.
    (...) # wywołanie metody .update używanych obiektów (mapy, okienek itp)
          # i wszystko inne, co potrzeba sprawdzać w każdej klatce gry
  end

  (...) # inne metody, zazwyczaj mniej znaczące, pomocnicze
end



Uff, trochę tego jest. Jak to wygląda w praktyce? Spróbuję pokazać na przykładzie Scene_GameOver, mało skomplikowanej klasy.
W main owej sceny mamy następujący początek:
  @sprite = Sprite.new
  @sprite.bitmap = RPG::Cache.gameover($data_system.gameover_name)
  $game_system.bgm_play(nil)
  $game_system.bgs_play(nil)
  $game_system.me_play($data_system.gameover_me)
  Graphics.transition(120)

Pierwsze dwie linijki tworzą obiekt, którego będziemy używać w scenie, a konkretniej - tworzą obraz wyświetlający się przy ekranie końcowym gry.
Kolejne dwie linijki zatrzymują aktualnie graną muzykę. Przedostatnia odtwarza muzykę ekranu końcowego, a ostania wykonuje przejście (powolne - liczba oznacza czas, w jakim ma się dokonać przejście).
Dalej mamy dokładnie to, co na schemacie - uaktualnienie ekranu, informacji na temat klawiatury i wywołanie metody update. Ta pętla wykonywać się bedzie tak długo, jak aktywna będzie scena Scene_GameOver.
Następnie następujący kod kończący metodę main:
  Graphics.freeze
  @sprite.bitmap.dispose
  @sprite.dispose
  Graphics.transition(40)
  Graphics.freeze

Czyli po kolei: przygotowanie do przejścia, usunięcie obrazka, wykonanie przejścia (czyli powolne usunięcie obrazka, tak by pozostał czarny ekran) i ponowne przygotowanie do przejścia (które pojawia się pod koniec każdej sceny). Mamy więc dokładnie to, co w schemacie wyżej - usunięcie niepotrzebnych rzeczy, zakończenie działania sceny.
Wróćmy jednak do metody update. Jak wspomniałem, będzie się ona wykonywana w każdym przebiegu pętli, czyli w tym przypadku w kazdej klatce gry. Zobaczmy, co zawiera ta metoda:
  if Input.trigger?(Input::C)
    $scene = Scene_Title.new
  end

Co to? Warunek, czy wciśnięto przycisk C (spacja, enter) --> jeśli tak, scena ustawiana jest na Scene_Title. Inaczej mówiąc, zamieszczono tutaj kontrolę
klawiatury. W ekranie końcowym gry (Scene_GameOver), po wciśnięciu przycisku powrócimy do ekranu tytułowego - Scene_Title.


W podobny sposób możemy konstruować inne sceny - np. nasz własny bestiariusz czy nowy skrypt dziennika.
Jak widzisz, z pomocą scen można kontrolować przebieg tego, co robi gra - trzeba jeno znać inne struktury (tutaj użyto tylko Sprite, obrazka) i umieć je wykorzystywać. Tak więc, żeby w pełni operować grą, musimy prócz scen wiedzieć, jak tworzyć nowe okienka, grafiki itp. i wykorzystywać je w scenach.

W następnym numerze:
 --> umieszczanie okien w scenach;
 --> tworzenie własnych okien wraz z zawartością;
 --> kontrolowanie okienek wyboru;
 --> chowanie/dezaktywowanie okienek.