Skocz do zawartości

Cień POD WSZYSTKIMI obiektami a nie tylko pod jednym


Huri

Rekomendowane odpowiedzi

Cześć to znowu ja.

Otóż zaplątałem się w tych wszystkich klockach i postanowiłem, że jednak przerzucę się na GML. Zacząłem od samego początku i napisałem kod odpowiedzialny za rysowanie poziomu (dla przypomnienia top-down fake isometric).

 

Mam sprite spr_wall i spr_w_template. Gdy w edytorze ROOM rysuje poziom gry uzywam obiektu z domyślnie przypisanym spr_w_template (dla ułatwienia rysowania). W kodzie obiektu obj_wall w EVENT CREATE wstawiłem wykonywanie skryptu room_draw(). Skrypt ten jest dosyć uniwersalny dzięki czemu mogę rysować różne sprite'y dla obiektu obj_wall. Moim głównym zamierzeniem było to żeby obj_wall w zależności czy i z której strony jest otoczony przez inne obiekty (solid) zmieniał sprite.

Wszystko działa super i tak jak chciałem... Ale zapragnęło mi się dodać cienie pod obiektami sciany. Skorzystałem więc z

GMLdraw_sprite_ext(sprite_index, image_index, x, y, image_xscale, image_yscale, image_angle, image_blend, image_alpha);

No spoko... Cień rysuje się nawet pod obj_wall... ale tylko tym, z którego został wygenerowany. Chciałbym żeby cienie były rysowane pod wszystkimi obiektami obj_wall a nie tylko pod jednym, z którego został wygenerowany.

 

Jakieś pomysły? Kombinowałem też z surface'ami ale coś pochrzaniłem (nie doszedłem jeszcze do tego etapu obcowania z GM) i zcrashowałem grę.

 

Część kodu odpowiedzialnego za przydzielanie sprite'ów do obj_wall (reszta wygląda tak samo tylko sprawdza czy obiekt jest/nie jest otoczony z innych stron):

GML
// Rysowanie ściany orientacji NE (Północ-Wschód)

if (!place_free(x-grid_s, y+0) && place_free(x+0,y-grid_s) && !place_free(x+0,y+grid_s) && place_free(x+grid_s, y+0))

{

image_index=w_ne;

//rysuj_cien(); <-- to nieaktualne już

}

 

W EVENT DRAW obj_wall wpisałem to:

 

GML
GMLdraw_sprite_ext(sprite_index, image_index, x-3, y-3, 1.3, 1.3, image_angle, c_black, 0.4);

depth=-x-y;

draw_self();

W grze wygląda to mniej więcej tak. Nie zwracajcie uwagi na tą niebieską gębę :P ... wziąłem najtańszego statystę z Avatara do testowania rozwiązań :P . W czerwonej ramce oczywiście nakładające się cienie.

 

shadows_problem.png

 

Jeszcze jeden obrazek. Może na tym będzie lepiej widać (Tu zaznaczone na zielono). Cień może nachodzić na gracza (ale tylko na niego).

 

shadows2_problem.png

 

Będę wdzięczny za pomoc.

Odnośnik do komentarza
Udostępnij na innych stronach

Przychodzą mi do głowy dwa rozwiązania:

Pierwsze: bardziej skomplikowane. Narysuj wszystkie cienie skrzynek do surface, po czym narysuj owy surface. Po narysowaniu rysuj skrzynki bez cienia. Tą technikę będziesz mógł potem rozwinąć (np. blurując shaderem utworzony cień).

Drugie: prościej się nie da. Najpierw rysujesz wszystkie cienie skrzynek, potem wszystkie skrzynki.

 

Zrób jakiś pojedynczy obiekt, nazywając go np. "obj_rysowanie_skrzynek", i daj mu do draw event mniej-więcej taki kod:

GML
with (skrzynka) {

rysuj cień skrzynki

}

with (skrzynka) {

rysuj skrzynke

}

Ze skrzynek natomiast usuń rysowanie (cienie i skrzynki). Wada: cienie skrzynek nakładają się na siebie. Pierwsze rozwiązanie, to trudniejsze, rozwiązuje problem.

Odnośnik do komentarza
Udostępnij na innych stronach

drugi raz na tym skrzynki.
W ten sposób nie będzi mógł schować się za skrzynkami (depth).

 

Wg mnie powinieneś stworzyć surface i na nim (z alpha=1!) rysować cienie. Depth po kolei: Gracz, Surface (teraz z alpha), skrzynki.

Odnośnik do komentarza
Udostępnij na innych stronach

kiedy cien "wychodzi" mimo prostokot sprite (x-3,y-3) to sproboj dac w depth poziom wall od -do w ktorym bedom tylko wall

nastepnie zmien depth kazdej wall w zaleznosci na x,y

tak by cienie sie nakladaly prawidlowo.

 

linie mogo miec depth+1000 ( w zaleznosci na resolution screen)

colmuny dept+1

 

dla optimalizacji mozna minimalizovac cykle i obszar zmian depth tak jak gra pozwoli

jesli niepozwoli to surface jest lepszy

Odnośnik do komentarza
Udostępnij na innych stronach

Przyznam szczerze, że nie potrafię zrozumieć. Póki co to chyba dla mnie zbyt zaawansowane.

Nawet z narysowanym w sprite'cie cieniem jest ten problem (w sumie logiczne).

 

Daruje sobie chyba Cienie dopóki nie nauczę się więcej.

 

kiedy cien "wychodzi" mimo prostokot sprite (x-3,y-3) to sproboj dac w depth poziom wall od -do w ktorym bedom tylko wall

nastepnie zmien depth kazdej wall w zaleznosci na x,y

tak by cienie sie nakladaly prawidlowo.

 

linie mogo miec depth+1000 ( w zaleznosci na resolution screen)

colmuny dept+1

 

dla optimalizacji mozna minimalizovac cykle i obszar zmian depth tak jak gra pozwoli

jesli niepozwoli to surface jest lepszy

Odnośnik do komentarza
Udostępnij na innych stronach

To wcale nie jest takie trudne. Jak już exigo wspomniał najlepszym sposobem będzie rysowanie tego na surface.

 

1.

Tworzysz 2 obiekty > oShadow i pShadowCaster. Pierwszy to będzie obiekt rysujący cień na ekranie. Drugi będzie parentem dla każdego obiektu który ma rzucać cień.

 

oShadow ustaw depth na tyle mały duży by inne obiekty go mogły przykryć oprócz podłogi. pShadowCaster zostaw jak jest.

2.

W obiekcie oShadow

GML (create)
globalvar gShadowSurface, gVx, gVy; // zmienne globalne

// tworzenie surface o rozmiarze viewa

gShadowSurface = surface_create( view_wview, view_hview );

// czyszczenie go

surface_set_target( gShadowSurface );

draw_clear_alpha( 0, 0 );

surface_reset_target();

// pozycja viewa

gVx = view_xview;

gVy = view_yview;

 

GML (BeginStep)
surface_set_target( gShadowSurface );

draw_clear_alpha( 0, 0 );

surface_reset_target();

 

gVx = view_xview;

gVy = view_yview;

GML (draw)
// zabezpieczenie na wypadek gdyby coś się stało z surfacem

if ( !surface_exists(gShadowSurface) ) gShadowSurface = surface_create( view_wview, view_hview );

// rysowanie surface na ekranie

draw_surface_ext( gShadowSurface, gVx, gVy, 1, 1, 0, 0, 0.5 );

 

3.

W obiekcie pShadowCaster

GML (Step)
// rysowanie cieni na surface

surface_set_target( gShadowSurface );

draw_sprite_ext( sprite_index, image_index, x-gVx-3, y-gVy-3, 1.3, 1.3, image_angle, 0, 1 );

surface_reset_target();

 

4.

Wszystkim obiektom które mają rzucać cienie daj parenta pShadowCaster i dodaj do step.

GML
event_inherited();

I postaw w roomie obiekt oShadow

Odnośnik do komentarza
Udostępnij na innych stronach

Dzięki :) .. Spróbuje jutro to ogarnąć (lubię rozumieć to co przepisuje). Teraz walczę z czym innym.

 

Jeszcze się za to nie zabrałem i możliwe, że mój pomysł polega na tym samym albo jest niewykonalny ale...

A gdyby tak narysować room tak jak odbywa się to normalnie, narysować jego tło, wypalić cienie na nim i zapisać cały room do pliku i odczytać go i ustawić jako tło?

Coś na wzór bake'owania textur w grafice 3D.

 

 

 

To wcale nie jest takie trudne. Jak już exigo wspomniał najlepszym sposobem będzie rysowanie tego na surface.

 

1.

Tworzysz 2 obiekty > oShadow i pShadowCaster. Pierwszy to będzie obiekt rysujący cień na ekranie. Drugi będzie parentem dla każdego obiektu który ma rzucać cień.

 

oShadow ustaw depth na tyle mały by inne obiekty go mogły przykryć oprócz podłogi. pShadowCaster zostaw jak jest.

2.

W obiekcie oShadow

GML (create)globalvar gShadowSurface, gVx, gVy; // zmienne globalne

 

// tworzenie surface o rozmiarze viewa

gShadowSurface = surface_create( view_wview, view_hview );

// czyszczenie go

surface_set_target( gShadowSurface );

draw_clear_alpha( 0, 0 );

surface_reset_target();

// pozycja viewa

gVx = view_xview;

gVy = view_yview;

 

GML (BeginStep)surface_set_target( gShadowSurface );

draw_clear_alpha( 0, 0 );

surface_reset_target();

 

gVx = view_xview;

gVy = view_yview;

GML (draw)// zabezpieczenie na wypadek gdyby coś się stało z surfacem

if ( !surface_exists(gShadowSurface) ) gShadowSurface = surface_create( view_wview, view_hview );

// rysowanie surface na ekranie

draw_surface_ext( gShadowSurface, gVx, gVy, 1, 1, 0, 0, 0.5 );

 

3.

W obiekcie pShadowCaster

GML (Step)// rysowanie cieni na surface

surface_set_target( gShadowSurface );

draw_sprite_ext( sprite_index, image_index, x-gVx-3, y-gVy-3, 1.3, 1.3, image_angle, 0, 1 );

surface_reset_target();

 

4.

Ustaw wszystkim obiektom które mają rzucać cienie daj im parenta pShadowCaster i dodaj do step.

GMLevent_inherited();

I postaw w roomie obiekt oShadow

Odnośnik do komentarza
Udostępnij na innych stronach

Jeśli room jest duży, to taki bake zajmie sporo miejsca w pamięci. Generalnie sposób HuderLorda polega na tym samym, ale bake obejmuje tylko widzialny obszar rooma. Bake jest update'owany co step (czyli np. 60 razy na sekundę, jeżeli room_speed = 60), więc dobrym pomysłem byłoby zmniejszenie częstości tego update'owania, jeżeli obiekty rzucające cienie są w miarę statyczne.

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ę...