Tilemap.set_tile error "SetGridShapHull" (SOLVED)

My tilemap is setting the tiles correctly, but each call to tilemap.set_tile triggers this error:

I’m confused because the the tile indexes I’m using are visually correct and definitely within the bounds of the tilemap. :confused:

1 Like

Can you please also share the code where you call tilemap.set_tile() and preferrably also a screenshot of the tilemap with it’s layers?

Hi Britzl,

This is the base tilemap that gets updated with tilemap.set_tile:

These tilemaps are used as definitions to reference:


Here is the code where the tilemap.set_tile is being called:

--uses 16-bit bitmasking to calculate tile value
local function calcTileValue(grid, x, y)
	local northCoord = y - 1
	local north = (grid[northCoord] and grid[northCoord][x] > 0) and 1 or 0

	local eastCoord = x + 1
	local east = (grid[y][eastCoord] and grid[y][eastCoord] > 0) and 1 or 0

	local southCoord = y + 1
	local south = (grid[southCoord] and grid[southCoord][x] > 0) and 1 or 0

	local westCoord = x - 1
	local west = (grid[y][westCoord] and grid[y][westCoord] > 0) and 1 or 0

	return north + (2 * east) + (4 * south) + (8 * west)
end

--[[
[table] filterCallbacks
[function] filterCallbacks[gridValue]
--]]
local function iterateGrid(grid, filterCallbacks)
	for y=1,#grid do
		for x=1,#grid[1] do
			local gridValue = grid[y][x]
			local callback = filterCallbacks[gridValue]			
			if callback then
				callback(calcTileValue(grid, x, y), x, y)
			end
		end
	end
end

local function getTileDefs(url, layer)
	local _,_,w,h = tilemap.get_bounds(url)
	local defs = {}
	local list = {}
	local y = h
	while y > 0 do
		for x=1,w do
			local tile = tilemap.get_tile(url, layer, x, y)
			defs[tile] = true
			table.insert(list, tile)
		end
		y = y - 1
	end
	return {
		hash = defs,
		list = list
	}
end

local function makeList(length, fillValue)
	local list = {}
	for i=1,length do
		list[i] = fillValue
	end
	return list
end

local function randomTile(tileList)
	local listIndex = math.random(1, #tileList)
	local tileIndex = tileList[listIndex]
	return tileIndex
end

local function makeGridFromTilemap()
	local impassableTiles = getTileDefs("#map-impassables", "walls")
	local groundTiles = getTileDefs("#map-ground", "base")
	local groundCoverTiles = getTileDefs("#map-ground", "extras")
	local originX,originY,w,h = tilemap.get_bounds("#map-objects")
	local grid = {}
	local adjustedH = h -1
	local adjustedW = w - 1
	
	-- setup binary grid data
	for y=1,adjustedH do
		local flippedY = h - y
		grid[y] = makeList(adjustedW, 0)
		for x=1,adjustedW do
			local curTileIndex = tilemap.get_tile("#map-objects", "wall", x, flippedY)
			local isWallTile = impassableTiles.hash[curTileIndex]
			if isWallTile then
				grid[y][x] = 1
			end
		end
	end

	local function setGroundTile(x, y)
		local groundTileIndex = groundTiles.list[1]
		tilemap.set_tile("#map-objects", "ground", x, y, groundTileIndex)		
	end

	local function addGroundCoverTile(x, y)
		local groundCoverTileIndex = randomTile(groundCoverTiles.list)
		tilemap.set_tile("#map-objects", "ground2", x, y, groundCoverTileIndex)
	end
	
	tilemapBitmask.iterateGrid(grid, {
		[0] = function(_, x, y)
			local flippedY = h - y
			setGroundTile(x, flippedY)
			local shouldAddGroundCover = math.random(0, 1) == 1
			if shouldAddGroundCover then
				addGroundCoverTile(x, flippedY)
			end
		end,
		[1] = function(tileValue, x, y)	
			local listIndex = tileValue + 1
			local tileIndex = impassableTiles.list[listIndex]
			local flippedY = h - y
			tilemap.set_tile("#map-objects", "wall", x, flippedY, tileIndex)

			setGroundTile(x, flippedY)
			grid[y][x] = 1
		end
	})
	
	return grid
end

Hmm, nothing obvious. The error actually relates to when the collision shape gets updated for the tilemap. Would you mind sharing the project with me (bjorn.ritzl@king.com)?

So, I updated the collision for the tilesource and that fixed it :smile:. It wasn’t obvious from the error message that this was the culprit though…

In any event, thanks a bunch for the pointer Britzl.

1 Like

I’m also getting the following error…

ERROR:GAMESYS: SetGridShapHull: specified hull index is out of bounds.

…upon calling:

tilemap.set_tile("/level#tilemap", "select", pos.x, pos.y, 0)

The function works as expected (the tile at position ‘pos’ is removed) but the error is still displayed in the console.

I’ve recently added some collision groups to the tileset and the error started after that.

Any ideas please?

1 Like

We added a range check for that function last sprint, it might have triggered something. 0 is a valid number since it clears the tile, so it must be something else. Do you have a project or a repro case that I can take a look at?

1 Like

Thanks - I can add you to the project if you’ve got an email address you’re happy to share?

2 Likes

Great! jhonny.goransson@king.com

1 Like

Found the issue and submitted a fix. Thanks for reporting!

6 Likes

I’m running into the same issue, and I don’t get why because the tilemap that causes the error doesn’t even have a collision shape assigned.

The occlusion tilemap is the one I’m editing with tilemap.set_tile(), causing the error, and as you can see from the screenshot, the collision object is using the regular tilemap for the shape. Deleting the collision object makes the error go away, but I don’t think it should be influenced in any way by a tilemap other than the one set to its shape. I’ve also made sure that the occlusion tilemap is using a separate tilesource, and experimented with setting that one to having no collision, or collision derived from the source image, no collision groups, one collision group for every tile, etc. all to no avail.

EDIT: I put together a minimal project to illustrate this issue, and it seems to be caused by having multiple tilemaps of a different size within the same the same game object, along with a collision object using one of the smaller tilemaps for the shape, then trying to alter one of the bigger tilemaps in a script.

project repo here: https://github.com/dblumin45/SetGridShapeHullTest

I believe this problem is related to, but not the same as, this issue: https://github.com/defold/defold/pull/6452

Do you also have a colllision object on the occlusion or tilemap tilemap components?

1 Like

The “tilemap.tilemap” component is used as the shape for the collision object in the screenshot, but there is no collision object for the “occlusion.tilemap”. In my test project I also experimented having both tilemaps in question have a collision object, or just one, and it made no difference. As long as one tilemap has a collision object, then the other tilemap is updated - if the updated tilemap’s bounds do not fall within the bounds of the other - you see this error. So yes, it seems like the exact same issue as that pull request.

For what it’s worth, it doesn’t crash or anything, and the tilemap is updated properly, it just doesn’t feel right having a bunch of errors thrown and is obviously indicative of some weird behavior.

EDIT: So after some more experimentation I discovered one pretty big problem. I got rid of the error messages by making sure that the bounds of the dummy occlusion tilemap matched my main tilemap. However, when the errors aren’t thrown that means it’s actually altering the collision object’s shape! To make matters worse, the “wrong” tilemap is shifted down by (1, 1) when altering the shape of the collision object, deforming the level’s collision.

To illustrate this, I shifted the occlusion tiles down by (1, 1) when they’re placed, so you can see their visuals offset from the original tilemap’s visuals/collision, and the erroneously generated collision offset from their visuals by another (-1, -1).

The solution is to have only one tilemap+collision object per game object. Try splitting your three tilemaps into three game objects.

1 Like

Yeah that’s what I’ll do for now. Sorry if this was a known issue that’s been put on the backburner, I just wanted to outline the weird behavior I found in case any of it’s new.

1 Like

You couldn’t know this was the case. We need to figure out a better solution at some point, or detect the situation and generate a warning either when building or at runtime.

1 Like