Skocz do zawartości

Temporal

Użytkownicy
  • Postów

    51
  • Dołączył

  • Ostatnia wizyta

  • Wygrane w rankingu

    3

Odpowiedzi opublikowane przez Temporal

  1. 14 godzin temu, Patryqss napisał:

    Właśnie się zastanawiam, czy nie dodać każdemu wrogowi paska życia nad głową. Nie wiem tylko czy gra nie będzie przez to brzydko wyglądać. Z dźwiękiem to samo - jak atakujesz czterema strzałami, to czterokrotnie powtórzone "ała" też może słabo brzmieć.

     

    Można zaprogramować, by dźwięki nie odpalały się, gdy już jeden jest odgrywany, grać je w pewnych odstępach czasowych, nagrać kilka wariacji dźwięku itp.

  2. Jedynym plusem tej gry to lektor, reszta rzeczy nie gra. Denne sterowanie, beznadziejna mechanika walki, totalnie skopane AI wrogów i gui wyświetla się nie tam gdzie trzeba. Dałbym screena, ale jakbym nie kombinował, to dostaję biały ekran, więc nici z przechwytu. Jak zostanę zaatakowany, to mogę się wbić w ścianę, a później z niej już nigdy nie wyjść. Nie chcę być okrutny, ale gra jest całkowicie niegrywalna.

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

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

  5. 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?

  6. Fajna ta laseczka. W sumie to nie wiem, czy to taka cartoonowa stylizacja i tak ma być, ale może fajnie byłoby wypalić AO z tego high poly i zmiksować trochę to z aktualną color mapą. O ile ta jaszczuro baba mi się średnio podobała, to te twoje nowe wrzuty są bardzo super. Mam nadzieję, że gra odniesie sukces, tyle włożonej pracy, więc nie może być inaczej :)

  7. Fajne, ale przez tą zieloną obwódkę, to czuję się jakbym potrzebował okularów 3d. Może warto poexperymentować i ten zielony zamienić na inny kolor? To tylko moja sugestia, nie musisz się do tego stosować.

  8. Ale to jest ładne :) Z assetami to jest tak, że jak się wymiesza z innymi to wygląda to nie za dobrze, a raczej nikt nie zrobi pakietu pod naszą gierkę, więc ja na pewno nie skorzystam, ale jak ktoś sobie coś tam dłubie, to do testów jak znalazł. Szkoda, że projekt anulowany, bo fajnie to wygląda na tych gifach.

  9. 22 godziny temu, exp napisał:

     

    no i muszę wspomnieć o najlepszej grze w historii, czyli falloucie. grając w niego towarzyszy mi uczucie, którego nie potrafię opisać, po prostu w falloucie czuję się jak we własnym domu :) przez całe życie spędziłem z F1 i F2 tyle czasu, że to absurd. nie jestem pewien, czy nie mówimy tu o pięciocyfrowej liczbie godzin. ale dla mnie to pierwsza część jest bezapelacyjnym czempionem i największym dziełem sztuki. tak naprawdę to znam tę grę na pamięć i nawet nie potrzebuję komputera, równie dobrze mogę ją sobie odegrać we własnej głowie

     

     

    Widać, że ktoś tu się dobrze zna na grach :) Z reguły jak przejdę jakąś grę single player, to do niej nie wracam, ale z pierwszym Falloutami mam tak, że raz na jakiś czas bierze mnie taka chcica, że muszę kolejny raz zatopić się w ten świat. Szkoda, że takich erpegów się nie robi. Prawdziwy brutalny świat bez elfów, magii i innych takich. RPG w którym naprawdę podejmujesz decyzję i masz wpływ na otoczenie. Większość erpgeów mydli oczy toną tekstu, marketingowym bełkotem, a jak przyjdzie co do czego, to gra jest strasznie liniowa i każdy quest wykonuje się na jeden przewidziany sposób. Ludzie do dzisiaj podniecają się Baldurami, a tam wszystko było iluzją, jakiej opcji dialogowej byś nie wybrał, to nie miało to zupełnie znaczenia. W Falloucie to każdy quest można wykonać na wiele sposobów, a i tak większość z nich jest opcjonalnych. Questy poboczne, to nie tylko fecz questy, ale normalne duże rozbudowane zadania, które można wykonać albo przejść grę o nich nawet nie wiedząc. F2 to już w ogóle, takie F1, tylko na sterydach.

  10. Tworzę sobie taki projekcik, gdzie wykorzystuję kolizję opartą o tilesy, a nie obiekty.

     

    Mój skrypt, który jest taką alternatywą dla "place_meeting()", tylko działa na tilesach:

     

    Cytuj

    ///@arg xx
    ///@arg yy
    ///@arg collision_layer

    var xx = argument0;
    var yy = argument1;
    var tilemap_id = layer_tilemap_get_id(layer_get_id(argument2));
    var right_collision = false;
    var left_collision = false;
    var top_collision = false;
    var bottom_collision = false;

    //save current position
    var xp = x;
    var yp = y;

    //update position and check for collision

    if (xx != xp){
        x = xx;
        if (xx > xp){     // right movment collision
            right_collision =    tilemap_get_at_pixel(tilemap_id, bbox_right, bbox_top) ||
                                tilemap_get_at_pixel(tilemap_id, bbox_right, bbox_top+sprite_height/2) ||
                                tilemap_get_at_pixel(tilemap_id, bbox_right, bbox_bottom);    
            } else {    // left movment collision
            left_collision =    tilemap_get_at_pixel(tilemap_id, bbox_left, bbox_top) ||
                                tilemap_get_at_pixel(tilemap_id, bbox_left, bbox_top+sprite_height/2) ||
                                tilemap_get_at_pixel(tilemap_id, bbox_left, bbox_bottom );
        }
    }

    if (yy != yp){
        y = yy;
        if (yy > yp){     // down movment collision
            bottom_collision =    
                                tilemap_get_at_pixel(tilemap_id, bbox_left, bbox_bottom )||
                                tilemap_get_at_pixel(tilemap_id, bbox_left+sprite_width/2, bbox_bottom)||
                                tilemap_get_at_pixel(tilemap_id, bbox_right, bbox_bottom);    
            } else {    // up movment collision
            top_collision =        tilemap_get_at_pixel(tilemap_id, bbox_left, bbox_top) ||
                                tilemap_get_at_pixel(tilemap_id, bbox_left+sprite_width/2, bbox_top)||
                                tilemap_get_at_pixel(tilemap_id, bbox_right, bbox_top);                    
        }
    }

    //move back
    x = xp;
    y = yp;

    //return
    return (right_collision || left_collision || top_collision || bottom_collision);

     

    Tak wygląda kod odnośnie kolizji:

     

    Cytuj

    // horizontal collision check
    if scr_tile_collision(x+hspd, y, "Collision"){
        while(!scr_tile_collision(x+sign(hspd), y, "Collision")){
            x+=sign(hspd);
        }
        hspd = 0;
    }

    x += hspd;

    // vertical collision check
    if scr_tile_collision(x, y+vspd, "Collision"){
        while(!scr_tile_collision(x, y+sign(vspd), "Collision")){
            y+=sign(vspd);
        }
        vspd = 0;
    }

    y += vspd;

     

    Nic odkrywczego, taki standard jeśli chodzi o precyzyjną kolizję, tutaj jednak odnosimy się do tilesów.

     

    Chcę w grze mieć wrogów, którzy mają zasięg widzenia i jeśli my jako gracz się w nim znajdziemy, to odpalają się pewne state'y. Problem jest taki, że ściany, platformy, to tilesy bez obiektów kolizyjnych, więc funkcja collision_line() odpada. Moje doświadczenie jest małe i coś tak kombinuję sobie, jak pierwszy lepszy pomysł do głowy trafi. Skoro mam własną funkcję do wykrywania kolizji między obiektami a tilesami, to pomyślałem, że może "wzrok" przeciwników, to będzie obiekt, ze spritem o wielkości 1 pixela, który będzie się skalował w osi x na maksymalny zasięg z zmiennej.

     

    Cytuj

    //line of sight
    with (my_line_of_sight){
        x = other.x;
        y = other.y;
        image_xscale = other.seeing_max * other.dir;
        
        if scr_tile_collision(x+other.hspd, y, "Collision"){
            while(scr_tile_collision(x+(other.hspd*2), y, "Collision")){
            image_xscale=image_xscale - (other.hspd*2);
        }
            image_xscale = image_xscale-other.hspd
            other.seeing_wall = true;
            } else {
            other.seeing_wall = false;
        }
    }

     

    Problem jest taki, że kolizja z tilesami jest oparta o punkty bounding boxa tilesa. Rózne rozmiary kolidujących spirtów mogę powodować różne błędy i niewykrycie kolizji. W moim przypadku mamy 8 punktów sprawdzania kolizji i większości przypadków daje radę. Jeśli biała linia przejdzie za bardzo przez tilesa, to kolizja nie zachodzi i zmienna seeing_wall = false; Na screenie widać o co mi chodzi. Chciałbym żeby linia wchodząc w tilesa scalowała się w dół. Tak by nadal kolidowała z tilesem a się skracała tak by nie wychodziła poza obszar tilesa.

    tsA1ocr.jpg

     

    Pewnie nie jest to najlepsze rozwiązanie, ale likwidacja tego jednego problemu dałaby mi to czego potrzebuję. Próbowałem coś na googlach szukać odnośnie collision_line z tilesami i jedyne co znalazłem jakiś niezrozumiały dla mnie skrypt, który był raycastem opartym o ds_grid. Jak na moje potrzeby, to jednak za bardzo skomplikowane.

     

    Może zamiast skalowanego obiektu na wzór linii zrobić obiekt "punkt", który jest w odległości od przeciwnika i w razie kolizji jest dopychany w pętli idealnie do punktu bounding boxa? samą linię mógłbym na potrzeby debbuginu rysować w drawie w odległości x przeciwnika do x punktu. Jakieś rady? Jeśli ktoś znałbym jakiś nie za bardzo skomplikowany sposób na zrobienie tego bez dodatkowych obiektów tylko na podstawie jakieś "zaawansowanej" matematyki, to się nie obrażę :)

  11. Płakać na grach, nie płaczę, ale są takie momenty gdzie się morda cieszy, człowiek wczuwa się w tą fikcyjną scenkę itd. Taki Fallout1 i scena wygnania ze schronu, albo alternatywne zakończenie, gdzie supermutanty wbijają się nam do schronu 13, coś pięknego :) Hollow Knight i pierwsze zakończenie.

  12. Trochę ze mnie debil, bo całkowicie zapomniałem, że alarm to po prostu wbudowana zmienna i mogę się do niej dostać tak samo jak do zdefiniowanych przez siebie zmiennych. Pytanie tylko teraz jest takie: po co jest to całe alarm_get? Sugerowałem się tym co jest napisane w helpie, ale teraz wychodzi, że prościej sczytywać sobie wartość bezpośrednio jak blabla = alarm[0] czy tak jak dla tego przypadku obj_player.alarm[0] Nie za bardzo widzę zastosowanie dla tego alarm_get... chyba, że to jakieś pozostałości ze starych wersji GM, gdzie inaczej się nie dało dobrać do tych wartości.

×
×
  • Dodaj nową pozycję...