第一人称移动 (相机移动)

全局变量

移动速度

1
const moveSpeed = ref(0.02)

键盘标识位

1
2
3
4
5
6
7
8
9
const keys = {
w: false, // 前移
a: false, // 左移
s: false, // 后移
d: false, // 右移
q: false, // 上升
e: false, // 下降
shift: false, // 加速键
}

键盘事件

按下

1
2
3
4
5
6
7
8
9
10
function onKeyDown(event) {
const key = event.key.toLowerCase()
if (keys.hasOwnProperty(key)) {
keys[key] = true
}
if (event.key === 'Shift') {
keys.shift = true
moveSpeed.value = 0.05 // 加速
}
}

释放

1
2
3
4
5
6
7
8
9
10
function onKeyUp(event) {
const key = event.key.toLowerCase()
if (keys.hasOwnProperty(key)) {
keys[key] = false
}
if (event.key === 'Shift') {
keys.shift = false
moveSpeed.value = 0.02 // 恢复正常速度
}
}

第一人称移动

通过更新 camera.position 来实现移动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
function handleFirstPersonMovement(delta) {
const speed = moveSpeed.value * (delta * 60) // 基于帧率调整速度

// 获取相机的方向向量
const direction = new THREE.Vector3()
camera.getWorldDirection(direction)

// 获取右侧向量
const right = new THREE.Vector3()
right.crossVectors(camera.up, direction).normalize()

// 前后移动 (W/S)
if (keys.w) {
camera.position.addScaledVector(direction, speed)
}
if (keys.s) {
camera.position.addScaledVector(direction, -speed)
}

// 左右移动 (A/D)
if (keys.a) {
camera.position.addScaledVector(right, speed)
}
if (keys.d) {
camera.position.addScaledVector(right, -speed)
}

// 垂直移动 (Q/E)
if (keys.q) {
camera.position.y += speed
}
if (keys.e) {
camera.position.y -= speed
}

// 更新控制器目标点,使其跟随相机
controls.target.copy(camera.position).add(direction)
}

init

相机参数

1
2
3
4
5
6
7
camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
)
camera.position.set(0.3, 0.7, 4) // 设置初始位置,高度为0.7模拟人眼高度

控制参数

1
2
3
4
controls = new OrbitControls(camera, renderer.domElement)
controls.target.set(0, 0.7, 0) // 控制目标点设为相机高度
controls.enableDamping = true // 启用阻尼
controls.dampingFactor = 0.1 // 阻尼系数

键盘监听

1
2
window.addEventListener('keydown', onKeyDown)
window.addEventListener('keyup', onKeyUp)

animate

添加第一人称移动逻辑

1
2
3
4
5
6
7
8
9
10
11
function animate() {
const delta = clock.getDelta()

handleFirstPersonMovement(delta) // 处理第一人称移动

// 更新
if (mixer) mixer.update(delta)
controls.update()
renderer.render(scene, camera)
stats.update()
}