Tutorial:Drawing Order (Русский)

Поскольку LÖVE не имеет встроенной системы порядка наложения (предполагается в будущем) вы можете столкнуться с некоторыми вопросами при попытке создания игры, которая автоматически отрисовывает персонажа перед или за объектами в зависимости от их положения, такое обычно встречается в приключенческих играх. Этот урок покажет вам, как сделать это в очень упрощенной форме.

Примечание: В этом уроке, когда я указываю, что объект "спереди" персонажа, я имею в виду, что он между персонажем и экраном (т.е. вами). "Позади" означает, что персонаж между экраном и объектом.

Во-первых, нам нужны ресурсы:

-- фон для нашей сцены
scene = love.graphics.newImage("room.png")
-- персонаж, которого мы будем двигать
person = love.graphics.newImage("guy.png")
-- объект для перемещения
object = love.graphics.newImage("ball.png")

Хорошо, теперь у нас есть ресурсы, далее нам нужны переменные содержащие позицию нашей персоны и объектов:

-- позиция персонажа
character = {400,400} -- x,y
 
-- куча объектов, каждый со своей позицией
objects = {}
objects[1] = {550,370}
objects[2] = {220,390}
objects[3] = {600,410}
objects[4] = {300,450}
objects[5] = {400,530}

Убедитесь, что ваш список объектов сортируются по позиции Y. Это становится важным, при их отрисовки. Для общего применения, можно сперва использовать функцию Lua table.sort.

function orderY(a,b)
  return a[2] < b[2]
end
table.sort(objects, orderY)

Вы должны быть осторожны, и не храните индекс объектов напрямую, поскольку индекс объектов изменится после сортировки (вы можете сделать копию для отрисовки).

Чтобы отрисовать эти объекты, мы будем использовать:

love.graphics.draw(object, objects[i][1] - object:getWidth()/2, objects[i][2] -  object:getHeight())

Параметр object указывает изображение, которое мы собираемся отрисовывать, а следующие два аргумента указывают, в каком месте в верхнем левом углу экрана, изображение должно быть отрисовано. Мы вычитаем половину от ширины и высоты изображение чтобы разместить изображение в нижнем горизонтальном центре на указанных в object[i] координатах X и Y.

Хорошо, теперь мы готовы отрисовать всю сцену, предполагая, что вы создали какой-то способ перемещения персонажа по экрану (иначе это просто бессмысленно, поскольку вы не увидите разницу). Если вы не знаете, как это сделать, я предлагаю взглянуть на другие наши уроки чтобы получить помощь. Для простоты, я просто покажу вам всю функцию love.draw, а затем объясню, что она делает:

function love.draw() 
    love.graphics.draw(scene, love.graphics:getWidth() / 2 - scene:getWidth()/2,
        love.graphics:getHeight() / 2 - scene:getHeight() / 2) -- отрисовать по центру игра
 
    local drawn = false -- истинно (true) если персонаж был отрисован
 
    for i,v in ipairs(objects) do
        if not drawn and objects[i][2] > character[2] then
            love.graphics.draw(person, character[1] - person:getWidth()/2, character[2] - person:getHeight())
            drawn = true
        end
	love.graphics.draw(object, objects[i][1] - object:getWidth()/2, objects[i][2] - object:getHeight())
   end
 
   if not drawn then -- если персона находится ниже всех объектов, она не будет отрисована в цикле
      love.graphics.draw(person, character[1] - person:getWidth()/2, character[2] - person:getHeight())
   end
 
   -- любые объекты переднего плана сваливаем сюда
 
end

Прежде всего мы отрисовываем нашу сцену, поскольку она обычно и бывает позади (как и любые потенциальные объекты переднего плана, всегда будет в двух направлениях). Затем я создаю переменную drawn. Она скажет нам, был ли персонаж отрисован, чтобы повторно не отрисовывать по несколько раз, что заставит его находиться спереди объектов, там, где не надо. Далее я перехожу к циклу и перебераю все наши объекты (которые упорядочены от дальнего к ближнему). Затем я проверяю, должен ли объект быть перед нашим персонажем, если да, то вы должны отрисовать персонажа (и задать переменную drawn). Причина этого в том, что этот цикл будет идти до конца и отрисует объекты ( в данном случае, то же самое изображение, но не обязательно должно быть так), пока речь идет об объектах, которые должны находиться спереди персонажа, когда отрисовывается персонаж, а затем продолжает отрисовывать остальные объекты. Если дело доходит до конца цикла, а персонаж ещё не отрисован, это означает, что персонаж находится спереди всех объектов, поэтому он отрисовывает его в конце.

Вот и всё. Скачайте демо-версию и побегайте. Это очень просто, этот урок рассказывает только о порядке отрисовки, и если вы хотите узнать, как проверить, столкнулся ли персонаж с объектом, или хотите чтобы персонаж шёл туда, куда вы нажали, то читайте прочие уроки. Если это не достаточно просто, то пожалуйста, не стесняйтесь комментировать урок на нашем форуме.

См. также

Альтернатива, масштабируемые реализации: Skip list:Drawing Order



На других языках