Xyridon Opublikowano 5 Marca 2022 Udostępnij Opublikowano 5 Marca 2022 Witam. Pracuję nad klonem BattleCity, do stworzenia cegieł zamiast pojedynczych obiektów użyłem sprite_create_from_surface, żeby gra nie lagowała przez tysiące obiektów. Wszystko spoko do momentu, kiedy zauważyłem, że po kilku minutach gra wykorzystuje już 3.7Gb i wtedy następuje crash. Zauważyłem też, że każda modyfikacja mapy (czyli zrobienie w niej dziury pociskiem gracza czy bota) dodaje kilka mega do wykorzystywanej pamięci. Według mnie wygląda to tak, jakby mapa przy każdym trafieniu w nią aktualizowaą się o nową dziurę, a stary sprite tej mapy jest zamieniany na nowy z dziurą, jednak gdzieś w pamięci pozostają poprzednie wersje tego sprite'a. Jak usunąć te zalegające wersje mapy? Mam nadzieję, że mówię dość jasno. Oto mój kod z Draw Event: if(HIT) {//make a new sprite code var _temp_surf = surface_create(sprite_width, sprite_height); surface_set_target(_temp_surf); draw_sprite(sprite_index, 0, 0, 0); gpu_set_blendmode(bm_subtract); draw_set_color(c_black); draw_rectangle(damage_x -8, damage_y -8, damage_x +7, damage_y +7, false); gpu_set_blendmode(bm_normal); sprite_index = sprite_create_from_surface(_temp_surf, 0, 0, sprite_width, sprite_height, false, false, 0, 0); <--- kiedy pamięć podręczna osiągnie 3.7Gb gra crashuje i pokazuje, że tu jest błąd sprite_collision_mask(sprite_index, false, 0, 0, 0, 0, 0, 0, 0); surface_reset_target(); surface_free(_temp_surf); HIT = false; } Nie jestem zaawansowanym programistą, więc jeśli mógłby mnie pokierować zaawansowany programista GMS'a, jak to zrobić, to byłbym niezmiernie wdzięczny, bo od lat o tym projekcie myślę, a totalnie nie orientuję się w surface'ach. Chciałbym też uniknąć zapisywania czegokolwiek w plikach, żeby zachować prostotę kodu do dalszego szlifowania Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
MamPytanie Opublikowano 5 Marca 2022 Udostępnij Opublikowano 5 Marca 2022 A ja zapytam jeśli to nie jest problem, dlaczego użycie surface ma pomóc? Chyba każdy z bloków cegieł i tak musi jakoś powodwoać kolizję? I jak to ma działać, że robisz surface jako cały room game i malujesz na nim bloki cegieł? Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
Xyridon Opublikowano 5 Marca 2022 Autor Udostępnij Opublikowano 5 Marca 2022 49 minut temu, MamPytanie napisał: A ja zapytam jeśli to nie jest problem, dlaczego użycie surface ma pomóc? Chyba każdy z bloków cegieł i tak musi jakoś powodwoać kolizję? I jak to ma działać, że robisz surface jako cały room game i malujesz na nim bloki cegieł? No tak. Nie, maska kolizji jest obliczana precyzyjnie i na nowo po każdym uszkodzeniu terenu. A "blokowość", czy inaczej wyrównanie do siatki jest zastosowane po stworzeniu wystrzelonego pocisku jak i po uderzeniu w teren. Czyli jeśli pocisk zostanie wystrzelony z pozycji x2 i y5, to ja to dopasowuję do siatki 4x4 piksele, czyli x0 i y4 i z tych nowych koordynatów dopiero leci pocisk. A do tego, jeśli miejscem jego kolizji z mapą/cegłami jest na przykład x42 i y85 to zmienia miejsce wybuchu, który uszkadza teren na x40 i y84. Mam nadzieję, że rozumiesz. Chociaż nie o tym chciałem rozmawiać, bo nie wiem, jak usunąć z pamięci poprzedni sprite mapy sprzed jej kolejnego uszkodzenia. A tak, jak pisałem, jeśli użyję ma przykład obiektów cegieł, to jeśli mapa będzie wypełniona cegłami na full, to gra będzie lagowała i to ostro nawet, jeśli cegły nie będą miały żadnych skryptów. A z moich obliczeń wyszło, że potrzebowałbym ponad 10.000 obiektów o ile nie więcej, bo już nie pamiętam. A jak niszczysz blok 16x16 pikseli, to powinien się podzielić na 4 bloki 8x8, a te z kolei na 16 bloczków 4x4, więc sam widzisz, jak liczba obiektów może się mnożyć podczas grania Nie wiem, czy mogę, ale wrzucam filmik jak to wygląda za każdym razem [FILMIK] Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
SimianVirus7 Opublikowano 6 Marca 2022 Udostępnij Opublikowano 6 Marca 2022 Swoją destrukcję ścian robię w bardzo podobny sposób i też zauważyłem, że zjada mi to ramu. Na początku się tym nie przejmowałem, bo to 1mb na odświeżenie ale w końcu musiałem to ogarnąć. Po mozolnym klepaniu doszedłem do ładu i robię to w następujący sposób. Create: sprite = sprite_duplicate(sprite_index); //duplikuje przypisany sprite, aby na nim przeprowadzać operacje. Ważne! (dlatego, że nie przypisuje ścieżki do pamięci, tylko tworzę osobny sprite, tak, żeby każdy obiekt miał swój własny, a przy restartowaniu gry, nie pokazuje błędu o nieistniejącym zasobie. Draw: sprite_delete(sprite) //usuwam aktualny sprite z pamięci sprite = sprite_create_from_surface(oGame.surface_wall, x, y, 32, 32, false, true, 0, 0) //przypisuje nowy sprite z surface sprite_collision_mask(sprite, 1, 0, 0, 0, 0, 0, bboxkind_precise, 0) //tworzę do niego maskę sprite_index = sprite; //przypisuje ścieżkę do sprite_index - nie muszę pamiętać, żeby pisać sprite zamiast sprite_index w reszcie kodu. Bardzo długo próbowałem to skrócić, tak, żeby nie musieć tworzyć nowej zmiennej sprite, ale zawsze było jakieś "ale". (zwiększający się stopniowo RAM, są wywołane przez tworzenie pocisków a nie tą sytuacją z surface) Untitled Project.mp4 Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
Administratorzy gnysek Opublikowano 7 Marca 2022 Administratorzy Udostępnij Opublikowano 7 Marca 2022 Dlaczego generujesz tyle nowych sprite w locie? Pamięć zapełni się szybko i jest to mega niewydajne, bowiem GM każdy sprite generuje jako osobną teksturę jeśli go tworzysz w grze, do tego trzyma dwie kopie do normalnego rysowania i blendingu, co daje WYSOKOŚĆ * SZEROKOŚĆ * 4 bajty. Obrazek 512x512px to jest 2 MB. Z tego kodu widać też, że faktycznie, nie usuwasz starych sprite'ów, wiec one faktycznie zostają w pamięci - GM nie zwalnia automatycznie zasobów jeśli nie są używane, robi to tylko ze strukturami i z tablicami, resztę trzeba usuwać ręcznie. Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
Xyridon Opublikowano 7 Marca 2022 Autor Udostępnij Opublikowano 7 Marca 2022 W moim przypadku to nie pociski, bo wszędzie dookoła tych czołgów są niezniszczalne szare ściany, przez które nic się nie przedostaje co oznacza, że pociski są przy takiej kolizji usuwane, żeby nie leciały w nieskończoność. Wrzuciłem Twój kod i przy uderzeniu w cegły, znikają wszystkie, a nie tylko fragment po uderzeniu/wybuchu. Jeszcze to próbuję ogarnąć, może jakoś to naprawię, bo serio głupi jestem ehh Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
SimianVirus7 Opublikowano 7 Marca 2022 Udostępnij Opublikowano 7 Marca 2022 Ten kod musisz dopasować do swojego, podałem Ci tylko część odpowiedzialną za główną funkcję. Czyli jeszcze gdzieś musisz mieć choćby draw_self() oraz co ważniejsze dopasować tą linijkę sprite = sprite_create_from_surface(oGame.surface_wall, x, y, 32, 32, false, true, 0, 0) //przypisuje nowy sprite z surface Z tego co widzę, kolosalną różnicą jest to, że Ty robisz surface dopasowany do wysokości/szerokości sprite'a i tak dla każdego bloku jest osobny surface. Ja natomiast mam jeden o wielkości room'u, a wszystkie moje bloki ściany odwołują się do tego jednego surface i tylko wycinam odpowiednie fragmenty z których tworzę nowe sprite'y Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
Xyridon Opublikowano 7 Marca 2022 Autor Udostępnij Opublikowano 7 Marca 2022 Ehh Panowie no to nie wiem. Teraz mam takie coś i to w dalszym ciągu po kolizji pocisku z cegłami usuwa wszystkie z mapy if(HIT) { sprite_delete(sprite) sprite = sprite_create_from_surface(sprite, 0, 0, room_width, room_height, false, true, 0, 0) sprite_collision_mask(sprite, 1, 0, 0, 0, 0, 0, bboxkind_precise, 0) //tworzę do niego maskę sprite_index = sprite; HIT = false; } draw_sprite(sprite_index, 0, 0, 0); Chciałbym, żeby po uderzeniu pocisku w cegły, te nie znikały. No i okej, po tej zmianie: if(HIT) {//make a new sprite code sprite_delete(sprite) sprite = sprite_create_from_surface(sprite, 0, 0, room_width, room_height, false, true, 0, 0) sprite_collision_mask(sprite, 1, 0, 0, 0, 0, 0, bboxkind_precise, 0) HIT = false; } draw_sprite(sprite, 0, 0, 0); Faktycznie teren pozostaje nietknięty po uderzeniu pocisku. Dobra. Teraz muszę tylko ponownie zaaplikować robienie dziur EDIT: Teraz robienie dziur mi nie działa if(HIT) { sprite_delete(sprite) sprite = sprite_create_from_surface(sprite, 0, 0, room_width, room_height, false, true, 0, 0) gpu_set_blendmode(bm_subtract); draw_set_color(c_black); draw_rectangle(damage_x -8, damage_y -8, damage_x +7, damage_y +7, false); gpu_set_blendmode(bm_normal); sprite_collision_mask(sprite, 1, 0, 0, 0, 0, 0, bboxkind_precise, 0) HIT = false; } draw_sprite(sprite, 0, 0, 0); Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
SimianVirus7 Opublikowano 8 Marca 2022 Udostępnij Opublikowano 8 Marca 2022 Cytat sprite_create_from_surface(sprite, 0, 0, room_width, room_height, false, true, 0, 0) nie nie nie, nie tak. Tutaj tworzysz spritea o wymiarach pokoju, a ja mówiłem o surface. Hymm... czyli coś takiego, nie pamiętam dokładnie Osobny obiekt dla ścian, np. oWallController Create: surface_wall = surface_create(room_width, room_height); i teraz w bloku ściany, coś takiego: Draw: draw_self(); if(HIT) { surface_set_target(oWallController.surface_wall); //Ustaw surface do edycji draw_sprite(sprite_index, image_index, x, y) //narysuj obiekt który oberwał od pocisku gpu_set_blendmode(bm_subtract) //zmień tryb na wycinanie draw_set_color(c_white) //c_white wycina sprite (u Ciebie to może być c_black, to chyba spowodowane niedawnym przejściem kolorów na rgb w gms) draw_rectangle(damage_x -8, damage_y -8, damage_x +7, damage_y +7, false); //wytnij kawałek bloku gpu_set_blendmode(bm_normal)// ustaw tryb na normalny surface_reset_target(); // wróć na domyślny surface //Odświerz sprite sprite_delete(sprite) sprite = sprite_create_from_surface(oWallController.surface_wall, x, y, 32, 32, false, true, 0, 0) //utwórz nowy sprite z pozycji x/y obiektu trafionego, o wymiarach 32x32 sprite_collision_mask(sprite, 1, 0, 0, 0, 0, 0, bboxkind_precise, 0) //tu bboxkind_rectangle może być w twoim przypadku, tak myślę. sprite_index = sprite; //podmień stary sprite na nowy HIT = false; } Mniej więcej coś takiego, choć może będziesz to nadal musiał dopasować do siebie. Pamiętaj, że jak robisz surface o małych wymiarach np. 32x32 i umieszczasz je w pokoju na współrzędnych x/y, to poruszając się po niej, zaczynasz od x: 0 y: 0 a nie po x/y pokoju. Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
Xyridon Opublikowano 10 Marca 2022 Autor Udostępnij Opublikowano 10 Marca 2022 Nadal nie działa, nie wiem jak to dostosować Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
Administratorzy gnysek Opublikowano 11 Marca 2022 Administratorzy Udostępnij Opublikowano 11 Marca 2022 Ale co konkretnie nie działa? Źle się wyświetla? Sprite jest pusty? Wywala jakiś błąd? Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
Rekomendowane odpowiedzi
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ę