Skip to content

Latest commit

 

History

History
434 lines (356 loc) · 14.7 KB

File metadata and controls

434 lines (356 loc) · 14.7 KB

中文 | English

three-player-controller

NPM Package

轻量的第三人称 / 第一人称玩家控制器,开箱即用,基于 three.js 和 three-mesh-bvh 实现人物胶囊体碰撞、BVH 碰撞检测、人物动画、第一/三人称切换与相机避障,利用 three-mesh-bvh 优化碰撞检测性能,大场景下高性能运行。

示例

普通控制

普通控制演示

飞行控制

飞行控制演示

车辆控制

车辆控制演示

移动端控制

移动端控制演示

安装

npm install three-player-controller three three-mesh-bvh

可选依赖

如果需要车辆功能,请额外安装 Rapier:

npm install @dimforge/rapier3d-compat

本地运行

git clone https://github.com/hh-hang/three-player-controller.git
npm install
npm run dev

浏览器访问 http://localhost:5173/three-player-controller/

使用

import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import { playerController } from "three-player-controller";

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 5000);
const controls = new OrbitControls(camera, renderer.domElement);

const player = playerController();

await player.init({
    scene,
    camera,
    controls,
    playerModelConfig: {
        url: "./glb/person.glb",
        scale: 0.001,
        idleAnim: "idle",
        walkAnim: "walk",
        runAnim: "run",
        jumpAnim: "jump",
        headBoneName: "Head",
        firstPersonCameraOffset: [0, 10, 20],
    },
    initPos: new THREE.Vector3(0, 0, 0),
    colliderMeshUrl: "./glb/world-collider.glb",
    isFirstPerson: false,
    enableOverShoulderView: false,
});

await player.loadVehicleModel({
    url: "./glb/bugatti.glb",
    position: new THREE.Vector3(22, 3.69, 14.5),
    wheelsNames: ["Wheel_LF", "Wheel_RF", "Wheel_LR", "Wheel_RR"],
    scale: 0.1,
    animations: {
        openDoorAnim: "openDoorLF",
    },
    boardingPoint: new THREE.Vector3(0.5, 0, 1.8),
    seatOffset: new THREE.Vector3(0, 0.6, 0),
    chassisRatio: 0.15,
    suspensionRestLengthRatio: 0.2,
});

function animate() {
    requestAnimationFrame(animate);
    player.update();
    renderer.render(scene, camera);
}

animate();

API

生命周期

方法 说明
init(opts, callback?) 初始化控制器,资源加载完成后执行 callback
update(dt?) 每帧更新移动、碰撞和动画。
destroy() 销毁控制器并移除事件监听。
reset(pos?) 将角色重置到指定位置或初始位置。
switchPlayerModel(model) 运行时切换角色模型,并保留当前位置和朝向。
loadVehicleModel(opts) 加载车辆,可重复调用加载多辆车。
changeView() 切换第一 / 第三人称视角。

状态获取

方法 返回内容
getPosition() 当前角色位置。
getVelocity() 当前角色速度,类型为 THREE.Vector3
getIsFirstPerson() 当前是否为第一人称。
getIsFlying() 当前是否处于飞行模式。
getIsOnGround() 当前是否在地面上。
getControllerMode() 控制模式,0 为人物,1 为车辆。
getPlayerModel() 当前加载的人物模型对象。
getPlayerCapsule() 角色胶囊体网格。
getActiveVehicle() 当前正在使用的车辆实例。
getAllVehicles() 所有已加载车辆实例。
getCollider() 用于 BVH 检测的合并碰撞网格。
getCurrentPlayerAnimationName() 当前播放的动画片段名,没有则返回 null
getCenterScreenRaycastHit() 屏幕中心射线检测结果,适合做瞄准或交互。

输入与运行时控制

方法 说明
setInput(input) 注入外部输入状态,适合手柄或自定义按键系统。
setMouseSensitivity(v) 设置鼠标灵敏度。
setPlayerScale(v) 动态修改角色缩放,并同步碰撞相关参数。
setPlayerSpeed(v) 设置移动速度。
setPlayerFlySpeed(v) 设置飞行速度。
setJumpHeight(v) 设置跳跃高度。
setGravity(v) 设置重力。
setMinCamDistance(v) 设置第三人称最小镜头距离。
setMaxCamDistance(v) 设置第三人称最大镜头距离。
setThirdMouseMode(v) 设置第三人称鼠标模式:`0
setEnableZoom(v) 设置是否允许镜头缩放。
setOverShoulderView(v) 开关过肩视角偏移。
setDebug(v) 开关碰撞体调试显示。
setEnableToward(v) 开关鼠标驱动的朝向 / 视角更新。

动画

方法 说明
registerAnimation(key, clipName, opts?) 注册自定义动画片段。
playAnimation(key, opts?) 播放已注册的自定义动画。
registerLocomotionSet(setName, map) 注册一套移动动画集合,用于替换内置移动动画。
switchLocomotionSet(setName, fade?) 切换到指定的移动动画集合。

registerAnimation

player.registerAnimation(key, clipName, {
    loop?: boolean,
    timeScale?: number,
    duration?: number,
    clampWhenFinished?: boolean,
    onFinished?: () => void,
});
  • 当前实现支持 duration,并且会优先于 timeScale 生效。

playAnimation

player.playAnimation(key, {
    fade?: number,
    force?: boolean,
});

registerLocomotionSet

player.registerLocomotionSet("combat", {
    idle: "CombatIdle",
    walking: "CombatWalk",
    walking_backward: "CombatBack",
    running: "CombatRun",
    jumping: "CombatJump",
    flyidle: "CombatFlyIdle",
    flying: "CombatFly",
});

事件

player.onAnimationChange((name, action) => {});
player.onBeforeViewChange((isFirstPerson) => {});
player.onViewChange((isFirstPerson) => {});
player.onGroundChange((onGround) => {});
player.onVehicleEnter((vehicle) => {});
player.onVehicleExit((vehicle) => {});
player.onTowardChange((dx, dy, speed) => {});
事件 说明
onAnimationChange 角色当前动画切换时触发。
onBeforeViewChange 第一 / 第三人称切换前触发。
onViewChange 第一 / 第三人称切换后触发。
onGroundChange 落地状态变化时触发。
onVehicleEnter 上车完成后触发。
onVehicleExit 下车完成后触发。
onTowardChange 朝向 / 视角输入更新时触发。

全局输入监听辅助函数

import { onAllEvent, offAllEvent } from "three-player-controller";
  • onAllEvent():开启键盘和鼠标输入监听。
  • offAllEvent():关闭键盘和鼠标输入监听。

默认键位

按键 功能
W / ArrowUp 前进
S / ArrowDown 后退
A / ArrowLeft 左移
D / ArrowRight 右移
Shift 冲刺
Space 跳跃
V 切换视角
F 切换飞行模式
E 上车 / 下车
鼠标移动 控制视角

setInput

player.setInput({
    moveX: 1 | 0 | -1,
    moveY: 1 | 0 | -1,
    lookDeltaX: number,
    lookDeltaY: number,
    jump: boolean,
    shift: boolean,
    toggleView: boolean,
    toggleFly: boolean,
    toggleVehicle: boolean,
});

类型定义

PlayerControllerOptions

type PlayerControllerOptions = {
    scene: THREE.Scene;
    camera: THREE.PerspectiveCamera;
    controls: any;
    playerModelConfig: PlayerModelOptions;
    initPos?: THREE.Vector3;
    mouseSensitivity?: number;
    minCamDistance?: number;
    maxCamDistance?: number;
    colliderMeshUrl?: string;
    isShowMobileControls?: boolean;
    mobileControls?: MobileControlsOptions;
    thirdMouseMode?: 0 | 1 | 2 | 3;
    enableZoom?: boolean;
    enableOverShoulderView?: boolean;
    isFirstPerson?: boolean;
};

PlayerModelOptions

type PlayerModelOptions = {
    url: string;
    scale: number;
    idleAnim: string;
    walkAnim: string;
    runAnim: string;
    jumpAnim: string;
    leftWalkAnim?: string;
    rightWalkAnim?: string;
    backwardAnim?: string;
    flyAnim?: string;
    flyIdleAnim?: string;
    enterCarAnim?: string;
    exitCarAnim?: string;
    gravity?: number;
    jumpHeight?: number;
    speed?: number;
    flySpeed?: number;
    rotateY?: number;
    headBoneName?: string;
    firstPersonCameraOffset?: [number, number, number];
    flyEnabled?: boolean;
    capsuleRadiusRatio?: number;
};

MobileControlsOptions

type MobileControlsOptions = {
    joystick?: boolean;
    jump?: boolean;
    fly?: boolean;
    view?: boolean;
    vehicle?: boolean;
};

VehicleOptions

type VehicleOptions = {
    url: string;
    position: THREE.Vector3;
    wheelsNames: string[];
    scale?: number;
    animations: { openDoorAnim?: string };
    boardingPoint: THREE.Vector3;
    seatOffset?: THREE.Vector3;
    chassisRatio?: number;
    suspensionRestLengthRatio?: number;
    followVehicleDirection?: boolean;
    speedMultiplier?: number;
};

字段说明

PlayerControllerOptions

字段 类型 必填 默认值 说明
scene THREE.Scene three.js 场景实例。
camera THREE.PerspectiveCamera three.js 相机实例。
controls any 外部相机控制器,实际通常传入 OrbitControls
playerModelConfig PlayerModelOptions 角色模型与角色参数配置。
initPos THREE.Vector3 (0, 0, 0) 初始出生点。
mouseSensitivity number 5 鼠标灵敏度。
minCamDistance number 100 第三人称最小镜头距离。
maxCamDistance number 440 第三人称最大镜头距离。
colliderMeshUrl string 自定义碰撞网格 GLB/GLTF 路径;不传时会从场景里收集网格生成碰撞体。
isShowMobileControls boolean true 是否在移动端显示虚拟控制 UI。
mobileControls MobileControlsOptions 全部显示 移动端按钮显隐配置。
thirdMouseMode 0 | 1 | 2 | 3 1 第三人称鼠标模式。
enableZoom boolean false 是否允许滚轮缩放。
enableOverShoulderView boolean false 是否启用过肩视角。
isFirstPerson boolean false 初始化时是否直接进入第一人称。

PlayerModelOptions

字段 类型 必填 默认值 说明
url string 人物模型路径(GLB/GLTF)。
scale number 人物模型缩放。
idleAnim string Idle 动画名,需与模型内动画名一致。
walkAnim string Walk 动画名,需与模型内动画名一致。
runAnim string Run 动画名,需与模型内动画名一致。
jumpAnim string Jump 动画名,需与模型内动画名一致。
leftWalkAnim string walkAnim 左移动画名,不填则复用 walkAnim
rightWalkAnim string walkAnim 右移动画名,不填则复用 walkAnim
backwardAnim string walkAnim 后退动画名,不填则复用 walkAnim
flyAnim string idleAnim 飞行动画名,不填则复用 idleAnim
flyIdleAnim string idleAnim 飞行待机动画名,不填则复用 idleAnim
enterCarAnim string 上车动画名;使用车辆功能时建议配置。
exitCarAnim string 下车动画名;使用车辆功能时建议配置。
gravity number -2400 重力基准值,会按角色 scale 缩放。
jumpHeight number 600 跳跃高度基准值,会按角色 scale 缩放。
speed number 300 角色移动速度基准值,会按角色 scale 缩放。
flySpeed number 2100 飞行速度基准值,会按角色 scale 缩放。
rotateY number 0 模型绕 Y 轴的额外旋转偏移。
headBoneName string 头部骨骼或节点名称,用于第一人称相机挂载。
firstPersonCameraOffset [number, number, number] 有内置默认值 第一人称相机局部偏移。若找到 headBoneName,偏移相对头骨骼;否则相对胶囊体。
flyEnabled boolean true 是否允许飞行模式。
capsuleRadiusRatio number 1 胶囊体半径倍率,用于微调碰撞宽度。

MobileControlsOptions

字段 类型 必填 默认值 说明
joystick boolean true 是否显示摇杆。
jump boolean true 是否显示跳跃按钮。
fly boolean true 是否显示飞行按钮。
view boolean true 是否显示视角切换按钮。
vehicle boolean true 是否显示上下车按钮。

VehicleOptions

字段 类型 必填 默认值 说明
url string 车辆模型路径(GLB/GLTF)。
position THREE.Vector3 车辆初始世界坐标。
wheelsNames string[] 车轮节点名数组,顺序为左前、右前、左后、右后。
scale number 1 车辆模型缩放。
animations.openDoorAnim string 车门开关动画名。
boardingPoint THREE.Vector3 上车点,局部坐标。
seatOffset THREE.Vector3 (0, 0, 0) 角色上车后座位偏移。
chassisRatio number 0.2 底盘高度比例。
suspensionRestLengthRatio number 0.2 悬挂静止长度比例。
followVehicleDirection boolean true 驾驶时镜头是否跟随车辆朝向。
speedMultiplier number 1 单车速度倍率。

致谢

three-mesh-bvh

three