# How to detect click on a tile?

#1

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.

0 Likes

#2

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

#3

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

#4

Chemaria is using tilemaps I think:

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

1 Like

#5

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

#6

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
``````
0 Likes

#7

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

0 Likes

#8

The round function is literally this:

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

#9

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

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

#10

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

2 Likes

#11

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

#12

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

#13

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.

0 Likes

#14

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 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! except in gamedev

1 Like

#15

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

#16

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