| Rozbudowany HUD. |
| Redaktor: Dan | Dodano: 01/07/2009 - 15:34 |
|
Poradnik: Jak zrobić rozbudowanego HUDa w Ruby (jednoosobowego) Opis: Zauważyłem niedawno, że w dziale 'Poradniki' nie ma żadnego tematu poświęconego robieniu HUDa w Ruby. Początkującym rzecz ta może wydawać się trudna (szczególnie w RGSS) jednak jest prawie że tak prosta jak na eventach =] Postanowiłem więc napisać poradnik, w którym umieszczę masę rzeczy dzięki którym każdy będzie mógł stworzyć swój własny HUD, bez podstawowych ograniczeń spowodowanych niewiedzą ;3 Wymagane: -Grafiki do naszego HUDa -RPG Maker XP -Umiejętność czytania i pisania (na klawiaturze ofc, nie ma tak łatwo) -Troszeczkę wolnego czasu -Podstawowa znajomość Ruby (tworzenie klas etc.) 1. Organizacja Pierwszym krokiem jest zaplanowanie wyglądu naszego HUDa oraz znalezienie grafik (zrobić też można, polecam). W tym celu otwieramy dowolny program graficzny (Paint rox), ustawiamy wymiar obrazu na 640x480 i rysujemy wszystko co będziemy chcieli mieć. Dzięki obrazowi o wymiarach 640x480 wiemy, ile miejsca będzie zajmował HUD (żeby się czasami nie zdarzyło tak, że obrazki będą zawalały połowę ekranu :>) Gdy już narysujemy zarys, standardowo chwalimy się kolegom. Mój szkic wygląda tak: ![]() Po co tak dużo? Po to by pokazać jak najwięcej możliwych opcji w HUDzie. Ok, skończyliśmy już względny plan, tak więc tworzymy (lololol) grafiki do HUDa. W moim przypadku będą to: -Background HUDa -Twarz bohatera -Pasek HP -Masek MP -Pasek Exp Po jakimś czasie spędzonym w GIMPie powstały proste graficzki (możecie brać, ale twarz nie moja) które wrzucamy w osobne pliki: ![]() No dobra, posiadamy już wszystkie graficzne rzeczy. Czas na modyfikację kodu :d 2. Podstawowe wyposażenie Na początek wrzucamy wszystkie grafiki do folderów gry (Tylko nie wrzucajcie do 'Audio/' XD, polecam dać wszystko do folderu 'Graphic/Pictures'). Następnie otwieramy projekt i wchodzimy do Edytora Skryptów, gdzie wykonujemy następujące czynności: -Tworzymy nową klasę nad 'Main' i nazywamy ją sobie jak chcemy (Np. 'HUD Script') -Odnajdujemy klasę 'Scene_Map', kopiujemy jej zawartość i wklejamy do stworzonej wcześniej klasy (od teraz wszystkie operacje ze 'Scene_Map' wykonujemy na tej klasie) -Odnajdujemy klasę 'Window_Base', kopiujemy jej zawartość i wklejamy do stworzonej wcześniej klasy (pod wklejoną zawartość 'Scene_Map') -Usuwamy z wklejonego 'Window_Base' wszystkie warunki (def cośtamy) tak by powstało coś takiego: #============================================================================== # ** Window_Base #------------------------------------------------------------------------------ # This class is for all in-game windows. #============================================================================== class Window_Base < Window end Ok, najtrudniejsze za nami xd Teraz po kolei robimy naszego HUDa. 3. Background HUDa Na początek zajmiemy się wyświetlaniem głównego obrazka HUDa, w miom przypadku tego: ![]() Wspinamy się na górę naszego HUDa, czyli do Scene_Map. Gdy zobaczymy komendę: # Make sprite set Długo się w nią wpatrujemy ;d Ok, teraz zajmiemy się wszystkim co jest między tym komentarzem a kolejnym. Wymyślamy sobie jakąś nazwę dla naszego obrazka, powiedzmy że hud_back. Gdy to zrobimy, pod znanym nam komentarzem wpisujemy: @hud_back = Sprite.new Zrobione? Ok, dzięki temu będziemy mogli wyświetlić obrazek. Pod tą komendą wpisujemy: @hud_back.bitmap = RPG::Cache.picture("Nazwa_obrazka") Zamiast 'nazwa_obrazka' wpisujemy nazwę naszego pliku z backgroundem HUDa. Ma sie on znajdować w folderze 'Pictures' ofc ;s Gdy to napiszemy, wklejamy takiego cosia: @hud_back.x = X @hud_back.y = Y @hud_back.z = Z @hud_back.opacity = O Czyli: X - położenie X na ekranie (poziom) Y - położenie Y na ekranie (pionowo) Z - położenie 'warstwowe' (możemy np. ustawić że obrazek będzie przykrywał niektóre rzeczy a niektóre nie). O - przezroczystość obrazka (0 - przezroczysty, 1-254 półprzezroczysty i 255 - brak przezroczystości). Ustawiamy sobie według własnych potrzeb, ja dam tak: @hud_back.x = 0 @hud_back.y = 0 @hud_back.z = 100 @hud_back.opacity = 255 Położyłem więc obrazek w lewym-górnym rogu ekranu, nieprzezroczysty. Jeżeli nei chcecie kombinować z warstwą obrazka, polecam ustawić ją na 100. Teraz zjeżdżamy na dół aż odnajdziemy: @spriteset.dispose I dajemy pod tym: @hud_back.dispose Dzięki temu nasz HUD zostanie usunięty przy włączaniu menusów itp. Jeżeli chcemy mieć swój HUD w menusach nie wpiczujemy nigdzie tego kodu Xc Na końcu znajdujemy: @spriteset.update I dajemy pod: @hud_back.update 4. Okienko HUDa Dodawanie napisów oraz obrazków na HUDzie ułatwi nam przezroczyste okienko nad nim. W tym celu robimy następującą rzecz: -Znajdujemy 'Window_Gold' i wklejamy jego zawartość na koniec naszego skrypciku -Zamieniamy: class Window_Gold < Window_Base Na nazwe okienka HUDa, dajmy na to: class Window_HUD < Window_Base Ok, teraz odnajdujemy w tym samym okienku: cx = contents.text_size($data_system.words.gold).width self.contents.font.color = normal_color self.contents.draw_text(4, 0, 120-cx-2, 32, $game_party.gold.to_s, 2) self.contents.font.color = system_color self.contents.draw_text(124-cx, 0, cx, 32, $data_system.words.gold, 2) I usuwamy to. Dzięki temu mamy czyste okienko. Została nam jeszcze jedna rzecz. Troszeczkę wyżej widzimy: super(0, 0, 160, 64) Nas interesują tylko dwie ostatnie wartości, początkowi dajemy spokój. Tak więc 160 oznacza szerokość okienka a 64 jego wysokość. Zamieniamy te wartości tak, by odpowiadały naszemui HUDowi. Pamiętajcie o tym, że im większe okienko i więcej będzie w nim obrazków i tekstów, tym bardziej zmniejszy się liczna FPS. Zazwyczaj daje się tam szerokość oraz wysokość taką jak Background, chyba że informacje w HUDzie mają być poza nim. Ja zamieniłem to tak: super(0, 0, 370, 160) Tak więc nadałem okienku szerokość taką jak background HUDa. Teraz musimy sprawić, by okienko pojawiło się na mapie. W tym celu znajdujemy: @hud_back = Sprite.new Wymyślamy sobie jakąś nazwę dla okienka, dajmy na to 'window_hud'. Pod komendami 'hud_back' dajemy coś takiego: @window_hud = Window_HUD.new @window_hud.opacity = O @window_hud.x = X @window_hud.y = Y @window_hud.z = Z Czyli: O - przezroczystość całego okienka X - położenie X na ekranie (poziom) Y - położenie Y na ekranie (pionowo) Z - warstwa Myślę, że X i Y najlepiej ustawić takie same jak X i Y obrazka. Przezroczystość okienka ustawiamy na 0, chyba że chcemy by było widoczne :d Co do warstwy to musi ona być wyższa niż warstwa backgrounda. U mnie wygląda to tak: @window_hud.opacity = 0 @window_hud.x = 0 @window_hud.y = 0 @window_hud.z = 101 Teraz pozostaje jeszcze wkminić @window_hud.dispose Pod disposem backgrounda oraz @window_hud.refresh Pod jego updatem ;p Teraz już możemy zapełniać naszego HUDzika obrazkami, tekstami, zmiennymi oraz wszystkim czym chcemy :D 5. Wypełnianie HUDa tekstem Przyszedł czas na wrzucenie do HUDa tekstu ;> Jest wiele możliwości jego wyświetlania. Może on przybrać wartości zmiennych oraz być pokazywanym w zależności od nich (warunki). Mój HUD chcę wypełnić: -Ilością kasy -Imieniem bohatera -Poziomem postaci -Statusem postaci -Atakiem oraz obroną bohtera -Zwykłą zmienną z gry (przykładem będzie Karma czyli wartość dobrej lub złej energii ;x) -HP oraz MP Hmm, trochę tego jest. Prawie każdy typ tekstu się od siebie różni, ale dosyć teorii - przejdźmy do praktyki. Zacznijmy od wyświetlenia kasy drużyny. Lecimy na sam dół skryptu, czyli do 'Window_HUDa'. Miejsce na tekst znajduje się pod takim ładnym napisem self.contents.clear Ok, wybieramy sobie jaki kolor ma mieć tekst. Załóżmy że normalny. Pod tekstem na górze wklejamy coś takiego: self.contents.font.color = normal_color Pozwala to zmienić kolor wyświetlanego tekstu. Domyślne kolory to: -normal_color (biały) -disable_color (szary) -system_color (błękitny) -crisis_color (żółty) -knockout_color (czerwony) Jeżeli chcemy uzyskać jakiś nowy kolorek, wspinamy się trochę wyżej (do naszej pustej klasy 'Window_Base' i dajemy tam coś takiego: def new_color return Color.new(R, G, B, O) end Zamiast 'new_color' dajemy nazwę koloru jaka będzie oznaczała nasz własny. Końcówka nie musi kończyć się na '_color'. Mogą to być też inne nazwy :o Nie używajcie tylko nazw wymienionych wcześniej, bo popsuje to wam inne kolory ;x Oznakowania: R - ilość koloru czerwonego w kolorze G - ilość koloru zielonego w kolorze B - ilość koloru niebieskiego w kolorze O - przezroczystość koloru Ja stworzyłem sobie dwa kolory poprzez dodanie ich do 'Window_Base', które później wykorzystam w HUDzie: def new_color return Color.new(255, 0, 0, 255) end def new_color return Color.new(0, 255, 0, 255) end Wróćmy do wyświetlania tekstu, bo trochę odbiegliśmy od tematu Xd Kod na wyświetlenie tekstu wygląda tak: self.contents.draw_text(X, Y, W, H, Text, T) Czyli: X - poziom X wyświetlonego tekstu w okienku Y - poziom Y wyświetlonego tekstu w okienku W - szerokość w której ma mieścić się tekst (jeżeli przekroczy tą długość zaczyna się zwężać) H - wysokość w której mieści się tekst (domyślnie 32) Text - chyba wiadomo o co chodzi xd Tekst który ma się wyświetlić zawsze wpisujemy w cudzysłowiu (tym podwójnym, np. "Tekst"), natomiast jeżeli ma się wyświetlić wartość zmiennej, wpisujemy ją bez cudzysłowia, dodając na jej końcu '.to_s' (np. $game_variables[51].to_s). Ta końcówka zamienia naszą zmienna w string, czyli ciąg znaków. Bez tego zmienna będzie miała wartość ale nie zostanie wyświetlona) T - sposób wyświetlania tekstu przyjmujący trzy wartości (0, 1 lub 2). 0 - do lewej, 1 - wyśrodkowanie, 2 - do prawej. Przed pokazywaniem powinniśmy też ustawić czcionkę tekstu oraz jego wielkość. W tym celu wracamy do 'Window_HUD' i znajdujemy napis self.contents = Bitmap.new(width - 32, height - 32) Następnie wklejamy pod nim takie cacko: self.contents.font.name = F self.contents.font.size = S F - nazwa czcionki jaką sobie wybierzemy (musi być w cudzysłowiu, np. "Arial" S - wielkość czcionki Przykład (domyślny): self.contents.font.name = "Arial" self.contents.font.size = 22 Wracając do kasy XD~ Zmienna odpowiadająca za ilość pieniędzy to $game_party.gold A zmienna zachowująca nazwę waluty podanej w bazie danych to $data_system.words.gold Tak więc pod self.contents.font.color = normal_color Wpisujemy poprzednie schematy wyświetlania tekstu oraz zmieniania kolorów (rozpis zmiennych globalnych znajduje się na końcu tego punktu). Ja sobie zrobiłem coś takiego self.contents.font.color = normal_color self.contents.draw_text(-766, 85, 999, 32, $game_party.gold.to_s, 2) self.contents.font.color = system_color self.contents.draw_text(235, 85, 999, 32, $data_system.words.gold) W tym przypadku wyświetla nam się ilość złota, a troszeczkę dalej waluta podana w bazie danych ^^" Im niżej komenda na tekst (zresztą nie tylko na tekst, również na obrazki itp.) tym wyższa jest jej warstwa. Z przykładu na górze wynika więc, że nazwa waluty przykrywałaby ilość pieniędzy. W grze często mamy rzeczy które zapisujemy do zwykłych zmiennych gry (np. uczciwość, czas w grze, punkty nauki, przejście gry w procentach, ilość obecnych questów). Zmienne możemy pokazać w HUDzie równie dobrze jak tekst. By pokazać zmienną w tekście, wystarczy wklepać coś takiego: self.contents.draw_text(X, Y, W, H, $game_variables[ID].to_s, T) Czyli: X - poziom X wyświetlonego tekstu w okienku Y - poziom Y wyświetlonego tekstu w okienku W - szerokość w której ma mieścić się tekst H - wysokość w której mieści się tekst ID - numer zmiennej jaka ma zostać wyświetlona. T - sposób wyświetlania tekstu przyjmujący trzy wartości, 0 - do lewej, 1 - wyśrodkowanie, 2 - do prawej. Dla przykładu posłużę się karmą (uczciwością, dobrą/złą energią - nazywajcie to jak chcecie). Gdy karma będzie ujemna czcionka będzie miała kolor czerwony, a gdy dodatni - czcionka będzie miała kolor zielony. Zapiszę ją do zmiennej o ID 1, oraz stworzę drugą zmienną o ID 2 która będzie dodatnia (gdy mniejsza od 0 mnożona przez -1 by odwrócić znak). Następnie robię bardzo przydatną rzecz czyli warunek na zmiennych gry, pod komendami do kasy. Warunek wygląda tak: if $game_variables[ID] == N 1st Action else 2nd Action end Pamiętajcie o podwójnym znaku równości, inaczej nic z tego nie będzie :p Tak więc za pomocą warunków robię wyświetlanie karmy. Wykombinowałem to sobie tak (posłużyłem się stworzonymi wcześniej kolorami): if $game_variables[1] > 0 self.contents.font.color = green_color else if $game_variables[1] < 0 self.contents.font.color = red_color else self.contents.font.color = normal_color end end self.contents.draw_text(-453, 68, 999, 32, "Karma: " + $game_variables[2].to_s , 1) Po polsku oznacza to: Jeżeli karma jest większa od 0, daj jej kolor zielony. Gdy karma jest mniejsza od 0 (else), daj jej kolor czerwony. Gdy żaden z tych warunków nie został spełniony (Karma wynosi 0) zmień kolor na biały. Prawda, że fajne ^^? Wystarczy tylko troszeczkę pokombinować. Ok, mamy już dwie rzeczy. Teraz pójdzie łatwo. Imię postaci, jej poziom, status, klasę itp. wyświetlamy za pomocą komend 'draw' (np. draw_actor_name). Tak właśnie zrobimy. Jednak by to podziałało, musimy znaleźć w 'Window_HUD' def initialize Zamienić na def initialize(actor) Potem dodać nad refreshem @actor = actor Potem znaleźć @window_hud = Window_HUD.new I zamienić na @window_hud = Window_HUD.new(@actor) Pod 'Main' wkleić @actor = $game_party.actors[@actor_index] A pod 'Scene_Map' wkleić def initialize(actor_index = 0, equip_index = 0) @actor_index = actor_index end Uff... Zrobione :D? To lecimy. Na dole tekstu wstawiamy odpowiednio to co nam się podoba (rozpis komend znajduje się na końcu tego punktu). Ja wybrałem sobię imię, poziom, status, HP, MP Attack oraz Total Defense postaci. Następnie zmieniłem to na kod i wbiłem w okienko: draw_actor_name(@actor, 92, -3) draw_actor_level(@actor, 180, -3) draw_actor_state(@actor, 215, -3) A potem jeszcze self.contents.font.color = normal_color attack = @actor.atk self.contents.draw_text(84, 87, 999, 32, attack.to_s) defend = @actor.pdef + @actor.mdef self.contents.draw_text(154, 87, 999, 32, defend.to_s) To ostatnie wyświetla w jednym atak a w drugim wyniku sumę obrony fizycznej i magicznej (Total Defense). Tak więc umiemy już dodawać tekst do naszego HUDa :DDD! Tutaj jest lista przydatnych komend 'draw': draw_actor_graphic - pokazuje character jaki posiada postać draw_actor_name - pokazuje imię bohatera draw_actor_class - pokazuję klasę postaci draw_actor_level - pokazuje level bohatera draw_actor_state - pokazuje postaci draw_actor_exp - pokazuje doświadczenie bohatera draw_actor_hp - pokazuje hit points postaci draw_actor_sp - pokazuje skill points bohatera draw_actor_parameter (actor, x, y, type) # pokazuje parametry postaci #(dla type: 0 - atak, 1 - obrona fizyczna, 2 - obrona magiczna, #3 - siła, 4 - zręczność, 5 - zwinność, 6 - inteligencja). Lista przydatnych zmiennych globalnych: $game_variables[N] - pokazuje wartość zmiennej nr N. $game_switches[N] - pokazuje wartość przełącznika nr N (True lub False) $game_system.save_count - pokazuje ilość zapisów gry $data_system.words.hp - pokazuje słowo 'HP' zapisane w bazie danych $data_system.words.sp - pokazuje słowo 'SP' zapisane w bazie danych $data_system.words.atk - pokazuje słowo "Atk" zapisane w bazie danych $data_system.words.pdef - pokazuje słowo "Pdef" zapisane w bazie danych $data_system.words.mdef - pokazuje słowo "Mdef" zapisane w bazie danych $data_system.words.str - pokazuje słowo "Str" zapisane w bazie danych $data_system.words.dex - pokazuje słowo "Dex" zapisane w bazie danych $data_system.words.agi - pokazuje słowo "Agi" zapisane w bazie danych $data_system.words.int - pokazuje słowo "Int" zapisane w bazie danych $data_actors[N].final_level - ostateczny poziom postaci o numerze N $data_actors[N].name - imię bohatera o numerze N $data_actors[N].level - poziom postaci o numerze N $data_actors[N].class_name - nazwa klasy bohatera o numerze N $data_actors[N].exp_s - doświadczenie postaci o numerze N $data_actors[N].next_exp_s - doświadczenie potrzebne do następnego poziomu dla postaci o numerze N $data_actors[N].hp - pokazuje ilość HP postaci o numerze N $data_actors[N].maxhp - pokazuje MaxHP postaci o numerze N $data_actors[N].sp - pokazuje ilość HP postaci o numerze N $data_actors[N].maxsp - pokazuje MaxSP postaci o numerze N $data_actors[N].skills.size - ilość umiejętności jakie posiada postać o numerze N $data_actors[N].item.size - ilość przedmiotów jakie posiada postać o numerze N $data_actors[N].str - ilość str postaci o numerze N $data_actors[N].dex - ilość dex postaci o numerze N $data_actors[N].agi - ilość agi postaci o numerze N $data_actors[N].int - ilość int postaci o numerze N $data_actors[N].atk - ilość atk postaci o numerze N $data_actors[N].pdef - ilość pdef postaci o numerze N $data_actors[N].mdef - ilość mdef postaci o numerze N $data_actors[N].eva - ilość eva postaci o numerze N 6. Paski HP, MP i Exp Hmm... Wreszcie to, co najważniejsze jest w HUDzie, czyli paski. Niestety i tu będzie trochę roboty ;p Na początek lecimy do 'Window_Base' i wklejamy taki szablonik: def draw_hp_meter(actor, x, y) hpbar = RPG::Cache.picture("File") cw = hpbar.width * actor.hp / actor.maxhp ch = hpbar.height src_rect = Rect.new(0, 0, cw, ch) self.contents.blt(x, y, hpbar, src_rect) end Zamiast 'File' wstawiamy tam nazwę pliku, który posiada pasek HP. Jeżeli chcemy, by nasz pasek zwęrzał się ku górze, to * actor.hp / actor.maxhp Usuwamy i dajemy po ch = hpbar.height Gdy już to zrobimy, idziemy do dobrze nam znanego 'Window_HUD' (tam gdzie są nasze napisy :d) i wklejamy na samej górze draw_hp_meter(@actor, X, Y) A zamiast X i Y wpisujemy współrzędne. Czemu komenda ta ma być najwyżej? Żeby w HUDzie nie przykrywała żadnych napisów, szczególnie tych z HP ;> I jak, zrobione? Teraz znowu lecimy do 'Window_Base', kopiujemy dopiero co wbity szablonik i zmieniamy w nim każde 'hp' na 'sp'. Potem już tylko dostosowujemy go do naszych potrzeb. Mój szablonik wygląda tak: def draw_mp_meter(actor, x, y) mpbar = RPG::Cache.picture("MP_Meter") cw = mpbar.width * actor.sp / actor.maxsp ch = mpbar.height src_rect = Rect.new(0, 0, cw, ch) self.contents.blt(x, y, mpbar, src_rect) end Teraz wystarczy wbić pod draw_hp_meter(@actor, X, Y) ten kod: def draw_mp_meter(@actor, X, Y) I poustawiać parametry ;d Te dwie rzeczy już zrobione, by zrobić pasek expa, wystarczy tylko skopiowaćjeden z szablonów, każde 'hp'/'sp' zamienić na 'exp' a w linijce trzeciej dać: actor.now_exp.to_f / actor.next_exp zamiast cw = hp(sp)bar.width * actor.hp(sp) / actor.maxhp(sp) Na koniec w wklejamy w klasie 'Game_Actor' (gdzieś pod 'def index'): def now_exp return @exp - @exp_list[@level] end def next_exp return @exp_list[@level+1] > 0 ? @exp_list[@level+1] - @exp_list[@level] : 0 end 7. Twarz zależna od HP bohatera Teraz trik który nieczęsto pojawia się w innych grach, czyli faceset postaci zależny od HP. Na początek upewnijmy się, że mamy w folderze z obrazkami twarze bohatera. Są? To fajnie. Nazwijmy je sobie 'Face[Liczba]', czyli np. Face01, Face07, Face666 itd. Teraz idziemy do dobrze nam już znanego 'Window_Base'. Piszemy tam nowy warunek: def draw_actor_faces(actor, x, y) end Ok, co teraz? Skoro chcemy by wyświetlanie twarzy było zależne od posiadanego HP z pewnością musimy porobić warunki. Zmienna odpowiadająca za obecne HP postaci to actor.hp a ta mówiąca ile bohater ma max.hp to actor.maxhp Tak więc między 'def' a 'end' wstukujemy warunki które pozwolą nam pokazać twarze w zależności od HP. Ja zrobiłem coś takiego: if actor.hp <= actor.maxhp * 0.25 else if actor.hp <= actor.maxhp * 0.5 else if actor.hp <= actor.maxhp * 0.75 else end end end end Co oznacza: Jeżeli bohater ma 25%HP lub mniej to coś, jeżeli inaczej - ma 50% lób mniej to coś, jeżeli jeszcze inaczej - ma mniej niż 75% to coś, a jeżeli mniej niż 100% to coś. Teraz do każdego else'a wbijamy face = RPG::Cache.picture("FaceFile") cw = face.width ch = face.height src_rect = Rect.new(0, 0, cw, ch) self.contents.blt(x, y, face, src_rect) A zamiast 'FaceFile' pliki z twarzą (np. Face01, Face07, Face666) Gdy już to zbudujemy, zjeżdżamy do okienka 'Window_Hud' i standardowo wklejamy komendę, w tym przypadku draw_actor_faces(@actor, X, Y) I ustawiamy parametry. Teraz możemy się cieszyć mordeczką naszego herosa :p 8. Wyświetlanie obecnie trzymanej broni oraz tarczy Teraz rzecz trochę łatwiejsza, czyli pokzywanie obecnie trzymanej tarczy oraz broni :o Pierwsze co, to powrót do 'Window_Base'. Wpisujemy tam kolejny warunek, for example: def draw_equip_items(item, x, y) end Teraz wklejamy w nim taki prosty szablonik: if item == nil return end itemicon = RPG::Cache.icon(item.icon_name) self.contents.blt(x, y, itemicon, Rect.new(0, 0, 24, 24)) Jeżeli chcemy zmienić wielkość ikony, to w Rect.new(0, 0, 24, 24) Zmieniamy 24 na inną wielkość =] Co potem? Jedziemy do 'Window_HUD' do naszego ukochanego 'def refresh' ;> Następnie wbijamy tam: @data = [] @data.push($data_weapons[@actor.weapon_id]) @data.push($data_armors[@actor.armor1_id]) draw_equip_items(@data[0], x, y) draw_equip_items(@data[1], x, y) Teraz tylko ustawiamy parametry. Lista innych armorów: actor.armor2_id - Głowa actor.armor3_id - Ciało actor.armor4_id - Akcesoria 9. Animowane obrazki Hmm... Mój HUD już zapchany, ale można jeszcze coś do niego dodać. Teraz będzie to mała animowana ikonka, wyświetlana tylko wtedy, gdy bohater ma full HP. Do roboty xd! Na początek wchodzimy w Common Eventy (Woot, coś nowego). Nazywamy nowe zdarzenie 'Animacja', czy jak kto sobie chce i dajemy na Parallel Proces. Potem tworzymy nową zmienną, do której dodajemy co kilka Frames wartość "1". Gdy dojdzie do maximum (tyle ile obrazków mamy, w moim przypadku 3) zostawiamy ją w spokoju. U mnie wygląda to tak: Control Variables: [0003: Animation] = 0 Wait: 5 frame(s) Control Variables: [0003: Animation] = 1 Wait: 5 frame(s) Control Variables: [0003: Animation] = 2 Wait: 5 frame(s) Control Variables: [0003: Animation] = 3 Wait: 5 frame(s) Dobra, zrobione. Pamiętajcie, by dać do folderu z obrazkami cztery obrazki. Nazwałem je sobie Animation 00, Animation01, Animation02 i Animation 03. ![]() K, teraz wracamy do skryptów ;s Idziemy do 'Window_Base' i tworzymy znów to nowy warunek, np. 'def draw_animated_icon(x, y)'. Wklejamy tam takie cuś: animicon = RPG::Cache.picture(Nazwa) self.contents.blt(x, y, itemicon, Rect.new(0, 0, 24, 24) Zamiast 'nazwa' wklejamy tam początek nazwy pliku (w moim przypadku "Animation0" a potem dodajemy do tego zwykła zmienną która zapisuje liczbę animacji. Będzie to wyglądało więc tak: animicon = RPG::Cache.picture("Animation0" + $game_variables[3].to_s) self.contents.blt(x, y, animicon, Rect.new(0, 0, 24, 24)) Pozostaje nam już tylko iść do 'Window_HUD' i wkleić warunek: if @actor.hp / @actor.maxhp == 1 end A w nim naszą animkę, czyli: draw_animated_icon(x, y) 10. Ukrywanie HUDa Przyszedł czas na ostatnią, jedną z najważniejszych rzeczy =) W tym celu posłużymy się Common Eventem (tworzymy nowy, ustawiony na Parralel) a następnie wklepujemy tam takie warunki (ID to nr przełącznika odpowiadającego za ukrywanie HUD'a): Canditional Branch: Switch [ID] == ON Canditional Branch: Script: Input.trigger?(Input::L) Control Switches: [ID] = OFF Branch end else Canditional Branch: Script: Input.trigger?(Input::L) Control Switches: [ID] = ON Branch end Brach end L możemy zamienić na dowolny klawisz który ma służyć do chowania i pokazywania HUDa :D Aha, warunek na wciskanie klawisza wstawiłem taki a nie inny, ponieważ w przypadku eventowego przy trzymaniu klawisza HUD chował by się i pokazywał (efekt zapętlania). Mamy to? Fajnie, teraz tylko okładamy idzemy do naszego starego 'Window_HUD' i wklejamy tam (w def refresh): if $game_switches[ID] == true self.x = 0 else self.x = -500 end Ostatecznie wklejamy ten kod w naszym 'Scene_Map' w updatach: if $game_switches[ID] == true @hud_back.x = 0 else @hud_back.x = 0 end Mam nadzieję, że wiecie o co czoklet. 11. Zakończenie Wreszcie koniec, teraz możecie od podstaw zrobić własnego HUDa ;> Oto mój ostateczny kod: #============================================================================== # ** Scene_Map #------------------------------------------------------------------------------ # This class performs map screen processing. #============================================================================== class Scene_Map #-------------------------------------------------------------------------- # * Object Initialization #   actor : actor #-------------------------------------------------------------------------- def initialize(actor_index = 0, equip_index = 0) @actor_index = actor_index end #-------------------------------------------------------------------------- # * Main Processing #-------------------------------------------------------------------------- def main # Make sprite set @actor = $game_party.actors[@actor_index] @spriteset = Spriteset_Map.new @hud_back = Sprite.new @hud_back.bitmap = RPG::Cache.picture("Hud_Background") @hud_back.x = 0 @hud_back.y = 0 @hud_back.z = 100 @hud_back.opacity = 255 @window_hud = Window_HUD.new(@actor) @window_hud.opacity = 0 @window_hud.x = 0 @window_hud.y = 0 @window_hud.z = 101 # Make message window @message_window = Window_Message.new # Transition run Graphics.transition # Main loop loop do # Update game screen Graphics.update # Update input information Input.update # Frame update update # Abort loop if screen is changed if $scene != self break end end # Prepare for transition Graphics.freeze # Dispose of sprite set @spriteset.dispose @hud_back.dispose @window_hud.dispose # Dispose of message window @message_window.dispose # If switching to title screen if $scene.is_a?(Scene_Title) # Fade out screen Graphics.transition Graphics.freeze end end #-------------------------------------------------------------------------- # * Frame Update #-------------------------------------------------------------------------- def update # Loop loop do # Update map, interpreter, and player order # (this update order is important for when conditions are fulfilled # to run any event, and the player isn't provided the opportunity to # move in an instant) $game_map.update $game_system.map_interpreter.update $game_player.update # Update system (timer), screen $game_system.update $game_screen.update # Abort loop if player isn't place moving unless $game_temp.player_transferring break end # Run place move transfer_player # Abort loop if transition processing if $game_temp.transition_processing break end end # Update sprite set @spriteset.update @hud_back.update if $game_switches[2] == true @hud_back.x = 0 else @hud_back.x = -500 end @window_hud.refresh # Update message window @message_window.update # If game over if $game_temp.gameover # Switch to game over screen $scene = Scene_Gameover.new return end # If returning to title screen if $game_temp.to_title # Change to title screen $scene = Scene_Title.new return end # If transition processing if $game_temp.transition_processing # Clear transition processing flag $game_temp.transition_processing = false # Execute transition if $game_temp.transition_name == "" Graphics.transition(20) else Graphics.transition(40, "Graphics/Transitions/" + $game_temp.transition_name) end end # If showing message window if $game_temp.message_window_showing return end # If encounter list isn't empty, and encounter count is 0 if $game_player.encounter_count == 0 and $game_map.encounter_list != [] # If event is running or encounter is not forbidden unless $game_system.map_interpreter.running? or $game_system.encounter_disabled # Confirm troop n = rand($game_map.encounter_list.size) troop_id = $game_map.encounter_list[n] # If troop is valid if $data_troops[troop_id] != nil # Set battle calling flag $game_temp.battle_calling = true $game_temp.battle_troop_id = troop_id $game_temp.battle_can_escape = true $game_temp.battle_can_lose = false $game_temp.battle_proc = nil end end end # If B button was pressed if Input.trigger?(Input::B) # If event is running, or menu is not forbidden unless $game_system.map_interpreter.running? or $game_system.menu_disabled # Set menu calling flag or beep flag $game_temp.menu_calling = true $game_temp.menu_beep = true end end # If debug mode is ON and F9 key was pressed if $DEBUG and Input.press?(Input::F9) # Set debug calling flag $game_temp.debug_calling = true end # If player is not moving unless $game_player.moving? # Run calling of each screen if $game_temp.battle_calling call_battle elsif $game_temp.shop_calling call_shop elsif $game_temp.name_calling call_name elsif $game_temp.menu_calling call_menu elsif $game_temp.save_calling call_save elsif $game_temp.debug_calling call_debug end end end #-------------------------------------------------------------------------- # * Battle Call #-------------------------------------------------------------------------- def call_battle # Clear battle calling flag $game_temp.battle_calling = false # Clear menu calling flag $game_temp.menu_calling = false $game_temp.menu_beep = false # Make encounter count $game_player.make_encounter_count # Memorize map BGM and stop BGM $game_temp.map_bgm = $game_system.playing_bgm $game_system.bgm_stop # Play battle start SE $game_system.se_play($data_system.battle_start_se) # Play battle BGM $game_system.bgm_play($game_system.battle_bgm) # Straighten player position $game_player.straighten # Switch to battle screen $scene = Scene_Battle.new end #-------------------------------------------------------------------------- # * Shop Call #-------------------------------------------------------------------------- def call_shop # Clear shop call flag $game_temp.shop_calling = false # Straighten player position $game_player.straighten # Switch to shop screen $scene = Scene_Shop.new end #-------------------------------------------------------------------------- # * Name Input Call #-------------------------------------------------------------------------- def call_name # Clear name input call flag $game_temp.name_calling = false # Straighten player position $game_player.straighten # Switch to name input screen $scene = Scene_Name.new end #-------------------------------------------------------------------------- # * Menu Call #-------------------------------------------------------------------------- def call_menu # Clear menu call flag $game_temp.menu_calling = false # If menu beep flag is set if $game_temp.menu_beep # Play decision SE $game_system.se_play($data_system.decision_se) # Clear menu beep flag $game_temp.menu_beep = false end # Straighten player position $game_player.straighten # Switch to menu screen $scene = Scene_Menu.new end #-------------------------------------------------------------------------- # * Save Call #-------------------------------------------------------------------------- def call_save # Straighten player position $game_player.straighten # Switch to save screen $scene = Scene_Save.new end #-------------------------------------------------------------------------- # * Debug Call #-------------------------------------------------------------------------- def call_debug # Clear debug call flag $game_temp.debug_calling = false # Play decision SE $game_system.se_play($data_system.decision_se) # Straighten player position $game_player.straighten # Switch to debug screen $scene = Scene_Debug.new end #-------------------------------------------------------------------------- # * Player Place Move #-------------------------------------------------------------------------- def transfer_player # Clear player place move call flag $game_temp.player_transferring = false # If move destination is different than current map if $game_map.map_id != $game_temp.player_new_map_id # Set up a new map $game_map.setup($game_temp.player_new_map_id) end # Set up player position $game_player.moveto($game_temp.player_new_x, $game_temp.player_new_y) # Set player direction case $game_temp.player_new_direction when 2 # down $game_player.turn_down when 4 # left $game_player.turn_left when 6 # right $game_player.turn_right when 8 # up $game_player.turn_up end # Straighten player position $game_player.straighten # Update map (run parallel process event) $game_map.update # Remake sprite set @spriteset.dispose @spriteset = Spriteset_Map.new # If processing transition if $game_temp.transition_processing # Clear transition processing flag $game_temp.transition_processing = false # Execute transition Graphics.transition(20) end # Run automatic change for BGM and BGS set on the map $game_map.autoplay # Frame reset Graphics.frame_reset # Update input information Input.update end end #============================================================================== # ** Window_Base #------------------------------------------------------------------------------ # This class is for all in-game windows. #============================================================================== class Window_Base < Window def red_color return Color.new(255, 0, 0, 255) end def green_color return Color.new(0, 255, 0, 255) end def draw_hp_meter(actor, x, y) hpbar = RPG::Cache.picture("HP_Meter") cw = hpbar.width * actor.hp / actor.maxhp ch = hpbar.height src_rect = Rect.new(0, 0, cw, ch) self.contents.blt(x, y, hpbar, src_rect) end def draw_mp_meter(actor, x, y) mpbar = RPG::Cache.picture("MP_Meter") cw = mpbar.width * actor.sp / actor.maxsp ch = mpbar.height src_rect = Rect.new(0, 0, cw, ch) self.contents.blt(x, y, mpbar, src_rect) end def draw_exp_meter(actor, x, y) expbar = RPG::Cache.picture("Exp_Meter") cw = expbar.width * actor.now_exp.to_f / actor.next_exp ch = expbar.height src_rect = Rect.new(0, 0, cw, ch) self.contents.blt(x, y, expbar, src_rect) end def draw_actor_faces(actor, x, y) if actor.hp <= actor.maxhp * 0.25 face = RPG::Cache.picture("Face04") cw = face.width ch = face.height src_rect = Rect.new(0, 0, cw, ch) self.contents.blt(x, y, face, src_rect) else if actor.hp <= actor.maxhp * 0.5 face = RPG::Cache.picture("Face03") cw = face.width ch = face.height src_rect = Rect.new(0, 0, cw, ch) self.contents.blt(x, y, face, src_rect) else if actor.hp <= actor.maxhp * 0.75 face = RPG::Cache.picture("Face02") cw = face.width ch = face.height src_rect = Rect.new(0, 0, cw, ch) self.contents.blt(x, y, face, src_rect) else face = RPG::Cache.picture("Face01") cw = face.width ch = face.height src_rect = Rect.new(0, 0, cw, ch) self.contents.blt(x, y, face, src_rect) end end end def draw_equip_items(item, x, y) if item == nil return end itemicon = RPG::Cache.icon(item.icon_name) self.contents.blt(x, y, itemicon, Rect.new(0, 0, 24, 24)) end end end def draw_animated_icon(x, y) animicon = RPG::Cache.picture("Animation0" + $game_variables[3].to_s) self.contents.blt(x, y, animicon, Rect.new(0, 0, 24, 24)) end #============================================================================== # ** Window_HUD #------------------------------------------------------------------------------ # This window displays HUD meters etc. #============================================================================== class Window_HUD < Window_Base #-------------------------------------------------------------------------- # * Object Initialization #-------------------------------------------------------------------------- def initialize(actor) super(0, 0, 370, 160) self.contents = Bitmap.new(width - 32, height - 32) self.contents.font.name = "Arial" self.contents.font.size = 22 @actor = actor refresh end #-------------------------------------------------------------------------- # * Refresh #-------------------------------------------------------------------------- def refresh self.contents.clear draw_hp_meter(@actor, 87, 19) draw_mp_meter(@actor, 85, 41) draw_exp_meter(@actor, 62, 59) draw_actor_faces(@actor, -1, 3) self.contents.font.color = normal_color self.contents.draw_text(-766, 87, 999, 32, $game_party.gold.to_s, 2) self.contents.font.color = system_color self.contents.draw_text(235, 87, 999, 32, $data_system.words.gold) if $game_variables[1] > 0 self.contents.font.color = green_color else if $game_variables[1] < 0 self.contents.font.color = red_color else self.contents.font.color = normal_color end end self.contents.draw_text(-453, 67, 999, 32, "Karma: " + $game_variables[2].to_s , 1) draw_actor_name(@actor, 92, -3) draw_actor_level(@actor, 180, -3) draw_actor_state(@actor, 215, -3) draw_actor_hp(@actor, 96, 19, width = 230) draw_actor_sp(@actor, 96, 42, width = 205) self.contents.font.color = normal_color attack = @actor.atk self.contents.draw_text(84, 87, 999, 32, attack.to_s) defend = @actor.pdef + @actor.mdef self.contents.draw_text(154, 87, 999, 32, defend.to_s) @data = [] @data.push($data_weapons[@actor.weapon_id]) @data.push($data_armors[@actor.armor1_id]) draw_equip_items(@data[0], 56, 92) draw_equip_items(@data[1], 126, 92) if @actor.hp / @actor.maxhp == 1 draw_animated_icon(25, 92) end if $game_switches[2] == true self.x = 0 else self.x = -500 end end end Ostateczny efekt: ![]() Gra demo: http://www.box.net/shared/os8t32y5i0 Jeżeli macie jakieś pytania, piszcie na PW - w miarę możliwości postaram się pomóc. Pozdrawiam, Dan. PS. Przeniesienie tego poradnika na forum było najbardziej monotonną rzeczą w moim życiu, SI. |
|