From e8bb7306ac2dcc36db8904f92d10646161b55030 Mon Sep 17 00:00:00 2001 From: Ivan Yuriev Date: Sun, 7 Sep 2025 14:27:02 +0300 Subject: [PATCH 1/2] Create priority_queue.lua --- lib/utils/priority_queue.lua | 106 +++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 lib/utils/priority_queue.lua diff --git a/lib/utils/priority_queue.lua b/lib/utils/priority_queue.lua new file mode 100644 index 0000000..89f2b32 --- /dev/null +++ b/lib/utils/priority_queue.lua @@ -0,0 +1,106 @@ +---@class PriorityQueue +---@field private data any[] # внутренний массив-куча (индексация с 1) +---@field private cmp fun(a:any, b:any):boolean # компаратор: true, если a выше по приоритету, чем b +local PriorityQueue = {} +PriorityQueue.__index = PriorityQueue + +---Создать очередь с приоритетом. +---@param cmp fun(a:any, b:any):boolean|nil # если nil, используется a < b (мин-куча) +---@return PriorityQueue +function PriorityQueue.new(cmp) + local self = setmetatable({}, PriorityQueue) + self.data = {} + self.cmp = cmp or function(a, b) return a < b end + return self +end + +-- ===== Внутренние утилиты ===== + +---@param i integer @индекс узла +---@param j integer @индекс узла +function PriorityQueue:_swap(i, j) + self.data[i], self.data[j] = self.data[j], self.data[i] +end + +---@param i integer +function PriorityQueue:_sift_up(i) + while i > 1 do + local p = math.floor(i / 2) + if self.cmp(self.data[i], self.data[p]) then + self:_swap(i, p) + i = p + else + break + end + end +end + +---@param i integer +function PriorityQueue:_sift_down(i) + local n = #self.data + while true do + local l, r = i * 2, i * 2 + 1 + local best = i + + if l <= n and self.cmp(self.data[l], self.data[best]) then + best = l + end + if r <= n and self.cmp(self.data[r], self.data[best]) then + best = r + end + + if best ~= i then + self:_swap(i, best) + i = best + else + break + end + end +end + +-- ===== Публичный API ===== + +---Вставка элемента. +---@param x any +function PriorityQueue:insert(x) + table.insert(self.data, x) + self:_sift_up(#self.data) +end + +---Посмотреть первый элемент без удаления. +---@return any|nil +function PriorityQueue:peek() + return self.data[1] +end + +---Извлечь первый элемент (корень кучи). +---@return any|nil +function PriorityQueue:pop() + local n = #self.data + if n == 0 then return nil end + + local top = self.data[1] + local last = self.data[n] + self.data[n] = nil + + if n > 1 then + self.data[1] = last + self:_sift_down(1) + end + + return top +end + +---Текущее количество элементов. +---@return integer +function PriorityQueue:size() + return #self.data +end + +---Пуста ли очередь. +---@return boolean +function PriorityQueue:is_empty() + return #self.data == 0 +end + +return PriorityQueue From 5cead3c28291a1785797ec0741342437535a0013 Mon Sep 17 00:00:00 2001 From: Ivan Yuriev Date: Sun, 7 Sep 2025 14:27:20 +0300 Subject: [PATCH 2/2] fixed character z-ordering while moving --- lib/level/grid/character_grid.lua | 10 ++++++++++ lib/level/level.lua | 6 +++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/lib/level/grid/character_grid.lua b/lib/level/grid/character_grid.lua index 1c51d2c..0192f1e 100644 --- a/lib/level/grid/character_grid.lua +++ b/lib/level/grid/character_grid.lua @@ -1,6 +1,8 @@ local utils = require "lib.utils.utils" +local pQueue = require "lib.utils.priority_queue" --- @class CharacterGrid : Grid --- @field __grid {string: Id|nil} +--- @field yOrderQueue PriorityQueue очередь отрисовки сверху вниз local grid = setmetatable({}, require "lib.level.grid.base") grid.__index = grid @@ -21,13 +23,21 @@ function grid:add(id) end end +--- @param a Character +--- @param b Character +local function drawCmp(a, b) + return a.logic.mapLogic.displayedPosition.y < b.logic.mapLogic.displayedPosition.y +end + --- fills the grid with the actual data --- --- should be called as early as possible during every tick function grid:reload() self:reset() + self.yOrderQueue = pQueue.new(drawCmp) utils.each(Tree.level.characters, function(c) self:add(c.id) + self.yOrderQueue:insert(c) end) end diff --git a/lib/level/level.lua b/lib/level/level.lua index 1c603ff..6362402 100644 --- a/lib/level/level.lua +++ b/lib/level/level.lua @@ -39,9 +39,9 @@ end function level:draw() self.tileGrid:draw() - utils.each(self.characters, function(el) - el:draw() - end) + while not self.characterGrid.yOrderQueue:is_empty() do -- по сути это сортировка кучей за n log n, но линейное + self.characterGrid.yOrderQueue:pop():draw() + end end return {