触摸控制:重复动作直到触摸结束

touch controls: repeat action until touchend

我正在尝试向 three.js 场景添加触摸控件。我想在用户触摸的任何方向上移动相机。使用键盘效果很好,因为您可以按住按钮,相机会连续移动。但是当我使用 touchstart 尝试同样的事情时,你必须一遍又一遍地点击屏幕才能移动,你不能像键盘或鼠标那样按住手指。

我看了touchmove,但是如果你只是点击并按住而不移动,就没有新的触摸。

有没有类似于使用触摸事件按住键盘或鼠标键的东西?

没有像键盘一样重复触发的触摸事件的内置回调。但是,您可以简单地跟踪触摸的开始和结束,然后以设定的时间间隔调用 move 方法。

首先,订阅正确的事件并设置一个 bool 来跟踪状态:

var isTouching = false;
window.addEventListener("touchstart", () => isTouching = true);
window.addEventListener("touchend", () => isTouching = false);

在 Three.js 中,您很可能已经有了一个渲染循环(例如,一个名为 "animate" 的函数)。在每次迭代时检查状态变量并每次应用运动。您可能还需要考虑 deltaTime(最后一帧的持续时间),以使移动帧速率独立。

function animate() {
    requestAnimationFrame(animate);
    mesh.rotation.x += 0.005;
    mesh.rotation.y += 0.01;

    if (isTouching) {
        console.log("move camera");
    }

    renderer.render(scene, camera);   
}

这是显示基本方法的片段。单击并按住输出的左半部分或右半部分 window 以移动相机。

var camera, scene, renderer, mesh, material, clock;
init();
animate();


var isTouching = false;
var mousePositionX;
window.addEventListener("mousedown", (e) => {
  isTouching = true;
  mousePositionX = e.clientX;
});
window.addEventListener("mouseup", (e) => isTouching = false);


function init() {
  renderer = new THREE.WebGLRenderer();
  renderer.setSize(window.innerWidth, window.innerHeight);
  document.body.appendChild(renderer.domElement);

  clock = new THREE.Clock();

  camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000);
  camera.position.z = 400;

  scene = new THREE.Scene();
  material = new THREE.MeshPhongMaterial();
  var geometry = new THREE.BoxGeometry(200, 200, 200);
  mesh = new THREE.Mesh(geometry, material);
  scene.add(mesh);

  var light = new THREE.AmbientLight(0x404040);
  scene.add(light);

  var directionalLight = new THREE.DirectionalLight(0xffffff);
  directionalLight.position.set(1, 1, 1).normalize();
  scene.add(directionalLight);

  window.addEventListener('resize', onWindowResize, false);
}

function animate() {
  requestAnimationFrame(animate);
  mesh.rotation.x += 0.005;
  mesh.rotation.y += 0.01;

  let deltaTime = clock.getDelta();

  if (isTouching) {
    let speed = 200; // px per second
    let movement = speed * deltaTime;

    if (mousePositionX > window.innerWidth / 2) {
      camera.translateX(-movement);
    } else {
      camera.translateX(movement);
    }
  }

  renderer.render(scene, camera);
}

function onWindowResize() {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);
}
body {
  padding: 0;
  margin: 0;
}

canvas {
  display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/93/three.min.js"></script>