Temporal Opublikowano 30 Marca 2019 Udostępnij Opublikowano 30 Marca 2019 Tak jak w temacie, da się jakoś grupować obiekty w GM inaczej niż za pomocą "child-parent"? Ten system parentowania działa spoko, ale co w przypadku jak chcę mieć dwie grupy np: kwadraty(obj_player, obj_kwadrat) i postacie (obj_player, obj_enemy)? obj_player może mieć tylko jednego parenta, więc nie mogę go podpiąć pod jakiś jeden obiekt "kwadraty" i drugi "postacie". Chciałbym dość często wykonywać kod dla poszczególnej grupy obiektów, a obecny system parentowania nie pozwoli mi tworzyć takich grup. Wiem, że parent może mieć kolejnego parenta, ale to nie jest dobre jak chcesz mieć grupy, które mają jeden obiekt, a innego nie mają. Da się jakoś inaczej? Ja wpadłem na taki pomysł tworzenia własnych funkcji/skrpytu, który zwraca 1 wymiarowego arraya i później przepuszczam pętlę razy ilość tych rzeczy w tym array'u. Wcześniej miałem taki kod i używałem obiektu "par_entity", który był taką jedną grupą. Niestety ta grupa zawierała w sobie obiekt gracza "obj_player", który występował też w innej grupie i jak się łatwo domyślić, to ten sposób powodował, że nie mogłem w różnych miejsach w kodzie odnosić się do obiektów typu par_ Cytuj var list = ds_list_create(); var instances = instance_place_list(x, y-1, par_entity, list, false); if (instances > 0 ){ for (var i = 0; i < instances; i++){ with (list[|i]){ if (on_solid == 0){ on_lift = true; grounded = jump_buffer; vspd = 0; if (other.vdir == 1){ y = other.y+other.spd-1; } else if (other.vdir == -1){ y = other.y-other.spd-1; } } } } } ds_list_destroy(list) Z czasem zmieniłem ten kod na coś takiego: Cytuj var group = g_entity(); var length = array_length_1d(group); for (var i = 0; i < length; i++){ var list = ds_list_create(); var instances = instance_place_list(x, y-1, group[i], list, false); if (instances > 0 ){ for (var j = 0; j < instances; j++){ with (list[|j]){ if (on_solid == 0){ on_lift = true; grounded = jump_buffer; vspd = 0; if (other.vdir == 1){ y = other.y+other.spd-1; } else if (other.vdir == -1){ y = other.y-other.spd-1; } } } } } ds_list_destroy(list); } Działa idealnie, choć nie wiem czy to nie odbija się jakoś znacząco na wydajności. Mój problem polega na tym, że nie wiem co wyczarować w kodzie, gdy chcę zrobić podobny myk w takim przypadku: Cytuj if collision_line_list(x, y, x+sight_range, y, par_spotted, false, true, spotted_list, true){ //seeing closest object var closest = spotted_list[|0]; spotted_point = closest.x-x; ds_list_clear(spotted_list); if (instance_exists(obj_player)) && (closest == obj_player.id) && !(status = state.attack){ // change state to attack status = state.attack; angry = 30; attack_buffer = 60; } else { // not seeing spotted_point = 0; } } Zamiast par_spotted chciałbym odnieść się jakoś inaczej do wyznaczonej grupy obiektów. Mógłbym pokombinować tak jak wcześniej z grupą w array'u i pętlami. W przypadku jednak użycia jakiejkolwiek funkcji typu collision_list potrzebuję utworzyć listę wszystkich id występujących kolizji i posortowania ich w jednym kroku. Jakbym nie kombinował to po zmianie ten kod nie działa tak jak trzeba i obiekt zmienia swój status na attack, nawet jeśli gracz jest za ścianą. W oryginalnej formie kod działa perfekcyjnie, ale wtedy jestem zmuszony do używania parentowania, a chciałbym bez tego, bo w przyszłości i tak nie poparentuje tak swoich "grup" bym miał w nich te obiekty, które chcę. Da się jakoś inaczej? Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
Konrad-GM Opublikowano 30 Marca 2019 Udostępnij Opublikowano 30 Marca 2019 W zasadzie nie opisałeś problemu, a problem ze swoim rozwiązaniem, które z założenia może być niepoprawne. W GMie, tak jak w wielu innych językach programowania, paradygmat pojedynczego dziedziczenia jest dość powszechnie stosowany. Nie powinieneś myśleć w kategoriach wielodziedziczenia tak jak chociażby pozwala na to C++ tworząc logikę gry. Nawet w C++ wielodziedziczenie jest dość powszechnie uznawane jako złe podejście do rozwiązania większości problemów, częściej stosuje się po prostu kompozycje obiektów - proste i efektywne. Z tego co widzę, tworzysz jakiś obiekt "system" odpowiedzialny za obsługę innych instancji w jakiejś dziwacznej pętli - a w zasadzie nie widzę tutaj sensownego wyjaśnienia, dlaczego. A nie możesz przenieść po prostu logiki do tych obiektów? Możesz chociażby napisać skrypty scr_unit_* i komponować z nich obiekty, np.: /// scr_unit_create(team) team = argument0; some_crazy_variable = 10; /// scr_unit_step() some_crazy_variable++; /// scr_unit_draw() draw_self(); Potem w obiektach np. obj_enemy, obj_player wykonujesz odpowiednio skrypty scr_unit_create w Event Create, scr_unit_step w Event Step i scr_unit_draw w Event Draw. Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
Temporal Opublikowano 30 Marca 2019 Autor Udostępnij Opublikowano 30 Marca 2019 4 godziny temu, Konrad-GM napisał: W zasadzie nie opisałeś problemu, a problem ze swoim rozwiązaniem, które z założenia może być niepoprawne. W GMie, tak jak w wielu innych językach programowania, paradygmat pojedynczego dziedziczenia jest dość powszechnie stosowany. Nie powinieneś myśleć w kategoriach wielodziedziczenia tak jak chociażby pozwala na to C++ tworząc logikę gry. Nawet w C++ wielodziedziczenie jest dość powszechnie uznawane jako złe podejście do rozwiązania większości problemów, częściej stosuje się po prostu kompozycje obiektów - proste i efektywne. Z tego co widzę, tworzysz jakiś obiekt "system" odpowiedzialny za obsługę innych instancji w jakiejś dziwacznej pętli - a w zasadzie nie widzę tutaj sensownego wyjaśnienia, dlaczego. A nie możesz przenieść po prostu logiki do tych obiektów? Możesz chociażby napisać skrypty scr_unit_* i komponować z nich obiekty, np.: /// scr_unit_create(team) team = argument0; some_crazy_variable = 10; /// scr_unit_step() some_crazy_variable++; /// scr_unit_draw() draw_self(); Potem w obiektach np. obj_enemy, obj_player wykonujesz odpowiednio skrypty scr_unit_create w Event Create, scr_unit_step w Event Step i scr_unit_draw w Event Draw. Nie do końca rozumiem jak to ma działać. Mam sobie stworzone trzy obiekty: obj_player, obj_enemy, obj_pietruszka. Wstawiam sobie je do room editora. W create event dla każdego z nich odpalam mój (twój) skrypt scr_unit_create(grupa). Nie wiem jaki cel jest pozostałych skryptów i po co miałbym je wywoływać? Teraz wszystkie moje trzy obiekty mają zmiennę "team" która równa się grupa? Hmmm, czyli scr_unit_create("grupa"), dobra teraz mam zmienną team ze stringiem "grupa". Co to mi daje? Chcę gdzieś w kodzie odpalić jakąś funkcję i zamiast odwołać się do danego obiektu odwołuję się do grupy np. Cytuj if collision_line_list(x, y-hot_spot, x+sight_range, y-hot_spot, "grupa", false, true, spotted_list, true){ //seeing closest object var closest = spotted_list[|0]; spotted_point = closest.x-x; ds_list_clear(spotted_list); if (instance_exists(obj_player)) && (closest == obj_player.id) && !(status = state.attack){ // change state to attack status = state.attack; angry = 30; attack_buffer = 60; } else { // not seeing spotted_point = 0; } } par_spotted zamieniłem na "grupa", ale to bez sensu, to odwołam się zmiennej team Cytuj if collision_line_list(x, y-hot_spot, x+sight_range, y-hot_spot, team, false, true, spotted_list, true){ //seeing closest object var closest = spotted_list[|0]; spotted_point = closest.x-x; ds_list_clear(spotted_list); if (instance_exists(obj_player)) && (closest == obj_player.id) && !(status = state.attack){ // change state to attack status = state.attack; angry = 30; attack_buffer = 60; } else { // not seeing spotted_point = 0; } } Ok, to nadal bez sensu. Konrad-GM, nadal nie rozumiem co te twoje skrypty robią i jak mają rozwiązać mój problem? W funkcjach zamiast odnosić się do jednego obiektu chcę do pewnej grupy obiektów. Co bym nie kombinował z twoimi skryptami i co nie ładował do pierwszego argumentu jak nazwa obiektu, czy co, to co ja zrobię z tą zmienną? Mogę zapisać kilka id do jednej zmiennej? Jeśli możesz to podaj jakiś przykładowy kod z zastosowaniem tego twojego sposobu. Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
Konrad-GM Opublikowano 4 Kwietnia 2019 Udostępnij Opublikowano 4 Kwietnia 2019 Moje skrypty są tylko przykładem kompozycji, pomysłem jak można rozwiązać problem z wielokrotnym dziedziczeniem. Nie bardzo rozumiem, dlaczego nie możesz wykonywać skryptu: if collision_line_list(x, y-hot_spot, x+sight_range, y-hot_spot, "grupa", false, true, spotted_list, true){ //seeing closest object var closest = spotted_list[|0]; spotted_point = closest.x-x; ds_list_clear(spotted_list); if (instance_exists(obj_player)) && (closest == obj_player.id) && !(status = state.attack){ // change state to attack status = state.attack; angry = 30; attack_buffer = 60; } else { // not seeing spotted_point = 0; } } W każdym obiekcie z osobna. Dodatkowo żeby sprawdzić "grupę" obiektów, to możesz zrobić coś takiego: var spotted_list = ds_list_create(); var instances = collision_line_list(x, y - hot_spot, x + sight_range, y - hot_spot, par_entities, false, true, spotted_list, true); var enemy_spotted = false; for (var i = 0; i < instances; i++) { var inst = spotted_list[| i]; // sprawdzamy przynaleznosc do teamu if (inst.team == "red" && status != state.attack) { enemy_spotted = true; spotted_point = inst.x - x; status = state.attack; angry = 30; attack_buffer = 60; break; } } if (!enemy_spotted) { spotted_point = 0; } ds_list_destroy(spotted_list); Jeżeli boisz się o optymalizację, możesz ten fragment kodu zamiast wykonywać w Step Event, np. ustawić Infinite Alarm (alarm ustawiający sam siebie) i np. uruchamiać ten skrypt co jakiś czas np. 100ms. (16ms to jedna klatka przy 60fps) Jeżeli chcesz dodać kilka team-ów, możesz zamiast zmiennej team dodawać zmienną teams jako tablicę, np. teams[0] = "red"; teams[1] = "green"; Stworzyć skrypt do sprawdzania zawartości tablicy: /// scr_array_includes(arr, value) var arr = argument0; var len = array_length_1d(arr); for (var i = 0; i < len ; i++) { if (arr[i] == argument1) { return true; } } return false; I wtedy powyższy skrypt z collision_line_list można przerobić na: var spotted_list = ds_list_create(); var instances = collision_line_list(x, y - hot_spot, x + sight_range, y - hot_spot, par_entities, false, true, spotted_list, true); var enemy_spotted = false; for (var i = 0; i < instances; i++) { var inst = spotted_list[| i]; // sprawdzamy przynaleznosc do teamu (z grupy teamow) if (scr_array_includes(inst.teams, "red") && status != state.attack) { enemy_spotted = true; spotted_point = inst.x - x; status = state.attack; angry = 30; attack_buffer = 60; break; } } if (!enemy_spotted) { spotted_point = 0; } ds_list_destroy(spotted_list); Temporal 1 Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
Temporal Opublikowano 4 Kwietnia 2019 Autor Udostępnij Opublikowano 4 Kwietnia 2019 Problem rozwiązałem już parę dni temu. Jeden z użytkowników GMclanu podpowiedział mi alternatywne podejście do tematu. Co prawda problem tworzenia grup nie odpadł całkowicie i bardziej się rozwiązał problem z tym konkretnym przypadkiem. Co do kodu powyżej, to podoba mi się pomysł, sprawdzaniem konkretnej zmiennej u danej istancji, ale niektórych rzeczy nie rozumiem. Możliwe, że się nie zrozumieliśmy dokładnie i stąd pewne nieścisłości. Cytuj var spotted_list = ds_list_create(); var instances = collision_line_list(x, y - hot_spot, x + sight_range, y - hot_spot, par_entities, false, true, spotted_list, true); var enemy_spotted = false; for (var i = 0; i < instances; i++) { var inst = spotted_list[| i]; // sprawdzamy przynaleznosc do teamu (z grupy teamow) if (scr_array_includes(inst.teams, "red") && status != state.attack) { enemy_spotted = true; spotted_point = inst.x - x; status = state.attack; angry = 30; attack_buffer = 60; break; } } if (!enemy_spotted) { spotted_point = 0; } ds_list_destroy(spotted_list); Ten kod sprawdza wszystkie instancje, które kolidują z linią i jeśli choć jedna z nich będzie danego typu, to zmienia się state machine obiektu, który ma ten kod. Jak widać w moim poprzednim kodzie, używałem sortowania listy, by zobaczyć czy dany obiekt jest widoczny, czy nie (jeśli obiekt gracza był pierwszy na liście, to oznaczało, że nie jest on za żadną osłoną). Mój wcześniejszy kod działał idealnie, ale wtedy byłem zmuszony do używania jakiegoś parenta, a chciałem znaleźć jakieś alternatywny sposób do tworzenie grup. Z parentami czasami dochodzi do sytuacji, gdzie chcemy mieć jeden obiekt w kilku grupach, a system parentowania to wyklucza. Znalazłem własny sposób by tworzyć własne skrypty przechowując grupę w tablicy. Później odpalałem pętlę razy ilość obiektów/pozycji tablicy. Ktoś mi doradził, że to głupie i zaproponował banalniejszy rozwiązanie. Twoje rozwiązanie jest nawet w pewnym sensie podobne do mojego, ale bawienie się w takie pętle zostało mi odradzone. Tak, czy siak dzięki za odzew, jestem wdzięczny za każdą radę od GMclanowiczów. Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
Konrad-GM Opublikowano 4 Kwietnia 2019 Udostępnij Opublikowano 4 Kwietnia 2019 12 minut temu, Temporal napisał: Ten kod sprawdza wszystkie instancje, które kolidują z linią i jeśli choć jedna z nich będzie danego typu, to zmienia się state machine obiektu, który ma ten kod. Jak widać w moim poprzednim kodzie, używałem sortowania listy, by zobaczyć czy dany obiekt jest widoczny, czy nie (jeśli obiekt gracza był pierwszy na liście, to oznaczało, że nie jest on za żadną osłoną). To super, że rozwiązałeś problem. Tak dodam jeszcze, że można sprawdzić, czy inst[ i ] nie jest ścianą (np. czy należy do grupy/teamu "walls"), jeżeli tak, to można przerwać pętlę break-em. Temporal 1 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ę