From ced3ae099355aa25d66664fcac39f3dd78e1e9d3 Mon Sep 17 00:00:00 2001 From: Kazhnuz Date: Tue, 5 Nov 2024 21:03:13 +0100 Subject: [PATCH] feat(world): add zSorting Fixes #73 --- framework/scenes/world/actors/init.lua | 1 + framework/scenes/world/init.lua | 29 ++++++++++++-- framework/scenes/world/terrain.lua | 1 + framework/scenes/world/zsort.lua | 54 ++++++++++++++++++++++++++ 4 files changed, 82 insertions(+), 3 deletions(-) create mode 100644 framework/scenes/world/zsort.lua diff --git a/framework/scenes/world/actors/init.lua b/framework/scenes/world/actors/init.lua index 604b391..194868c 100644 --- a/framework/scenes/world/actors/init.lua +++ b/framework/scenes/world/actors/init.lua @@ -39,6 +39,7 @@ function Actor:new(world, position) self:_initVisual(self.def.visuals or {}) self.isDestroyed = false + self.depth = self.def.depth or 0 self.timers = TweenManager(self) diff --git a/framework/scenes/world/init.lua b/framework/scenes/world/init.lua index 74b6e3b..082a837 100644 --- a/framework/scenes/world/init.lua +++ b/framework/scenes/world/init.lua @@ -37,6 +37,8 @@ local Vector3D = require "framework.libs.brinevector3D" local GFX = require "framework.scenes.world.actors.gfx" +local comparisons = require "framework.scenes.world.zsort" + local function _tryFunction(toUpdate, dt, func) if (toUpdate ~= nil) then func(dt) @@ -63,11 +65,21 @@ function World:new(datas) self.type = self.def.type or "2D" self.drawShadow = (self.def.drawShadow == true) + self.currentCreationID = 0 + World.super.new(self) + self:_setSorting() self:_load() end +function World:_setSorting() + self.sort = comparisons.depthSort + if self.type == "3D" then + self.sort = comparisons.zSort + end +end + function World:onLoad() end @@ -229,16 +241,23 @@ function World:newActor(name, x, y, z, properties, mapname) end function World:showGFX(effect, position, useMiddle) - table.insert(self.actors, GFX(self, position, effect, false, (useMiddle == true))) + local gfx = GFX(self, position, effect, false, (useMiddle == true)) + gfx.creationID = self.currentCreationID + self.currentCreationID = self.currentCreationID + 1 + table.insert(self.actors, gfx) end function World:addActor(name, position) local Actor = self:_getActorObject(name) if (name == "player") then self.player = Actor(self, position) + self.player.creationID = self.currentCreationID else - table.insert(self.actors, Actor(self, position)) + local actor = Actor(self, position) + table.insert(self.actors, actor) + actor.creationID = self.currentCreationID end + self.currentCreationID = self.currentCreationID + 1 end function World:removeActor(actor) @@ -309,7 +328,10 @@ function World:getBodiesInCube(x, y, z, w, h, d) -- Handle shapes, which make know what object is visible or not function World:addTerrain(body) - self:registerShape(Terrain(self, body.position, body.dimensions)) + local terrain = Terrain(self, body.position, body.dimensions) + terrain.creationID = self.currentCreationID + self.currentCreationID = self.currentCreationID + 1 + self:registerShape(terrain) end function World:registerShape(actor) @@ -337,6 +359,7 @@ end function World:drawShapes() local position, dimensions = self.camera:getViewCoordinate() local shapes = self:getShapeInRect(position, dimensions) + table.sort(shapes, self.sort) for _, shape in ipairs(shapes) do shape:draw() end diff --git a/framework/scenes/world/terrain.lua b/framework/scenes/world/terrain.lua index d6ecb2d..ec77515 100644 --- a/framework/scenes/world/terrain.lua +++ b/framework/scenes/world/terrain.lua @@ -27,6 +27,7 @@ local Vector3D = require "framework.libs.brinevector3D" function MappedBox:new(world, position, dimensions) self.world = world self.position = Vector3D(position.x, position.y, position.z or 0) + self.depth = -1 MappedBox.super.new(self, dimensions) self.haveLine = false diff --git a/framework/scenes/world/zsort.lua b/framework/scenes/world/zsort.lua new file mode 100644 index 0000000..b141543 --- /dev/null +++ b/framework/scenes/world/zsort.lua @@ -0,0 +1,54 @@ +local comparisons = {} + + +function comparisons.depthSort(itemA, itemB) + local aDepth, aID = itemA.depth, itemA.creationID + local bDepth, bID = itemB.depth, itemB.creationID + local comparison = 0 + if aDepth > bDepth then + comparison = 1 + elseif aDepth < bDepth then + comparison = -1 + else + if aID > bID then + comparison = 1 + elseif aID < bID then + comparison = -1 + end + end + return comparison == -1 +end + +function comparisons.zSort(itemA, itemB) + local aY, aZ, aH, aD = itemA.position.y, itemA.position.z, itemA.dimensions.h, itemA.dimensions.d + local bY, bZ,bH, bD = itemB.position.y, itemB.position.z, itemB.dimensions.h, itemB.dimensions.d + + local comparison = 0 + + if aY + aH <= bY then + -- item A is completely behind item B + comparison = -1 + elseif bY + bH <= aY then + -- item B is completely behind item A + comparison = 1 + elseif aZ >= bZ + bD then + -- item A is completely above item B + comparison = 1 + elseif bZ >= aZ + aD then + -- item B is completely above item A + comparison = -1 + elseif aY + aH > bY + bH then --(aY - aZ) + aH > (bY - bZ) + bH then + -- item A's forward-most point is in front of item B's forward-most point + comparison = 1 + elseif aY + aH < bY + bH then --aY < (bY - bZ) + bH then + -- item B's forward-most point is in front of item A's forward-most point + comparison = -1 + else + -- item A's forward-most point is the same than item B's forward-most point + return comparisons.depthSort(itemA, itemB) + end + + return comparison == -1 +end + +return comparisons \ No newline at end of file