Skocz do zawartości

Surfaces Tutorial


Rekomendowane odpowiedzi

Witam! Artykuł ten pokaże wam jak używać surfaces, które są baaardzo przydatne do gier (np. strategicznych - mgła).

Na początek potrzeba nam zarejestrowanej wersji GM. Mamy? No to do dzieła! ;)

 

Artykuł podzieliłem na kilka części:

- Wstęp

- Proste rysowanie (Paint)

- Tworzenie mgły (Fog)

- Efektowny ogień (Fire)

 

Na końcu zamieściłem przykład w pliku gm6 byście mogli zobaczyć jak to działa

 

 

Wstęp

Po krótce opiszę wam funkcje rodziny surfaces:

 

surface_create(width,height) - tworzy nową powierzchnię (surfaces) i zwraca do zmiennej jej identyfikator. Argumenty width oraz height oznaczają szerokość i wysokość powierzchni.

 

surface_free(id) - zwalnia powierzchnię o indentyfikatorze id z pamięci (powierzchnie są przechowywane tylko w pamięci karty graficznej, więc od niej zależy ilość możliwych surfaces), by nie zabierała miejsca gdy jej nie używamy.

 

surface_exists(id) - sprawdza czy surfaces o danym id istnieje i zwraca odpowiednią wartość (true - istnieje, false - nie istnieje).

 

surface_get_width(id) - zwraca wartość szerokości danej powierzchni.

 

surface_get_height(id) - zwraca wartość wysokości danej powierzchni.

 

surface_get_texture(id) - zwraca id tekstury danej powierzchni.

 

surface_set_target(id) - kluczowa funkcja powierzchni. Ustala cel dalszego rysowania dla danej powierzchni, czyli wszystko po użyciu tej funkcji będzie rysowane na danej powierzchni.

 

surface_reset_target(id) - gdy skończymy rysować na powierzchni, musimy użyć tej funkcji - ona przywraca cel rysowania do okna gry (po użyciu tej funkcji znów rysowanie będzie się odbywać na ekranie gry).

 

surface_getpixel(id,x,y) - zwraca kolor pixela na pozycji x, y na danej powierzchni (bardzo wolna funkcja - należy używać sporadycznie).

 

surface_save(id,fname) - zapisuje powierzchnię do bitmapy (raczej pixelmapy, czyli kolorowej bitmapy ;P) z podaną nazwą pliku.

 

surface_save_part(id,fname,x,y,w,h) - wykonuje to co powyższa funkcja, tyle że zapisuje część powierzchni (od pozycji x, y, z daną szerokością i wysokością).

 

draw_surface(id,x,y) - rysuje powierzchnię na pozycji x, y.

 

draw_surface_stretched(id,x,y,w,h) - rysuje powierzchnię na pozycji x, y rozciągniętą na daną szerokość i wysokość.

 

draw_surface_tiled(id,x,y) - wypełnia room 'kafelkując' (czyli zapełnia cały room - surfaces obok surfaces :P ) daną powierzchnią, z przesunięciem x oraz y.

 

draw_surface_part(id,left,top,width,height,x,y) - rysuje część powierzchni zaczynając od położenia left oraz top, o szerokości width i wysokości height, na pozycji x, y.

 

draw_surface_ext(id,x,y,xscale,yscale,rot,color,alpha) - rysuje powierzchnię na pozycji x i y, o skali xscale i yscale, obróconą o kąt rot, blendowane (kolorowane) kolorem color i z przezroczystością alpha.

 

draw_surface_stretched_ext(id,x,y,w,h,color,alpha) - rysuje powierzchnię na pozycji x, y rozciągniętą na daną szerokość i wysokość, z nałożonym kolorem color i z przezroczystością alpha.

 

draw_surface_tiled_ext(id,x,y,xscale,yscale,color,alpha) - i znów rysowanie 'kafelkowane' xD, tyle że dodatkowo skalowane, kolorowane i z daną przezroczystością.

 

draw_surface_part_ext(id,left,top,width,height,x,y,xscale,yscale,color,alpha) - rysuje część powierzchni, z możliwością skalowania, kolorowania i przezroczystością.

 

draw_surface_general(id,left,top,width,height,x,y,xscale,yscale,rot,c1,c2,c3,c4,

alpha) - ulepszona wersja draw_surface_part_ext() ^^ - rysuje część powierzchni tak jak draw_surface_part_ext(), ale zamiast jednego koloru rysowania ma 4 dla każdego wierzchołka owierzchni.

 

surface_copy(dest,x,y,src) - kopiuje powierzchnię ze źródła src do powierzchni dest na pozycji x oraz y.

 

surface_copy_part(destination,x,y,source,xs,ys,ws,hs) - kopiuje część powierzchni ze źródła src, od pozycji sx i sy, o wysokości ws i szerokości hs źródła, do powierzchni dest na pozycji x, y.

 

 

Proste rysowanie (Paint)

Na początek tworzymy obiekt obj_paint, w create piszemy:

 

color=c_black // kolor rysowania - czarny
// początek linii
tx=mouse_x
ty=mouse_y
painting=false // wylaczamy rysowanie linii
paint_sur=surface_create(room_width,room_height) // tworzymy nową powierzchnię o szerokości i wysokości zgodnej z rozmiarem rooma
surface_set_target(paint_sur) // ustawiamy cel rysowania na powierzchnię paint_sur
draw_set_color(c_white) // ustalamy kolor tła powierzchni
draw_rectangle(0,0,surface_get_width(paint_sur),surface_get_height(paint_sur),0) // rysujemy tło powierzchni o rozmiarze takim jak nasza powierzchnia
surface_reset_target() // resetujemy cel rysowania do ekranu gry

 

Teraz step:

// gdy naciskamy LPM ustalana jest pozycja początku linii oraz włączane jest jej rysowanie
if(mouse_check_button_pressed(mb_left))
{
tx=mouse_x
ty=mouse_y
painting=true
}
// jeśli rysowanie linii jest włączone to rysujemy linię i ustalamy znów początek linii
if(painting)
{
// rysujemy linię na powierzchni paint_sur
surface_set_target(paint_sur)
draw_line_color(tx,ty,mouse_x,mouse_y,color,color)
surface_reset_target()
// ustalamy początek linii
tx=mouse_x
ty=mouse_y
}
if(mouse_check_button_released(mb_left))painting=false // jeśli puścimy LPM to wyłączamy rysowanie linii

 

I na koniec draw:

draw_surface(paint_sur,0,0) // rysujemy nasz surface

 

To tyle jeśli chodzi o rysowanie prostych powierzchni :)

 

 

Tworzenie mgły (Fog)

No to teraz nieco trudniej, bo nauczymy sie robić mgłe.

Stwórzmy obiekt obj_fog. W create dajemy:

 

// ustalamy pozycje mgły na x=0 i y=0
fog_x=0
fog_y=0
fog_sur=surface_create(room_width,room_height) // tworzymy powierzchnię mgły o rozmiarze roomu
surface_set_target(fog_sur) // cel rysowania - powierzchnia fog_sur
draw_set_color(c_white) // kolor mgły - czarny, więc czemu napisałem c_white? Bo podczas blendingu typu subtract wszystkie kolory są 'odwracane', tzn. kolor biały jest czarny, a zielony jest fioletowy;P
draw_rectangle(0,0,room_width,room_height,0) // rysujemy mgłe
surface_reset_target() // resetujemy cel rysowania jako ekran gry
draw_set_color(c_white)

 

Event Mouse Global Left Pressed:

 

surface_set_target(fog_sur) // ustalamy cel rysowania do fog_sur
draw_set_color(c_black) // ustalamy kolor - biały (w subtract blending odwrócenie czarnego)
draw_set_blend_mode(bm_subtract) // ustalamy tryb blendingu (kolorowania) na subtract, czyli co dalej bedzie rysowane z odwróconymi kolorami
draw_circle_color(mouse_x-fog_x,mouse_y-fog_y,128,c_white,c_black,0) // rysujemy dwukolorowy okrąg na pozycji myszki względem pozycji mgły, o promieniu 128 pixeli. Dwukolorowy dlatego, by występowało płynne przejście mgły
draw_set_blend_mode(bm_normal) // przywracamy blending do normalności
surface_reset_target() // resetujemy cel rysowania
draw_set_color(c_white) // domyślny kolor - biały

 

A teraz rysowanie w draw:

draw_set_blend_mode(bm_subtract) // ustalamy blending na subtract by mgła nie była biała, tylko czarna
draw_surface(fog_sur,fog_x,fog_y) // rysujemy nasz surface mgły
draw_set_blend_mode(bm_normal) // reset blendingu

 

I to był nieco trudniejszy przykład, który można zastosować np. do gier strategicznych.

 

 

Efektowny ogień (Fire)

No to teraz trudniej, bo do surfaces dochodzą obliczenia dotyczące płomieni. Przykład ten stosujcie rozważnie - jakość szczegółów płomieni będzie wpływała na szybkość gry.

 

Zróbmy obiekt obj_fire.

Create:

 

fire_sur=surface_create(0,0) // tworzymy powierzchnię ognia fire_sur
fire_delay=0 // alarm odświerzania powierzchni
fire_delay_max=3 // czas odświerzania powierzchni - co 3 klatki (stepy, etc.)

 

Następnie step uzupełniamy o kod:

 

if(fire_delay<=0) // jeśli alarm odświerzania ognia jest aktywny
{
quality=12 // jakość płomieni
width=128 // szerokość ognia
height=128 // wysokość ognia
// tymczasowe zmienne opisujące wielkość płomieni
tmns=width/quality 
tmxs=tmns*1.5
if(surface_exists(fire_sur))surface_free(fire_sur) // jeśli istnieje powierzchnia fire_sur to jest ona kasowana
fire_sur=surface_create(width,height) // na nowo tworzymy powierzchnię ognia z nowym rozmiarem
surface_set_target(fire_sur) // cel rysowania - powierzchnia fire_sur
draw_set_color(c_black) // tło czarne bo takie nie będzie rysowane
draw_rectangle(0,0,argument1,argument2,0) // rysujemy tło dla ognia
draw_set_color(c_white) // kolor domyślny - biały
for(j=0;j<2;j+=1) // ilość warstw koloru płomieni (dwie - czerwona i żółta)
{
if(j=0)tc=c_red // jeśli j=0 to rysujemy czerwone płomienie
if(j=1)tc=c_yellow // jeśli j=0 to rysujemy żółte płomienie
for(i=0;i<quality;i+=1) // rysowanie zaczyna się od dołu ku górze ognia
{
repeat(quality-i) // rysowanie płomieni poziomo zależnie od wysokości
{
// wyliczenia losowego położenia płomienia tak, by ogień 'zachował' kształt trójkąta
ts=tmns+random(tmxs-tmns)
tl=random((width-2*ts)/sqrt(sqrt(i+1)))-((width-2*ts)/sqrt(sqrt(i+1)))/2
tx=width/2+tl
ty=height-ts-i*(height-2*ts)/quality
draw_set_alpha(1/sqrt(i+1)/(j+1)) // ustalenie przeźroczystości płomienia zależnie od wysokości
draw_set_blend_mode(bm_add) // blending typu add - przezroczystość dla czarnego koloru
draw_ellipse_color(tx-ts,ty-ts*height/width,tx+ts,ty+ts*height/width,tc,c_black,0) // rysowanie elipsy jako płomienia z zachowanym skalowaniem względem wysokości i szerokości ognia
draw_set_blend_mode(bm_normal) // reset blendingu - bez przezroczystości
draw_set_alpha(1)
}
}
}
surface_reset_target() // cel rysowania - ekran gry
fire_delay=fire_delay_max // ustalenie alarmu odświerzania na maksymalną wartość podaną jako czas
}
fire_delay-=1 // tik-tak naszego alarmu odświerzania

 

To co wyżej uważam za najtrudniejsze w tym dziale (opisać te obliczenia to koszmar xD).

To teraz draw:

 

draw_set_blend_mode(bm_add) // blending typu add - przezroczystość czarnego koloru
draw_surface(fire_sur,x-surface_get_width(fire_sur)/2,y-surface_get_height(fire_sur)) // rysowanie ognia na pozycji x i y względem szerokości i wysokości ognia
draw_set_blend_mode(bm_normal) // reset blendingu

 

Tak więc nauczyliśmy się robić painta, mgłę oraz ogień. Miła zabawa, nie? A jeszcze milsze uczucie, że znamy teraz surfaces i wiemy jak je używać :)

 

Do tutka dołączam plik z przykładami:

https://gmclan.org/up1105_11_surface_tutorial.html

 

Życzę ciekawych pomysłów na wykorzystanie powierzchni do Waszych gier!

PS. Już nie długo pojawi się seria kursów o tworzeniu gier poszczególnych gatunków - cierpliwego czekania! ^^

Odnośnik do komentarza
Udostępnij na innych stronach

Chyba jest błędzik : :P

 

draw_surface_ext(id,x,y,xscale,yscale,rot,color,alpha) - rysuje powierzchnię na pozycji x i y...

 

draw_surface_ext(id,x,y,w,h,color,alpha) - rysuje powierzchnię na pozycji x, y ...

Co nie? Chyba winno być streched_ext :P

 

A poza tym - świetna robota - naprawdę dobry tutek- właśnie zasysam przykład ;)

Odnośnik do komentarza
Udostępnij na innych stronach

@UP: juz poprawiam - na szybkiego ostatnie poprawki robilem xD

Odnośnik do komentarza
Udostępnij na innych stronach

Etam, po prostu poszedlem im na reke i pokazalem co jak zrobic i dalem w miare zrozumiale opisy. Jak chcesz to popraw opisy Tymon ;P Grunt że sie przyda.

Odnośnik do komentarza
Udostępnij na innych stronach

No nie no :) Widze, iz moj mistrz PsichiX wykresal z siebie siodme poty i napisal na wczorej ten tutek.

 

Co do tutka to omawia on najwazniejsze zagadnienia ktore interesuja ludzi. Jak na przyklad mgla, albo tez rysowanie :) Co do ognia... Hmm... Ogien w surfaces ssie i to mocno :P Najlepszy ogien (ktory zachowuje sie jak realistyczny) mozesz wykrzesac z particli :)

 

Jezeli tutki sie ocenia... To dalbym mu z cala satysfakcja 4.7/5 (Drobne problemy w zrozumieniu mialem. )

Odnośnik do komentarza
Udostępnij na innych stronach

Jeśli chcesz dodać odpowiedź, zaloguj się lub zarejestruj nowe konto

Jedynie zarejestrowani użytkownicy mogą komentować zawartość tej strony.

Zarejestruj nowe konto

Załóż nowe konto. To bardzo proste!

Zarejestruj się

Zaloguj się

Posiadasz już konto? Zaloguj się poniżej.

Zaloguj się
  • Ostatnio przeglądający   0 użytkowników

    • Brak zarejestrowanych użytkowników przeglądających tę stronę.
×
×
  • Dodaj nową pozycję...