Tworzenie prostej animacji elementów 2d na silniku LÖVE

in #pl-artykuly7 years ago

Cześć,
niedawno natrafiłem dosyć przyjemny silnik do tworzenia gier 2D o nazwie LÖVE. Silnik ten pozwala na tworzenie gier używając języka interpretowalnego zwanego LUA. LUA to język podobny do JavaScript i jest on przyjazny osobom, które dopiero zaczynają swoją przygodę z programowaniem. Można napisać tam naprawdę zaawansowane rzeczy w dosyć przyjemny sposób. Można też z silnika 2D zrobić 3D poprzez dodatkowe biblioteki rozszerzające funkcjonalności silnika. Grę można uruchomić praktycznie na każdej platformie.

W tym artykule chciałbym przedstawić wam jak wczytać jakąś teksturę i jak przesuwać obiekty używając czasu. Jak bardziej wkręcę się w ten silnik, to pokażę wam więcej jego możliwości.

Jak już was zachęciłem (bądź nie) do wypróbowania tego silnika, to możecie sobie zainstalować silnik na swoim systemie. Ja zainstaluję go na Windows 10, ale generalne zainstalować można go na dowolnym systemie. Aby pobrać silnik wchodzimy tutaj. Strona z pobraniem wygląda tak

Możecie pobrać instalator albo wersję spakowaną. Decyzja należy do was. Trzeba także wybrać wersję 32 bitową albo 64 bitową. Większość systemów jest już 64 bitowe, ale jak nie wiesz to pobierz 32 bitową wersję. Instalator powinien pozwolić na rozpoznanie plików z rozszerzeniem ".love", który uruchamia grę.

Po instalacji silnika, uruchamiając love.exe powinniśmy zobaczyć

Gdy tak jest, jesteście gotowi do działania.

Jeżeli jesteście na systemie Windows, utwórzcie sobie folder, gdzie będziecie trzymać swoją napisaną grę. Ja stworzyłem go na pulpicie i nazwałem go loveGame. Następnie utwórzmy skrót do programu love.exe, który znajduje się w folerze wskazanym podczas instalacji silnika lub w folderze wypakowanym przez nas. Skrót skopiujmy do naszego folderu z grą.

Następnym krokiem jest stworzenie pliku main.lua, który jest głównym plikiem dla naszej gry. Musimy jeszcze skonfigurować nasz skrót, żeby interpretował naszą grę poprzez love.exe. Aby to zrobić kliknijmy prawym klawiszem na skrót i wybierzemy opcję Właściwości. Powinniśmy widzieć coś takiego

W polu Element docelowy mamy ścieżkę do interpretera silnika. Aby silnik interpretował naszą grę, po znaku " dodajmy ścieżkę do folderu z plikiem main.lua. To pozwoli na bezpośrednie interpretowanie naszej gry. Możliwości uruchomienia gry jest wiele, ale na razie ten sposób jest prosty i wystarczy.
Po dodaniu ścieżki, powinniśmy mieć coś takiego

Gdy tak zrobiliśmy klikamy OK.

Przejdźmy teraz do tworzenia "gry".

Będziemy potrzebowali trzech podstawowych funkcji udostępnionych przez silnik LÖVE:

function love.load() -- wczytywanie
 
end

function love.update(dt) -- aktualizacja co klatkę
  
end

function love.draw() -- rysowanie co klatkę
 
end

funkcja love.load uruchamia się przy starcie gry, love.update aktualizuje nasze dane co każdą klatkę a funkcja love.draw służy do rysowania co klatkę. Gry standardowo mogą mieć 30 klatek na sekundę, 60 klatek na sekundę albo tyle ile nasz komputer ogarnie.

Teraz kilka informacji o składni jaką wykorzystamy tutaj. Pierwsza to taka, że komentarz oznaczamy poprzez -- komentarz. Tworzenie if-ów wygląda tak

if(x < 10) then
-- jakaś instrukcja
end

Instrukcje nie kończą się średnikiem ;.
Każda zmienna jest globalna, chyba, że ma przedrostek local.
Funkcję tworzymy tak

function nazwa()

end

Po tym szybkim kursie zacznijmy od implementacji naszej gry.

Zacznijmy od wczytywania danych.

Potrzebujemy wczytać jakąś teksturę, pozycję początkową x dla obiektów, długość prostokąta, szerokość okna, prędkość przesuwania obiektów i jakieś obliczanie granicy do "odbijania" obiektów. Wszystko to zrobimy w funcji love.load

function love.load()
    x = 0 
    speed = 150
    crateWidth = 200;
    crateImg = love.graphics.newImage("crate.png")
    windowWidth = love.graphics.getWidth()
    border = windowWidth - crateWidth
end

Nie będę tutaj się rozbijał krokami i zrobię kilka kroków naraz.

Zmienna x przechowuje pozycję startową obiektów. speed przechowuje prędkość przesuwania obiektów, crateImg przechowuje obiekt wczytanego obrazka nazwanego crate.png. Do wczytania wykorzystałem metody love.graphics.newImage, której parametrem jest ścieżka do obrazka. Obrazek wczytałem tej strony. Następnie pobrałem szerokość okna do zmiennej windowWidth a na końcu obliczyłem granicę dla naszego prostokąta. Jest to potrzebne, aby nie odbijać się na lewej granicy prostokąta, tylko na prawej stronie prostokąta. Zobaczycie o co mi chodzi w dalszej części artykułu.

Następnie wypadałoby rysować nasze obiekty. Możemy to zrobić w funkcji love.draw w następujący sposób

function love.draw()
    love.graphics.rectangle("line", x, 50, 200, 150)
    love.graphics.draw(crateImg, x, 200)
end

W powyższym kodzie wykorzystaliśmy metodę love.graphics.rectangle, która rysuje prostokąt bez wypełnienia (parametrline albo fill). Pozycja x prostokąta ma wartość w zmiennej x. Ta zmienna zmienia się przy każdej klatce w określonym czasie. Wartość 50 to pozycja y. Natomiast 200 to width - długość a 150 to height - wysokość. Jeżeli chodzi o metodę love.graphics.draw, to rysuje ona nam teksturę na pozycji x dynamicznie ustawianej oraz współrzędnej y o wartości stałej wynoszącej 200.

Pozostało nam teraz obliczanie pozycji obiektów i przesuwanie ich

function love.update(dt)
    change = false
    
    if(x < 0) then
        speed = -speed
    end
    if(x > border) then
        change = true
    end
    if(change) then
        speed = -speed
        change = false
    end
    x = x + speed * dt
end

Nie jest to najpiękniejszy kod, ale generalnie powoduje odbicie obiektów jeżeli współrzędna x dojdzie do początku lub końca okna. Najważniejsza jest ostatnia linijka x = x + speed * dt, która decyduje o obecnej pozycji obiektów. Parametr dt odpowiada za czas jaki zajmuje komputerowi na wygenerowanie klatki. To generalnie potrzebne jest, żeby gra działała identycznie na szybkich i wolnych komputerach, gdzie liczba klatek może być różna. Jeżeli zmienna speed posiada ujemną wartość, obiekty przesuwają się w odwrotnym kierunku. Jak widzimy, wykorzystujemy tu zmienną border, ponieważ gdybyśmy zamiast tego wzięli długość okna, to obcięłoby nam nasz narysowany prostokąt podczas przesuwania w prawo.

Jeżeli chodzi o obrazek "crate.png". Jeżeli pobraliście go z tej strony co podałem, to upewnijcie się, że obrazek ma odpowiednią nazwę jak w kodzie oraz, że jego wielkość jest równa 32 piksele na 32 piksele. Tak przynajmniej ja ustawiłem i wy tak możecie zrobić. Zmienić wielkość obrazka możecie nawet w paincie.

To teraz czas uruchomić naszą grę używając skrótu stworzonego na samym początku. Naszym oczom powinno wyjść coś takiego

Powinny poruszać się równocześnie dwa obiekty. Jest tak, ponieważ ich współrzędna x jest identyczna. Jedyna różnica to pozycja y.

Jeżeli chcecie jeszcze łatwiej uruchamiać grę, to możecie wziąć teksturę i main.lua, i skompresować to do pliku nazwaPliku.love. Dzięki takiemu wyjściu, jeżeli zainstalowaliście silnik, możecie uruchomić grę bezpośrednio dwukrotnie klikając na plik lewym klawiszem myszy.

Możecie także zainstalować silnik
na androidzie i wrzucić pliki naszej gry do folderu /sdcard/lovegame (główny katalog telefonu. Jak nie ma folderu lovegame, to trzeba go stworzyć). Następnie uruchomić aplikację, która powinna wyświetlić naszą grę.

Jest to skrótowa wersja artykułu, ale jak widzicie, przy niewielkiej pracy możecie stworzyć coś "w miarę" sensownego. Jeżeli wam się spodoba, to przygotuję coś bardziej użytecznego. Pamiętajcie o dokumentacji zawartej tutaj, ponieważ macie tam wszystko co potrzeba. Są tam także różne poradniki, które pozwolą wam na stworzenie czegoś fajnego.

Sort:  

Ogólnie wolę Enigmę niż Love2D. Po pierwsze nie ma żadnej kompatybilności wstecznej. Praktycznie co wersję jest regres. Po drugie brak IDE, w zasadzie wszystko robi się kodem, to może być wada.

Ale jak działa komuś ... :D

Brak IDE to nie jest jakaś tragedia. Silnik wyświetla błędy, gdy takie występują, mały jest próg wejścia. A co do kompatybilności wstecznej, to chyba zależy od wykorzystywanego api. Niektóre funkcjonalności są na nowszą wersję silnika, co może być problemem, ale niczym specjalnie trudnym do rozwiązania.

Nom, ale są też regresy w samych funkcjach. Na przykład screenshoty od 0.10 można robić tylko w PNG, a kiedyś w każdym formacie. Musiałem lekko przerobić mój "card generator" do gry (bo gra przyjmuje JPG)