Tworzenie prostej animacji elementów 2d na silniku LÖVE
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.
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)