Primeiro, aqui está o código. Uma explicação será a seguir:
/*
* tw, th contain the tile width and height.
*
* hitTest contains a single channel taken from a tile-shaped hit-test
* image. Data was extracted with getImageData()
*/
worldToTilePos = function(x, y) {
var eventilex = Math.floor(x%tw);
var eventiley = Math.floor(y%th);
if (hitTest[eventilex + eventiley * tw] !== 255) {
/* On even tile */
return {
x: Math.floor((x + tw) / tw) - 1,
y: 2 * (Math.floor((y + th) / th) - 1)
};
} else {
/* On odd tile */
return {
x: Math.floor((x + tw / 2) / tw) - 1,
y: 2 * (Math.floor((y + th / 2) / th)) - 1
};
}
};
Observe que esse código não funcionará imediatamente para o mapa mostrado na sua pergunta. Isso ocorre porque os ladrilhos ímpares são deslocados para a esquerda, enquanto os ladrilhos ímpares costumam ser deslocados para a direita (como é o caso no editor de mapas lado a lado ). Você deve ser capaz de remediar isso facilmente, ajustando o valor x retornado no caso de blocos ímpares.
Explicação
Pode parecer um método um pouco mais de força bruta para realizar essa tarefa, mas pelo menos tem a vantagem de ser perfeito em pixels e um pouco mais flexível.
O truque consiste em visualizar o mapa não como uma única grade escalonada, mas como duas grades sobrepostas umas sobre as outras. Há a grade de linhas ímpares e a grade de linhas pares, mas vamos chamá-las de vermelho e verde para que possamos criar um diagrama bonito ...
Observe à direita dessa imagem que marquei um ponto com um ponto roxo. Este é o ponto de exemplo que tentaremos encontrar em nosso espaço de mosaico original.
O que deve ser observado em qualquer ponto do mundo é que ele sempre estará exatamente em duas regiões - uma vermelha e uma verde (a menos que esteja em uma aresta, mas você provavelmente estará cortando dentro do limite da aresta irregular). Vamos encontrar essas regiões ...
Agora, escolha qual das duas regiões é a correta. Sempre haverá exatamente uma resposta.
A partir daqui, poderíamos fazer uma aritmética mais simples e calcular a distância ao quadrado do nosso ponto de amostra até cada ponto central das duas regiões. O que for mais próximo será a nossa resposta.
Existe uma maneira alternativa no entanto. Para cada região de teste, criamos um bitmap que corresponde à forma exata de nossos blocos. Amostra-lo em um ponto traduzido em coordenadas locais para esse bloco único. Para o nosso exemplo, seria algo parecido com isto:
À esquerda, verificamos a região verde e obtemos um acerto (pixel preto). À direita, testamos a região vermelha e falhamos (pixel branco). O segundo teste é obviamente redundante, pois sempre será exatamente um ou outro, nunca os dois.
Chegamos então à conclusão de que temos um sucesso no quadro ímpar em 1,1. Essa coordenada deve ser simples de mapear para as coordenadas originais do bloco, usando uma transformação diferente para linhas pares e ímpares.
Esse método também permite que você tenha propriedades simples por pixel no (s) bitmap (s) de teste de pixel. Por exemplo, o branco é irregular, o preto é um sucesso, o azul é a água, o vermelho é sólido.