Three.js输入系统基础
在虚拟现实游戏中,输入系统是实现用户与游戏互动的关键部分。Three.js 提供了多种方式来处理用户输入,包括键盘、鼠标、触摸屏和游戏控制器等。本节将详细介绍如何在 Three.js 中实现基本的输入处理,帮助开发者构建更加互动和沉浸式的游戏体验。
键盘输入
键盘输入是最常见的用户输入方式之一,可以用于控制游戏中的角色移动、视角切换等操作。Three.js 本身并没有直接提供键盘输入的处理函数,但我们可以利用 JavaScript 的事件监听机制来实现。
基本原理
JavaScript 的 addEventListener
方法可以用于监听键盘事件,包括 keydown
、keyup
和 keypress
。通过这些事件,我们可以捕获用户的键盘输入,并在 Three.js 场景中做出相应的响应。
代码示例
以下是一个简单的示例,展示如何在 Three.js 中使用键盘输入来控制相机的移动:
// 引入 Three.js
import * as THREE from 'three';
// 创建场景
const scene = new THREE.Scene();
// 创建相机
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 5;
// 创建渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 创建一个简单的立方体
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
// 设置键盘状态
const keys = {
ArrowUp: false,
ArrowDown: false,
ArrowLeft: false,
ArrowRight: false
};
// 监听键盘按下事件
window.addEventListener('keydown', (event) => {
if (event.code in keys) {
keys[event.code] = true;
}
});
// 监听键盘松开事件
window.addEventListener('keyup', (event) => {
if (event.code in keys) {
keys[event.code] = false;
}
});
// 渲染循环
function animate() {
requestAnimationFrame(animate);
// 根据键盘状态更新相机位置
if (keys.ArrowUp) {
camera.position.z -= 0.1;
}
if (keys.ArrowDown) {
camera.position.z += 0.1;
}
if (keys.ArrowLeft) {
camera.position.x -= 0.1;
}
if (keys.ArrowRight) {
camera.position.x += 0.1;
}
// 旋转立方体
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
// 渲染场景
renderer.render(scene, camera);
}
// 开始动画
animate();
代码解释
-
引入 Three.js:首先,我们引入了 Three.js 库。
-
创建场景、相机和渲染器:创建了一个基本的 Three.js 场景、透视相机和渲染器,并将渲染器的 DOM 元素添加到页面中。
-
创建立方体:创建了一个简单的立方体并添加到场景中。
-
设置键盘状态:定义了一个
keys
对象,用于存储各个键盘键的状态(按下或松开)。 -
监听键盘事件:
-
keydown
事件:当用户按下键盘上的键时,将对应键的状态设置为true
。 -
keyup
事件:当用户松开键盘上的键时,将对应键的状态设置为false
。
-
-
渲染循环:在
animate
函数中,根据keys
对象的状态更新相机的位置,并旋转立方体,最后渲染场景。
鼠标输入
鼠标输入是另一个常见的用户输入方式,可以用于控制相机的视角、选择物体等操作。Three.js 提供了一些工具类来帮助处理鼠标输入,如 THREE.Raycaster
和 THREE.Vector2
。
基本原理
THREE.Raycaster
类可以用于从鼠标位置发射光线,检测光线与场景中物体的交点。THREE.Vector2
类用于表示二维向量,通常用于存储鼠标在屏幕上的坐标。
代码示例
以下是一个示例,展示如何在 Three.js 中使用鼠标输入来选择并高亮显示场景中的物体:
// 引入 Three.js
import * as THREE from 'three';
// 创建场景
const scene = new THREE.Scene();
// 创建相机
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 10;
// 创建渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 创建一个简单的立方体
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
// 创建一个光线投射器
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
// 监听鼠标点击事件
window.addEventListener('click', (event) => {
// 将鼠标位置归一化为设备坐标范围
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
// 通过鼠标位置更新光线投射器
raycaster.setFromCamera(mouse, camera);
// 获取所有与光线相交的物体
const intersects = raycaster.intersectObjects(scene.children);
if (intersects.length > 0) {
// 高亮显示第一个相交的物体
intersects[0].object.material.color.set(0xff0000);
}
});
// 渲染循环
function animate() {
requestAnimationFrame(animate);
// 旋转立方体
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
// 渲染场景
renderer.render(scene, camera);
}
// 开始动画
animate();
代码解释
-
引入 Three.js:首先,我们引入了 Three.js 库。
-
创建场景、相机和渲染器:创建了一个基本的 Three.js 场景、透视相机和渲染器,并将渲染器的 DOM 元素添加到页面中。
-
创建立方体:创建了一个简单的立方体并添加到场景中。
-
创建光线投射器和鼠标向量:创建了一个
THREE.Raycaster
对象和一个THREE.Vector2
对象,用于存储鼠标在屏幕上的坐标。 -
监听鼠标点击事件:
-
将鼠标位置归一化为设备坐标范围。
-
使用
raycaster.setFromCamera
方法将鼠标位置转换为射线。 -
使用
raycaster.intersectObjects
方法检测射线与场景中物体的交点。 -
如果有相交的物体,高亮显示第一个相交的物体。
-
-
渲染循环:在
animate
函数中,旋转立方体并渲染场景。
触摸屏输入
触摸屏输入在移动设备上非常常见,可以用于控制相机视角、滑动选择物体等操作。Three.js 也可以通过 JavaScript 的触摸事件来处理触摸屏输入。
基本原理
触摸屏输入可以通过 touchstart
、touchmove
和 touchend
事件来处理。这些事件提供了触摸点的坐标信息,可以用于计算触摸屏上的操作。
代码示例
以下是一个示例,展示如何在 Three.js 中使用触摸屏输入来控制相机的视角旋转:
// 引入 Three.js
import * as THREE from 'three';
// 创建场景
const scene = new THREE.Scene();
// 创建相机
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 10;
// 创建渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 创建一个简单的立方体
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
// 触摸状态
let isDragging = false;
let lastTouchX = 0;
let lastTouchY = 0;
// 监听触摸开始事件
renderer.domElement.addEventListener('touchstart', (event) => {
if (event.touches.length === 1) {
isDragging = true;
lastTouchX = event.touches[0].clientX;
lastTouchY = event.touches[0].clientY;
}
});
// 监听触摸移动事件
renderer.domElement.addEventListener('touchmove', (event) => {
if (isDragging && event.touches.length === 1) {
const touchX = event.touches[0].clientX;
const touchY = event.touches[0].clientY;
// 计算触摸移动的距离
const deltaX = touchX - lastTouchX;
const deltaY = touchY - lastTouchY;
// 更新相机的旋转角度
camera.rotation.y -= deltaX * 0.01;
camera.rotation.x -= deltaY * 0.01;
// 更新上次触摸位置
lastTouchX = touchX;
lastTouchY = touchY;
}
});
// 监听触摸结束事件
renderer.domElement.addEventListener('touchend', (event) => {
isDragging = false;
});
// 渲染循环
function animate() {
requestAnimationFrame(animate);
// 旋转立方体
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
// 渲染场景
renderer.render(scene, camera);
}
// 开始动画
animate();
代码解释
-
引入 Three.js:首先,我们引入了 Three.js 库。
-
创建场景、相机和渲染器:创建了一个基本的 Three.js 场景、透视相机和渲染器,并将渲染器的 DOM 元素添加到页面中。
-
创建立方体:创建了一个简单的立方体并添加到场景中。
-
触摸状态:定义了
isDragging
变量来表示是否正在拖动,lastTouchX
和lastTouchY
变量用于存储上一次触摸的位置。 -
监听触摸事件:
-
touchstart
事件:当用户触摸屏幕时,设置isDragging
为true
,并记录初始触摸位置。 -
touchmove
事件:当用户在屏幕上移动手指时,计算触摸移动的距离,并更新相机的旋转角度。 -
touchend
事件:当用户松开手指时,设置isDragging
为false
。
-
-
渲染循环:在
animate
函数中,旋转立方体并渲染场景。
游戏控制器输入
游戏控制器输入对于虚拟现实游戏尤为重要,可以提供更加丰富的交互体验。Three.js 通过 THREE.Gamepad
类来处理游戏控制器输入。
基本原理
THREE.Gamepad
类可以用于检测连接的游戏控制器,并获取按钮和摇杆的状态。通过这些状态,我们可以实现更加复杂的控制逻辑。
代码示例
以下是一个示例,展示如何在 Three.js 中使用游戏控制器输入来控制相机的移动和旋转:
// 引入 Three.js
import * as THREE from 'three';
// 创建场景
const scene = new THREE.Scene();
// 创建相机
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 10;
// 创建渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 创建一个简单的立方体
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
// 获取游戏控制器
const gamepads = navigator.getGamepads ? navigator.getGamepads() : (navigator.webkitGetGamepads ? navigator.webkitGetGamepads : [] );
// 控制器状态
let isControllerConnected = false;
let controllerIndex = -1;
// 检测控制器连接状态
function checkControllerConnection() {
const pads = gamepads();
for (let i = 0; i < pads.length; i++) {
if (pads[i]) {
isControllerConnected = true;
controllerIndex = i;
break;
}
}
}
// 监听控制器连接事件
window.addEventListener('gamepadconnected', (event) => {
isControllerConnected = true;
controllerIndex = event.gamepad.index;
console.log('Controller connected at index ' + controllerIndex);
});
// 监听控制器断开事件
window.addEventListener('gamepaddisconnected', (event) => {
isControllerConnected = false;
controllerIndex = -1;
console.log('Controller disconnected at index ' + event.gamepad.index);
});
// 渲染循环
function animate() {
requestAnimationFrame(animate);
// 旋转立方体
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
// 检测控制器状态
if (isControllerConnected) {
const pad = gamepads()[controllerIndex];
// 使用左摇杆控制相机移动
const leftStickX = pad.axes[0];
const leftStickY = pad.axes[1];
camera.position.x += leftStickX * 0.1;
camera.position.z -= leftStickY * 0.1;
// 使用右摇杆控制相机旋转
const rightStickX = pad.axes[2];
const rightStickY = pad.axes[3];
camera.rotation.y -= rightStickX * 0.01;
camera.rotation.x -= rightStickY * 0.01;
}
// 渲染场景
renderer.render(scene, camera);
}
// 开始动画
animate();
代码解释
-
引入 Three.js:首先,我们引入了 Three.js 库。
-
创建场景、相机和渲染器:创建了一个基本的 Three.js 场景、透视相机和渲染器,并将渲染器的 DOM 元素添加到页面中。
-
创建立方体:创建了一个简单的立方体并添加到场景中。
-
获取游戏控制器:定义了一个
gamepads
函数,用于获取连接的游戏控制器。 -
控制器状态:定义了
isControllerConnected
和controllerIndex
变量,用于存储控制器的连接状态和索引。 -
检测控制器连接状态:定义了一个
checkControllerConnection
函数,用于检测是否有控制器连接。 -
监听控制器连接和断开事件:
-
gamepadconnected
事件:当控制器连接时,更新isControllerConnected
和controllerIndex
,并输出连接信息。 -
gamepaddisconnected
事件:当控制器断开时,更新isControllerConnected
和controllerIndex
,并输出断开信息。
-
-
渲染循环:在
animate
函数中,根据控制器的状态更新相机的位置和旋转角度,并渲染场景。
总结
通过本节的学习,您应该掌握了如何在 Three.js 中处理键盘、鼠标、触摸屏和游戏控制器输入的基本方法。这些输入方式可以用于实现各种复杂的交互逻辑,帮助您构建更加丰富和沉浸式的虚拟现实游戏。在接下来的章节中,我们将进一步探讨如何利用这些输入方式来实现更高级的交互功能。