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

如何用Three.js的PointerLockControls实现第三人称视角控制?

问题描述

我想基于Three.js制作第三人称游戏,类似某Demo的效果。旧版Three.js中,可以将Object3D作为锚点绑定相机后传入PointerLockControls,实现场景围绕角色旋转;但新版PointerLockControls构造函数只能传入相机,我当前的代码导致场景围绕相机旋转,尝试移动相机、组合相机与模型等方法都没解决,想知道如何用新版PointerLockControls实现围绕角色旋转的第三人称控制效果。

旧版Demo代码:

let anchor = new THREE.Object3D()
// anchor = character
anchor.position.y = 10

// 此处定义了一个透视相机

anchor.add(camera) // 将相机挂载到锚点上
controls = new PointerLockControls(anchor, container)

我的当前代码:

// 此处定义了一个透视相机

camera.position.set(4, 4, 0)
const webglContainer = document.getElementById('webgl-container')

if (webglContainer) {
    const controls = new PointerLockControls(camera, webglContainer)

    scene.add(controls.getObject())

    webglContainer.addEventListener('click', () => {
        controls.lock()
    })
}
解决方案

核心思路是让角色对象作为旋转锚点,相机作为角色的子对象跟随旋转,同时让PointerLockControls的旋转逻辑作用于角色而非直接作用于相机。具体实现步骤:

  1. 创建角色对象(作为锚点),将相机添加为角色的子对象,设置相机相对于角色的固定偏移(比如后上方的第三人称视角位置)。
  2. 初始化PointerLockControls时仍传入相机,但不要将controls.getObject()添加到场景,而是将角色对象添加到场景。
  3. 监听PointerLockControls的change事件,将相机的旋转同步到角色对象上(只同步Y轴旋转,避免相机俯仰影响角色朝向)。
  4. 处理角色移动时,基于角色的当前朝向计算移动方向,确保移动逻辑符合第三人称视角的预期。

完整代码示例

// 1. 定义基础场景、相机、渲染器
const scene = new THREE.Scene()
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000)
const renderer = new THREE.WebGLRenderer({ antialias: true })
renderer.setSize(window.innerWidth, window.innerHeight)
document.body.appendChild(renderer.domElement)

// 2. 创建角色对象(作为旋转锚点)
const character = new THREE.Object3D()
character.position.y = 1 // 角色基础高度
scene.add(character)

// 3. 将相机挂载到角色上,设置第三人称视角偏移
camera.position.set(0, 2, -5) // 相机在角色后上方
camera.lookAt(character.position) // 相机始终看向角色
character.add(camera)

// 4. 初始化PointerLockControls
const webglContainer = renderer.domElement
const controls = new THREE.PointerLockControls(camera, webglContainer)

// 5. 同步相机旋转到角色(仅Y轴,保持角色水平旋转)
let prevCameraRotationY = 0
controls.addEventListener('change', () => {
    const rotationDelta = camera.rotation.y - prevCameraRotationY
    character.rotation.y += rotationDelta
    prevCameraRotationY = camera.rotation.y
    // 重置相机自身的Y轴旋转,避免累积
    camera.rotation.y = 0
})

// 6. 角色移动逻辑(示例)
const moveSpeed = 0.1
const keys = {}
document.addEventListener('keydown', (e) => keys[e.code] = true)
document.addEventListener('keyup', (e) => keys[e.code] = false)

function updateCharacterMovement() {
    if (!controls.isLocked) return

    const direction = new THREE.Vector3()
    // 基于角色朝向计算移动方向
    if (keys['KeyW']) direction.z -= 1
    if (keys['KeyS']) direction.z += 1
    if (keys['KeyA']) direction.x -= 1
    if (keys['KeyD']) direction.x += 1

    direction.normalize().multiplyScalar(moveSpeed)
    // 将方向转换为世界坐标系下的移动
    character.translateOnAxis(direction, 1)
}

// 7. 渲染循环
function animate() {
    requestAnimationFrame(animate)
    updateCharacterMovement()
    renderer.render(scene, camera)
}
animate()

// 8. 锁定/解锁控制
webglContainer.addEventListener('click', () => {
    if (controls.isLocked) {
        controls.unlock()
    } else {
        controls.lock()
    }
})

关键说明

  • 角色对象作为旋转的核心,相机挂载在其下,所以旋转角色时相机会自然围绕角色转动。
  • 仅同步相机的Y轴旋转到角色,避免相机的俯仰(X轴旋转)影响角色的朝向,保持第三人称视角的合理性。
  • 移动逻辑基于角色的当前朝向,确保WASD移动是相对于角色的前方/后方/左右,符合玩家预期。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 19:05:20