Lua Academy · Lekcja

Ruch i kolizje

Stworzy Pan/Pani grywalną scenę.

Lekcja 4 z 413 kroki

Ruch i kolizje to bezpłatna lekcja Lua Academy na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Lua Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Lua Academy zawiera 4 lekcji w sumie.

Pozycja i prędkość

Ruch w LÖVE polega na zmienianiu pozycji obiektu w czasie. Należy przechowywać wartości x i y, a następnie dodawać prędkość w love.update, skalując ją za pomocą dt.

Przechowywanie prędkości jako dx i dy na sekundę ułatwia obsługę ruchu po przekątnej i fizyki oraz uniezależnia je od liczby klatek.

function love.update(dt)
  player.x = player.x + player.dx * dt
  player.y = player.y + player.dy * dt
end

Ruch sterowany danymi wejściowymi

Odpytywanie należy połączyć z prędkością, aby sterować obiektem. W love.update trzeba odczytywać klawisze kierunkowe i stosować iloczyn prędkości oraz dt.

Ponieważ love.keyboard.isDown jest sprawdzane w każdej klatce, gracz porusza się płynnie tak długo, jak długo klawisz jest wciśnięty.

function love.update(dt)
  if love.keyboard.isDown('left') then player.x = player.x - player.speed*dt end
  if love.keyboard.isDown('right') then player.x = player.x + player.speed*dt end
end

Normalizacja prędkości ruchu po przekątnej

Naciśnięcie jednocześnie dwóch klawiszy kierunkowych powoduje szybszy ruch po przekątnej, ponieważ obie osie dodają pełną prędkość. Aby temu zapobiec, należy znormalizować wektor ruchu.

Należy podzielić kierunek przez jego długość, aby jego długość wynosiła 1, a następnie pomnożyć go przez prędkość. Dzięki temu ruch po przekątnej ma taką samą prędkość jak ruch w linii prostej.

local dx, dy = ix, iy
local len = math.sqrt(dx*dx + dy*dy)
if len > 0 then
  player.x = player.x + (dx/len) * player.speed * dt
end

Utrzymywanie obiektów na ekranie

Należy ograniczyć pozycję, aby obiekty pozostawały na ekranie. Rozmiar okna można odczytać za pomocą love.graphics.getWidth i getHeight, a następnie ograniczyć współrzędne do odpowiedniego zakresu.

Połączenie funkcji math.max i math.min pozwala w prosty sposób ograniczyć wartość do zakresu między minimum a maksimum.

local w = love.graphics.getWidth()
player.x = math.max(0, math.min(player.x, w - player.size))

Prostokąty ograniczające wyrównane do osi

Najprostsze kolizje wykorzystują prostokąty, nazywane AABB (axis-aligned bounding boxes). Każdy obiekt ma wartości x, y, szerokość i wysokość.

Dwa prostokąty nakładają się, gdy przecinają się jednocześnie na osi poziomej i pionowej. To sprawdzenie jest szybkie i wystarczające dla większości gier 2D.

-- box: { x, y, w, h }

Test nakładania się AABB

Dwa prostokąty nakładają się, gdy na żadnej z osi jeden z nich nie znajduje się całkowicie za drugim. Klasyczny test łączy cztery porównania.

Jeśli wszystkie cztery warunki są spełnione, prostokąty się przecinają. Ten pojedynczy warunek stanowi podstawę wykrywania kolizji w grach 2D.

function overlaps(a, b)
  return a.x < b.x + b.w and
         b.x < a.x + a.w and
         a.y < b.y + b.h and
         b.y < a.y + a.h
end

Reagowanie na kolizję

Gdy overlaps zwróci wartość true, należy zdecydować, co ma się wydarzyć: podnieść monetę, otrzymać obrażenia lub zatrzymać ruch. Kolizje należy sprawdzać w love.update po wykonaniu ruchu.

W przypadku przedmiotów do zebrania wystarczy usunąć przedmiot lub zwiększyć wynik. W przypadku litych ścian należy wypchnąć gracza z powrotem na zewnątrz.

function love.update(dt)
  movePlayer(dt)
  if overlaps(player, coin) then
    score = score + 1
    coin.dead = true
  end
end

Kolizje okręgów

W przypadku okrągłych obiektów dokładniejsze jest wykrywanie kolizji na podstawie odległości. Dwa okręgi kolidują, gdy odległość między ich środkami jest mniejsza niż suma ich promieni.

Porównywanie kwadratów odległości pozwala uniknąć kosztownego obliczania pierwiastka kwadratowego. Jest to często stosowana optymalizacja podczas sprawdzania wielu obiektów.

function circlesHit(a, b)
  local dx, dy = a.x - b.x, a.y - b.y
  local rsum = a.r + b.r
  return dx*dx + dy*dy < rsum*rsum
end

Rozwiązywanie kolizji ze ścianami

Aby zatrzymać gracza przy ścianie, można poruszać nim osobno wzdłuż każdej osi i cofać krok powodujący nakładanie się obiektów.

Należy przesunąć obiekt w osi x i sprawdzić kolizję; jeśli wystąpi, cofnąć zmianę x. Następnie należy powtórzyć to samo dla osi y. Rozwiązywanie kolizji osobno dla każdej osi zapobiega blokowaniu się na rogach.

player.x = player.x + vx * dt
if overlaps(player, wall) then player.x = player.x - vx * dt end
player.y = player.y + vy * dt
if overlaps(player, wall) then player.y = player.y - vy * dt end

Stosowanie grawitacji

Gry platformowe dodają stałe przyspieszenie w dół. W każdej klatce należy zwiększyć prędkość pionową o iloczyn grawitacji i dt, a następnie zastosować prędkość do pozycji.

Gdy gracz wyląduje na ziemi, należy wyzerować jego prędkość pionową, aby zatrzymać spadanie. Skok nadaje prędkości pionowej wartość ujemną.

function love.update(dt)
  player.dy = player.dy + GRAVITY * dt
  player.y = player.y + player.dy * dt
end

Usuwanie nieaktywnych obiektów

Po kolizjach często trzeba usuwać obiekty. Należy iterować po liście od końca i wywoływać table.remove, aby indeksy pozostały prawidłowe podczas usuwania.

Iterowanie od końca to bezpieczny idiom Lua służący do usuwania elementów w środku pętli. Zapobiega pomijaniu elementów, do którego doszłoby podczas iterowania od początku.

for i = #coins, 1, -1 do
  if coins[i].dead then
    table.remove(coins, i)
  end
end

Szybki test

Sprawdź swoje zrozumienie ruchu i kolizji w LÖVE.

Podsumowanie

Ruch łączy pozycję, prędkość i dt, a normalizacja zapewnia równą prędkość ruchu po przekątnej, zaś ograniczanie utrzymuje obiekty na ekranie. Wykrywanie kolizji zaczyna się od testów nakładania AABB, a w przypadku okrągłych obiektów stosuje się sprawdzanie odległości.

Kolizje ze ścianami należy rozwiązywać przez cofanie ruchu osobno dla każdej osi, w grach platformowych dodać grawitację, a nieaktywne obiekty usuwać, iterując od końca za pomocą table.remove.

Bezpłatny start

Ucz się Lua dzięki korepetycjom AI — za darmo

Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.

Kursy
40
Lekcje
159

Często zadawane pytania

Czy lekcja „Ruch i kolizje” jest bezpłatna?

Tak — pełny tekst „Ruch i kolizje” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Lua Academy, przejdź na CoddyKit PRO. Kurs Lua Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Ruch i kolizje”?

Stworzy Pan/Pani grywalną scenę. Ćwiczysz Lua Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Lua Academy?

Nie wymagamy żadnego doświadczenia. Lua Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.

Ile czasu zajmuje lekcja „Ruch i kolizje”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Lua Academy?

Tak. Każda lekcja Lua Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Pętla gry LOVE
  2. Rysowanie kształtów i obrazów
  3. Obsługa wejścia
  4. Ruch i kolizje
← Powrót do Lua Academy