D'abord, voici le code. Une explication suivra:
/*
* 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
};
}
};
Notez que ce code ne fonctionnera pas hors de la boîte pour la carte affichée dans votre question. Cela est dû au fait que les tuiles impaires sont décalées vers la gauche, alors que la tuile impaire est plus généralement décalée vers la droite (comme c'est le cas dans l' éditeur de carte en mosaïque ). Vous devriez pouvoir y remédier facilement en modifiant la valeur x renvoyée dans le cas des tuiles impaires.
Explication
Cela peut sembler être une méthode légèrement plus brutale pour accomplir cette tâche, mais elle a au moins l'avantage d'être parfaite au pixel près et légèrement plus flexible.
L'astuce consiste à visualiser la carte non pas comme une seule grille décalée, mais comme deux grilles superposées. Il y a la grille des lignes impaires et la grille des lignes paires, mais appelons-les plutôt rouges et vertes pour que nous puissions créer un joli diagramme ...
Remarquez à droite de cette image que j'ai marqué un point avec un point violet. C'est le point d'exemple que nous essaierons de trouver dans notre espace d'origine.
La chose à noter à propos de n'importe quel point du monde est qu'il se trouvera toujours dans exactement deux régions - une rouge et une verte (à moins qu'elle ne soit sur un bord, mais vous serez probablement coupée dans la limite du bord dentelé de toute façon). Trouvons ces régions ...
Maintenant, choisissez laquelle des deux régions est la bonne. Il y aura toujours exactement une réponse.
À partir de là, nous pourrions faire une arithmétique plus simple et calculer la distance au carré de notre point d'échantillonnage à chaque point central des deux régions. Le plus proche sera notre réponse.
Il existe cependant une alternative. Pour chaque région de test, nous échantillonnons une image bitmap qui correspond à la forme exacte de nos carreaux. Nous l'échantillons à un point traduit en coordonnées locales pour cette seule tuile. Pour notre exemple, cela ressemblerait à ceci:
Sur la gauche, nous vérifions la zone verte et obtenons un hit (pixel noir). Sur la droite, nous testons la région rouge et obtenons un échec (pixel blanc). Le deuxième test est bien sûr redondant puisqu'il sera toujours exactement l'un ou l'autre, jamais les deux.
Nous arrivons alors à la conclusion que nous avons un coup sûr dans la tuile impaire à 1,1. Cette coordonnée doit être simple à mapper aux coordonnées de tuile d'origine en utilisant une transformation différente pour les lignes paires et impaires.
Cette méthode vous permet également d'avoir des propriétés simples par pixel sur la ou les images bitmap de test de pixels. Par exemple, le blanc est hors tuile, le noir est un hit, le bleu est l'eau, le rouge est solide.