Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Object visibility is not respected #181

Open
Amadman opened this issue May 7, 2018 · 5 comments
Open

Object visibility is not respected #181

Amadman opened this issue May 7, 2018 · 5 comments

Comments

@Amadman
Copy link

Amadman commented May 7, 2018

Creating an object layer in tiled, then adding an object with "Visible: False" property should make the object invisible when loaded in. Currently this variable seems to be ignored.

@karai17
Copy link
Owner

karai17 commented May 7, 2018

The issue with that is how sprite batches work. STI batches all the tiles in a layer into single draw calls, so toggling the visibility of individual objects would require manually modifying the batch upon toggle.

I could probably add a function to each object that you could use to toggle the object's visibility which would adjust the sprite batch.

@Amadman
Copy link
Author

Amadman commented May 7, 2018

My (admittedly uninformed) fix is:

	for _, object in ipairs(layer.objects) do
		if object.visible == true then
			if object.shape == "rectangle" and not object.gid then
				drawShape(object.rectangle, "rectangle")
			elseif object.shape == "ellipse" then
				drawShape(object.ellipse, "ellipse")
			elseif object.shape == "polygon" then
				drawShape(object.polygon, "polygon")
			elseif object.shape == "polyline" then
				drawShape(object.polyline, "polyline")
			end
		end
	end

I'm not too well informed about sprite batches so this "fix" probably doesn't fully work for the problem but it has worked in my simple case.

https://github.com/karai17/Simple-Tiled-Implementation/blob/master/sti/init.lua#L820

@karai17
Copy link
Owner

karai17 commented May 7, 2018

That would work for Tiled's geometry objects, but not so well for tile objects that draw sprites, those get batched into a single draw call.

@karai17 karai17 added the bug label May 7, 2018
@ikhaliq15
Copy link

ikhaliq15 commented Jun 18, 2019

Okay, so I ran into this same problem and my solution was to add a function that would recreate the batch for the layer and then in the Map:setObjectSpriteBatches function, I just added a condition of the object being visible.

--- Recreates the batch for a layer.
-- @param index Draw order within Layer stack
function Map:updateLayerBatches(index)
	local layer = assert(self.layers[index], "Layer not found: " .. index)
	self:setObjectSpriteBatches(layer)
end
--- Batch Tiles in Object Layer for improved draw speed
-- @param layer The Object Layer
function Map:setObjectSpriteBatches(layer)
	local newBatch = lg.newSpriteBatch
	local batches  = {}

	if layer.draworder == "topdown" then
		table.sort(layer.objects, function(a, b)
			return a.y + a.height < b.y + b.height
		end)
	end

	for _, object in ipairs(layer.objects) do
		if object.gid and object.visible then
			local tile    = self.tiles[object.gid] or self:setFlippedGID(object.gid)
			local tileset = tile.tileset
			local image   = self.tilesets[tileset].image

			batches[tileset] = batches[tileset] or newBatch(image)

			local sx = object.width  / tile.width
			local sy = object.height / tile.height

			-- Tiled rotates around bottom left corner, where love2D rotates around top left corner
			local ox = 0
			local oy = tile.height

			local batch = batches[tileset]
			local tileX = object.x + tile.offset.x
			local tileY = object.y + tile.offset.y
			local tileR = math.rad(object.rotation)

			-- Compensation for scale/rotation shift
			if tile.sx == -1 then
				tileX = tileX + object.width

				if tileR ~= 0 then
					tileX = tileX - object.width
					ox = ox + tile.width
				end
			end

			if tile.sy == -1 then
				tileY = tileY - object.height

				if tileR ~= 0 then
					tileY = tileY + object.width
					oy = oy - tile.width
				end
			end

			local instance = {
				id    = batch:add(tile.quad, tileX, tileY, tileR, tile.sx * sx, tile.sy * sy, ox, oy),
				batch = batch,
				layer = layer,
				gid   = tile.gid,
				x     = tileX,
				y     = tileY,
				r     = tileR,
				oy    = oy
			}

			self.tileInstances[tile.gid] = self.tileInstances[tile.gid] or {}
			table.insert(self.tileInstances[tile.gid], instance)
		end
	end

	layer.batches = batches
end

So whenever I changed the visibility of an object, I called the updateLayerBatches and it worked great. I don't know if this is at all efficient or anything so let me know if this is totally stupid.

@karai17
Copy link
Owner

karai17 commented Jun 19, 2019

The issue with the above code is that you're creating a whole new batch and rebuilding all of the objects instead of just updating the current batch and the one object. You're also not clearing any of the old data so your tileInstances table becomes dirty and unreliable, not to mention introducing a memory leak.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants