From c043bb8ecfae0aed494d1c76e973b006d361824a Mon Sep 17 00:00:00 2001 From: Kazhnuz Date: Mon, 1 Jul 2019 18:06:25 +0200 Subject: [PATCH] feat(actor3D): add zSorting support --- gamecore/modules/world/world3D.lua | 99 ++++++++++++++++++++++++++---- 1 file changed, 88 insertions(+), 11 deletions(-) diff --git a/gamecore/modules/world/world3D.lua b/gamecore/modules/world/world3D.lua index 06813db..e910d13 100644 --- a/gamecore/modules/world/world3D.lua +++ b/gamecore/modules/world/world3D.lua @@ -29,6 +29,7 @@ local World3D = BaseWorld:extend() local Sti = require(cwd .. "libs.sti") local Bump = require(cwd .. "libs.bump") local Bump3D = require(cwd .. "libs.bump-3dpd") +local Tsort = require(cwd .. "libs.tsort") local CameraSystem = require(cwd .. "camera") local PADDING_VALUE = 10/100 @@ -79,17 +80,7 @@ function BaseWorld:getVisibleActors(id) actors = self:getActors() end - table.sort(actors, function(a,b) - if (a.y == b.y) then - if (a.depth == b.depth) then - return a.creationID < b.creationID - else - return a.depth > b.depth - end - else - return a.y < b.y - end - end) + actors = self:zSortItems(actors) return actors end @@ -199,4 +190,90 @@ function World3D:getShapeInRect(x, y, w, h) return self.shapes:queryRect(x, y, w, h) end +-- DRAW FUNCTIONS +-- Functions to draw the world + +function World3D:zSortItems(items) + -- zSorting algorithm taken from bump3D example, adapted to gamecore. + local graph = Tsort.new() + local noOverlap = {} + + -- Iterate through all visible items, and calculate ordering of all pairs + -- of overlapping items. + -- TODO: Each pair is calculated twice currently. Maybe this is slow? + for _, itemA in ipairs(items) do repeat + local x, y, w, h = self.shapes:getRect(itemA) + local otherItemsFilter = function(other) return other ~= itemA end + local overlapping, len = self.shapes:queryRect(x, y, w, h, otherItemsFilter) + + if len == 0 then + table.insert(noOverlap, itemA) + + break + end + + local _, aY, aZ, _, aH, aD = self.bodies:getCube(itemA.mainHitbox) + aDepth = itemA.depth + aID = itemA.id + aType = itemA.type + aZ = math.ceil(aZ) + aY = math.ceil(aY) + + for _, itemB in ipairs(overlapping) do + local _, bY, bZ, _, bH, bD = self.bodies:getCube(itemB.mainHitbox) + bDepth = itemB.depth + bID = itemB.id + bType = itemB.type + bZ = math.ceil(bZ) + bY = math.ceil(bY) + + if aZ >= bZ + bD then + -- item A is completely above item B + graph:add(itemB, itemA) + elseif bZ >= aZ + aD then + -- item B is completely above item A + graph:add(itemA, itemB) + elseif aY + aH <= bY then + -- item A is completely behind item B + graph:add(itemA, itemB) + elseif bY + bH <= aY then + -- item B is completely behind item A + graph:add(itemB, itemA) + elseif (aY - aZ) + aH > (bY - bZ) + bH then + -- item A's forward-most point is in front of item B's forward-most point + graph:add(itemB, itemA) + elseif (aY - aZ) + aH < (bY - bZ) + bH then + -- item B's forward-most point is in front of item A's forward-most point + graph:add(itemA, itemB) + else + -- item A's forward-most point is the same than item B's forward-most point + if aDepth > bDepth then + graph:add(itemB, itemA) + elseif aDepth < bDepth then + graph:add(itemA, itemB) + else + if aID > bID then + graph:add(itemA, itemB) + elseif aID < bID then + graph:add(itemB, itemA) + else + err("two object can't have the same ID") + end + end + end + end + until true end + + local sorted, err = graph:sort() + if err then + error(err) + end + for _, item in ipairs(noOverlap) do + table.insert(sorted, item) + end + + return sorted + +end + return World3D