0Pricing
Lua Academy · Урок

Движение и столкновения

Создайте игровую сцену.

«Движение и столкновения» — бесплатный урок Lua Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Lua Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Lua Academy содержит 4 уроков всего.

Положение и скорость

Движение в LÖVE означает изменение положения объекта с течением времени. Храните x и y, а затем прибавляйте скорость в love.update, умноженную на dt.

Хранение скорости как dx и dy в единицах за секунду упрощает движение по диагонали и физику, не зависящими от частоты кадров.

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

Движение под управлением ввода

Объедините опрос с использованием скорости, чтобы управлять объектом. Считывайте клавиши направления в love.update и применяйте скорость, умноженную на dt.

Поскольку love.keyboard.isDown проверяется в каждом кадре, игрок плавно движется, пока клавиша удерживается.

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

Нормализация скорости по диагонали

Одновременное нажатие двух клавиш направления делает движение по диагонали более быстрым, поскольку обе оси добавляют полную скорость. Чтобы исправить это, нормализуйте вектор движения.

Разделите направление на его длину, чтобы его модуль стал равен 1, а затем умножьте результат на скорость. Теперь движение по диагонали соответствует движению по прямой.

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

Удержание объектов в пределах экрана

Ограничивайте положение, чтобы объекты оставались на экране. Получите размеры окна с помощью love.graphics.getWidth и getHeight, а затем ограничьте координаты.

math.max и math.min вместе аккуратно ограничивают значение диапазоном от минимума до максимума.

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

Ограничивающие прямоугольники, выровненные по осям

Самый простой способ обнаружения столкновений использует прямоугольники, называемые AABB — ограничивающие прямоугольники, выровненные по осям. У каждого объекта есть x, y, ширина и высота.

Два прямоугольника перекрываются, когда они одновременно пересекаются по горизонтальной и вертикальной осям. Такая проверка выполняется быстро и подходит для большинства двумерных игр.

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

Проверка перекрытия AABB

Два прямоугольника перекрываются, если ни по одной из осей левый край одного не расположен правее правого края другого. Классическая проверка объединяет четыре сравнения.

Если все четыре условия истинны, прямоугольники пересекаются. Это единственное условие — рабочая основа обнаружения столкновений в двумерных играх.

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

Реакция на столкновение

Как только overlaps возвращает значение true, определите дальнейшее действие: подобрать монету, получить урон или остановить движение. Проверяйте столкновения в love.update после перемещения.

Для предметов, которые можно подобрать, просто удалите предмет или увеличьте счёт. Для твёрдых стен вытолкните игрока обратно наружу.

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

Столкновения кругов

Для круглых объектов точнее использовать столкновения на основе расстояния. Два круга сталкиваются, когда расстояние между их центрами меньше суммы их радиусов.

Сравнение квадратов расстояний позволяет избежать затратного вычисления квадратного корня, что часто оптимизирует проверку множества объектов.

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

Разрешение столкновений со стенами

Чтобы остановить игрока у стены, можно перемещать его отдельно по каждой оси и отменять шаг, вызвавший перекрытие.

Переместите по x и проверьте; если произошло столкновение, верните прежнее значение x. Повторите для y. Такое разрешение по отдельным осям предотвращает застревание в углах.

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

Применение гравитации

В платформерах добавляется постоянное ускорение вниз. Увеличивайте вертикальную скорость на величину, равную гравитации, умноженной на dt, в каждом кадре, а затем применяйте скорость к положению.

Когда игрок приземляется на землю, обнулите вертикальную скорость, чтобы он перестал падать. Прыжок задаёт отрицательную вертикальную скорость.

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

Удаление уничтоженных объектов

После столкновений часто требуется удалять объекты. Проходите список с конца и вызывайте table.remove, чтобы индексы оставались корректными во время удаления.

Обход с конца — безопасный идиоматичный способ Lua удалять элементы в середине цикла: он предотвращает пропуск элементов, который возник бы при обходе вперёд.

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

Проверка знаний

Проверьте, насколько хорошо вы поняли движение и столкновения в LÖVE.

Итоги

Движение объединяет положение, скорость и dt, а нормализация обеспечивает одинаковую скорость по диагонали, и ограничение удерживает объекты на экране. Обнаружение столкновений начинается с проверки перекрытия AABB, а для круглых объектов используются проверки расстояния между кругами.

Разрешайте столкновения со стенами, отменяя перемещения по отдельным осям, добавляйте гравитацию в платформерах и удаляйте уничтоженные объекты, проходя список с конца и используя table.remove.

Часто задаваемые вопросы

Урок «Движение и столкновения» бесплатный?

Да — полный текст урока «Движение и столкновения» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Lua Academy, подпишись на CoddyKit PRO. Курс Lua Academy содержит 4 уроков всего.

Чему я научусь в уроке «Движение и столкновения»?

Создайте игровую сцену. Ты практикуешь Lua Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Lua Academy?

Предыдущий опыт не требуется. Lua Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.

Сколько времени занимает урок «Движение и столкновения»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Lua Academy?

Да. Каждый урок Lua Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Игровой цикл LOVE
  2. Отрисовка фигур и изображений
  3. Обработка ввода
  4. Движение и столкновения
← Назад к Lua Academy