You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript中event.touches[1].clientX坐标偏移问题求助

解决多触摸场景下坐标偏移的问题

问题描述

代码包含3个可触摸交互的div元素,通过ee.touches[0]和ee.touches[1]获取触摸坐标时,先触摸botondisparoContenedor元素后,再触摸botonleftContenedor或botonrightContenedor会出现clientX坐标偏移,无法正常识别触摸操作。

问题根源

  1. 固定依赖触摸点的索引(touches[0]/touches[1])判断触摸元素,但多触摸时触摸点的顺序会动态变化,导致拿错对应坐标。
  2. 通过elementFromPoint反查元素的逻辑冗余且易出错,触摸事件本身可以直接通过event.target获取触发元素。
  3. 单个变量 tomaEstaDireccion被多个触摸操作覆盖,无法同时跟踪多个触摸状态。

解决方案

  1. 利用触摸事件的identifier属性唯一标识每个触摸点,维护触摸点与元素的映射关系。
  2. 直接通过event.target获取触发触摸的元素,无需通过坐标反查。
  3. 分离移动和射击的触摸状态,避免变量冲突。

修改后的完整代码

<style>
.botonleftContenedor{
    width:19vw;
    height:100vh;
    float:left;
    background-color: #00000090
}
.botonrightContenedor{
    width:19vw;
    height:100vh;
    float:left;
    background-color: #00000090
}
.botondisparoContenedor{
    width:19vw;
    height:100vh;
    float:right;
    background-color: #00000090
}
.inicio{
    width:90vw;
    height:10vh;
}
</style>

<div id="botonleftContenedor" class="botonleftContenedor"></div>
<div id="botonrightContenedor" class="botonrightContenedor"></div>
<div id="botondisparoContenedor" class="botondisparoContenedor"></div>
<div id="inicio" class="inicio"></div>

<script>
// 玩家状态
let actDireccion = 0; // 0 静止 / 1 向右 / 2 向左
let disparo = 0;
let activadoDisp = 0;
let iniciarDisparos;

// 跟踪触摸点与元素的映射
const touchMap = new Map();

// 移动控制逻辑
function handleMovement(event) {
    const targetId = event.target.id;
    const touchId = event.type.includes('touch') ? event.changedTouches[0].identifier : 'mouse';

    if (event.type === 'touchstart' || event.type === 'mousedown' || event.type === 'pointerdown') {
        touchMap.set(touchId, targetId);
        updateDirection();
    } else if (event.type === 'touchend' || event.type === 'mouseup' || event.type === 'pointerup') {
        touchMap.delete(touchId);
        updateDirection();
    } else if (event.type === 'touchmove') {
        // 触摸移动时更新坐标显示
        const touch = event.changedTouches[0];
        document.getElementById("inicio").innerHTML = `${touch.clientX} -- ${touch.clientY}`;
    } else if (event.type === 'keydown') {
        if (event.keyCode === 39) {
            actDireccion = 1;
        } else if (event.keyCode === 37) {
            actDireccion = 2;
        }
    } else if (event.type === 'keyup') {
        if (event.keyCode === 39 || event.keyCode === 37) {
            actDireccion = 0;
        }
    }
}

// 更新移动方向
function updateDirection() {
    const hasRight = Array.from(touchMap.values()).includes('botonrightContenedor');
    const hasLeft = Array.from(touchMap.values()).includes('botonleftContenedor');
    
    if (hasRight && !hasLeft) {
        actDireccion = 1;
    } else if (hasLeft && !hasRight) {
        actDireccion = 2;
    } else {
        actDireccion = 0;
    }
}

// 射击控制逻辑
function dispararAhoraa(event) {
    if ((event.keyCode === 32 || event.target.id === "botondisparoContenedor") && activadoDisp === 0) {
        disparo++;
        iniciarDisparos = setInterval(() => {
            disparo++;      
        }, 20);
        activadoDisp = 1;
    }
}

function dejaDeDisparar(event){
    if (event.keyCode === 32 || event.target.id === "botondisparoContenedor") {
        activadoDisp = 0;
        clearInterval(iniciarDisparos);
    }   
}

// 绑定事件
const clickMoverRight = document.getElementById('botonrightContenedor');
const clickMoverLeft = document.getElementById('botonleftContenedor');
const clickdisparar = document.getElementById("botondisparoContenedor");

// 移动按钮事件
clickMoverRight.addEventListener("touchstart", handleMovement);
clickMoverRight.addEventListener("touchend", handleMovement);
clickMoverRight.addEventListener("touchmove", handleMovement);

clickMoverLeft.addEventListener("touchstart", handleMovement);
clickMoverLeft.addEventListener("touchend", handleMovement);
clickMoverLeft.addEventListener("touchmove", handleMovement);

// 射击按钮事件
clickdisparar.addEventListener("touchstart", dispararAhoraa);
clickdisparar.addEventListener("touchend", dejaDeDisparar);

// 键盘事件
document.addEventListener("keydown", handleMovement);
document.addEventListener("keyup", handleMovement);
document.addEventListener("keydown", dispararAhoraa);
document.addEventListener("keyup", dejaDeDisparar);
</script>

关键改进点

  • 使用touchMap跟踪每个触摸点对应的元素ID,避免多触摸时顺序错乱。
  • 直接通过event.target获取触发元素,无需坐标反查,彻底解决坐标偏移问题。
  • 分离方向更新逻辑为单独函数,代码更清晰易维护。
  • 增加clearInterval清理定时器,避免内存泄漏。

内容的提问来源于stack exchange,提问作者Donjode

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 00:14:57