Subtraia a origem do canvas e aplique a escala ao ponto
Comece com clientX e clientY do evento e o retângulo retornado por canvas.getBoundingClientRect(). Esse retângulo é relativo à área visível do navegador: subtraia seus valores left e top antes de aplicar a escala. Se o jogo lógico mede 800 por 450 e o retângulo exibido mede 400 por 225, multiplique as coordenadas locais x e y por dois. Assim, o centro exibido corresponde ao ponto lógico (400, 225), independentemente da posição de rolagem da página.
Use o retângulo real do conteúdo, sem deduzi-lo pela largura da janela. Considere as bordas CSS e o preenchimento ao redor do canvas e atualize a conversão após mudanças de tamanho ou orientação. Se o jogo usa deslocamento de câmera, faixas vazias ou outra transformação do mundo, desfaça essas operações na ordem inversa antes de comparar o ponto com as formas das áreas clicáveis.
Teste toda a superfície, inclusive os espaços vazios
Coloque uma mira temporária na posição convertida do ponteiro e teste os quatro cantos do canvas, o centro e cada borda de um alvo. Para verificar a calibração, clique no centro de um círculo desenhado e confirme que o ponto obtido no mundo do jogo fica perto desse centro. Depois, clique logo fora para conferir se o limite de detecção respeita a margem de tolerância prevista. A MDN descreve clientX como relativo à área visível do navegador e getBoundingClientRect() como o método que retorna os limites do elemento em relação à mesma área. Usar essas medidas em conjunto evita misturar sistemas de coordenadas.
Mantenha o desenho e as áreas clicáveis vinculados
Guarde a posição e as dimensões do alvo no mundo do jogo uma única vez. Use esses dados tanto para desenhá-lo quanto para verificar se o ponteiro está dentro dele. Evite digitar coordenadas de tela separadas para o ícone visível e sua área clicável. Repita os testes ao mudar a escala do canvas, o tamanho CSS, a proporção de pixels do dispositivo ou o deslocamento da câmera. Se a posição de teste estiver correta, mas o alvo continuar sem responder, confira os cálculos da forma e a ordem de processamento da entrada antes de acrescentar deslocamentos arbitrários em pixels.
Perguntas sobre coordenadas para detecção de cliques no canvas
Devo usar offsetX e offsetY para detectar cliques no canvas?
Eles podem ser práticos em um canvas simples, sem transformações. Porém, usar explicitamente as coordenadas do evento, os limites do elemento e a transformação do jogo deixa cada etapa mais clara quando o layout ou a escala da câmera muda.
Devo incluir devicePixelRatio na conversão do ponteiro?
Somente se o ponto do ponteiro e as formas de detecção usarem pixels do buffer interno do canvas. Uma abordagem comum converte as coordenadas da área visível em unidades lógicas do jogo e deixa a escala de pixels do dispositivo apenas na transformação de renderização.
Leitura complementar
Viu alguma informação desatualizada? Informar uma correção