How to detect click on a tile?

Do you have maybe some checked solutions for that? I did tile detection in Water Sources, but it’s not accurate and I would like to create a better solution.

Seems simple enough, from tilemap position, tilemap scale, tile size and click coordinates transformed into local space you should be able to calculate selected tile no problems. Where inaccuracy comes from?

1 Like

From http://pixcade.com/cosmos/web I was using GOs but the same logic applies. Reminder that the bottom left tile is 1,1. If you chunk your tilemaps you’ll want to account for that… I used GOs in this because it was easier. I was more of a Defold noob then and would do things differently now.

function round(num)
    under = math.floor(num)
    upper = math.floor(num) + 1
    underV = -(under - num)
    upperV = upper - num
    if (upperV > underV) then
        return under
    else
        return upper
    end
end

Important bits are the / and * based off rounded number to get the x,y of the tile. So in this example self.grid_position becomes the x,y of the current block. Same logic goes for tilemap.

	self.current_position = go.get_position()
	self.offset_position = self.current_position - self.original_position
	camera_offset_helper.offset_x = self.offset_position.x
	camera_offset_helper.offset_y = self.offset_position.y
	camera_offset_helper.offset = self.offset_position

	self.nearest_x = round(self.current_position.x / grid_size) * grid_size
	self.nearest_y = round(self.current_position.y / grid_size) * grid_size
	self.grid_position = vmath.vector3((self.nearest_x / grid_size), (self.nearest_y / grid_size), 0)
	self.block_position = vmath.vector3(self.nearest_x, self.nearest_y, 0)
	go.set_position(self.block_position, "grid_position_marker")
1 Like

Chemaria is using tilemaps I think:

Maybe @gamzwithjamz can share some code or give some tips?

1 Like

Your round function seems way too complicated and probably goes wrong.
You should be fine with just math.floor(something) or math.floor(something + 0.5).

2 Likes

I include it for reference of what the code was using. Here are defmath ones.

-- Round
function M.round(x)
	local a = x % 1
	x = x - a
	if a < 0.5 then a = 0
	else a = 1 end
	return x + a
end

-- Round to decimal point
function M.round_decimal(number, decimal)
	decimal = 10 ^ (decimal or 0)
	return math.floor(number*decimal+0.5)/decimal
end

My code is based on rendercam.screen_to_world_2d and it was quickly used in on_input here

The round function is literally this:

local function round(x)
  return math.floor(x + 0.5)
end
1 Like

You can blame me for that one, I added that ages ago. :smiley:

I actually recently updated the one I’ve been using to this:

local floor = math.floor
local ceil = math.ceil

math.round = function(x, interval)
	if interval then  return math.round(x / interval) * interval  end
	if x < 0 then  return ceil(x - 0.5)  end
	return floor(x + 0.5)
end

The caveat with just using math.floor(x + 0.5) is that it doesn’t work correctly for negative numbers. -0.5 gives you 0 instead of -1.

1 Like

But -0.5 becoming 0 is mathematically correct, since it goes towards increase of value.

2 Likes

I am actually not using tilemaps. Because I need the world to both render and physically be removed from the world tracking system as I move around because it is so large, I actually do all of that by hand.

I use a combination of the orthographic camera extensions functions for converting screen to world position, along with my own transforms for converting to my internal block/tile tracking system.

1 Like

I use this round function to handle clicking blocks in negative coordinates properly.

function round(num)
	if num > 0 then
		return math.floor(num + 0.5)
	else
		return math.ceil(num - 0.5)
	end
end
1 Like

I am astonished that people have to use modified round() function for negative values, can’t wrap my head around why is that needed… The only explanation I come up with is if Defold has no 0 rows/columns for the tilemap.

Is that the case? So instead of 3, 2, 1, 0, -1, -2, -3 the tilemap goes 3, 2, 1, -1, -2, -3, skipping the zero altogether.

If so that’s not the math being wrong about rounding numbers, but Defold being not so straightforward with tilemaps.

Defold’s tilemap has 0 coordinates on both axis, so it shouldn’t be the case.
So it’s more dependable on a design of a grid.
I guess it’s kind of like with probability, when you think chances are better to have a desired result after a few failures :stuck_out_tongue: It’s human to think that e.g. -0.5 should be rounded to -1, while -0.49 should be 0 then.

There are different approaches to round:
https://www.quora.com/Why-do-we-round-off-0-5-to-1-and-not-to-0

Math is always right! :smiley: except in gamedev :stuck_out_tongue:

1 Like

Ugh, then I am lost.

It’s a convention to round 0.5 to 1, I know that. But I don’t find it a “convention” to round to the upper for positive numbers and to the lower for negative numbers, that sounds to me plain wrong from algorithms standpoint.

For instance the distance between -0.5 and 0.5 is 1, with always to upper/lower rounding round(0.5) - round(-0.5) is also 1, so the differential of original series of numbers is the same as the differential of rounded series of the same numbers. That is correct.

But with “human” rounding the distance between rounded -0.5 and 0.5 becomes 1 - (-1) = 2, two times the original! Therefore the differentials are no longer equal of original series and rounded series. That may lead to trouble somehow.

Ok then, whatever works, probably just a nuance on the implementation.

2 Likes

I don’t think it’s ever “needed” at all, it’s just personal preference and being perfectionist. Apparently there isn’t a convention for it. In the end it’s literally splitting infinity, -0.499999999 and 0.499999999 will both round to zero whichever way you do it.

1 Like