Skocz do zawartości

Konrad-GM

Użytkownicy
  • Postów

    2 728
  • Dołączył

  • Ostatnia wizyta

  • Wygrane w rankingu

    44

Treść opublikowana przez Konrad-GM

  1. Polecam odświeżyć sobie podstawy z fizyki newtona Przypisz każdemu obiektowi co ma masę wektor prędkości liniowej (np. stwórz wektor linear_velocity). Posługuj się przyśpieszeniem grawitacyjnym i dodawaj do tej zmiennej (wektora) wartość przyśpieszenia co step pomnożoną przez delta_time. Wzór ogólny dla przyśpieszenia grawitacyjnego: - warto chociaż przejrzeć https://pl.wikipedia.org/wiki/Przyspieszenie_grawitacyjne Żeby obliczyć dla każdego obiektu przyciąganie, możesz posłużyć się opcją z with, np. var gc = 0.0000000000667408 // 6.67408E-11, stała grawitacyjna with (obj_asteroid) { if (other.id == id) { continue; } // zakladamy rowniez, ze (x,y) to srodek masy obiektu var r = point_distance(x, y, other.x, other.y) var r2inv = 1.0 / (r * r); var accel = gc * mass * r2inv * delta_time other.linear_velocity_x += accel; other.linear_velocity_y += accel; } Potem tylko już aplikujemy ruch: x += linear_velocity_x * delta_time; y += linear_velocity_y * delta_time;
  2. Konrad-GM

    Sezon #2, Tura #1

    W sumie mam kilka gier z bundli, Samorost 3, Warhammer: End Times - Vermintide z jakimś DLC, Verdun a nawet Solstice i jeszcze parę - z możliwością wysłania jako gift na steam, nawet mam Game Maker Studio 1 Pro z Android Exportem. Ale to stary GM , to nie wiem, czy się nadaje na ligę. Bundle kupowałem specjalnie dla jakichś pojedynczych gier czy eksportów do GMa, więc większość kluczy nawet nie aktywowałem i nie wiem do końca, co w nich jest, musiałbym jeszcze przejrzeć. Też nie wiem, jak jest z żywotnością tych kluczy na steam, czy nie przedawniają się po jakimś czasie.
  3. Konrad-GM

    Sezon #2, Tura #1

    Przyznam, że to "gra żart", ale super, że się koncept spodobał. Chociaż miałem okazję przetestować Godot 3.1 Beta. BTW widziałem też, że w akademii jest sekcja Godot, może udałoby mi się napisać jakiś artykuł bądź dwa. Ja zagłosowałem natomiast na grę @Uzjel, ciekawie wygląda, fajny klimat a i fajnie się gra, do tego bonusy, chociaż brakuje oddzielnego licznika punktacji ogólnej, bo za wszystko się płaci punktami. Gra @Korodzik też jest super, pewnie jakby nie wyświetlanie punktów w tabeli podczas głosowania, zagłosowałbym na tę grę, ale IMO podium dla @Uzjel też się należy za fajną grę Bonus: mały hack w grze @SLy setInterval(() => { Array.from(document.getElementsByClassName('clown')).forEach(clown => clown.click()) }, 250) Fajnie, że liga ożyła, oby tak było co najmniej do następnego sezonu
  4. Cześć, najłatwiej byłoby po prostu dla każdej jednostki z oddziału "zapamiętać" z jakiego spawna pochodzą. Po prostu zrobić jakiś prosty licznik i sprawdzać, czy został on wyzerowany: W obiekcie powiedzmy obj_spawn dodajesz zmienną w Create Event: units_alive = 0; Potem przy tworzeniu jednostki obj_unit nadać mu dodatkowo ID instancji obj_spawn jako "pochodzenie", np. w obiekcie obj_spawn w User Event 0 dać coś takiego: // tworzymy instancje jednostki var unit = instance_create(x, y, obj_unit); unit.spawn_id = id; // dodajemy jednostke do licznika units_alive += 1; A na koniec w obiekcie obj_unit w Destroy Event wystarczy dekrementować licznik powiązanej instancji obj_spawn: spawn_id.units_alive -= 1; Potem sprawdzenie ile jednostek pozostało żywych jest chyba oczywiste
  5. Możesz jeszcze użyć dezaktywacji obiektów, ale trzeba pamiętać, aby obiekt popup-a był aktywny, bo inaczej nie będzie można wrócić do gry W Create Event obiektu obj_popup daj taki kod: instance_deactivate_all(); instance_activate_object(obj_popup); Ale pamiętaj też o aktywacji obiektów po zniknięciu komunikatu, np. w Event Destroy obiektu obj_popup daj: instance_activate_all(); Edit: GameMaker nie udostępnia funkcji do przetworzenia zdarzeń systemowych -> pętla w grze po prostu Ci nie zadziała, bo nie będziesz w stanie obsłużyć żadnego kliknięcia, nawet krzyżyka na belce okna. Jeżeli pisałeś kiedykolwiek aplikacje na Windowsa, to jest tam taka funkcja jak GetMessage/PeekMessage, GameMaker nie udostępnia swojego odpowiednika Pętla musiałaby wyglądać tak: 1. obsłuż zdarzenia systemowe 2. jezeli nacisniete esc lub myszka na ok skocz do 6<- tutaj można sprawdzić, czy esc/myszka została naciśnięta bo zdarzenia systemowe zostały zinterpretowane 3. wyswietl napis 4. swap buffers - wyświetl na ekran wygenerowany obraz 5. skocz do 1 6. <kontynuuj program> Ale w GameMakerze jest to niemożliwe. Przynajmniej nie znalazłem funkcji do obsługi systemowych zdarzeń.
  6. Cześć, musisz przyblokować wykonywanie się kodu innym obiektom, pętla while Ci nie zadziała ze względu na to, jak działa pętla główna Game Makera. Jak używasz pętli while, to GameMaker nie przetwarza systemowych zdarzeń jak np. kliknięcie myszką czy klawisza. Żeby przyblokować wykonywanie kodu w obiektach, możesz stworzyć np. zmienną globalną jak: global.is_paused = false; A potem w każdym z obiektów w Step Event, przed blokiem całego kodu dodaj po prostu taką linijkę: if (global.is_paused) exit; Jak chcesz zapałzować grę, to po prostu ustawiasz zmiennej global.is_paused na true, analogicznie odblokowujesz grę po ustawieniu global.is_paused na false.
  7. Bezszwowe tekstury to normalna praktyka by się pozbyć tego efektu, ale czasami to nie wystarcza, zwłaszcza jak się podzieli teksturę na mniejsze elementy, bo po prostu limit rozmiaru tekstury nie pozwala na to. Efekt co prawda nie jest idealny, ale można i z tym powalczyć, np. przekopiowując krańce tekstury z tekstury sąsiadującej. Coś na zasadzie dodawania 1px obramowania do sprite'ów w atlasie tekstur, żeby też ominąć te brzydkie łączenia z sąsiednim spritem. (w 3D tekstura musi być rozmiaru potęgi dwójki, dlatego np. 2050px odpada i trzeba obraz skalować)
  8. Ważne, że działało i dawało zadowalające efekty, tyle, że to takie mini-piekło dla perfekcjonisty Jednak ten problem z interpolacją dotyczy każdego silnika czy biblioteki graficznej, brak shaderów czy chociaż podstawowych ustawień tekstur to już rzeźnia po prostu. Ale warto wiedzieć jak sobie radzić z takimi problemami gdy ogranicza narzędzie
  9. Cześć, problem z interpolacją tekstur jest jak najbardziej "normalną" odpowiedzią od karty graficznej, generalnie ten problem występuje od zawsze, odkąd istnieje interpolacja sampli. Jednym z rozwiązań jest wyłączenie powtarzalności tekstur np. w OpenGL jest to ustawienie w teksturze flagi GL_TEXTURE_WRAP_S/T na GL_CLAMP_TO_EDGE, jednak GameMaker nie udostępnia takowych funkcji Przykładowe ustawienia wrap-owania tekstur w OpenGL (opcje te występują również w DirectX); W Twoim przypadku GameMaker prawdopodobnie ustawia teksturom odpowiednik GL_REPEAT w DirectX, dlatego pojawiają Ci się te "artefakty" na krańcach tekstury. Dodatkowo każda tekstura musiałaby być "stworzona" jako oddzielna tekstura w VRAM, atlas tekstur nie zadziała, jak to się dzieje w przypadku GMS1.4+ (tzw. grupy obrazków w ustawieniach GMa, ale da się to akurat ominąć). Więc w skrócie problem polega na tym, że interpolacja sampli w fragment shaderze miesza sąsiadujące kolory, tworząc tzw. texel, jak się pewnie domyślasz, artefakty które pojawiają Ci się na krańcach modelu podłogi to po prostu zmieszane kolory z drugiego krańca tekstury, dlatego też warto czasami używać tekstur seamless Po więcej teorii dot. tekstur i metod samplowania odsyłam do https://cglearn.eu/pub/computer-graphics/textures-and-sampling Jako, że nie możemy wyłączyć powtarzalności tekstur, można za to wykluczyć krańce tekstury z samplowania, efekt nie jest idealny, ale nie ma tak oczojebnych artefaktów. Przykład poniżej: Jednak aby wykluczyć krańce tekstury w GMie, trzeba stworzyć własny model podłogi, bo draw_floor nie udostępnia funkcji do modyfikacji UV per vertex, ani GameMaker 8.0 nie wspiera shaderów. Kod obj_floor w Create Event u mnie wygląda tak: // tworzymy model podlogi tylko raz i przypisujemy model do zmiennej globalnej if (!variable_global_exists("model_floor")) { // obliczamy polowe texela tekstury do wykluczenia go z sampla // teraz kazdy kafelek Twojej podlogi musi miec taka sama wielkosc var u, v; u = (1.0 / background_get_width(texTile)) * 0.5; v = (1.0 / background_get_height(texTile)) * 0.5; // szerokosc i dlugosc podlogi var w, h; w = 64; h = 64; // tworzymy model podlogi (tylko raz) global.model_floor = d3d_model_create() d3d_model_primitive_begin(global.model_floor, pr_trianglefan); d3d_model_vertex_texture(global.model_floor, 0, 0, 0, 0.0 + u, 0.0 + v); d3d_model_vertex_texture(global.model_floor, w, 0, 0, 1.0 - u, 0.0 + v); d3d_model_vertex_texture(global.model_floor, w, h, 0, 1.0 - u, 1.0 - v); d3d_model_vertex_texture(global.model_floor, 0, h, 0, 0.0 + u, 1.0 - v); d3d_model_primitive_end(global.model_floor); } // tekstura podlogi texid = background_get_texture(texTile); Natomiast obj_floor i Draw Event: d3d_model_draw(global.model_floor, x, y, 0, texid); Można też poprawić wygląd łączeń, ale tutaj jest trochę więcej roboty - musiałbyś zeskalować tekstury powiedzmy z 2048 do 2046 na środek i te wolne piksele na krańcach przekopiować z sąsiadujących ze sobą tekstur (tekstura nadal musi mieć 2048px).
  10. Pomysł @gnysek może się sprawdzić, ale zamiast with i place_meeting spróbuj użyć collision_circle w step event obj_pocisk: var potwor = collision_circle(x, y, 8, obj_potwor, true, true); if (potwor != noone) { if (z < 24) { with (potwor) { instance_destroy(); } } } Wartość parametru rad = 8 możesz modyfikować wedle uznania, żeby dostosować promień kolizji.
  11. W poprzednim temacie napisałem co można by zrobić, ale powtórzę: BTW. Nazwa tematu nie jest dostatecznie opisowa.
  12. Cześć, funkcja collision_circle (jak każda funkcja zaczynająca się od collision_*) zwraca ID instancji, także other Ci tutaj nie zadziała. Musisz zapisać ID do zmiennej tj. var potwor = collision_circle(x, y, 100, obj_potwor, false, true); while (potwor != noone) { with (potwor) { instance_destroy(); } potwor = collision_circle(x, y, 100, obj_potwor, false, true); } Dałem funkcję w pętli, ponieważ funkcje collision_* zwracają Ci tylko ID jednej instancji. Dla GMS1.4+ zamiast with(potwor) można zapisać instance_destroy(potwor)
  13. Dokładnie, bez sensownego mierzenia wydajności, jakakolwiek próba optymalizacji nie ma sensu, bo może to być zwykłą stratą czasu. Edit: Na szybko sprawdziłem, czy zmiana visible połowy sprite na false ma jakiś wpływ na FPS - i nie ma żadnego, FPS tak samo niski jaki był
  14. IMO przedwczesna optymalizacja też jest zła, optymalizuj rysowanie sprite, kiedy faktycznie będzie miało to wpływ na wydajność Przejrzyj może artykuł dot. optymalizacji na Yoyo, jest tam kilka wzmianek o optymalizacji rysowania spritów.
  15. To też nie do końca prawda, odrzucane są trójkąty podczas renderingu, po vertex shaderze (Vertex Post-Processing). Także żeby zminimalizować draw call'e, które też mają wpływ na wydajność, stosuje się własny clipping. Podejrzewam, że o to chodziło autorowi
  16. Widzę, że wkraczasz w bardziej złożone kwestie z programowaniem fizyki w grach Podejrzewam, że problem jest z dużą ilość wrogów na mapie - albo użyj dezaktywacji obiektów poza pewnym rejonem dookoła gracza funkcjami z rodziny instance_(de)activate_*, albo porzuć stosowanie flagi solid i oprogramuj swoją obsługę kolizji w Collision Event-ach. Nie mam pojęcia, jak GameMaker obsługuje kolizje i czy stosuje coś na wzór spatial partitioning - quadtree, spatial hash itp., może ktoś bardziej obeznany w tych kwestiach z GMem by podpowiedział. Ale mógłbyś też posilić się własną implementacją sprawdzania kolizji używając quadtree czy prostszym w implementacji spatial hashing (quadtree vs spatial hashing). PS. Możesz skrócić swój kod with(obj_potwor) do with(obj_potwory) ustawiając wrogom tego samego rodzica parent obj_potwory.
  17. Też raczej bym się tym nie przejmował, jak zrobisz interesującą grę, to więcej osób po prostu ją pobierze (co jest chyba ważniejsze). Zamiast tracić czas na implementację *byle* zabezpieczeń (które i tak można złamać) to poświęć ten czas na jakiś fajny feature w grze Ale żeby nie odchodzić od tematu kompletnie bez rozwiązania żadnego, to można zastosować jakieś proste triki jak np. oszukiwać gracza "hakera" o wartościach zmiennych, np. złoto w grze byłoby przesunięte o 3 bity, co dawałoby kompletnie inne wartości w Cheat Engine (potem trzeba tego pilnować przy odczycie/zapisie ilości złota!), albo użyć coś na wzór XOR-owania zmiennych przed i po zapisie w pamięci RAM. Albo jak gnysek wspomniał, użyj hashowania zmiennych kluczowych, ale też w pamięci gry, a jak ktoś Cheat Enginem spróbuje je zmienić, to hash się nie będzie zgadzał przed np. odczytem ilości złota albo dodatków. Wtedy będziesz mógł obsłużyć próbę "zhakowania" gry i odczytać te zmienne np. z zaszyfrowanego save-a.
  18. Cześć, GameMaker Studio 1.4 tworzy backupy w katalogu %USERPROFILE%\Documents\GameMaker\Backups (ustawienia standardowe), generalnie polecam używać jakiś VCS jak np. Git.
  19. W większości przypadków self praktycznie Ci się nie przyda, osobiście sam nie stosowałem tego rodzaju odwołania i nie potrafię powiedzieć, do czego byłoby to użyteczne, ponieważ i tak blok kodu jest wykonywany w kontekście self.
  20. Mam wrażenie, że nie przeczytałeś tego co napisał @I am Lord Średnik ';' służy tylko do oddzielania wyrażeń, także jeżeli napiszesz dwa wyrażenia w jednej linii oddzielając je średnikiem, to nie ma to żadnego znaczenia, poza formatowaniem kodu. Także w Twoim przypadku zmienna 'z' będzie zmieniona w instancji obiektu obj_pocisk.
  21. Jeżeli w obiekcie obj_pocisk, stworzysz event Collision Event z obiektem obj_wrog, to ten kod: z = 10; Będzie dotyczyć instancji obiektu, w którym ten event (kod eventu) jest wykonywany. W tym wypadku będzie to instancja obiektu obj_pocisk. Aby odwołać się do instancji obiektu obj_wrog, używasz referencji other, tj. other.z = 10; Dodatkowo, w GM jak edytujesz skrypt, to w belce edycji jest taka opcja jak Applies To. Jeżeli zaznaczysz np. opcję Other, to cały kod będzie objęty tak jakby blokiem with: with(other) { <kod_skryptu> } Nie polecam tej opcji, utrudnia tylko czytanie kodu, także warto mieć to na uwadze, żeby z tej opcji nie korzystać.
  22. @LionX Dagger robił grę o kucach, zapewne chodzi o NHFEA, to też muszę przyznać, że styl mógł się skojarzyć
  23. Cześć, mi to wygląda na to, że Twój obiekt obj_krew nie ma zmiennej 'z'. Zmienne przeważnie tworzy się w Create Event, bo jest to event, który jest wykonywany wraz z funkcją instance_create i potem te zmienne są dostępne w referencjach na instancję zaraz po jej stworzeniu (np. "other.zmienna = 10", czy "var inst=instance_create(x,y,obj_krew); inst.zmienna = 10"). Artykułów dot. zmiennych na GMClan jest kilka, np. https://gmclan.org/index.php?czytajart=30 , przejrzyj listę artykułów na stronie https://gmclan.org/index.php?artykuly=17 mogą Ci się przydać w zrozumieniu zmiennych, argumentów, funkcji, operacji na nich itd. EDIT: v
  24. Wyrażenie other jest tak jakby referencją na instancję, także każdy parametr instancji jest dostępny poprzez other.parametr_instancji, polecam przejrzeć dokumentację: https://docs.yoyogames.com/source/dadiospice/002_reference/001_gml language overview/keywords.html
  25. Jeżeli używasz tego kodu na obj_pocisk co Ci przesłałem, to ten pocisk nie używa zmiennej direction, dlatego direction zawsze będzie równe 0. Spróbuj odczytać kierunek pocisku od jego zmiennych motion_xyz. Jest to wektor lotu pocisku i można za jego pomocą policzyć wektor normalny w którym kierunku leci pocisk na płaszczyźnie 2D tj.: // normalizujemy wektor 2D motion_xy var motionlen = sqrt(other.motion_x*other.motion_x + other.motion_y*other.motion_y); var xdir = other.motion_x / motionlen; var ydir = other.motion_y / motionlen; // teraz przesuwamy wroga x += xdir * 5; y += ydir * 5;
×
×
  • Dodaj nową pozycję...