Dowolnego, jaki tylko obsługuje Elten, czyli... wav, mp3, ogg, aac, flac, opus, aiff, wma, m4a, pewnie o czymś zapomniałem. Ale ogg jest preferowane, bo po prostu jego implementacja jest najlepiej napisana, tzn. załadowanie ogg do pamięci jest nawet 8-9 razy szybsze od mp3. To niby mała różnica, bo w grę wchodzą milisekundy, ale... ziarnko do ziarnka...
#StandWithUkraine
Shoot for the Moon. Even if you miss, you'll land among the stars.
Oczywiście ograniczeniem i zaletą jest to, że gry będą uruchamiane w środowisku Eltena, na razie tylko jako programy, potem rozważę opcję jakiejś pseudokompilacji, ale i tak będą wymagały zainstalowanego Eltena. Wada to z przyczyn oczywistych, zaleta, bo umożliwi banalnie proste konkurowanie graczy, robienie tablic wyników itp. Pracuję także nad API do tego, które pozwoli prostymi funkcjami na tworzenie tablic osiągnięć itd, a także na komunikację między użytkownikami przez serwer Eltena, bez public IP, to do multiplayerek, ale raczej nie w najbliższej becie.
#StandWithUkraine
Shoot for the Moon. Even if you miss, you'll land among the stars.
Wracam do map na moment. No i do czegoś przyda się Revina. Przekopiowałem jej API do prostego tworzenia obiektów. Obiekty mogą się poruszać, wydawać dźwięk, który się przesuwa zależnie od odległości. Tutaj przykład: map = Map.new(10,10) { object(5,5) { # obiekt na współrzędnych 5,5 sound(appfile("wolf.ogg")) # dźwięk wydawany przez obiekt sound_range(5) # zasięg, z którego obiekt jest słyszany move_type(:random) # jak się porusza: :fixed, :random, :follow range(0) # zasięg, z którego można wejść w interakcje, 0 oznacza stanie na tym samym polu on(:range) { play(appfile("roar.ogg")) # gdy znajdziemy się w zasięgu zdarzenia } on(:touch) { # gdy dotkniemy obiektu } on(:key_enter) { # gdy wciśniemy na nim enter } } }
#StandWithUkraine
Shoot for the Moon. Even if you miss, you'll land among the stars.
Dwa rodzaje timerów, globalne i mapy. Globalne dotyczą wszystkiego:
timer = Timer.new(1, true) { # ten kod będzie wykonywał się co jedną sekundę # aż ktoś nie wywoła timer.stop }
Drugi rodzaj to timery mapy. Powstały, by nie musieć ręcznie zamykać wszystkich timerów (mapa sama je zamyka przy wywołaniu dispose), ale także by móc bez przeszkód otwierać różnego rodzaju menu, zdarzenia itp. ze wstrzymaniem timerów:
timer = @map.timer(0.5, true) { # ten kod będzie wywoływał się co pół sekundy, ale tylko, gdy mapa jest wyświetlana # można zrobić timer.stop albo wyczyścić wszystkie timery komendą @map.clear_timers }
#StandWithUkraine
Shoot for the Moon. Even if you miss, you'll land among the stars.
Napisałem prosty sample, będzie w Eltenie 2.4 Beta 6. Gra to nudna, banalna i o prostej mechanice strzelanka, ale jest przykład. Mamy pistolet i musimy strzelać do spawnujących się potworów. Controlem strzelamy, shiftem przeładowujemy. W trakcie gry pojawiają się na mapie dodatkowe magazynki z amunicją i punkty leczenia. To zasadniczo tyle. Całość zajęła dokładnie 96 linijek.
#StandWithUkraine
Shoot for the Moon. Even if you miss, you'll land among the stars.
Zakończyłem prace nad nowym API, no, prawie. Poniżej wklejam kod przykładowej, małej gierki (98 linijek). To ostatni moment na zgłaszanie wszystkich sugestii, niepewności co do nazw funkcji, składni itp.
Gra to typowy, prosty shooter trwający na mapie o wymiarach 20x20 pól. Co losowy czas między 3 a 8 sekund na mapie pojawia się potwór (w odległości min. 5 pól od gracza) i zaczyna podążać w jego stronę. W losowym czasie między 20 a 40 sekund pojawia się pole lecznicze w losowym miejscu. Po wejściu na nie, te znika, a gracz odzyskuje wszystkie punkty życia i amunicję. Klawiszem shift się przeładowuje, a controlem strzela. Dodatkowo A podaje pozostałą amunicję, H punkty życia, a C ilość zabitych przeciwników. Grę dołączę jako sample do następnej bety. Kod udostępniam celowo bez komentarzy, by sprawdzić jego czytelność, jednak w wypadku niepewności co do którejś linijki proszę o zapytanie. :)
class Program_Shooter < Program Name="Shooter" Author="pajper" Version="1.0" def main menu=Menu.new { option("New game") { return game } option("Game info") { alert("Your goal is to shoot as many enemies as you can before they will defeat you. Simple. Shoot using control key, reload using shift key.") return main } option("Exit") {} } menu.open finish end def game @hp=10 @ammo=10 @loaded=false @killed=0 @map = Map.new(20,20) {|m| m.direction_delay m.direction_sound(appfile("direct.ogg")) m.move_sound(appfile("step.ogg")) m.timer(3..8, true) { x,y=m.random_position(5) m.object(x,y){|o| o.sound(appfile("monster.ogg")) o.move_type(:follow) o.on(:touch, 1) { o.play(appfile("attack.ogg")) @hp-=1 if @hp<=0 m.dispose delay(0.5) alert("You were killed. You have shot #{@killed} monsters.") end } } } m.on(:key_escape) {@map.dispose} m.on(:key_shift) { if @loading!=true if @ammo>0 and @loaded==false @loading=true @ammo-=1 m.timer(0.5) { @loaded=true @loading=false }.start play(appfile("reload.ogg")) end end } m.timer(20..40, true) { x,y=m.random_position m.object(x,y){|o| o.sound(appfile("healing.ogg")) o.sound_range(10) o.on(:touch) { @hp=10 @ammo=10 play(appfile("heal.ogg")) m.delete_object(o) } } } m.on(:key_h) { speak(@hp.to_s) } m.on(:key_a) { speak(@ammo.to_s) } m.on(:key_c) { speak(@killed.to_s) } m.on(:key_control) { if @loaded==true play(appfile("shoot.ogg")) for o in m.objects if m.distance(o.x,o.y)<5 and m.directs?(o.x,o.y) o.play(appfile("fall.ogg")) @killed+=1 m.delete_object(o) break end end @loaded=false end } } @map.show(10,10) return main end end
#StandWithUkraine
Shoot for the Moon. Even if you miss, you'll land among the stars.
Aaaa, miałem jeszcze wyjaśnić kilka możliwych niepewności co do składni Rubiego. Są tam takie linijki, jak:
@map = Map.new(20,20) {|m| albo m.object(x,y){|o|
To taka typowo Rubiowska składnia. Kiedy definiujemy mapę czy obiekt, to słowo w kreseczkach jest nazwą zmiennej, która go będzie zawierała. Gdybyśmy zrezygnowali z tych kresek, moglibyśmy zrobić tak: @map=Map.new(20,20) { move_sound(appfile("move.ogg")) sound_delay }
itd. Tylko wtedy stracilibyśmy możliwość odwoływania się do zmiennych naszego programu. Ta nazwa zmiennej w kreseczkach sprawia, że wywołujemy nasze polecenia w kontekście programu, a do mapy, obiektu itp. odwołujemy się przez jego referencję. Gdyby z nich zrezygnować w tym przykładzie, moglibyśmy stworzyć mapę, przeciwników, ale nie byłoby sposobu, by zapamiętywać ilość amunicji, hp czy też informacji o załadowaniu broni, bo... stracilibyśmy możliwość odniesienia do zmiennych naszego programu. Mam nadzieję, że dość jasno wyjaśniłem.
#StandWithUkraine
Shoot for the Moon. Even if you miss, you'll land among the stars.
Hmm. Ja ze strony użytkownika rozszerzył bym losowość respienia się różnych rzeczy na mapie na przykład do jednej minuty. co by było jeszcze ciekawiej.
Pamiętaj Denisie, że to nie jest faktyczna gra tylko takie demo, które ma pokazać jak się programuje więc w gruncie rzeczy wszelkie wartości czasów, rozmiarów i innych takich mogą być dowolne. Szczerze mówiąc osobiście chciałbym aby możliwe było łatwe implementowanie jakiegoś modelowania dźwięku tj. albo Openall, bo tam jest w cholerę efektów więc jakieś pogłosy czy inne takie możnaby tworzyć względnie prosto, a tego w grach audio rozpaczliwie brakuje, do tego jakiś prosty generator audio przydatny przy różnego rodzaju celownikach czy innych wskaźnikach, bo tego też nie ma, ale obawiam się, że tego raczej nie będzie.
Przy okazji, czy będzie jakaś łatwa możliwość skorzystania z aplikacji zewnętrznych np. konsolowych? Pytam, bo ciągle chodzi mi po głowie ten nieszczęsny konwerterek audio, a w dłuższej perspektywie i edytor, ale jestem na prawdę cienki jeśli chodzi o tworzenie własnych algorytmów więc im łatwiej skorzystać z czegoś, co już jest tym dla mnie lepiej.
EltenAPI nie zajmuje się efektami dźwiękowymi. To znaczy jest zaimplementowanych kilka algorytmów, jest prosta funkcja do odtwarzania dźwięków, plus mapki implementują stereo i zmianę wysokości/głośności. Z zasady jednak implementacja własnego interfejsu dla dźwięku w EltenAPI mija się z celem i tylko komplikowałaby sprawę. Elten wykorzystuje bibliotekę Bass i jej implementacja dla Rubiego jest jak najbardziej do użycia w dowolnym programie, zrobię sample. Ona pozwala na podstawowe rzeczy: stereo panning, wysokość, głośność. Jest też sporo efektów FX. Przyznam, że się nimi nie interesowałem, ale zerknę na nie i umieszczę w Samplu. Ale to Bass, nie Elten API. Są także implementacje OpenAL czy FMOD dla Rubiego i nic nie stoi na przeszkodzie, by ich twórca aplikacji dla Eltena użył, wystarczy dodać do programu odpowiednie pliki i skrypty.
Co do aplikacji konsolowych, mamy Rubiowski interfejs system i potoki w Elten API, można ich najbardziej użyć. Tak Elten komunikuje się np. z Youtube-DL. Klasa ChildProc, też będzie sample.
#StandWithUkraine
Shoot for the Moon. Even if you miss, you'll land among the stars.
Hm, prosty algorytm tych strzałów tam jest. Nawet nie sprawdza, czy aby na pewno ten pseudopocisk poleciał tam, gdzie miał dokłądnie, albo ja jestem ślepy.
@żywek Algorytm jest banalny, ale to tylko sample. Ale sprawdza. Funkcja Map#directs? sprawdza, czy gracz skierowany jest w odpowiednią stronę. Interesują Ciebie te linijki:
m.direction_delay # sprawia, że pierwszy krok w nową stronę odwraca gracza, to znaczy imituje obroty m.direction_sound(appfile("direct.ogg")) # tu jest dźwięk na obracanie się gracza i w implementacji strzału if m.distance(o.x,o.y)<5 and m.directs?(o.x,o.y) sprawdza, czy odległość do obiektu o jest mniejsza niż 5 i czy gracz jest w jego stronę skierowany.
#StandWithUkraine
Shoot for the Moon. Even if you miss, you'll land among the stars.
Jak przeciwnik jest przed graczem mniej-więcej, a gracz patrzy do przodu, strzał trafi. Jak gracz idzie w lewo czy w tył, nie trafi. Oczywiście, strzelanie tu jest banalne i wymaga obrotu mniej-więcej w stronę wroga, bez precyzyjnego kierowania, ale to na potrzeby sample wystarczy. Precyzyjniejszy system byłby do implementacji własnej.
#StandWithUkraine
Shoot for the Moon. Even if you miss, you'll land among the stars.
This site uses cookies to enhance your experience.