Skocz do zawartości

Amaterasu

Użytkownicy
  • Postów

    390
  • Dołączył

  • Ostatnia wizyta

Treść opublikowana przez Amaterasu

  1. Generatory to potężne narzędzia, pozwalające na ułatwienie życia designerowi (do pewnego stopnia - projektant musi zdecydować, jak dane obiekty mają być generowane). Ten generator ma za zadanie stworzyć, na podstawie zdefiniowanych przez użytkownika parametrów, coś na kształt poziomu do gry. Wychodzi mu to nieźle, wg mnie, więc szkoda by było, gdybym się tym z nikim nie podzielił. Zatem, proszę. LINK Generator ma następujące opcje: a ) Modyfikacja metody działania algorytmu generowania pierwotnego szumu Zanim wyjaśnię, przejrzyjcie artykuł o zastosowanym algorytmie generowania szumu. Iteration flags oznacza, które iteracje zostaną wykonane - tzn. dla liczby 27 (011011) zostaną wykonane iteracje 1, 2, 4, 5 - to spowoduje, że szum będzie miększy, a mapa - bardziej gładka. Im większa mapa, tym więcej iteracji - ilość iteracji rośnie logarytmicznie do większego z rozmiarów mapy (dla mapy 80x64 log2(80)=6.32<=7, zatem zostanie wykonanych 7 iteracji). Iteration amplification start pokazuje, jak duży wpływ będzie miała pierwsza iteracja, a iteration amplification speed - jak duży wpływ będą miały kolejne iteracje. b ) Tworzenie losowych bąbli Bąble można sobie wyobrazić jako łagodne pagórki (lub strome, zależnie od blob intensity). Można regulować ich liczbę (blob number) i ich rozmiar (blob radius - promień każdego bąbla mieści się w przedziale od blob_radius/2 do blob_radius). c ) Tworzenie pierścienia Pierścień powoduje stworzenie doliny lub wzniesienia na środku. Zależnie od ring radius, pierścień będzie obejmował całą mapę (1), nic (0), lub pewien fragment (wartości pośrednie). Wysoki ring inner intensity stworzy wzniesienie, a wysoki ring outer intensity - dolinę. Uwaga - liczy się różnica między ring inner a ring outer, nie ich absolutne wartości. d ) Tworzenie linii (korytarzy) Linie można sobie wyobrażać jako coś na kształt bruzdy - im większe line intensity, tym większa szansa, że w tym miejscu będzie podłoga. Można modyfikować ilość linii (line number) i ich szerokość (line width). e ) Tworzenie ściany zewnętrznej Ściana zewnętrzna to użyteczny modyfikator, który zamyka teren naokoło mapy. Od border intensity zależy, jak duże szanse są na powstanie ściany, a od border inner edge i border outer edge zależy grubość ściany. (UWAGA: w tej chwili jest bug powodujący, że zmiana outer edge nie działa tak, jak powinna - niewielki problem, bo i tak zwykle jest na wartości 1, ale na razie nie zmieniać) f ) Zmiana wielkości mapy Niby nic, a cieszy. g ) Modyfikacja progu tworzenia ścian Dzięki tej opcji, niezależnie od jakości szumu, powstała mapa zawsze będzie zawierała zdefiniowany przez bias floor percentage procent pól będących podłogą (bierze pod uwagę jedynie szum, modyfikacja mapy może spowodować, że mniejszy procent pól będzie podłogą). Bias randomization to parametr definiujący, jak mocno krawędzie ścian będą poszarpane (zależnie od kontrastu szumu, ten parametr powinien być mały lub całkiem spory - domyśnie 0). h ) Usuwanie dziur w ścianach Ustawienie holes removal na Y spowoduje, że zostaną zlikwidowane wszystkie dziury, których wielkość jest nie większa niż holes minimum size. Dla algorytmu dziurą jest każde pole, które jest podłogą, a rozmiarem dziury - ilość wszystkich pól, do których można dotrzeć z danego pola bez przechodzenia przez ściany. (Holes diagonal check oznacza, że pola, które sąsiadują z dziurą jedynie po przekątnej również są dołączane do dziury) Pozostałe opcje są jedynie pomocnicze: Generate from current noise wczytuje ponownie mapę z wygenerowanego wcześniej szumu, wykorzystując parametry z punktów g) i h) Save/Load preset pozwala na zapisanie/wczytanie ustawień modyfikowanych w programie, aby móc z nich generować własne mapy Save map zapisuje mapę do pliku, jeżeli masz chęć wykorzystać wygenerowaną mapę w swojej grze. Odczyt wykonuje się za pomocą funkcji file_to_map, znajdującej się w projekcie. Ściana to 0, podłoga to 1. Mapa jest wczytana do ds_grid. Sterowanie: Spacja - generuj nową mapę Shift - przełączaj pomiędzy widokiem minimapy (noise/map) Ctrl - przełączaj pomiędzy trybem interfejsu (pre-processing, post-processing) Strzałki - zmiana pozycji widoku To chyba tyle póki co. Projekt jest w wersji 1.0, na razie nie mam ochoty tego ulepszać : P
  2. Problem może powstać, gdy komórka 0,0 jest otoczona przez kilka zamkniętych pomieszczeń, wtedy może się zdarzyć, że obiekt jest na zewnątrz, ale wg algorytmu nie istnieje ścieżka prowadząca do komórki 0,0. Poza tym jednak, ta metoda jest bardzo dobra (mp_grid_* korzystają z wewnętrznych metod, które są szybsze od tych pisanych przez użytkownika). Tylko że tworzenie siatki i niszczenie jej przy każdym sprawdzaniu, czy obiekt jest w pomieszczeniu, jest bez sensu. Lepiej zamiast tego na początku gry stworzyć jedną siatkę, a potem w trakcie gry dodawać/usuwać przeszkody.
  3. Dowolny kształt bardzo utrudnia sprawę. Są metody do rozwiązywania takich spraw: 1. Metoda "zamalowywania", działająca jak narzędzie wypełniania w Paincie - rekurencyjnie sprawdzaj kolejne obszary wokół komórki, czy są puste czy zajęte. Sprawdzanie zakończy się, jeżeli sprawdzana komórka wyjdzie poza zakres mapy. Ta metoda żre dużo procesora, ale działa niezawodnie, i o ile mapa nie jest duża, to można ją stosować, jeśli sprawdzanie odbywa się tylko przy stawianiu obiektu (tzn. obiekt się nie rusza). 2. Metoda topologiczna - przy postawieniu każdego murku dokonuj triangulacji całego zespołu murków połączonych z tym świeżo postawionym, a następnie wylicz dla tej triangulacji liczbę Eulera - liczba utworzonych pomieszczeń jest równa (1-liczbaEulera). Problem polega na tym, jak znaleźć taką triangulację (sam dokładnie nie wiem, ale to nie jest trywialna sprawa). Nie jestem w stanie nic powiedzieć nt. wydajności, ale sposób niżej jest chyba możliwszy do zrealizowania. 3. Automat komórkowy - każdy murek ma trzy stany 0, 1 lub 2. Przy każdym postawieniu murku X, stwórz listę L zawierającą wszystkie murki połączone z X (niekoniecznie sąsiedzi). Zresetuj wszystkim murkom z L stan na 0. Następnie, począwszy od X, zmieniaj stan na 1, i zmieniaj stan na 1 sąsiadom, o ile ci nie mają stanu 1 lub 2. Jeżeli jednak mają, to ustaw im, i wszystkim murkom z nimi połączonymi i mającymi stan 1, stan 2. Po zakończeniu działania automatu, wszystkie murki ze stanem 2 tworzą zamkniętą przestrzeń. To tylko jeśli chodzi o sprawdzanie, czy mur jest zamknięty - sprawdzanie, czy obiekt jest wewnątrz muru, jest zagadnieniem rozwiązywalnym przy pomocy struktur danych (głównie ds_grid). Zaletą jest to, że sprawdzanie, czy obiekt jest wewnątrz, jest bardzo szybkie. Jak widać, problem jest niefajny, ale rozwiązywalny. EDIT: odnośnie metody 2, to triangulacja powinna wyglądać następująco: V - ilość wierzchołków E - ilość krawędzi F - ilość ścian liczbaEulera=V-E+F dla figury złożonej ze wszystkich ścian mających połączenie ze świeżo położonym murkiem: V=2+2N E=5N_0+4N_1+3N_2+2N_3+N_4 F=2N gdzie N - liczba wszystkich murków branych pod uwagę N_X - liczba murków mających X sąsiadów liczbaEulera<1 => mur zamknięty chyba metoda 2 wychodzi nieco prościej (co do sprawdzania zamkniętości muru)
  4. Czy te pomieszczenia mają być prostokątne, czy dowolnego rozmiaru?
  5. Weź zrób, żeby się tło się poruszało, fajny efekt: GML //w evencie Step postaci background_x[0]=view_x*A //A - prędkość poruszania się tła w osi X background_y[0]=view_y*B //B - w osi Y A ogólnie to mi się podoba.
  6. @Threef, @MaxGaming: może i pokomplikowałem, ale przynajmniej zmiana kodu będzie tylko polegać na zmianie w skrypcie Przewroc, a nie w tych kilku miejscach w kodzie, gdzie się przewraca karty.
  7. Create karty: GML tryb=1; //1, gdy odkryta, 0, gdy zakryta skrypt Przewroc() GML tryb=1-tryb; Draw karty: GML if(tryb==1) { //tu rysuj sprite'a dla odwroconej karty } else if(tryb==0) { //rysuj sprite'a dla zakrytej karty } Potem, gdy chcesz zmienić stronę karty, używasz (gdziekolwiek): with(id_karty) Przewroc(); gdzie id_karty jest kartą, którą chcesz przewrócić. Zależnie od wartości zmiennej tryb karty możesz powodować, że zakrytych kart nie można zagrać itd.
  8. Amaterasu

    Galeria Grafik

    klasyczny 9gag, dodaje logo i konwertuje na jpg
  9. Zniszczenie obiektu pociąga za sobą usunięcie zmiennych i tablic w obiekcie. Zniszczeniem obiektu jest użycie instance_destroy() lub przejście do innego rooma, jeżeli obiekt nie ma zaznaczonego "persistent". Co powinieneś zrobić, to dać "persistent" ekwipunkowi, a drzewu - nie. Wtedy drzewo nie zostanie na mapie, a ekwipunek zostanie. Chyba że to jakoś inaczej wygląda, nie jestem pewien, może powinieneś trochę doprecyzować
  10. Jak nie ma się zasobów (tj. czasu i/lub skilla w rysowaniu i/lub kasy na zatrudnienie grafika), to podwojenie wielkości pikseli to najtańszy chwyt na wywołanie wrażenia, że grafika jest "ok"
  11. 1. Obiekty, które mają nie znikać po przejściu do kolejnego rooma, powinny mieć zaznaczoną opcję "permament". Wszystkie pozostałe obiekty ulegną zniszczeniu/usunięciu. 2. Zapisuj w zmiennej globalnej ten room, z którego przechodzisz do następnego. Potem, w zależności od tego, jaki jest ten zapisany room, ustawiaj pozycję postaci. Możesz to zrobić if-ami, inne sposoby są może lepsze, ale dłuższe do zapisania. 3. Niech x=100, y=40 x=-y spowoduje, że x=-40 x-=y spowoduje, że x=60 Problem u ciebie polega na tym, że kolizja obiektu z dzidą trwa dłużej niż 1 step, więc kod w kolizji (czyli hp-=40) wykonuje się w wiele razy. HP spada do zera w bardzo krótkim czasie. Aby to naprawić, musisz skorzystać ze zmiennej pomocniczej i timera. W Create obj_dzida: GML can_hit=1 //tworzy zmienna pomocnicza</span> W kolizji wroga z obj_dzida dodaj na początku: GML if(other.can_hit !=1) exit //dzida nie zada obrazen, jezeli niedawno zadawala obrazenia</span> a na końcu: GML other.can_hit=0 //zablokuj zadawanie obrazen dzidy other.alarm[0]=30 //ustaw timer dzidy</span> W Alarm 0 obiektu obj_dzida: GML can_hit=1 //gdy timer dojdzie do 0, dzida moze znowu zadac obrazenia</span>
  12. To dlatego, że sprite_exists odnosi się do zasobu w pamięci RAM (wszystkie sprite'y w projekcie gry podczas uruchamiania gry są tam ładowane, więc na 100% istnieją). Ty chcesz sprawdzić, czy dla danego sprite'a istnieje obiekt, do którego jest on przypisany. Ale to też nie zadziała. Zakładam, że wszystkie obrazki masz w jednym sprite (inaczej nie używałbyś image_index), tak więc każda karta ma przypisany ten sam sprite. Tak jak Threef napisał, podchodzisz do tego od złej strony. Najlepszym rozwiązaniem byłoby, żeby już podczas wybierania karty dodawać ją do właściwej listy, żeby później uniknąć kosztownego sprawdzania, czy istnieje obiekt z danym indeksem karty. Innymi słowy, tę część kodu, która wkłada kartę do odpowiedniej listy, powinieneś przesunąć tam, gdzie losujesz te pięć kart, i zmodyfikować, by działało.
  13. Tworzysz listę z 55 elementami, ale kart w talii jest chyba 52? (Zakładając, że chodzi o zwykłą talię do gry) W każdym razie, z tych prostych opcji, to do wyboru masz dwie: -wkładasz kartę do listy zależnie od reszty z dzielenia jej indeksu przez liczbę (będącą ilością wszystkich kolorów, dla talii do gry byłoby to 4); -wkładasz kartę do listy zależnie od całości z ilorazu jej indeksu i liczby (będącej ilością wszystkich kart jednego koloru w talii, dla talii do gry byłoby to 13). W pierwszym przypadku, jeżeli pierwszą listą jest global.www, to do niej wejdą karty z numerami 0,4,8 itd. W drugim przypadku - karty z numerami od 0 do 12. Pisząc "indeks", mam na myśli "image_index"
  14. uhhh Jeżeli w kodzie (np. tym podanym przeze mnie) masz coś w stylu argumentX (gdzie X to liczba od 0 do 15), to ten kod jest skryptem i wkładasz go do zakładki "Scripts". Nazwij ten skrypt tak, jak w pierwszej linijce komentarza. Po prostu w Draw walnij GML draw_sprite_line(spr,subimg,x1,y1,x2,y2) gdzie zamiast tych podanych nazw wstawiasz to, co chcesz, zgodnie z regułami , które zapisałem w komentarzu. Traktuj podany przeze mnie kod jak zwykłą funkcję, tak jak draw_sprite_ext(), tylko z nieco innymi argumentami i z nieco innym działaniem.
  15. GML //draw_sprite_line //argumenty: //sprite index, image index //x1,y1 - pozycja poczatku linii //x2,y2 - pozycja konca linii //wazne, aby sprite byl symetryczny, a origin sprite'a byl na jego srodku (ale tylko w osi Y, w osi X moze byc gdzie chce) var x1,y1,x2,y2; x1=argument2; x2=argument4; y1=argument3; y2=argument5; //tu byl kod //i go nie ma draw_sprite_ext(argument0,argument1, x1+(x2-x1)*(sprite_get_xoffset(sprite1)/sprite_get_width(sprite1)), y1+(y2-y1)*(sprite_get_xoffset(sprite1)/sprite_get_width(sprite1)), point_distance(x1,y1,x2,y2)/sprite_get_width(sprite1),1,point_direction(x1,y1,x2,y2),c_white,1); powinni mi za to zapłacić w złocie
  16. Równania ruchu wahadłowego dla dowolnego kąta nie są proste, ale istnieje forma dla małych kątów, która jest wygodna i dobrze je przybliża. W Create dodaj: GML tmp_t=0; gamma=30; //maksymalny kat wychylenia wahadla</span> W Step zmień GML anim+=1; na GML tmp_t+=K; //im wieksze K, tym szybsze wahadlo anim=gamma*dsin(tmp_t)-90;
  17. Musisz zrobić system kolejkowania akcji. Każda gra, w której możesz dawać postaci do wykonania kilka akcji pod rząd ma taki. Ogólnie wygląda to tak, że masz strukturę danych, w której zapisujesz różne dane nt. akcji (np. dla akcji "atakuj wroga" powinieneś podać ID tego wroga). Postać wykonuje akcje po kolei, czyli od akcji podanej najwcześniej do akcji podanej najpóźniej. Najważniejsza część polega na tym, że pewne zdarzenia (np. wróg ginie, zanim postać zacznie wykonywanie akcji, albo postać ma za mało punktów ruchu, aby zaatakować wroga, coś w tym stylu) powinny powodować usunięcie danej akcji z tej struktury, przez co postać nie będzie jej wykonywać. To nie jest prosta rzecz do zrobienia. GM ma do dyspozycji parę prostych struktur (przydatnymi będą ds_queue i ds_grid), ale jak te struktury będą działać, zależy tylko i wyłącznie od programisty, bo to on decyduje, jakie akcje mogą zostać w grze wykonane.
  18. Prościej będzie na przykładzie. Parent ma kod w Create i Step, child ma kod w Create i Draw. Wtedy child przejmuje tylko event Step od parenta, a w Create i Draw wykonuje własny kod.
  19. edie, lord - zauważyłem to, ale nie chciałem tego wytykać, więc trochę ubarwiłem : P Jakby zewnętrzny obserwator czytał mój post, to by się z nim zgodził w 100%
  20. https://forum.gmclan.org/index.php?s=&s...st&p=437984 where is your god now
  21. Fajne jest to, że praktycznie każdy bot obrał inną strategię i miał inny zestaw środków do dyspozycji. ŚCIANA TEKSTU Threef nie poruszał paletką dopóki nie było to absolutnie konieczne, miał dobrą celność, podążał za wszystkimi piłkami i łapał dobre bonusy, gdy tylko mógł, ale nie unikał złych bonusów i miał bardzo wąską paletkę, przez co nie mógł żonglować piłkami. Danielus postawił na użycie mocy obliczeniowej do wyliczenia trajektorii, która pozwala piłce na dotarcie do sufitu. Bot łapał i unikał jak trzeba, ale miał słabą celność. Gdyby miał taką celność, jak mój bot, to by mnie spokojnie przebił, bo zastosował chyba najlepszą strategię. Matrix_ zmodyfikował początkowego bota, aby łapał bonusy i piłki, ale ograniczył się do jednej piłki i jednego bonusa. Miał też znikomą celność, ale dzięki temu, że paletka starała się ustawić dokładnie tam, gdzie wyląduje piłka, uzyskał nienajgorszy wynik. Bot Ignatusa nie był na tyle zaawansowany, aby móc "widzieć" bonusy i reagować na nie, nie brał też pod uwagę pozycji cegieł przy celowaniu, przez co uzyskał wynik, jaki uzyskał. Przynajmniej nie stracił życia, tak jak Huder xD ediepl starał się odbijać piłki pod jak najmniejszym kątem względem poziomu w nadziei, że ta dotrze do sufitu, gdzie będzie mogła zbić jak najwięcej cegiełek. Pewnie dlatego wyniki tak bardzo się różnią w zależności od seeda - im więcej piłek, tym lepsza ta strategia. Bot ignorował złe bonusy, ale dobrze łapał piłki i dobre bonusy. Dzięki temu osiągnął dobry wynik pomimo braku mechanizmu celowania. bLaze zmodyfikował podstawowego bota, zmniejszając jego losowy rozrzut i sprawiając, by paletka odbijała piłkę praktycznie pionowo, ale z drobnym odchyleniem w stronę klocków. Może to bezpieczna opcja, ale bez łapania/unikania bonusów i idących za tym mechanizmów łapania piłek i celowania daleko się nie zajedzie. Amaterasu (ja) ma dwa tryby celowania: płaski, gdy jest dużo cegieł, i dokładny, gdy jest mało cegieł. "Obrał" strategię robienia dziur na początku, aby przy chaosie, jaki powstaje przy celowaniu w kolejne piłki, osiągnąć odbicie się piłek od wielu klocków. Dzięki praktycznie 100% celności i dokładnemu łapaniu piłek i dobrych bonusów przy jednoczesnym unikaniu złych bonusów osiągnął najlepszy wynik pomimo praktycznego braku strategii. I am Lord obrał strategię czyszczenia planszy rząd po rzędzie. Miał dobrą celność (prawie 100%), ale słabo zrobione łapanie/unikanie bonusów, przez co stracił punkty. Podobnie z YXE - ale tutaj bot dodatkowo próbował wybić piłkę nad planszę, by zbić klocki u góry. Ten bot również miał doskonałą celność i pewnie przebiłby mój wynik, gdyby tylko poprawił swój system łapania/unikania bonusów. Widać, że dobry bot składa się z następujących komponentów: -system celowania -system łapania piłek i dobrych bonusów oraz unikania złych bonusów -strategia czyszczenia planszy
  22. Zakładając, że miał jakiś randomizowany algorytm - pewnie miał pecha.
  23. Ayy lmao Ciekawe jaka będzie druga kategoria
  24. Przejrzałem na szybko projekt gry. Zauważ, że pomimo dodania tylu różnych obiektów, funkcjonalność twojej gry jest znikoma, a w dodatku ilość błędów jest porażająca. Rozumiem ten proces myślowy - sam, gdy zaczynałem, miałem tendencję do tworzenia całej masy obiektów, które niewiele się od siebie różniły. Głównie z braku doświadczenia, ale też z niedopatrzenia różnych rzeczy. Takie coś nie zamuli gry, ale spowoduje, że implementacja zmian w trakcie tworzenia projektu jest w zasadzie niemożliwa, tak samo jak zapanowanie nad całym projektem. Weźmy np. wszystko, co masz w folderze pkt_atak. Wszystko, co robią twoje obiekty, to wyświetlają cyfrę - po jednym obiekcie dla każdej cyfry. Zamiast tego, możesz zrobić jeden obiekt, który rysuje za pomocą draw_text() wartość jakiejś zmiennej przypisanej w evencie Create. Co prawda na taki obiekt nie możesz kliknąć, ale wystarczy w evencie Step sprawdzać, czy mysz podczas kliknięcia jest wystarczająco blisko tego obiektu, i na tej podstawie zmieniać wartość tej zmiennej - co uwidoczni się podczas rysowania obiektu. W ten sposób możesz od razu pozbyć się dziewięciu obiektów, oraz zyskujesz funkcjonalność. Obiekty znajdujące się w Player_combat są potwornym przekomplikowaniem czegoś, co można zrobić w zasadzie w jednym obiekcie. Jeżeli tylko masz możliwość, wsadzaj potrzebny kod do jednego obiektu - w ten sposób łatwiej będzie monitorować zmiany w projekcie. Brakuje również komentarzy - przez to, że projekt jest kompletnie nieczytelny, nie jestem w stanie dać żadnej szczegółowej rady dotyczącej tego projektu. Komentuj swój kod.
×
×
  • Dodaj nową pozycję...