three-player-controller 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -38,6 +38,17 @@ declare function playerController(): {
38
38
  destroy: () => void;
39
39
  setInput: (i: any) => void;
40
40
  getposition: () => THREE.Vector3;
41
+ loadVehicleModel: (params: {
42
+ url: string;
43
+ position: THREE.Vector3;
44
+ scale?: number;
45
+ animations: {
46
+ openDoorAnim?: string;
47
+ wheelsTurnAnim?: string;
48
+ turnLeftAnim?: string;
49
+ turnRightAnim?: string;
50
+ };
51
+ }) => Promise<void>;
41
52
  };
42
53
  declare function onAllEvent(): void;
43
54
  declare function offAllEvent(): void;
package/dist/index.d.ts CHANGED
@@ -38,6 +38,17 @@ declare function playerController(): {
38
38
  destroy: () => void;
39
39
  setInput: (i: any) => void;
40
40
  getposition: () => THREE.Vector3;
41
+ loadVehicleModel: (params: {
42
+ url: string;
43
+ position: THREE.Vector3;
44
+ scale?: number;
45
+ animations: {
46
+ openDoorAnim?: string;
47
+ wheelsTurnAnim?: string;
48
+ turnLeftAnim?: string;
49
+ turnRightAnim?: string;
50
+ };
51
+ }) => Promise<void>;
41
52
  };
42
53
  declare function onAllEvent(): void;
43
54
  declare function offAllEvent(): void;
package/dist/index.js CHANGED
@@ -60,7 +60,7 @@ var PlayerController = class {
60
60
  constructor() {
61
61
  // ==================== 基本配置与参数 ====================
62
62
  this.loader = new import_GLTFLoader.GLTFLoader();
63
- // 0: 隐藏鼠标控制朝向及视角,1: 隐藏鼠标仅控制视角,2: 显示鼠标拖拽控制朝向及视角, 3: 显示鼠标拖拽仅控制视角
63
+ // 0: 普通 1: 飞行 2: 车辆
64
64
  // ==================== 玩家基本属性 ====================
65
65
  this.playerRadius = 45;
66
66
  this.playerHeight = 180;
@@ -74,6 +74,7 @@ var PlayerController = class {
74
74
  this.collider = null;
75
75
  this.visualizer = null;
76
76
  this.person = null;
77
+ this.vehicle = null;
77
78
  // ==================== 状态开关 ====================
78
79
  this.playerIsOnGround = false;
79
80
  this.isupdate = true;
@@ -236,6 +237,9 @@ var PlayerController = class {
236
237
  this.playPersonAnimationByName("jumping");
237
238
  }
238
239
  break;
240
+ case "KeyE":
241
+ this.setDrive();
242
+ break;
239
243
  }
240
244
  };
241
245
  /**
@@ -503,6 +507,50 @@ var PlayerController = class {
503
507
  this.reset();
504
508
  this.player.rotateY(this.playerModel.rotateY ?? 0);
505
509
  }
510
+ // ==================== 车辆模型相关 ====================
511
+ /**
512
+ * 加载车辆模型与动画
513
+ */
514
+ async loadVehicleModel(params) {
515
+ try {
516
+ const { url, position, scale = 1 } = params;
517
+ const gltf = await this.loader.loadAsync(url);
518
+ this.vehicle = gltf.scene;
519
+ this.vehicle.scale.set(scale, scale, scale);
520
+ this.vehicle.position.copy(position);
521
+ this.vehicle.traverse((child) => {
522
+ if (child.isMesh) {
523
+ child.castShadow = true;
524
+ child.receiveShadow = true;
525
+ }
526
+ });
527
+ this.scene.add(this.vehicle);
528
+ const animations = gltf.animations ?? [];
529
+ this.vehicleActions = /* @__PURE__ */ new Map();
530
+ this.vehicleMixer = new THREE.AnimationMixer(this.vehicle);
531
+ const animationMappings = [
532
+ [params.animations?.openDoorAnim ?? "", "open_door"],
533
+ [params.animations?.wheelsTurnAnim ?? "", "wheels_turn"],
534
+ [params.animations?.turnLeftAnim ?? "", "turn_left"],
535
+ [params.animations?.turnRightAnim ?? "", "turn_right"]
536
+ ];
537
+ const findClip = (name) => animations.find((a) => a.name === name);
538
+ for (const [clipName, actionName] of animationMappings) {
539
+ const clip = findClip(clipName);
540
+ if (!clip) continue;
541
+ const action = this.vehicleMixer.clipAction(clip);
542
+ action.setLoop(THREE.LoopOnce, 1);
543
+ action.clampWhenFinished = true;
544
+ action.setEffectiveTimeScale(2);
545
+ action.enabled = true;
546
+ action.setEffectiveWeight(0);
547
+ this.vehicleActions.set(actionName, action);
548
+ }
549
+ console.log("\u5F00\u95E8\u52A8\u753B", this.vehicleActions.get("open_door"));
550
+ } catch (error) {
551
+ console.error("\u52A0\u8F7D\u8F66\u8F86\u6A21\u578B\u5931\u8D25:", error);
552
+ }
553
+ }
506
554
  // ==================== 相机与视角控制 ====================
507
555
  /**
508
556
  * 第一/三人称视角切换
@@ -524,6 +572,10 @@ var PlayerController = class {
524
572
  }
525
573
  this.setPointerLock();
526
574
  }
575
+ setDrive() {
576
+ this.controllerMode = 2;
577
+ this.person?.attach(this.vehicle);
578
+ }
527
579
  /**
528
580
  * 设置指针锁定
529
581
  */
@@ -766,8 +818,12 @@ var PlayerController = class {
766
818
  this.player.position.addScaledVector(this.playerVelocity, delta);
767
819
  this.playerIsOnGround = true;
768
820
  } else {
769
- this.playerVelocity.set(0, 0, 0);
770
- this.playerIsOnGround = true;
821
+ if (this.spacePressed) {
822
+ this.playerVelocity.y += delta * this.gravity;
823
+ } else {
824
+ this.playerVelocity.set(0, 0, 0);
825
+ this.playerIsOnGround = true;
826
+ }
771
827
  }
772
828
  } else if (playerDistanceFromGround > minH && playerDistanceFromGround < h) {
773
829
  this.playerVelocity.set(0, 0, 0);
@@ -898,6 +954,7 @@ var PlayerController = class {
898
954
  */
899
955
  updateMixers(delta) {
900
956
  if (this.personMixer) this.personMixer.update(delta);
957
+ if (this.vehicleMixer) this.vehicleMixer.update(delta);
901
958
  }
902
959
  /**
903
960
  * 重置玩家位置
@@ -1220,7 +1277,8 @@ function playerController() {
1220
1277
  update: (dt) => c.update(dt),
1221
1278
  destroy: () => c.destroy(),
1222
1279
  setInput: (i) => c.setInput(i),
1223
- getposition: () => c.getPosition()
1280
+ getposition: () => c.getPosition(),
1281
+ loadVehicleModel: (params) => c.loadVehicleModel(params)
1224
1282
  };
1225
1283
  }
1226
1284
  function onAllEvent() {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/playerController.ts"],"sourcesContent":["export * from \"./playerController\";\r\n","import * as THREE from \"three\";\nimport { acceleratedRaycast, MeshBVH, MeshBVHHelper } from \"three-mesh-bvh\";\nimport type { GLTF } from \"three/examples/jsm/Addons.js\";\nimport { OrbitControls } from \"three/examples/jsm/controls/OrbitControls.js\";\nimport { RoundedBoxGeometry } from \"three/examples/jsm/geometries/RoundedBoxGeometry.js\";\nimport { DRACOLoader } from \"three/examples/jsm/loaders/DRACOLoader.js\";\nimport { GLTFLoader } from \"three/examples/jsm/loaders/GLTFLoader.js\";\nimport * as BufferGeometryUtils from \"three/examples/jsm/utils/BufferGeometryUtils.js\";\nimport flyIconModule from \"../assets/imgs/fly.png\";\nimport jumpIconModule from \"../assets/imgs/jump.png\";\nimport viewIconModule from \"../assets/imgs/view.png\";\n\nTHREE.Mesh.prototype.raycast = acceleratedRaycast; // 启用加速 raycast\n\nlet controllerInstance: PlayerController | null = null;\nconst clock = new THREE.Clock();\n\nexport type PlayerControllerOptions = {\n scene: THREE.Scene;\n camera: THREE.PerspectiveCamera;\n controls: OrbitControls;\n playerModel: {\n url: string;\n idleAnim: string;\n walkAnim: string;\n runAnim: string;\n jumpAnim: string;\n leftWalkAnim?: string;\n rightWalkAnim?: string;\n backwardAnim?: string;\n flyAnim?: string;\n flyIdleAnim?: string;\n scale: number;\n gravity?: number;\n jumpHeight?: number;\n speed?: number;\n rotateY?: number;\n };\n initPos?: THREE.Vector3;\n mouseSensity?: number;\n minCamDistance?: number;\n maxCamDistance?: number;\n colliderMeshUrl?: string;\n isShowMobileControls?: boolean;\n thirdMouseMode?: 0 | 1 | 2 | 3;\n};\n\nclass PlayerController {\n // ==================== 基本配置与参数 ====================\n loader: GLTFLoader = new GLTFLoader();\n scene!: THREE.Scene;\n camera!: THREE.PerspectiveCamera;\n controls!: OrbitControls;\n playerModel!: PlayerControllerOptions[\"playerModel\"];\n initPos!: THREE.Vector3;\n visualizeDepth!: number;\n gravity!: number;\n jumpHeight!: number;\n playerSpeed!: number;\n mouseSensity!: number;\n originPlayerSpeed!: number;\n colliderMeshUrl!: string;\n isShowMobileControls!: boolean;\n thirdMouseMode!: 0 | 1 | 2 | 3; // 0: 隐藏鼠标控制朝向及视角,1: 隐藏鼠标仅控制视角,2: 显示鼠标拖拽控制朝向及视角, 3: 显示鼠标拖拽仅控制视角\n\n // ==================== 玩家基本属性 ====================\n playerRadius: number = 45;\n playerHeight: number = 180;\n isFirstPerson: boolean = false;\n boundingBoxMinY: number = 0;\n\n // ==================== 测试参数 ====================\n displayPlayer: boolean = false;\n displayCollider: boolean = false;\n displayVisualizer: boolean = false;\n\n // ==================== 场景对象 ====================\n collider: THREE.Mesh | null = null;\n visualizer: MeshBVHHelper | null = null;\n player!: THREE.Mesh & { capsuleInfo?: any };\n person: THREE.Object3D | null = null;\n\n // ==================== 状态开关 ====================\n playerIsOnGround: boolean = false;\n isupdate: boolean = true;\n isFlying: boolean = false;\n\n // ==================== 输入状态 ====================\n fwdPressed: boolean = false;\n bkdPressed: boolean = false;\n lftPressed: boolean = false;\n rgtPressed: boolean = false;\n spacePressed: boolean = false;\n ctPressed: boolean = false;\n shiftPressed: boolean = false;\n\n // ==================== 移动端输入 ====================\n prevJoyState = { dirX: 0, dirY: 0, shift: false };\n nippleModule: any = null;\n joystickManager: any = null;\n joystickZoneEl: HTMLDivElement | null = null;\n lookAreaEl: HTMLDivElement | null = null;\n jumpBtnEl: HTMLButtonElement | null = null;\n flyBtnEl: HTMLButtonElement | null = null;\n viewBtnEl: HTMLButtonElement | null = null;\n lookPointerId: number | null = null;\n isLookDown = false;\n lastTouchX = 0;\n lastTouchY = 0;\n\n // ==================== 第三人称相机参数 ====================\n _camCollisionLerp: number = 0.18; // 平滑系数\n _camEpsilon: number = 0.35; // 摄像机与障碍物之间的安全距离\n _minCamDistance: number = 1.0; // 摄像机最小距离\n _maxCamDistance: number = 4.4; // 摄像机最大距离\n orginMaxCamDistance: number = 4.4;\n\n // ==================== 物理/运动 ====================\n playerVelocity = new THREE.Vector3(); // 玩家速度向量\n readonly upVector = new THREE.Vector3(0, 1, 0);\n\n // ==================== 临时复用向量/矩阵 ====================\n readonly tempVector = new THREE.Vector3();\n readonly tempVector2 = new THREE.Vector3();\n readonly tempBox = new THREE.Box3();\n readonly tempMat = new THREE.Matrix4();\n readonly tempSegment = new THREE.Line3();\n\n // ==================== 动画相关 ====================\n personMixer?: THREE.AnimationMixer;\n personActions?: Map<string, THREE.AnimationAction>;\n idleAction!: THREE.AnimationAction;\n walkAction!: THREE.AnimationAction;\n leftWalkAction!: THREE.AnimationAction;\n rightWalkAction!: THREE.AnimationAction;\n backwardAction!: THREE.AnimationAction;\n jumpAction!: THREE.AnimationAction;\n runAction!: THREE.AnimationAction;\n flyidleAction!: THREE.AnimationAction;\n flyAction!: THREE.AnimationAction;\n actionState!: THREE.AnimationAction;\n recheckAnimTimer: any | null = null;\n\n // ==================== 相机朝向/移动复用向量 ====================\n readonly camDir = new THREE.Vector3();\n readonly moveDir = new THREE.Vector3();\n readonly targetQuat = new THREE.Quaternion();\n readonly targetMat = new THREE.Matrix4();\n readonly rotationSpeed = 10;\n readonly DIR_FWD = new THREE.Vector3(0, 0, -1);\n readonly DIR_BKD = new THREE.Vector3(0, 0, 1);\n readonly DIR_LFT = new THREE.Vector3(-1, 0, 0);\n readonly DIR_RGT = new THREE.Vector3(1, 0, 0);\n readonly DIR_UP = new THREE.Vector3(0, 1, 0);\n\n // ==================== 射线检测 ====================\n readonly _personToCam = new THREE.Vector3();\n readonly _originTmp = new THREE.Vector3();\n readonly _raycaster = new THREE.Raycaster(new THREE.Vector3(), new THREE.Vector3(0, -1, 0));\n readonly _raycasterPersonToCam = new THREE.Raycaster(new THREE.Vector3(), new THREE.Vector3());\n\n constructor() {\n // 射线检测时只返回第一个碰撞\n (this._raycaster as any).firstHitOnly = true;\n (this._raycasterPersonToCam as any).firstHitOnly = true;\n }\n\n // ==================== 初始化相关方法 ====================\n\n /**\n * 初始化控制器\n */\n async init(opts: PlayerControllerOptions, callback?: () => void) {\n this.scene = opts.scene;\n this.camera = opts.camera;\n this.camera.rotation.order = \"YXZ\";\n this.controls = opts.controls;\n this.playerModel = opts.playerModel;\n this.initPos = opts.initPos ?? new THREE.Vector3(0, 0, 0);\n this.mouseSensity = opts.mouseSensity ?? 5;\n\n const s = this.playerModel.scale;\n this.visualizeDepth = 0 * s;\n this.gravity = (opts.playerModel.gravity ?? -2400) * s;\n this.jumpHeight = (opts.playerModel.jumpHeight ?? 800) * s;\n this.originPlayerSpeed = (opts.playerModel.speed ?? 400) * s;\n this.playerSpeed = this.originPlayerSpeed;\n this.playerModel.rotateY = opts.playerModel.rotateY ?? 0;\n\n this._camCollisionLerp = 0.18;\n this._camEpsilon = 35 * s;\n this._minCamDistance = (opts.minCamDistance ?? 100) * s;\n this._maxCamDistance = (opts.maxCamDistance ?? 440) * s;\n this.orginMaxCamDistance = this._maxCamDistance;\n this.thirdMouseMode = opts.thirdMouseMode ?? 1;\n\n // 判断是否移动端\n const isMobileDevice = () => (navigator.maxTouchPoints && navigator.maxTouchPoints > 0) || \"ontouchstart\" in window || /Mobi|Android|iPhone|iPad|iPod/i.test(navigator.userAgent);\n\n this.isShowMobileControls = (opts.isShowMobileControls ?? true) && isMobileDevice();\n if (this.isShowMobileControls) {\n await this.initMobileControls();\n }\n\n // 创建BVH碰撞体\n await this.createBVH(opts.colliderMeshUrl);\n\n // 创建玩家胶囊体\n this.createPlayer();\n\n // 加载玩家模型\n await this.loadPersonGLB();\n\n // 等待资源加载完毕再设置摄像机\n if (this.isFirstPerson && this.person) {\n this.person.add(this.camera);\n }\n\n this.onAllEvent();\n this.setCameraPos();\n this.setControls();\n if (callback) callback();\n }\n\n /**\n * 初始化加载器\n */\n async initLoader() {\n const dracoLoader = new DRACOLoader();\n dracoLoader.setDecoderPath(\"https://unpkg.com/three@0.180.0/examples/jsm/libs/draco/gltf/\");\n dracoLoader.setDecoderConfig({ type: \"js\" });\n this.loader.setDRACOLoader(dracoLoader);\n }\n\n // ==================== 玩家模型相关方法 ====================\n\n /**\n * 加载玩家模型与动画\n */\n async loadPersonGLB() {\n try {\n const gltf: GLTF = await this.loader.loadAsync(this.playerModel.url);\n this.person = gltf.scene;\n const sc = this.playerModel.scale;\n const h = this.playerHeight * sc;\n\n this.person.scale.set(sc, sc, sc);\n this.person.position.set(0, -h * 0.75, 0);\n this.person.traverse((child: any) => {\n if (child.isMesh) {\n child.castShadow = true;\n child.receiveShadow = true;\n }\n });\n\n this.player.add(this.person);\n this.reset();\n\n // 创建动画混合器\n this.personMixer = new THREE.AnimationMixer(this.person);\n const animations = gltf.animations ?? [];\n this.personActions = new Map<string, THREE.AnimationAction>();\n\n // 动画映射表\n const animationMappings: [string, string][] = [\n [this.playerModel.idleAnim, \"idle\"],\n [this.playerModel.walkAnim, \"walking\"],\n [this.playerModel.leftWalkAnim || this.playerModel.walkAnim, \"left_walking\"],\n [this.playerModel.rightWalkAnim || this.playerModel.walkAnim, \"right_walking\"],\n [this.playerModel.backwardAnim || this.playerModel.walkAnim, \"walking_backward\"],\n [this.playerModel.jumpAnim, \"jumping\"],\n [this.playerModel.runAnim, \"running\"],\n [this.playerModel.flyIdleAnim || this.playerModel.idleAnim, \"flyidle\"],\n [this.playerModel.flyAnim || this.playerModel.idleAnim, \"flying\"],\n ];\n\n // 注册动画动作\n const findClip = (name: string) => animations.find((a: any) => a.name === name);\n for (const [clipName, actionName] of animationMappings) {\n const clip = findClip(clipName);\n if (!clip) continue;\n\n const action = this.personMixer.clipAction(clip);\n\n if (actionName === \"jumping\") {\n action.setLoop(THREE.LoopOnce, 1);\n action.clampWhenFinished = true;\n action.setEffectiveTimeScale(1.2);\n } else {\n action.setLoop(THREE.LoopRepeat, Infinity);\n action.clampWhenFinished = false;\n action.setEffectiveTimeScale(1);\n }\n\n action.enabled = true;\n action.setEffectiveWeight(0);\n this.personActions.set(actionName, action);\n }\n\n // 获取动画动作引用\n this.idleAction = this.personActions.get(\"idle\")!;\n this.walkAction = this.personActions.get(\"walking\")!;\n this.leftWalkAction = this.personActions.get(\"left_walking\")!;\n this.rightWalkAction = this.personActions.get(\"right_walking\")!;\n this.backwardAction = this.personActions.get(\"walking_backward\")!;\n this.jumpAction = this.personActions.get(\"jumping\")!;\n this.runAction = this.personActions.get(\"running\")!;\n this.flyidleAction = this.personActions.get(\"flyidle\")!;\n this.flyAction = this.personActions.get(\"flying\")!;\n\n // 激活空闲动作\n this.idleAction.setEffectiveWeight(1);\n this.idleAction.play();\n this.actionState = this.idleAction;\n\n // 监听动画完成事件\n this.personMixer.addEventListener(\"finished\", (ev: any) => {\n const finishedAction: THREE.AnimationAction = ev.action;\n\n if (finishedAction === this.jumpAction) {\n if (this.fwdPressed) {\n this.playPersonAnimationByName(this.shiftPressed ? \"running\" : \"walking\");\n return;\n }\n if (this.bkdPressed) {\n this.playPersonAnimationByName(\"walking_backward\");\n return;\n }\n if (this.rgtPressed || this.lftPressed) {\n this.playPersonAnimationByName(\"walking\");\n return;\n }\n this.playPersonAnimationByName(\"idle\");\n }\n });\n } catch (error) {\n console.error(\"加载玩家模型失败:\", error);\n }\n }\n\n /**\n * 平滑切换人物动画\n */\n playPersonAnimationByName(name: string, fade = 0.18) {\n if (!this.personActions || this.ctPressed) return;\n\n const next = this.personActions.get(name);\n if (!next || this.actionState === next) return;\n\n const prev = this.actionState;\n\n next.reset();\n next.setEffectiveWeight(1);\n next.play();\n\n if (prev && prev !== next) {\n prev.fadeOut(fade);\n next.fadeIn(fade);\n } else {\n next.fadeIn(fade);\n }\n\n this.actionState = next;\n }\n\n /**\n * 创建玩家胶囊体\n */\n createPlayer() {\n const material = new THREE.MeshStandardMaterial({\n color: new THREE.Color(1, 0, 0),\n shadowSide: THREE.DoubleSide,\n depthTest: false,\n transparent: true,\n opacity: this.displayPlayer ? 0.5 : 0,\n wireframe: true,\n depthWrite: false,\n });\n\n const r = this.playerRadius * this.playerModel.scale;\n const h = this.playerHeight * this.playerModel.scale;\n this.player = new THREE.Mesh(new RoundedBoxGeometry(r * 2, h, r * 2, 1, 75), material) as typeof this.player;\n\n this.player.geometry.translate(0, -h * 0.25, 0);\n this.player.capsuleInfo = {\n radius: r,\n segment: new THREE.Line3(new THREE.Vector3(), new THREE.Vector3(0, -h * 0.5, 0)),\n };\n\n this.player.name = \"capsule\";\n this.scene.add(this.player);\n this.reset();\n\n // 设置初始朝向\n this.player.rotateY(this.playerModel.rotateY ?? 0);\n }\n\n // ==================== 相机与视角控制 ====================\n\n /**\n * 第一/三人称视角切换\n */\n changeView() {\n this.isFirstPerson = !this.isFirstPerson;\n\n if (this.isFirstPerson) {\n this.player.attach(this.camera);\n this.camera.position.set(0, 40 * this.playerModel.scale, 30 * this.playerModel.scale);\n this.camera.rotation.set(0, Math.PI, 0);\n } else {\n this.scene.attach(this.camera);\n const worldPos = this.player.position.clone();\n const dir = new THREE.Vector3(0, 0, -1).applyQuaternion(this.player.quaternion);\n const angle = Math.atan2(dir.z, dir.x);\n const offset = new THREE.Vector3(Math.cos(angle) * 400 * this.playerModel.scale, 200 * this.playerModel.scale, Math.sin(angle) * 400 * this.playerModel.scale);\n this.camera.position.copy(worldPos).add(offset);\n this.controls.target.copy(worldPos);\n }\n\n this.setPointerLock();\n }\n\n /**\n * 设置指针锁定\n */\n setPointerLock() {\n if (((this.thirdMouseMode === 0 || this.thirdMouseMode === 1) && !this.isFirstPerson) || this.isFirstPerson) {\n document.body.requestPointerLock();\n }\n }\n\n /**\n * 设置摄像机初始位置\n */\n setCameraPos() {\n if (this.isFirstPerson) {\n this.camera.position.set(0, 40 * this.playerModel.scale, 30 * this.playerModel.scale);\n } else {\n const worldPos = this.player.position.clone();\n const dir = new THREE.Vector3(0, 0, -1).applyQuaternion(this.player.quaternion);\n const angle = Math.atan2(dir.z, dir.x);\n const offset = new THREE.Vector3(Math.cos(angle) * 400 * this.playerModel.scale, -100 * this.playerModel.scale, Math.sin(angle) * 400 * this.playerModel.scale);\n this.camera.position.copy(worldPos).add(offset);\n }\n this.camera.updateProjectionMatrix();\n }\n\n /**\n * 设置控制器\n */\n setControls() {\n this.controls.enabled = !(this.thirdMouseMode === 0 || this.thirdMouseMode === 1);\n this.controls.rotateSpeed = this.mouseSensity * 0.05;\n this.controls.maxPolarAngle = Math.PI * (300 / 360);\n }\n\n /**\n * 重置控制器\n */\n resetControls() {\n if (!this.controls) return;\n this.controls.enabled = true;\n this.controls.enablePan = true;\n this.controls.maxPolarAngle = Math.PI / 2;\n this.controls.rotateSpeed = 1;\n this.controls.enableZoom = true;\n this.controls.mouseButtons = { LEFT: 0, MIDDLE: 1, RIGHT: 2 };\n }\n\n /**\n * 设置朝向\n */\n setToward(dx: number, dy: number, speed: number) {\n if (this.isFirstPerson) {\n const yaw = -dx * speed * this.mouseSensity;\n const pitch = -dy * speed * this.mouseSensity;\n this.player.rotateY(yaw);\n this.camera.rotation.x = THREE.MathUtils.clamp(this.camera.rotation.x + pitch, -1.1, 1.4);\n } else {\n const sensitivity = this.mouseSensity;\n const deltaX = -dx * speed * sensitivity;\n const deltaY = -dy * speed * sensitivity;\n\n const target = this.player.position.clone();\n const distance = this.camera.position.distanceTo(target);\n const currentPosition = this.camera.position.clone().sub(target);\n\n let theta = Math.atan2(currentPosition.x, currentPosition.z);\n let phi = Math.acos(currentPosition.y / distance);\n\n theta += deltaX;\n phi += deltaY;\n phi = Math.max(0.1, Math.min(Math.PI - 0.1, phi));\n\n const newX = distance * Math.sin(phi) * Math.sin(theta);\n const newY = distance * Math.cos(phi);\n const newZ = distance * Math.sin(phi) * Math.cos(theta);\n\n this.camera.position.set(target.x + newX, target.y + newY, target.z + newZ);\n this.camera.lookAt(target);\n }\n }\n\n // ==================== 物理与碰撞检测 ====================\n\n /**\n * BVH碰撞体构建\n */\n async createBVH(meshUrl: string = \"\"): Promise<void> {\n await this.initLoader();\n\n const ensureAttributesMinimal = (geom: THREE.BufferGeometry): THREE.BufferGeometry | null => {\n if (!geom.attributes.position) return null;\n if (!geom.attributes.normal) geom.computeVertexNormals();\n if (!geom.attributes.uv) {\n const count = geom.attributes.position.count;\n const dummyUV = new Float32Array(count * 2);\n geom.setAttribute(\"uv\", new THREE.BufferAttribute(dummyUV, 2));\n }\n return geom;\n };\n\n const collected: THREE.BufferGeometry[] = [];\n\n if (meshUrl === \"\") {\n // 从场景中收集几何体\n if (this.collider) {\n this.scene.remove(this.collider);\n this.collider = null;\n }\n\n this.scene.traverse((c) => {\n const mesh = c as THREE.Mesh;\n if (mesh?.isMesh && mesh.geometry && c.name !== \"capsule\") {\n try {\n let geom = (mesh.geometry as THREE.BufferGeometry).clone();\n geom.applyMatrix4(mesh.matrixWorld);\n if (geom.index) geom = geom.toNonIndexed();\n const safe = ensureAttributesMinimal(geom);\n if (safe) collected.push(safe);\n } catch (e) {\n console.warn(\"处理网格时出错:\", mesh, e);\n }\n }\n });\n\n if (!collected.length) return;\n\n // 统一属性集合\n type AttrMeta = { itemSize: number; arrayCtor: any; examples: number };\n const attrMap = new Map<string, AttrMeta>();\n const attrConflict = new Set<string>();\n\n for (const g of collected) {\n for (const name of Object.keys(g.attributes)) {\n const attr = g.attributes[name] as THREE.BufferAttribute;\n const ctor = (attr.array as any).constructor;\n const itemSize = attr.itemSize;\n\n if (!attrMap.has(name)) {\n attrMap.set(name, { itemSize, arrayCtor: ctor, examples: 1 });\n } else {\n const m = attrMap.get(name)!;\n if (m.itemSize !== itemSize || m.arrayCtor !== ctor) {\n attrConflict.add(name);\n } else {\n m.examples++;\n }\n }\n }\n }\n\n // 删除冲突属性\n if (attrConflict.size) {\n for (const g of collected) {\n for (const name of Array.from(attrConflict)) {\n if (g.attributes[name]) g.deleteAttribute(name);\n }\n }\n for (const name of attrConflict) attrMap.delete(name);\n }\n\n // 补全缺失属性\n const attrNames = Array.from(attrMap.keys());\n for (const g of collected) {\n const count = g.attributes.position.count;\n for (const name of attrNames) {\n if (!g.attributes[name]) {\n const meta = attrMap.get(name)!;\n const len = count * meta.itemSize;\n const array = new meta.arrayCtor(len);\n g.setAttribute(name, new THREE.BufferAttribute(array, meta.itemSize));\n }\n }\n }\n } else {\n // 从URL加载模型\n const gltf: GLTF = await this.loader.loadAsync(meshUrl);\n const mesh = gltf.scene.children[0] as THREE.Mesh;\n mesh.name = \"BVH加载模型\";\n\n let geom = mesh.geometry.clone();\n geom.applyMatrix4(mesh.matrixWorld);\n if (geom.index) geom = geom.toNonIndexed();\n const safe = ensureAttributesMinimal(geom);\n if (safe) collected.push(safe);\n }\n\n // 合并几何体\n const merged = BufferGeometryUtils.mergeGeometries(collected, false);\n if (!merged) {\n console.error(\"合并几何失败\");\n return;\n }\n\n // 构建BVH\n (merged as any).boundsTree = new MeshBVH(merged, { maxDepth: 100 });\n this.collider = new THREE.Mesh(\n merged,\n new THREE.MeshBasicMaterial({\n opacity: 0.5,\n transparent: true,\n wireframe: true,\n })\n );\n\n if (this.displayCollider) this.scene.add(this.collider);\n if (this.displayVisualizer) {\n if (this.visualizer) this.scene.remove(this.visualizer);\n this.visualizer = new MeshBVHHelper(this.collider, this.visualizeDepth);\n this.scene.add(this.visualizer);\n }\n\n this.boundingBoxMinY = (this.collider as any).geometry.boundingBox.min.y;\n }\n\n /**\n * 获取法线与Y轴的夹角\n */\n getAngleWithYAxis(normal: { x: number; y: number; z: number }): number {\n const yAxis = { x: 0, y: 1, z: 0 };\n const dotProduct = normal.x * yAxis.x + normal.y * yAxis.y + normal.z * yAxis.z;\n const normalMagnitude = Math.sqrt(normal.x * normal.x + normal.y * normal.y + normal.z * normal.z);\n const cosTheta = dotProduct / normalMagnitude;\n return Math.acos(cosTheta);\n }\n\n // ==================== 循环更新 ====================\n\n /**\n * 每帧更新\n */\n async update(delta: number = clock.getDelta()) {\n if (!this.isupdate || !this.player || !this.collider) return;\n delta = Math.min(delta, 1 / 30);\n\n // 应用速度\n if (!this.isFlying) {\n this.player.position.addScaledVector(this.playerVelocity, delta);\n }\n\n // 更新动画\n this.updateMixers(delta);\n\n // 计算移动方向\n this.camera.getWorldDirection(this.camDir);\n let angle = Math.atan2(this.camDir.z, this.camDir.x) + Math.PI / 2;\n angle = 2 * Math.PI - angle;\n\n this.moveDir.set(0, 0, 0);\n if (this.fwdPressed) this.moveDir.add(this.DIR_FWD);\n if (this.bkdPressed) this.moveDir.add(this.DIR_BKD);\n if (this.lftPressed) this.moveDir.add(this.DIR_LFT);\n if (this.rgtPressed) this.moveDir.add(this.DIR_RGT);\n\n if (this.isFlying) {\n if (this.fwdPressed) this.moveDir.y = this.camDir.y;\n else this.moveDir.y = 0;\n if (this.spacePressed) this.moveDir.add(this.DIR_UP);\n }\n\n // 设置速度\n if (this.isFlying && this.fwdPressed) {\n this.playerSpeed = this.shiftPressed ? this.originPlayerSpeed * 12 : this.originPlayerSpeed * 7;\n } else {\n this.playerSpeed = this.shiftPressed ? this.originPlayerSpeed * 2 : this.originPlayerSpeed;\n }\n\n this.moveDir.normalize().applyAxisAngle(this.upVector, angle);\n this.player.position.addScaledVector(this.moveDir, this.playerSpeed * delta);\n\n // 向下射线检测地面高度\n let playerDistanceFromGround = Infinity;\n this._originTmp.set(this.player.position.x, this.player.position.y, this.player.position.z);\n this._raycaster.ray.origin.copy(this._originTmp);\n const intersects = this._raycaster.intersectObject(this.collider as THREE.Object3D, false);\n\n if (intersects.length > 0) {\n playerDistanceFromGround = this.player.position.y - intersects[0].point.y;\n const normal = intersects[0].normal as THREE.Vector3;\n const angle = (this.getAngleWithYAxis(normal) * 180) / Math.PI;\n const maxH = this.playerHeight * this.playerModel.scale * 0.9; // 坡度高度阈值\n const h = this.playerHeight * this.playerModel.scale * 0.75; // 正常高度\n const minH = this.playerHeight * this.playerModel.scale * 0.7; // 最小高度\n\n if (!this.isFlying) {\n if (playerDistanceFromGround > maxH) {\n // 下落状态\n this.playerVelocity.y += delta * this.gravity;\n this.player.position.addScaledVector(this.playerVelocity, delta);\n this.playerIsOnGround = false;\n } else if (playerDistanceFromGround > h && playerDistanceFromGround < maxH) {\n if (angle >= 0 && angle < 5) {\n // 平地\n this.playerVelocity.y += delta * this.gravity;\n this.player.position.addScaledVector(this.playerVelocity, delta);\n this.playerIsOnGround = true;\n } else {\n // 坡地\n this.playerVelocity.set(0, 0, 0);\n this.playerIsOnGround = true;\n }\n } else if (playerDistanceFromGround > minH && playerDistanceFromGround < h) {\n // 误差范围内在平地\n this.playerVelocity.set(0, 0, 0);\n this.playerIsOnGround = true;\n } else if (playerDistanceFromGround < minH) {\n // 强行拉回\n this.playerVelocity.set(0, 0, 0);\n this.player.position.set(this.player.position.x, intersects[0].point.y + h, this.player.position.z);\n this.playerIsOnGround = true;\n }\n }\n }\n\n // 更新玩家矩阵\n this.player.updateMatrixWorld();\n\n // BVH碰撞检测\n const capsuleInfo = this.player.capsuleInfo;\n this.tempBox.makeEmpty();\n this.tempMat.copy(this.collider!.matrixWorld).invert();\n this.tempSegment.copy(capsuleInfo.segment);\n this.tempSegment.start.applyMatrix4(this.player.matrixWorld).applyMatrix4(this.tempMat);\n this.tempSegment.end.applyMatrix4(this.player.matrixWorld).applyMatrix4(this.tempMat);\n\n this.tempBox.expandByPoint(this.tempSegment.start);\n this.tempBox.expandByPoint(this.tempSegment.end);\n this.tempBox.expandByScalar(capsuleInfo.radius);\n\n const bvh = this.collider?.geometry as any;\n bvh?.boundsTree?.shapecast({\n // 检测包围盒碰撞\n intersectsBounds: (box: THREE.Box3) => box.intersectsBox(this.tempBox),\n // 检测三角形碰撞\n intersectsTriangle: (tri: any) => {\n const triPoint = this.tempVector;\n const capsulePoint = this.tempVector2;\n const distance = tri.closestPointToSegment(this.tempSegment, triPoint, capsulePoint);\n // 距离小于人物半径,发生碰撞\n if (distance < capsuleInfo.radius) {\n const depth = capsuleInfo.radius - distance;\n const direction = capsulePoint.sub(triPoint).normalize();\n this.tempSegment.start.addScaledVector(direction, depth);\n this.tempSegment.end.addScaledVector(direction, depth);\n }\n },\n });\n\n // 设置玩家位置\n const newPosition = this.tempVector.copy(this.tempSegment.start).applyMatrix4(this.collider!.matrixWorld);\n const deltaVector = this.tempVector2.subVectors(newPosition, this.player.position);\n const offset = Math.max(0, deltaVector.length() - 1e-5);\n deltaVector.normalize().multiplyScalar(offset);\n this.player.position.add(deltaVector);\n\n // 第三人称-朝向\n if (!this.isFirstPerson && !this.isFlying) {\n this.camDir.y = 0;\n this.camDir.normalize();\n this.camDir.negate();\n this.moveDir.normalize();\n this.moveDir.negate();\n\n let lookTarget: THREE.Vector3;\n if (this.thirdMouseMode === 0 || this.thirdMouseMode === 2) {\n if (this.moveDir.lengthSq() > 0) {\n lookTarget = this.player.position.clone().add(this.moveDir);\n } else {\n lookTarget = this.player.position.clone().add(this.camDir);\n }\n this.targetMat.lookAt(this.player.position, lookTarget, this.player.up);\n this.targetQuat.setFromRotationMatrix(this.targetMat);\n const alpha = Math.min(1, this.rotationSpeed * delta);\n this.player.quaternion.slerp(this.targetQuat, alpha);\n }\n if ((this.thirdMouseMode === 1 || this.thirdMouseMode === 3) && this.moveDir.lengthSq() > 0) {\n lookTarget = this.player.position.clone().add(this.moveDir);\n this.targetMat.lookAt(this.player.position, lookTarget, this.player.up);\n this.targetQuat.setFromRotationMatrix(this.targetMat);\n const alpha = Math.min(1, this.rotationSpeed * delta);\n this.player.quaternion.slerp(this.targetQuat, alpha);\n }\n }\n\n // 飞行模式朝向\n if (this.isFlying) {\n this.camDir.y = 0;\n this.camDir.normalize();\n this.camDir.negate();\n this.moveDir.normalize();\n this.moveDir.negate();\n const lookTarget = this.player.position.clone().add(this.fwdPressed ? this.moveDir : this.camDir);\n this.targetMat.lookAt(this.player.position, lookTarget, this.player.up);\n this.targetQuat.setFromRotationMatrix(this.targetMat);\n const alpha = Math.min(1, this.rotationSpeed * delta);\n this.player.quaternion.slerp(this.targetQuat, alpha);\n }\n\n // 第三人称-相机跟随\n if (!this.isFirstPerson) {\n const lookTarget = this.player.position.clone();\n lookTarget.y += 30 * this.playerModel.scale;\n this.camera.position.sub(this.controls.target);\n this.controls.target.copy(lookTarget);\n this.camera.position.add(lookTarget);\n this.controls.update();\n\n // 当视线被遮挡时的处理\n this._personToCam.subVectors(this.camera.position, this.player.position);\n const origin = this.player.position.clone().add(new THREE.Vector3(0, 0, 0));\n const direction = this._personToCam.clone().normalize();\n const desiredDist = this._personToCam.length();\n this._raycasterPersonToCam.set(origin, direction);\n this._raycasterPersonToCam.far = desiredDist;\n\n const intersects = this._raycasterPersonToCam.intersectObject(this.collider as THREE.Object3D, false);\n\n if (intersects.length > 0) {\n // 相机拉近\n const hit = intersects[0];\n const safeDist = Math.max(hit.distance - this._camEpsilon, this._minCamDistance);\n const targetCamPos = origin.clone().add(direction.clone().multiplyScalar(safeDist));\n this.camera.position.lerp(targetCamPos, this._camCollisionLerp);\n } else {\n // 相机恢复\n this._raycasterPersonToCam.far = this._maxCamDistance;\n const intersectsMaxDis = this._raycasterPersonToCam.intersectObject(this.collider as THREE.Object3D, false);\n\n let safeDist = this._maxCamDistance;\n if (intersectsMaxDis.length) {\n const hitMax = intersectsMaxDis[0];\n safeDist = hitMax.distance - this._camEpsilon;\n }\n const targetCamPos = origin.clone().add(direction.clone().multiplyScalar(safeDist));\n this.camera.position.lerp(targetCamPos, this._camCollisionLerp);\n }\n }\n\n // 掉出场景重置\n if (this.player.position.y < this.boundingBoxMinY - 1) {\n this._originTmp.set(this.player.position.x, 10000, this.player.position.z);\n this._raycaster.ray.origin.copy(this._originTmp);\n const intersects = this._raycaster.intersectObject(this.collider as THREE.Object3D, false);\n\n if (intersects.length > 0) {\n // 出现碰撞 说明玩家为bug意外掉落\n console.log(\"玩家为bug意外掉落\");\n this.reset(new THREE.Vector3(this.player.position.x, intersects[0].point.y + 5, this.player.position.z));\n } else {\n // 无碰撞 正常掉落\n console.log(\"玩家正常掉落\");\n this.reset(new THREE.Vector3(this.player.position.x, this.player.position.y + 15, this.player.position.z));\n }\n }\n }\n\n /**\n * 更新模型动画\n */\n private updateMixers(delta: number) {\n if (this.personMixer) this.personMixer.update(delta);\n }\n\n /**\n * 重置玩家位置\n */\n reset(position?: THREE.Vector3) {\n if (!this.player) return;\n this.playerVelocity.set(0, 0, 0);\n this.player.position.copy(position ?? this.initPos);\n }\n\n /**\n * 获取玩家位置\n */\n getPosition() {\n return this.player.position;\n }\n\n // ==================== 输入处理 ====================\n\n /**\n * 设置输入\n */\n setInput(\n input: Partial<{\n moveX: 1 | 0 | -1;\n moveY: 1 | 0 | -1;\n lookDeltaX: number;\n lookDeltaY: number;\n jump: boolean;\n shift: boolean;\n toggleView: boolean;\n toggleFly: boolean;\n }>\n ) {\n // 控制人物移动\n if (typeof input.moveX === \"number\") {\n this.lftPressed = input.moveX === -1;\n this.rgtPressed = input.moveX === 1;\n this.setAnimationByPressed();\n }\n if (typeof input.moveY === \"number\") {\n this.fwdPressed = input.moveY === 1;\n this.bkdPressed = input.moveY === -1;\n this.setAnimationByPressed();\n }\n\n // 控制朝向\n if (typeof input.lookDeltaX === \"number\" && typeof input.lookDeltaY === \"number\") {\n this.setToward(input.lookDeltaX, input.lookDeltaY, 0.002);\n }\n\n // 跳跃\n if (typeof input.jump === \"boolean\") {\n if (input.jump) {\n this.spacePressed = true;\n if (!this.playerIsOnGround || this.isFlying) return;\n this.playPersonAnimationByName(\"jumping\");\n this.playerVelocity.y = this.jumpHeight;\n this.playerIsOnGround = false;\n } else {\n this.spacePressed = false;\n }\n }\n\n // 加速\n if (typeof input.shift === \"boolean\") {\n this.shiftPressed = input.shift;\n }\n\n // 切换视角\n if (input.toggleView) {\n this.changeView();\n }\n\n // 切换飞行\n if (input.toggleFly) {\n this.isFlying = !this.isFlying;\n this.setAnimationByPressed();\n if (!this.isFlying && !this.playerIsOnGround) {\n this.playPersonAnimationByName(\"jumping\");\n }\n }\n }\n\n /**\n * 根据按键设置人物动画\n */\n private setAnimationByPressed = () => {\n this._maxCamDistance = this.orginMaxCamDistance;\n\n if (this.isFlying) {\n if (!this.fwdPressed) {\n this.playPersonAnimationByName(\"flyidle\");\n return;\n }\n this.playPersonAnimationByName(\"flying\");\n this._maxCamDistance = this.orginMaxCamDistance * 2;\n return;\n }\n\n if (this.playerIsOnGround) {\n if (!this.fwdPressed && !this.bkdPressed && !this.lftPressed && !this.rgtPressed) {\n this.playPersonAnimationByName(\"idle\");\n return;\n }\n\n if (this.fwdPressed) {\n this.playPersonAnimationByName(this.shiftPressed ? \"running\" : \"walking\");\n return;\n }\n\n // 第三人称下动画统一使用前进动画\n if (!this.isFirstPerson && (this.lftPressed || this.rgtPressed || this.bkdPressed)) {\n this.playPersonAnimationByName(this.shiftPressed ? \"running\" : \"walking\");\n return;\n }\n\n // 第一人称下根据方向播放不同动画\n if (this.lftPressed) {\n this.playPersonAnimationByName(\"left_walking\");\n return;\n }\n if (this.rgtPressed) {\n this.playPersonAnimationByName(\"right_walking\");\n return;\n }\n if (this.bkdPressed) {\n this.playPersonAnimationByName(\"walking_backward\");\n return;\n }\n }\n\n // 销毁旧的定时器\n if (this.recheckAnimTimer !== null) {\n clearTimeout(this.recheckAnimTimer);\n }\n\n // 200ms后重新检测动画\n this.recheckAnimTimer = setTimeout(() => {\n this.setAnimationByPressed();\n this.recheckAnimTimer = null;\n }, 200);\n };\n\n // ==================== 事件处理 ====================\n\n /**\n * 键盘按下事件\n */\n private _boundOnKeydown = async (e: KeyboardEvent) => {\n if (e.ctrlKey && [\"KeyW\", \"KeyA\", \"KeyS\", \"KeyD\"].includes(e.code)) {\n e.preventDefault();\n }\n\n switch (e.code) {\n case \"KeyW\":\n this.fwdPressed = true;\n this.setAnimationByPressed();\n break;\n case \"KeyS\":\n this.bkdPressed = true;\n this.setAnimationByPressed();\n break;\n case \"KeyD\":\n this.rgtPressed = true;\n this.setAnimationByPressed();\n break;\n case \"KeyA\":\n this.lftPressed = true;\n this.setAnimationByPressed();\n break;\n case \"ShiftLeft\":\n this.shiftPressed = true;\n this.setAnimationByPressed();\n this.controls.mouseButtons = { LEFT: 2, MIDDLE: 1, RIGHT: 0 };\n break;\n case \"Space\":\n this.spacePressed = true;\n if (!this.playerIsOnGround || this.isFlying) return;\n const next = this.personActions?.get(\"jumping\");\n if (next && this.actionState === next) return;\n this.playPersonAnimationByName(\"jumping\");\n this.playerVelocity.y = this.jumpHeight;\n this.playerIsOnGround = false;\n break;\n case \"ControlLeft\":\n this.ctPressed = true;\n break;\n case \"KeyV\":\n this.changeView();\n break;\n case \"KeyF\":\n this.isFlying = !this.isFlying;\n this.setAnimationByPressed();\n if (!this.isFlying && !this.playerIsOnGround) {\n this.playPersonAnimationByName(\"jumping\");\n }\n break;\n }\n };\n\n /**\n * 键盘抬起事件\n */\n private _boundOnKeyup = (e: KeyboardEvent) => {\n switch (e.code) {\n case \"KeyW\":\n this.fwdPressed = false;\n this.setAnimationByPressed();\n break;\n case \"KeyS\":\n this.bkdPressed = false;\n this.setAnimationByPressed();\n break;\n case \"KeyD\":\n this.rgtPressed = false;\n this.setAnimationByPressed();\n break;\n case \"KeyA\":\n this.lftPressed = false;\n this.setAnimationByPressed();\n break;\n case \"ShiftLeft\":\n this.shiftPressed = false;\n this.setAnimationByPressed();\n this.controls.mouseButtons = { LEFT: 0, MIDDLE: 1, RIGHT: 2 };\n break;\n case \"Space\":\n this.spacePressed = false;\n break;\n case \"ControlLeft\":\n this.ctPressed = false;\n break;\n }\n };\n\n /**\n * 鼠标移动事件\n */\n private _mouseMove = (e: MouseEvent) => {\n if (document.pointerLockElement !== document.body) return;\n this.setToward(e.movementX, e.movementY, 0.0001);\n };\n\n /**\n * 鼠标点击事件\n */\n private _mouseClick = (e: MouseEvent) => {\n this.setPointerLock();\n };\n\n /**\n * 事件绑定\n */\n onAllEvent() {\n this.isupdate = true;\n this.setPointerLock();\n\n window.addEventListener(\"keydown\", this._boundOnKeydown);\n window.addEventListener(\"keyup\", this._boundOnKeyup);\n window.addEventListener(\"mousemove\", this._mouseMove);\n window.addEventListener(\"click\", this._mouseClick);\n }\n\n /**\n * 事件解绑\n */\n offAllEvent() {\n this.isupdate = false;\n document.exitPointerLock();\n window.removeEventListener(\"keydown\", this._boundOnKeydown);\n window.removeEventListener(\"keyup\", this._boundOnKeyup);\n window.removeEventListener(\"mousemove\", this._mouseMove);\n window.removeEventListener(\"click\", this._mouseClick);\n }\n\n // ==================== 移动端控制 ====================\n\n /**\n * 指针按下事件\n */\n onPointerDown = (e: PointerEvent) => {\n if (e.pointerType !== \"touch\") return;\n this.isLookDown = true;\n this.lookPointerId = e.pointerId;\n this.lastTouchX = e.clientX;\n this.lastTouchY = e.clientY;\n\n this.lookAreaEl?.setPointerCapture?.(e.pointerId);\n e.preventDefault();\n };\n\n /**\n * 指针移动事件\n */\n onPointerMove = (e: PointerEvent) => {\n if (!this.isLookDown || e.pointerId !== this.lookPointerId) return;\n const dx = e.clientX - this.lastTouchX;\n const dy = e.clientY - this.lastTouchY;\n this.lastTouchX = e.clientX;\n this.lastTouchY = e.clientY;\n\n this.setInput({ lookDeltaX: dx, lookDeltaY: dy });\n e.preventDefault();\n };\n\n /**\n * 指针抬起事件\n */\n onPointerUp = (e: PointerEvent) => {\n if (e.pointerId !== this.lookPointerId) return;\n this.isLookDown = false;\n this.lookPointerId = null;\n this.lookAreaEl?.releasePointerCapture?.(e.pointerId);\n };\n\n /**\n * 初始化移动端摇杆控制\n */\n async initMobileControls() {\n this.controls.maxPolarAngle = Math.PI * (300 / 360);\n this.controls.touches = { ONE: null as any, TWO: null as any };\n this.nippleModule = await import(\"nipplejs\");\n const nipple = this.nippleModule?.default;\n const JOY_SIZE = 120;\n\n const container = document.body;\n\n // 摇杆容器\n this.joystickZoneEl = document.createElement(\"div\");\n this.joystickZoneEl.id = \"joy-zone\";\n Object.assign(this.joystickZoneEl.style, {\n position: \"absolute\",\n left: \"16px\",\n bottom: \"16px\",\n width: `${JOY_SIZE + 40}px`,\n height: `${JOY_SIZE + 40}px`,\n touchAction: \"none\",\n zIndex: \"999\",\n pointerEvents: \"auto\",\n WebkitUserSelect: \"none\",\n userSelect: \"none\",\n });\n container.appendChild(this.joystickZoneEl);\n\n // 阻止touch的默认行为\n [\"touchstart\", \"touchmove\", \"touchend\", \"touchcancel\"].forEach((evtName) => {\n this.joystickZoneEl?.addEventListener(evtName, (e) => e.preventDefault(), {\n passive: false,\n });\n });\n\n // 创建摇杆\n this.joystickManager = nipple.create({\n zone: this.joystickZoneEl,\n mode: \"static\",\n position: {\n left: `${(JOY_SIZE + 40) / 2}px`,\n bottom: `${(JOY_SIZE + 40) / 2}px`,\n },\n color: \"#ffffff\",\n size: JOY_SIZE,\n multitouch: true,\n maxNumberOfNipples: 1,\n });\n\n this.joystickManager.on(\"move\", (_evt: any, data: any) => {\n if (!data) return;\n\n const rawX = data.vector?.x ?? 0;\n const rawY = data.vector?.y ?? 0;\n const distance = data.distance ?? 0;\n const deadzone = 0.5;\n\n const dirX = rawX > deadzone ? 1 : rawX < -deadzone ? -1 : 0;\n const dirY = rawY > deadzone ? 1 : rawY < -deadzone ? -1 : 0;\n\n const sprintThreshold = JOY_SIZE / 2;\n const isSprinting = distance >= sprintThreshold;\n\n const prev = this.prevJoyState || { dirX: 0, dirY: 0, shift: false };\n if (dirX === prev.dirX && dirY === prev.dirY && isSprinting === prev.shift) {\n return;\n }\n\n this.prevJoyState = { dirX, dirY, shift: isSprinting };\n this.setInput({ moveX: dirX, moveY: dirY, shift: isSprinting });\n });\n\n this.joystickManager.on(\"end\", () => {\n const prev = this.prevJoyState || { dirX: 0, dirY: 0, shift: false };\n if (prev.dirX !== 0 || prev.dirY !== 0 || prev.shift !== false) {\n this.prevJoyState = { dirX: 0, dirY: 0, shift: false };\n this.setInput({ moveX: 0, moveY: 0, shift: false });\n }\n });\n\n // 右侧视角控制区域\n this.lookAreaEl = document.createElement(\"div\");\n Object.assign(this.lookAreaEl.style, {\n position: \"absolute\",\n right: \"0\",\n bottom: \"0\",\n width: \"50%\",\n height: \"100%\",\n zIndex: \"998\",\n touchAction: \"none\",\n WebkitUserSelect: \"none\",\n userSelect: \"none\",\n });\n container.appendChild(this.lookAreaEl);\n\n [\"touchstart\", \"touchmove\", \"touchend\", \"touchcancel\"].forEach((evtName) => {\n this.lookAreaEl?.addEventListener(evtName, (e) => e.preventDefault(), {\n passive: false,\n });\n });\n\n this.lookAreaEl.addEventListener(\"pointerdown\", this.onPointerDown, { passive: false });\n this.lookAreaEl.addEventListener(\"pointermove\", this.onPointerMove, { passive: false });\n this.lookAreaEl.addEventListener(\"pointerup\", this.onPointerUp, { passive: false });\n this.lookAreaEl.addEventListener(\"pointercancel\", this.onPointerUp, { passive: false });\n\n // 创建按钮\n const createBtn = (rightPx: number, bottomPx: number, bgUrl?: string) => {\n const btn = document.createElement(\"button\");\n const styles: Partial<CSSStyleDeclaration> = {\n position: \"absolute\",\n right: `${rightPx}px`,\n bottom: `${bottomPx}px`,\n width: \"56px\",\n height: \"56px\",\n zIndex: \"1000\",\n borderRadius: \"50%\",\n border: \"2px solid black\",\n background: \"rgba(0,0,0)\",\n padding: \"20px\",\n opacity: \"0.95\",\n touchAction: \"none\",\n fontSize: \"14px\",\n userSelect: \"none\",\n overflow: \"hidden\",\n boxSizing: \"border-box\",\n backgroundColor: \"transparent\",\n backgroundRepeat: \"no-repeat, no-repeat\",\n backgroundPosition: \"center center, center center\",\n backgroundSize: \"100% 100%, 80% 80%\",\n };\n\n if (bgUrl) {\n const overlayColor = \"rgba(0,0,0,0.5)\";\n styles.backgroundImage = `linear-gradient(${overlayColor}, ${overlayColor}), url(\"${bgUrl}\")`;\n }\n\n Object.assign(btn.style, styles);\n container.appendChild(btn);\n [\"touchstart\", \"touchend\", \"touchcancel\"].forEach((evtName) => {\n btn.addEventListener(evtName, (e) => e.preventDefault(), { passive: false });\n });\n\n return btn;\n };\n\n // 跳跃按钮\n this.jumpBtnEl = createBtn(14, 14, jumpIconModule);\n this.jumpBtnEl.addEventListener(\n \"touchstart\",\n (e) => {\n e.preventDefault();\n this.setInput({ jump: true });\n },\n { passive: false }\n );\n this.jumpBtnEl.addEventListener(\n \"touchend\",\n (e) => {\n e.preventDefault();\n this.setInput({ jump: false });\n },\n { passive: false }\n );\n this.jumpBtnEl.addEventListener(\n \"touchcancel\",\n (e) => {\n e.preventDefault();\n this.setInput({ jump: false });\n },\n { passive: false }\n );\n\n // 切换飞行按钮\n this.flyBtnEl = createBtn(14, 14 + 80, flyIconModule);\n this.flyBtnEl.addEventListener(\n \"touchstart\",\n (e) => {\n e.preventDefault();\n this.setInput({ toggleFly: true });\n },\n { passive: false }\n );\n\n // 切换视角按钮\n this.viewBtnEl = createBtn(14, 14 + 200, viewIconModule);\n this.viewBtnEl.addEventListener(\n \"touchstart\",\n (e) => {\n e.preventDefault();\n this.setInput({ toggleView: true });\n },\n { passive: false }\n );\n }\n\n /**\n * 销毁移动端摇杆控制\n */\n destroyMobileControls() {\n try {\n if (this.joystickManager && this.joystickManager.destroy) {\n this.joystickManager.destroy();\n this.joystickManager = null;\n }\n if (this.joystickZoneEl?.parentElement) {\n this.joystickZoneEl.parentElement.removeChild(this.joystickZoneEl);\n this.joystickZoneEl = null;\n }\n if (this.lookAreaEl?.parentElement) {\n this.lookAreaEl.parentElement.removeChild(this.lookAreaEl);\n this.lookAreaEl = null;\n }\n if (this.jumpBtnEl?.parentElement) {\n this.jumpBtnEl.parentElement.removeChild(this.jumpBtnEl);\n this.jumpBtnEl = null;\n }\n if (this.flyBtnEl?.parentElement) {\n this.flyBtnEl.parentElement.removeChild(this.flyBtnEl);\n this.flyBtnEl = null;\n }\n if (this.viewBtnEl?.parentElement) {\n this.viewBtnEl.parentElement.removeChild(this.viewBtnEl);\n this.viewBtnEl = null;\n }\n\n // 监听\n this.lookAreaEl?.removeEventListener(\"pointerdown\", this.onPointerDown);\n this.lookAreaEl?.removeEventListener(\"pointermove\", this.onPointerMove);\n this.lookAreaEl?.removeEventListener(\"pointerup\", this.onPointerUp);\n this.lookAreaEl?.removeEventListener(\"pointercancel\", this.onPointerUp);\n } catch (e) {\n console.warn(\"销毁移动端摇杆控制时出错:\", e);\n }\n }\n\n // ==================== 销毁 ====================\n\n /**\n * 销毁人物控制器\n */\n destroy() {\n this.offAllEvent();\n if (this.player) {\n this.player.remove(this.camera);\n this.scene.remove(this.player);\n }\n (this.player as any) = null;\n if (this.person) {\n this.scene.remove(this.person);\n this.person = null;\n }\n\n this.resetControls();\n\n // 清理 BVH 可视化\n if (this.visualizer) {\n this.scene.remove(this.visualizer);\n this.visualizer = null;\n }\n if (this.collider) {\n this.scene.remove(this.collider);\n this.collider = null;\n }\n\n this.destroyMobileControls();\n\n controllerInstance = null;\n }\n}\n\n// 导出API\nexport function playerController() {\n if (!controllerInstance) controllerInstance = new PlayerController();\n const c = controllerInstance;\n return {\n init: (opts: PlayerControllerOptions, callback?: () => void) => c.init(opts, callback),\n changeView: () => c.changeView(),\n reset: (pos?: THREE.Vector3) => c.reset(pos),\n update: (dt?: number) => c.update(dt),\n destroy: () => c.destroy(),\n setInput: (i: any) => c.setInput(i),\n getposition: () => c.getPosition(),\n };\n}\n\n// 打开所有事件\nexport function onAllEvent(): void {\n if (!controllerInstance) controllerInstance = new PlayerController();\n controllerInstance.onAllEvent();\n}\n\n// 关闭所有事件\nexport function offAllEvent(): void {\n if (!controllerInstance) return;\n controllerInstance.offAllEvent();\n}\n"],"mappings":"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","names":["angle","intersects"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/playerController.ts"],"sourcesContent":["export * from \"./playerController\";\r\n","import * as THREE from \"three\";\nimport { acceleratedRaycast, MeshBVH, MeshBVHHelper } from \"three-mesh-bvh\";\nimport type { GLTF } from \"three/examples/jsm/Addons.js\";\nimport { OrbitControls } from \"three/examples/jsm/controls/OrbitControls.js\";\nimport { RoundedBoxGeometry } from \"three/examples/jsm/geometries/RoundedBoxGeometry.js\";\nimport { DRACOLoader } from \"three/examples/jsm/loaders/DRACOLoader.js\";\nimport { GLTFLoader } from \"three/examples/jsm/loaders/GLTFLoader.js\";\nimport * as BufferGeometryUtils from \"three/examples/jsm/utils/BufferGeometryUtils.js\";\nimport flyIconModule from \"../assets/imgs/fly.png\";\nimport jumpIconModule from \"../assets/imgs/jump.png\";\nimport viewIconModule from \"../assets/imgs/view.png\";\n\nTHREE.Mesh.prototype.raycast = acceleratedRaycast; // 启用加速 raycast\n\nlet controllerInstance: PlayerController | null = null;\nconst clock = new THREE.Clock();\n\nexport type PlayerControllerOptions = {\n scene: THREE.Scene;\n camera: THREE.PerspectiveCamera;\n controls: OrbitControls;\n playerModel: {\n url: string;\n idleAnim: string;\n walkAnim: string;\n runAnim: string;\n jumpAnim: string;\n leftWalkAnim?: string;\n rightWalkAnim?: string;\n backwardAnim?: string;\n flyAnim?: string;\n flyIdleAnim?: string;\n scale: number;\n gravity?: number;\n jumpHeight?: number;\n speed?: number;\n rotateY?: number;\n };\n initPos?: THREE.Vector3;\n mouseSensity?: number;\n minCamDistance?: number;\n maxCamDistance?: number;\n colliderMeshUrl?: string;\n isShowMobileControls?: boolean;\n thirdMouseMode?: 0 | 1 | 2 | 3;\n};\n\nclass PlayerController {\n // ==================== 基本配置与参数 ====================\n loader: GLTFLoader = new GLTFLoader();\n scene!: THREE.Scene;\n camera!: THREE.PerspectiveCamera;\n controls!: OrbitControls;\n playerModel!: PlayerControllerOptions[\"playerModel\"];\n initPos!: THREE.Vector3;\n visualizeDepth!: number;\n gravity!: number;\n jumpHeight!: number;\n playerSpeed!: number;\n mouseSensity!: number;\n originPlayerSpeed!: number;\n colliderMeshUrl!: string;\n isShowMobileControls!: boolean;\n thirdMouseMode!: 0 | 1 | 2 | 3; // 0: 隐藏鼠标控制朝向及视角,1: 隐藏鼠标仅控制视角,2: 显示鼠标拖拽控制朝向及视角, 3: 显示鼠标拖拽仅控制视角\n controllerMode!: 0 | 1 | 2; // 0: 普通 1: 飞行 2: 车辆\n\n // ==================== 玩家基本属性 ====================\n playerRadius: number = 45;\n playerHeight: number = 180;\n isFirstPerson: boolean = false;\n boundingBoxMinY: number = 0;\n\n // ==================== 测试参数 ====================\n displayPlayer: boolean = false;\n displayCollider: boolean = false;\n displayVisualizer: boolean = false;\n\n // ==================== 场景对象 ====================\n collider: THREE.Mesh | null = null;\n visualizer: MeshBVHHelper | null = null;\n player!: THREE.Mesh & { capsuleInfo?: any };\n person: THREE.Object3D | null = null;\n vehicle: THREE.Object3D | null = null;\n\n // ==================== 状态开关 ====================\n playerIsOnGround: boolean = false;\n isupdate: boolean = true;\n isFlying: boolean = false;\n\n // ==================== 输入状态 ====================\n fwdPressed: boolean = false;\n bkdPressed: boolean = false;\n lftPressed: boolean = false;\n rgtPressed: boolean = false;\n spacePressed: boolean = false;\n ctPressed: boolean = false;\n shiftPressed: boolean = false;\n\n // ==================== 移动端输入 ====================\n prevJoyState = { dirX: 0, dirY: 0, shift: false };\n nippleModule: any = null;\n joystickManager: any = null;\n joystickZoneEl: HTMLDivElement | null = null;\n lookAreaEl: HTMLDivElement | null = null;\n jumpBtnEl: HTMLButtonElement | null = null;\n flyBtnEl: HTMLButtonElement | null = null;\n viewBtnEl: HTMLButtonElement | null = null;\n lookPointerId: number | null = null;\n isLookDown = false;\n lastTouchX = 0;\n lastTouchY = 0;\n\n // ==================== 第三人称相机参数 ====================\n _camCollisionLerp: number = 0.18; // 平滑系数\n _camEpsilon: number = 0.35; // 摄像机与障碍物之间的安全距离\n _minCamDistance: number = 1.0; // 摄像机最小距离\n _maxCamDistance: number = 4.4; // 摄像机最大距离\n orginMaxCamDistance: number = 4.4;\n\n // ==================== 物理/运动 ====================\n playerVelocity = new THREE.Vector3(); // 玩家速度向量\n readonly upVector = new THREE.Vector3(0, 1, 0);\n\n // ==================== 临时复用向量/矩阵 ====================\n readonly tempVector = new THREE.Vector3();\n readonly tempVector2 = new THREE.Vector3();\n readonly tempBox = new THREE.Box3();\n readonly tempMat = new THREE.Matrix4();\n readonly tempSegment = new THREE.Line3();\n\n // ==================== 动画相关 ====================\n personMixer?: THREE.AnimationMixer;\n personActions?: Map<string, THREE.AnimationAction>;\n idleAction!: THREE.AnimationAction;\n walkAction!: THREE.AnimationAction;\n leftWalkAction!: THREE.AnimationAction;\n rightWalkAction!: THREE.AnimationAction;\n backwardAction!: THREE.AnimationAction;\n jumpAction!: THREE.AnimationAction;\n runAction!: THREE.AnimationAction;\n flyidleAction!: THREE.AnimationAction;\n flyAction!: THREE.AnimationAction;\n actionState!: THREE.AnimationAction;\n recheckAnimTimer: any | null = null;\n\n vehicleMixer?: THREE.AnimationMixer;\n vehicleActions?: Map<string, THREE.AnimationAction>;\n\n // ==================== 相机朝向/移动复用向量 ====================\n readonly camDir = new THREE.Vector3();\n readonly moveDir = new THREE.Vector3();\n readonly targetQuat = new THREE.Quaternion();\n readonly targetMat = new THREE.Matrix4();\n readonly rotationSpeed = 10;\n readonly DIR_FWD = new THREE.Vector3(0, 0, -1);\n readonly DIR_BKD = new THREE.Vector3(0, 0, 1);\n readonly DIR_LFT = new THREE.Vector3(-1, 0, 0);\n readonly DIR_RGT = new THREE.Vector3(1, 0, 0);\n readonly DIR_UP = new THREE.Vector3(0, 1, 0);\n\n // ==================== 射线检测 ====================\n readonly _personToCam = new THREE.Vector3();\n readonly _originTmp = new THREE.Vector3();\n readonly _raycaster = new THREE.Raycaster(new THREE.Vector3(), new THREE.Vector3(0, -1, 0));\n readonly _raycasterPersonToCam = new THREE.Raycaster(new THREE.Vector3(), new THREE.Vector3());\n\n constructor() {\n // 射线检测时只返回第一个碰撞\n (this._raycaster as any).firstHitOnly = true;\n (this._raycasterPersonToCam as any).firstHitOnly = true;\n }\n\n // ==================== 初始化相关方法 ====================\n\n /**\n * 初始化控制器\n */\n async init(opts: PlayerControllerOptions, callback?: () => void) {\n this.scene = opts.scene;\n this.camera = opts.camera;\n this.camera.rotation.order = \"YXZ\";\n this.controls = opts.controls;\n this.playerModel = opts.playerModel;\n this.initPos = opts.initPos ?? new THREE.Vector3(0, 0, 0);\n this.mouseSensity = opts.mouseSensity ?? 5;\n\n const s = this.playerModel.scale;\n this.visualizeDepth = 0 * s;\n this.gravity = (opts.playerModel.gravity ?? -2400) * s;\n this.jumpHeight = (opts.playerModel.jumpHeight ?? 800) * s;\n this.originPlayerSpeed = (opts.playerModel.speed ?? 400) * s;\n this.playerSpeed = this.originPlayerSpeed;\n this.playerModel.rotateY = opts.playerModel.rotateY ?? 0;\n\n this._camCollisionLerp = 0.18;\n this._camEpsilon = 35 * s;\n this._minCamDistance = (opts.minCamDistance ?? 100) * s;\n this._maxCamDistance = (opts.maxCamDistance ?? 440) * s;\n this.orginMaxCamDistance = this._maxCamDistance;\n this.thirdMouseMode = opts.thirdMouseMode ?? 1;\n\n // 判断是否移动端\n const isMobileDevice = () => (navigator.maxTouchPoints && navigator.maxTouchPoints > 0) || \"ontouchstart\" in window || /Mobi|Android|iPhone|iPad|iPod/i.test(navigator.userAgent);\n\n this.isShowMobileControls = (opts.isShowMobileControls ?? true) && isMobileDevice();\n if (this.isShowMobileControls) {\n await this.initMobileControls();\n }\n\n // 创建BVH碰撞体\n await this.createBVH(opts.colliderMeshUrl);\n\n // 创建玩家胶囊体\n this.createPlayer();\n\n // 加载玩家模型\n await this.loadPersonGLB();\n\n // 等待资源加载完毕再设置摄像机\n if (this.isFirstPerson && this.person) {\n this.person.add(this.camera);\n }\n\n this.onAllEvent();\n this.setCameraPos();\n this.setControls();\n if (callback) callback();\n }\n\n /**\n * 初始化加载器\n */\n async initLoader() {\n const dracoLoader = new DRACOLoader();\n dracoLoader.setDecoderPath(\"https://unpkg.com/three@0.180.0/examples/jsm/libs/draco/gltf/\");\n dracoLoader.setDecoderConfig({ type: \"js\" });\n this.loader.setDRACOLoader(dracoLoader);\n }\n\n // ==================== 玩家模型相关方法 ====================\n\n /**\n * 加载玩家模型与动画\n */\n async loadPersonGLB() {\n try {\n const gltf: GLTF = await this.loader.loadAsync(this.playerModel.url);\n this.person = gltf.scene;\n const sc = this.playerModel.scale;\n const h = this.playerHeight * sc;\n\n this.person.scale.set(sc, sc, sc);\n this.person.position.set(0, -h * 0.75, 0);\n this.person.traverse((child: any) => {\n if (child.isMesh) {\n child.castShadow = true;\n child.receiveShadow = true;\n }\n });\n\n this.player.add(this.person);\n this.reset();\n\n // 创建动画混合器\n this.personMixer = new THREE.AnimationMixer(this.person);\n const animations = gltf.animations ?? [];\n this.personActions = new Map<string, THREE.AnimationAction>();\n\n // 动画映射表\n const animationMappings: [string, string][] = [\n [this.playerModel.idleAnim, \"idle\"],\n [this.playerModel.walkAnim, \"walking\"],\n [this.playerModel.leftWalkAnim || this.playerModel.walkAnim, \"left_walking\"],\n [this.playerModel.rightWalkAnim || this.playerModel.walkAnim, \"right_walking\"],\n [this.playerModel.backwardAnim || this.playerModel.walkAnim, \"walking_backward\"],\n [this.playerModel.jumpAnim, \"jumping\"],\n [this.playerModel.runAnim, \"running\"],\n [this.playerModel.flyIdleAnim || this.playerModel.idleAnim, \"flyidle\"],\n [this.playerModel.flyAnim || this.playerModel.idleAnim, \"flying\"],\n ];\n\n // 注册动画动作\n const findClip = (name: string) => animations.find((a: any) => a.name === name);\n for (const [clipName, actionName] of animationMappings) {\n const clip = findClip(clipName);\n if (!clip) continue;\n\n const action = this.personMixer.clipAction(clip);\n\n if (actionName === \"jumping\") {\n action.setLoop(THREE.LoopOnce, 1);\n action.clampWhenFinished = true;\n action.setEffectiveTimeScale(1.2);\n } else {\n action.setLoop(THREE.LoopRepeat, Infinity);\n action.clampWhenFinished = false;\n action.setEffectiveTimeScale(1);\n }\n\n action.enabled = true;\n action.setEffectiveWeight(0);\n this.personActions.set(actionName, action);\n }\n\n // 获取动画动作引用\n this.idleAction = this.personActions.get(\"idle\")!;\n this.walkAction = this.personActions.get(\"walking\")!;\n this.leftWalkAction = this.personActions.get(\"left_walking\")!;\n this.rightWalkAction = this.personActions.get(\"right_walking\")!;\n this.backwardAction = this.personActions.get(\"walking_backward\")!;\n this.jumpAction = this.personActions.get(\"jumping\")!;\n this.runAction = this.personActions.get(\"running\")!;\n this.flyidleAction = this.personActions.get(\"flyidle\")!;\n this.flyAction = this.personActions.get(\"flying\")!;\n\n // 激活空闲动作\n this.idleAction.setEffectiveWeight(1);\n this.idleAction.play();\n this.actionState = this.idleAction;\n\n // 监听动画完成事件\n this.personMixer.addEventListener(\"finished\", (ev: any) => {\n const finishedAction: THREE.AnimationAction = ev.action;\n\n if (finishedAction === this.jumpAction) {\n if (this.fwdPressed) {\n this.playPersonAnimationByName(this.shiftPressed ? \"running\" : \"walking\");\n return;\n }\n if (this.bkdPressed) {\n this.playPersonAnimationByName(\"walking_backward\");\n return;\n }\n if (this.rgtPressed || this.lftPressed) {\n this.playPersonAnimationByName(\"walking\");\n return;\n }\n this.playPersonAnimationByName(\"idle\");\n }\n });\n } catch (error) {\n console.error(\"加载玩家模型失败:\", error);\n }\n }\n\n /**\n * 平滑切换人物动画\n */\n playPersonAnimationByName(name: string, fade = 0.18) {\n if (!this.personActions || this.ctPressed) return;\n\n const next = this.personActions.get(name);\n if (!next || this.actionState === next) return;\n\n const prev = this.actionState;\n\n next.reset();\n next.setEffectiveWeight(1);\n next.play();\n\n if (prev && prev !== next) {\n prev.fadeOut(fade);\n next.fadeIn(fade);\n } else {\n next.fadeIn(fade);\n }\n\n this.actionState = next;\n }\n\n /**\n * 创建玩家胶囊体\n */\n createPlayer() {\n const material = new THREE.MeshStandardMaterial({\n color: new THREE.Color(1, 0, 0),\n shadowSide: THREE.DoubleSide,\n depthTest: false,\n transparent: true,\n opacity: this.displayPlayer ? 0.5 : 0,\n wireframe: true,\n depthWrite: false,\n });\n\n const r = this.playerRadius * this.playerModel.scale;\n const h = this.playerHeight * this.playerModel.scale;\n this.player = new THREE.Mesh(new RoundedBoxGeometry(r * 2, h, r * 2, 1, 75), material) as typeof this.player;\n\n this.player.geometry.translate(0, -h * 0.25, 0);\n this.player.capsuleInfo = {\n radius: r,\n segment: new THREE.Line3(new THREE.Vector3(), new THREE.Vector3(0, -h * 0.5, 0)),\n };\n\n this.player.name = \"capsule\";\n this.scene.add(this.player);\n this.reset();\n\n // 设置初始朝向\n this.player.rotateY(this.playerModel.rotateY ?? 0);\n }\n\n // ==================== 车辆模型相关 ====================\n\n /**\n * 加载车辆模型与动画\n */\n async loadVehicleModel(params: {\n url: string;\n position: THREE.Vector3;\n scale?: number;\n animations?: {\n openDoorAnim?: string;\n wheelsTurnAnim?: string;\n turnLeftAnim?: string;\n turnRightAnim?: string;\n };\n }) {\n try {\n const { url, position, scale = 1 } = params;\n const gltf: GLTF = await this.loader.loadAsync(url);\n this.vehicle = gltf.scene;\n this.vehicle.scale.set(scale, scale, scale);\n this.vehicle.position.copy(position);\n this.vehicle.traverse((child: any) => {\n if (child.isMesh) {\n child.castShadow = true;\n child.receiveShadow = true;\n }\n });\n\n this.scene.add(this.vehicle);\n\n const animations = gltf.animations ?? [];\n // console.log(\"车辆所有动画\", animations);\n this.vehicleActions = new Map<string, THREE.AnimationAction>();\n this.vehicleMixer = new THREE.AnimationMixer(this.vehicle);\n\n // 动画映射表\n const animationMappings: [string, string][] = [\n [params.animations?.openDoorAnim ?? \"\", \"open_door\"],\n [params.animations?.wheelsTurnAnim ?? \"\", \"wheels_turn\"],\n [params.animations?.turnLeftAnim ?? \"\", \"turn_left\"],\n [params.animations?.turnRightAnim ?? \"\", \"turn_right\"],\n ];\n\n // 注册动画动作\n const findClip = (name: string) => animations.find((a: any) => a.name === name);\n for (const [clipName, actionName] of animationMappings) {\n const clip = findClip(clipName);\n if (!clip) continue;\n const action = this.vehicleMixer.clipAction(clip);\n action.setLoop(THREE.LoopOnce, 1);\n action.clampWhenFinished = true;\n action.setEffectiveTimeScale(2);\n action.enabled = true;\n action.setEffectiveWeight(0);\n this.vehicleActions.set(actionName, action);\n }\n\n console.log(\"开门动画\", this.vehicleActions.get(\"open_door\"));\n\n // const next = this.vehicleActions.get(\"open_door\") as THREE.AnimationAction;\n // next.setEffectiveWeight(1);\n // next.play();\n } catch (error) {\n console.error(\"加载车辆模型失败:\", error);\n }\n }\n\n // ==================== 相机与视角控制 ====================\n\n /**\n * 第一/三人称视角切换\n */\n changeView() {\n this.isFirstPerson = !this.isFirstPerson;\n\n if (this.isFirstPerson) {\n this.player.attach(this.camera);\n this.camera.position.set(0, 40 * this.playerModel.scale, 30 * this.playerModel.scale);\n this.camera.rotation.set(0, Math.PI, 0);\n } else {\n this.scene.attach(this.camera);\n const worldPos = this.player.position.clone();\n const dir = new THREE.Vector3(0, 0, -1).applyQuaternion(this.player.quaternion);\n const angle = Math.atan2(dir.z, dir.x);\n const offset = new THREE.Vector3(Math.cos(angle) * 400 * this.playerModel.scale, 200 * this.playerModel.scale, Math.sin(angle) * 400 * this.playerModel.scale);\n this.camera.position.copy(worldPos).add(offset);\n this.controls.target.copy(worldPos);\n }\n\n this.setPointerLock();\n }\n\n setDrive() {\n this.controllerMode = 2;\n this.person?.attach(this.vehicle as THREE.Object3D);\n }\n\n /**\n * 设置指针锁定\n */\n setPointerLock() {\n if (((this.thirdMouseMode === 0 || this.thirdMouseMode === 1) && !this.isFirstPerson) || this.isFirstPerson) {\n document.body.requestPointerLock();\n }\n }\n\n /**\n * 设置摄像机初始位置\n */\n setCameraPos() {\n if (this.isFirstPerson) {\n this.camera.position.set(0, 40 * this.playerModel.scale, 30 * this.playerModel.scale);\n } else {\n const worldPos = this.player.position.clone();\n const dir = new THREE.Vector3(0, 0, -1).applyQuaternion(this.player.quaternion);\n const angle = Math.atan2(dir.z, dir.x);\n const offset = new THREE.Vector3(Math.cos(angle) * 400 * this.playerModel.scale, -100 * this.playerModel.scale, Math.sin(angle) * 400 * this.playerModel.scale);\n this.camera.position.copy(worldPos).add(offset);\n }\n this.camera.updateProjectionMatrix();\n }\n\n /**\n * 设置控制器\n */\n setControls() {\n this.controls.enabled = !(this.thirdMouseMode === 0 || this.thirdMouseMode === 1);\n this.controls.rotateSpeed = this.mouseSensity * 0.05;\n this.controls.maxPolarAngle = Math.PI * (300 / 360);\n }\n\n /**\n * 重置控制器\n */\n resetControls() {\n if (!this.controls) return;\n this.controls.enabled = true;\n this.controls.enablePan = true;\n this.controls.maxPolarAngle = Math.PI / 2;\n this.controls.rotateSpeed = 1;\n this.controls.enableZoom = true;\n this.controls.mouseButtons = { LEFT: 0, MIDDLE: 1, RIGHT: 2 };\n }\n\n /**\n * 设置朝向\n */\n setToward(dx: number, dy: number, speed: number) {\n if (this.isFirstPerson) {\n const yaw = -dx * speed * this.mouseSensity;\n const pitch = -dy * speed * this.mouseSensity;\n this.player.rotateY(yaw);\n this.camera.rotation.x = THREE.MathUtils.clamp(this.camera.rotation.x + pitch, -1.1, 1.4);\n } else {\n const sensitivity = this.mouseSensity;\n const deltaX = -dx * speed * sensitivity;\n const deltaY = -dy * speed * sensitivity;\n\n const target = this.player.position.clone();\n const distance = this.camera.position.distanceTo(target);\n const currentPosition = this.camera.position.clone().sub(target);\n\n let theta = Math.atan2(currentPosition.x, currentPosition.z);\n let phi = Math.acos(currentPosition.y / distance);\n\n theta += deltaX;\n phi += deltaY;\n phi = Math.max(0.1, Math.min(Math.PI - 0.1, phi));\n\n const newX = distance * Math.sin(phi) * Math.sin(theta);\n const newY = distance * Math.cos(phi);\n const newZ = distance * Math.sin(phi) * Math.cos(theta);\n\n this.camera.position.set(target.x + newX, target.y + newY, target.z + newZ);\n this.camera.lookAt(target);\n }\n }\n\n // ==================== 物理与碰撞检测 ====================\n\n /**\n * BVH碰撞体构建\n */\n async createBVH(meshUrl: string = \"\"): Promise<void> {\n await this.initLoader();\n\n const ensureAttributesMinimal = (geom: THREE.BufferGeometry): THREE.BufferGeometry | null => {\n if (!geom.attributes.position) return null;\n if (!geom.attributes.normal) geom.computeVertexNormals();\n if (!geom.attributes.uv) {\n const count = geom.attributes.position.count;\n const dummyUV = new Float32Array(count * 2);\n geom.setAttribute(\"uv\", new THREE.BufferAttribute(dummyUV, 2));\n }\n return geom;\n };\n\n const collected: THREE.BufferGeometry[] = [];\n\n if (meshUrl === \"\") {\n // 从场景中收集几何体\n if (this.collider) {\n this.scene.remove(this.collider);\n this.collider = null;\n }\n\n this.scene.traverse((c) => {\n const mesh = c as THREE.Mesh;\n if (mesh?.isMesh && mesh.geometry && c.name !== \"capsule\") {\n try {\n let geom = (mesh.geometry as THREE.BufferGeometry).clone();\n geom.applyMatrix4(mesh.matrixWorld);\n if (geom.index) geom = geom.toNonIndexed();\n const safe = ensureAttributesMinimal(geom);\n if (safe) collected.push(safe);\n } catch (e) {\n console.warn(\"处理网格时出错:\", mesh, e);\n }\n }\n });\n\n if (!collected.length) return;\n\n // 统一属性集合\n type AttrMeta = { itemSize: number; arrayCtor: any; examples: number };\n const attrMap = new Map<string, AttrMeta>();\n const attrConflict = new Set<string>();\n\n for (const g of collected) {\n for (const name of Object.keys(g.attributes)) {\n const attr = g.attributes[name] as THREE.BufferAttribute;\n const ctor = (attr.array as any).constructor;\n const itemSize = attr.itemSize;\n\n if (!attrMap.has(name)) {\n attrMap.set(name, { itemSize, arrayCtor: ctor, examples: 1 });\n } else {\n const m = attrMap.get(name)!;\n if (m.itemSize !== itemSize || m.arrayCtor !== ctor) {\n attrConflict.add(name);\n } else {\n m.examples++;\n }\n }\n }\n }\n\n // 删除冲突属性\n if (attrConflict.size) {\n for (const g of collected) {\n for (const name of Array.from(attrConflict)) {\n if (g.attributes[name]) g.deleteAttribute(name);\n }\n }\n for (const name of attrConflict) attrMap.delete(name);\n }\n\n // 补全缺失属性\n const attrNames = Array.from(attrMap.keys());\n for (const g of collected) {\n const count = g.attributes.position.count;\n for (const name of attrNames) {\n if (!g.attributes[name]) {\n const meta = attrMap.get(name)!;\n const len = count * meta.itemSize;\n const array = new meta.arrayCtor(len);\n g.setAttribute(name, new THREE.BufferAttribute(array, meta.itemSize));\n }\n }\n }\n } else {\n // 从URL加载模型\n const gltf: GLTF = await this.loader.loadAsync(meshUrl);\n const mesh = gltf.scene.children[0] as THREE.Mesh;\n mesh.name = \"BVH加载模型\";\n\n let geom = mesh.geometry.clone();\n geom.applyMatrix4(mesh.matrixWorld);\n if (geom.index) geom = geom.toNonIndexed();\n const safe = ensureAttributesMinimal(geom);\n if (safe) collected.push(safe);\n }\n\n // 合并几何体\n const merged = BufferGeometryUtils.mergeGeometries(collected, false);\n if (!merged) {\n console.error(\"合并几何失败\");\n return;\n }\n\n // 构建BVH\n (merged as any).boundsTree = new MeshBVH(merged, { maxDepth: 100 });\n this.collider = new THREE.Mesh(\n merged,\n new THREE.MeshBasicMaterial({\n opacity: 0.5,\n transparent: true,\n wireframe: true,\n })\n );\n\n if (this.displayCollider) this.scene.add(this.collider);\n if (this.displayVisualizer) {\n if (this.visualizer) this.scene.remove(this.visualizer);\n this.visualizer = new MeshBVHHelper(this.collider, this.visualizeDepth);\n this.scene.add(this.visualizer);\n }\n\n this.boundingBoxMinY = (this.collider as any).geometry.boundingBox.min.y;\n }\n\n /**\n * 获取法线与Y轴的夹角\n */\n getAngleWithYAxis(normal: { x: number; y: number; z: number }): number {\n const yAxis = { x: 0, y: 1, z: 0 };\n const dotProduct = normal.x * yAxis.x + normal.y * yAxis.y + normal.z * yAxis.z;\n const normalMagnitude = Math.sqrt(normal.x * normal.x + normal.y * normal.y + normal.z * normal.z);\n const cosTheta = dotProduct / normalMagnitude;\n return Math.acos(cosTheta);\n }\n\n // ==================== 循环更新 ====================\n\n /**\n * 每帧更新\n */\n async update(delta: number = clock.getDelta()) {\n if (!this.isupdate || !this.player || !this.collider) return;\n delta = Math.min(delta, 1 / 30);\n\n // 应用速度\n if (!this.isFlying) {\n this.player.position.addScaledVector(this.playerVelocity, delta);\n }\n\n // 更新动画\n this.updateMixers(delta);\n\n // 计算移动方向\n this.camera.getWorldDirection(this.camDir);\n let angle = Math.atan2(this.camDir.z, this.camDir.x) + Math.PI / 2;\n angle = 2 * Math.PI - angle;\n\n this.moveDir.set(0, 0, 0);\n if (this.fwdPressed) this.moveDir.add(this.DIR_FWD);\n if (this.bkdPressed) this.moveDir.add(this.DIR_BKD);\n if (this.lftPressed) this.moveDir.add(this.DIR_LFT);\n if (this.rgtPressed) this.moveDir.add(this.DIR_RGT);\n\n if (this.isFlying) {\n if (this.fwdPressed) this.moveDir.y = this.camDir.y;\n else this.moveDir.y = 0;\n if (this.spacePressed) this.moveDir.add(this.DIR_UP);\n }\n\n // 设置速度\n if (this.isFlying && this.fwdPressed) {\n this.playerSpeed = this.shiftPressed ? this.originPlayerSpeed * 12 : this.originPlayerSpeed * 7;\n } else {\n this.playerSpeed = this.shiftPressed ? this.originPlayerSpeed * 2 : this.originPlayerSpeed;\n }\n\n this.moveDir.normalize().applyAxisAngle(this.upVector, angle);\n this.player.position.addScaledVector(this.moveDir, this.playerSpeed * delta);\n\n // 向下射线检测地面高度\n let playerDistanceFromGround = Infinity;\n this._originTmp.set(this.player.position.x, this.player.position.y, this.player.position.z);\n this._raycaster.ray.origin.copy(this._originTmp);\n const intersects = this._raycaster.intersectObject(this.collider as THREE.Object3D, false);\n\n if (intersects.length > 0) {\n playerDistanceFromGround = this.player.position.y - intersects[0].point.y;\n const normal = intersects[0].normal as THREE.Vector3;\n const angle = (this.getAngleWithYAxis(normal) * 180) / Math.PI;\n const maxH = this.playerHeight * this.playerModel.scale * 0.9; // 坡度高度阈值\n const h = this.playerHeight * this.playerModel.scale * 0.75; // 正常高度\n const minH = this.playerHeight * this.playerModel.scale * 0.7; // 最小高度\n\n // console.log(\"人物中心点距离地面高度\", playerDistanceFromGround, \"坡度高度阈值\", maxH, \"正常高度\", h, \"最小高度\", minH);\n // console.log(\"坡度角度\", angle);\n\n // console.log(\"this.playerVelocity.y\", this.playerVelocity.y);\n\n if (!this.isFlying) {\n if (playerDistanceFromGround > maxH) {\n // 下落状态\n this.playerVelocity.y += delta * this.gravity;\n this.player.position.addScaledVector(this.playerVelocity, delta);\n this.playerIsOnGround = false;\n // console.log(\"下落\");\n } else if (playerDistanceFromGround > h && playerDistanceFromGround < maxH) {\n if (angle >= 0 && angle < 5) {\n // 平地\n this.playerVelocity.y += delta * this.gravity;\n this.player.position.addScaledVector(this.playerVelocity, delta);\n this.playerIsOnGround = true;\n // console.log(\"平地\");\n } else {\n // 坡地\n if (this.spacePressed) {\n this.playerVelocity.y += delta * this.gravity;\n } else {\n // console.log(\"坡地\", this.spacePressed);\n this.playerVelocity.set(0, 0, 0);\n this.playerIsOnGround = true;\n }\n }\n } else if (playerDistanceFromGround > minH && playerDistanceFromGround < h) {\n // 误差范围内在平地\n this.playerVelocity.set(0, 0, 0);\n this.playerIsOnGround = true;\n } else if (playerDistanceFromGround < minH) {\n // 强行拉回\n this.playerVelocity.set(0, 0, 0);\n this.player.position.set(this.player.position.x, intersects[0].point.y + h, this.player.position.z);\n this.playerIsOnGround = true;\n }\n }\n\n // console.log(\"是否在地面\", this.playerIsOnGround);\n }\n\n // 更新玩家矩阵\n this.player.updateMatrixWorld();\n\n // BVH碰撞检测\n const capsuleInfo = this.player.capsuleInfo;\n this.tempBox.makeEmpty();\n this.tempMat.copy(this.collider!.matrixWorld).invert();\n this.tempSegment.copy(capsuleInfo.segment);\n this.tempSegment.start.applyMatrix4(this.player.matrixWorld).applyMatrix4(this.tempMat);\n this.tempSegment.end.applyMatrix4(this.player.matrixWorld).applyMatrix4(this.tempMat);\n\n this.tempBox.expandByPoint(this.tempSegment.start);\n this.tempBox.expandByPoint(this.tempSegment.end);\n this.tempBox.expandByScalar(capsuleInfo.radius);\n\n const bvh = this.collider?.geometry as any;\n bvh?.boundsTree?.shapecast({\n // 检测包围盒碰撞\n intersectsBounds: (box: THREE.Box3) => box.intersectsBox(this.tempBox),\n // 检测三角形碰撞\n intersectsTriangle: (tri: any) => {\n const triPoint = this.tempVector;\n const capsulePoint = this.tempVector2;\n const distance = tri.closestPointToSegment(this.tempSegment, triPoint, capsulePoint);\n // 距离小于人物半径,发生碰撞\n if (distance < capsuleInfo.radius) {\n const depth = capsuleInfo.radius - distance;\n const direction = capsulePoint.sub(triPoint).normalize();\n this.tempSegment.start.addScaledVector(direction, depth);\n this.tempSegment.end.addScaledVector(direction, depth);\n }\n },\n });\n\n // 设置玩家位置\n const newPosition = this.tempVector.copy(this.tempSegment.start).applyMatrix4(this.collider!.matrixWorld);\n const deltaVector = this.tempVector2.subVectors(newPosition, this.player.position);\n const offset = Math.max(0, deltaVector.length() - 1e-5);\n deltaVector.normalize().multiplyScalar(offset);\n this.player.position.add(deltaVector);\n\n // 第三人称-朝向\n if (!this.isFirstPerson && !this.isFlying) {\n this.camDir.y = 0;\n this.camDir.normalize();\n this.camDir.negate();\n this.moveDir.normalize();\n this.moveDir.negate();\n\n let lookTarget: THREE.Vector3;\n if (this.thirdMouseMode === 0 || this.thirdMouseMode === 2) {\n if (this.moveDir.lengthSq() > 0) {\n lookTarget = this.player.position.clone().add(this.moveDir);\n } else {\n lookTarget = this.player.position.clone().add(this.camDir);\n }\n this.targetMat.lookAt(this.player.position, lookTarget, this.player.up);\n this.targetQuat.setFromRotationMatrix(this.targetMat);\n const alpha = Math.min(1, this.rotationSpeed * delta);\n this.player.quaternion.slerp(this.targetQuat, alpha);\n }\n if ((this.thirdMouseMode === 1 || this.thirdMouseMode === 3) && this.moveDir.lengthSq() > 0) {\n lookTarget = this.player.position.clone().add(this.moveDir);\n this.targetMat.lookAt(this.player.position, lookTarget, this.player.up);\n this.targetQuat.setFromRotationMatrix(this.targetMat);\n const alpha = Math.min(1, this.rotationSpeed * delta);\n this.player.quaternion.slerp(this.targetQuat, alpha);\n }\n }\n\n // 飞行模式朝向\n if (this.isFlying) {\n this.camDir.y = 0;\n this.camDir.normalize();\n this.camDir.negate();\n this.moveDir.normalize();\n this.moveDir.negate();\n const lookTarget = this.player.position.clone().add(this.fwdPressed ? this.moveDir : this.camDir);\n this.targetMat.lookAt(this.player.position, lookTarget, this.player.up);\n this.targetQuat.setFromRotationMatrix(this.targetMat);\n const alpha = Math.min(1, this.rotationSpeed * delta);\n this.player.quaternion.slerp(this.targetQuat, alpha);\n }\n\n // 第三人称-相机跟随\n if (!this.isFirstPerson) {\n const lookTarget = this.player.position.clone();\n lookTarget.y += 30 * this.playerModel.scale;\n this.camera.position.sub(this.controls.target);\n this.controls.target.copy(lookTarget);\n this.camera.position.add(lookTarget);\n this.controls.update();\n\n // 当视线被遮挡时的处理\n this._personToCam.subVectors(this.camera.position, this.player.position);\n const origin = this.player.position.clone().add(new THREE.Vector3(0, 0, 0));\n const direction = this._personToCam.clone().normalize();\n const desiredDist = this._personToCam.length();\n this._raycasterPersonToCam.set(origin, direction);\n this._raycasterPersonToCam.far = desiredDist;\n\n const intersects = this._raycasterPersonToCam.intersectObject(this.collider as THREE.Object3D, false);\n\n if (intersects.length > 0) {\n // 相机拉近\n const hit = intersects[0];\n const safeDist = Math.max(hit.distance - this._camEpsilon, this._minCamDistance);\n const targetCamPos = origin.clone().add(direction.clone().multiplyScalar(safeDist));\n this.camera.position.lerp(targetCamPos, this._camCollisionLerp);\n } else {\n // 相机恢复\n this._raycasterPersonToCam.far = this._maxCamDistance;\n const intersectsMaxDis = this._raycasterPersonToCam.intersectObject(this.collider as THREE.Object3D, false);\n\n let safeDist = this._maxCamDistance;\n if (intersectsMaxDis.length) {\n const hitMax = intersectsMaxDis[0];\n safeDist = hitMax.distance - this._camEpsilon;\n }\n const targetCamPos = origin.clone().add(direction.clone().multiplyScalar(safeDist));\n this.camera.position.lerp(targetCamPos, this._camCollisionLerp);\n }\n }\n\n // 掉出场景重置\n if (this.player.position.y < this.boundingBoxMinY - 1) {\n this._originTmp.set(this.player.position.x, 10000, this.player.position.z);\n this._raycaster.ray.origin.copy(this._originTmp);\n const intersects = this._raycaster.intersectObject(this.collider as THREE.Object3D, false);\n\n if (intersects.length > 0) {\n // 出现碰撞 说明玩家为bug意外掉落\n console.log(\"玩家为bug意外掉落\");\n this.reset(new THREE.Vector3(this.player.position.x, intersects[0].point.y + 5, this.player.position.z));\n } else {\n // 无碰撞 正常掉落\n console.log(\"玩家正常掉落\");\n this.reset(new THREE.Vector3(this.player.position.x, this.player.position.y + 15, this.player.position.z));\n }\n }\n }\n\n /**\n * 更新模型动画\n */\n private updateMixers(delta: number) {\n if (this.personMixer) this.personMixer.update(delta);\n if (this.vehicleMixer) this.vehicleMixer.update(delta);\n }\n\n /**\n * 重置玩家位置\n */\n reset(position?: THREE.Vector3) {\n if (!this.player) return;\n this.playerVelocity.set(0, 0, 0);\n this.player.position.copy(position ?? this.initPos);\n }\n\n /**\n * 获取玩家位置\n */\n getPosition() {\n return this.player.position;\n }\n\n // ==================== 输入处理 ====================\n\n /**\n * 设置输入\n */\n setInput(\n input: Partial<{\n moveX: 1 | 0 | -1;\n moveY: 1 | 0 | -1;\n lookDeltaX: number;\n lookDeltaY: number;\n jump: boolean;\n shift: boolean;\n toggleView: boolean;\n toggleFly: boolean;\n }>\n ) {\n // 控制人物移动\n if (typeof input.moveX === \"number\") {\n this.lftPressed = input.moveX === -1;\n this.rgtPressed = input.moveX === 1;\n this.setAnimationByPressed();\n }\n if (typeof input.moveY === \"number\") {\n this.fwdPressed = input.moveY === 1;\n this.bkdPressed = input.moveY === -1;\n this.setAnimationByPressed();\n }\n\n // 控制朝向\n if (typeof input.lookDeltaX === \"number\" && typeof input.lookDeltaY === \"number\") {\n this.setToward(input.lookDeltaX, input.lookDeltaY, 0.002);\n }\n\n // 跳跃\n if (typeof input.jump === \"boolean\") {\n if (input.jump) {\n this.spacePressed = true;\n if (!this.playerIsOnGround || this.isFlying) return;\n this.playPersonAnimationByName(\"jumping\");\n this.playerVelocity.y = this.jumpHeight;\n this.playerIsOnGround = false;\n } else {\n this.spacePressed = false;\n }\n }\n\n // 加速\n if (typeof input.shift === \"boolean\") {\n this.shiftPressed = input.shift;\n }\n\n // 切换视角\n if (input.toggleView) {\n this.changeView();\n }\n\n // 切换飞行\n if (input.toggleFly) {\n this.isFlying = !this.isFlying;\n this.setAnimationByPressed();\n if (!this.isFlying && !this.playerIsOnGround) {\n this.playPersonAnimationByName(\"jumping\");\n }\n }\n }\n\n /**\n * 根据按键设置人物动画\n */\n private setAnimationByPressed = () => {\n this._maxCamDistance = this.orginMaxCamDistance;\n\n if (this.isFlying) {\n if (!this.fwdPressed) {\n this.playPersonAnimationByName(\"flyidle\");\n return;\n }\n this.playPersonAnimationByName(\"flying\");\n this._maxCamDistance = this.orginMaxCamDistance * 2;\n return;\n }\n\n if (this.playerIsOnGround) {\n if (!this.fwdPressed && !this.bkdPressed && !this.lftPressed && !this.rgtPressed) {\n this.playPersonAnimationByName(\"idle\");\n return;\n }\n\n if (this.fwdPressed) {\n this.playPersonAnimationByName(this.shiftPressed ? \"running\" : \"walking\");\n return;\n }\n\n // 第三人称下动画统一使用前进动画\n if (!this.isFirstPerson && (this.lftPressed || this.rgtPressed || this.bkdPressed)) {\n this.playPersonAnimationByName(this.shiftPressed ? \"running\" : \"walking\");\n return;\n }\n\n // 第一人称下根据方向播放不同动画\n if (this.lftPressed) {\n this.playPersonAnimationByName(\"left_walking\");\n return;\n }\n if (this.rgtPressed) {\n this.playPersonAnimationByName(\"right_walking\");\n return;\n }\n if (this.bkdPressed) {\n this.playPersonAnimationByName(\"walking_backward\");\n return;\n }\n }\n\n // 销毁旧的定时器\n if (this.recheckAnimTimer !== null) {\n clearTimeout(this.recheckAnimTimer);\n }\n\n // 200ms后重新检测动画\n this.recheckAnimTimer = setTimeout(() => {\n this.setAnimationByPressed();\n this.recheckAnimTimer = null;\n }, 200);\n };\n\n // ==================== 事件处理 ====================\n\n /**\n * 键盘按下事件\n */\n private _boundOnKeydown = async (e: KeyboardEvent) => {\n if (e.ctrlKey && [\"KeyW\", \"KeyA\", \"KeyS\", \"KeyD\"].includes(e.code)) {\n e.preventDefault();\n }\n\n switch (e.code) {\n case \"KeyW\":\n this.fwdPressed = true;\n this.setAnimationByPressed();\n break;\n case \"KeyS\":\n this.bkdPressed = true;\n this.setAnimationByPressed();\n break;\n case \"KeyD\":\n this.rgtPressed = true;\n this.setAnimationByPressed();\n break;\n case \"KeyA\":\n this.lftPressed = true;\n this.setAnimationByPressed();\n break;\n case \"ShiftLeft\":\n this.shiftPressed = true;\n this.setAnimationByPressed();\n this.controls.mouseButtons = { LEFT: 2, MIDDLE: 1, RIGHT: 0 };\n break;\n case \"Space\":\n this.spacePressed = true;\n // console.log(\"点击跳跃\", this.playerIsOnGround, this.isFlying);\n if (!this.playerIsOnGround || this.isFlying) return;\n const next = this.personActions?.get(\"jumping\");\n if (next && this.actionState === next) return;\n this.playPersonAnimationByName(\"jumping\");\n this.playerVelocity.y = this.jumpHeight;\n this.playerIsOnGround = false;\n break;\n case \"ControlLeft\":\n this.ctPressed = true;\n break;\n case \"KeyV\":\n this.changeView();\n break;\n case \"KeyF\":\n this.isFlying = !this.isFlying;\n this.setAnimationByPressed();\n if (!this.isFlying && !this.playerIsOnGround) {\n this.playPersonAnimationByName(\"jumping\");\n }\n break;\n case \"KeyE\":\n this.setDrive();\n break;\n }\n };\n\n /**\n * 键盘抬起事件\n */\n private _boundOnKeyup = (e: KeyboardEvent) => {\n switch (e.code) {\n case \"KeyW\":\n this.fwdPressed = false;\n this.setAnimationByPressed();\n break;\n case \"KeyS\":\n this.bkdPressed = false;\n this.setAnimationByPressed();\n break;\n case \"KeyD\":\n this.rgtPressed = false;\n this.setAnimationByPressed();\n break;\n case \"KeyA\":\n this.lftPressed = false;\n this.setAnimationByPressed();\n break;\n case \"ShiftLeft\":\n this.shiftPressed = false;\n this.setAnimationByPressed();\n this.controls.mouseButtons = { LEFT: 0, MIDDLE: 1, RIGHT: 2 };\n break;\n case \"Space\":\n this.spacePressed = false;\n break;\n case \"ControlLeft\":\n this.ctPressed = false;\n break;\n }\n };\n\n /**\n * 鼠标移动事件\n */\n private _mouseMove = (e: MouseEvent) => {\n if (document.pointerLockElement !== document.body) return;\n this.setToward(e.movementX, e.movementY, 0.0001);\n };\n\n /**\n * 鼠标点击事件\n */\n private _mouseClick = (e: MouseEvent) => {\n this.setPointerLock();\n };\n\n /**\n * 事件绑定\n */\n onAllEvent() {\n this.isupdate = true;\n this.setPointerLock();\n\n window.addEventListener(\"keydown\", this._boundOnKeydown);\n window.addEventListener(\"keyup\", this._boundOnKeyup);\n window.addEventListener(\"mousemove\", this._mouseMove);\n window.addEventListener(\"click\", this._mouseClick);\n }\n\n /**\n * 事件解绑\n */\n offAllEvent() {\n this.isupdate = false;\n document.exitPointerLock();\n window.removeEventListener(\"keydown\", this._boundOnKeydown);\n window.removeEventListener(\"keyup\", this._boundOnKeyup);\n window.removeEventListener(\"mousemove\", this._mouseMove);\n window.removeEventListener(\"click\", this._mouseClick);\n }\n\n // ==================== 移动端控制 ====================\n\n /**\n * 指针按下事件\n */\n onPointerDown = (e: PointerEvent) => {\n if (e.pointerType !== \"touch\") return;\n this.isLookDown = true;\n this.lookPointerId = e.pointerId;\n this.lastTouchX = e.clientX;\n this.lastTouchY = e.clientY;\n\n this.lookAreaEl?.setPointerCapture?.(e.pointerId);\n e.preventDefault();\n };\n\n /**\n * 指针移动事件\n */\n onPointerMove = (e: PointerEvent) => {\n if (!this.isLookDown || e.pointerId !== this.lookPointerId) return;\n const dx = e.clientX - this.lastTouchX;\n const dy = e.clientY - this.lastTouchY;\n this.lastTouchX = e.clientX;\n this.lastTouchY = e.clientY;\n\n this.setInput({ lookDeltaX: dx, lookDeltaY: dy });\n e.preventDefault();\n };\n\n /**\n * 指针抬起事件\n */\n onPointerUp = (e: PointerEvent) => {\n if (e.pointerId !== this.lookPointerId) return;\n this.isLookDown = false;\n this.lookPointerId = null;\n this.lookAreaEl?.releasePointerCapture?.(e.pointerId);\n };\n\n /**\n * 初始化移动端摇杆控制\n */\n async initMobileControls() {\n this.controls.maxPolarAngle = Math.PI * (300 / 360);\n this.controls.touches = { ONE: null as any, TWO: null as any };\n this.nippleModule = await import(\"nipplejs\");\n const nipple = this.nippleModule?.default;\n const JOY_SIZE = 120;\n\n const container = document.body;\n\n // 摇杆容器\n this.joystickZoneEl = document.createElement(\"div\");\n this.joystickZoneEl.id = \"joy-zone\";\n Object.assign(this.joystickZoneEl.style, {\n position: \"absolute\",\n left: \"16px\",\n bottom: \"16px\",\n width: `${JOY_SIZE + 40}px`,\n height: `${JOY_SIZE + 40}px`,\n touchAction: \"none\",\n zIndex: \"999\",\n pointerEvents: \"auto\",\n WebkitUserSelect: \"none\",\n userSelect: \"none\",\n });\n container.appendChild(this.joystickZoneEl);\n\n // 阻止touch的默认行为\n [\"touchstart\", \"touchmove\", \"touchend\", \"touchcancel\"].forEach((evtName) => {\n this.joystickZoneEl?.addEventListener(evtName, (e) => e.preventDefault(), {\n passive: false,\n });\n });\n\n // 创建摇杆\n this.joystickManager = nipple.create({\n zone: this.joystickZoneEl,\n mode: \"static\",\n position: {\n left: `${(JOY_SIZE + 40) / 2}px`,\n bottom: `${(JOY_SIZE + 40) / 2}px`,\n },\n color: \"#ffffff\",\n size: JOY_SIZE,\n multitouch: true,\n maxNumberOfNipples: 1,\n });\n\n this.joystickManager.on(\"move\", (_evt: any, data: any) => {\n if (!data) return;\n\n const rawX = data.vector?.x ?? 0;\n const rawY = data.vector?.y ?? 0;\n const distance = data.distance ?? 0;\n const deadzone = 0.5;\n\n const dirX = rawX > deadzone ? 1 : rawX < -deadzone ? -1 : 0;\n const dirY = rawY > deadzone ? 1 : rawY < -deadzone ? -1 : 0;\n\n const sprintThreshold = JOY_SIZE / 2;\n const isSprinting = distance >= sprintThreshold;\n\n const prev = this.prevJoyState || { dirX: 0, dirY: 0, shift: false };\n if (dirX === prev.dirX && dirY === prev.dirY && isSprinting === prev.shift) {\n return;\n }\n\n this.prevJoyState = { dirX, dirY, shift: isSprinting };\n this.setInput({ moveX: dirX, moveY: dirY, shift: isSprinting });\n });\n\n this.joystickManager.on(\"end\", () => {\n const prev = this.prevJoyState || { dirX: 0, dirY: 0, shift: false };\n if (prev.dirX !== 0 || prev.dirY !== 0 || prev.shift !== false) {\n this.prevJoyState = { dirX: 0, dirY: 0, shift: false };\n this.setInput({ moveX: 0, moveY: 0, shift: false });\n }\n });\n\n // 右侧视角控制区域\n this.lookAreaEl = document.createElement(\"div\");\n Object.assign(this.lookAreaEl.style, {\n position: \"absolute\",\n right: \"0\",\n bottom: \"0\",\n width: \"50%\",\n height: \"100%\",\n zIndex: \"998\",\n touchAction: \"none\",\n WebkitUserSelect: \"none\",\n userSelect: \"none\",\n });\n container.appendChild(this.lookAreaEl);\n\n [\"touchstart\", \"touchmove\", \"touchend\", \"touchcancel\"].forEach((evtName) => {\n this.lookAreaEl?.addEventListener(evtName, (e) => e.preventDefault(), {\n passive: false,\n });\n });\n\n this.lookAreaEl.addEventListener(\"pointerdown\", this.onPointerDown, { passive: false });\n this.lookAreaEl.addEventListener(\"pointermove\", this.onPointerMove, { passive: false });\n this.lookAreaEl.addEventListener(\"pointerup\", this.onPointerUp, { passive: false });\n this.lookAreaEl.addEventListener(\"pointercancel\", this.onPointerUp, { passive: false });\n\n // 创建按钮\n const createBtn = (rightPx: number, bottomPx: number, bgUrl?: string) => {\n const btn = document.createElement(\"button\");\n const styles: Partial<CSSStyleDeclaration> = {\n position: \"absolute\",\n right: `${rightPx}px`,\n bottom: `${bottomPx}px`,\n width: \"56px\",\n height: \"56px\",\n zIndex: \"1000\",\n borderRadius: \"50%\",\n border: \"2px solid black\",\n background: \"rgba(0,0,0)\",\n padding: \"20px\",\n opacity: \"0.95\",\n touchAction: \"none\",\n fontSize: \"14px\",\n userSelect: \"none\",\n overflow: \"hidden\",\n boxSizing: \"border-box\",\n backgroundColor: \"transparent\",\n backgroundRepeat: \"no-repeat, no-repeat\",\n backgroundPosition: \"center center, center center\",\n backgroundSize: \"100% 100%, 80% 80%\",\n };\n\n if (bgUrl) {\n const overlayColor = \"rgba(0,0,0,0.5)\";\n styles.backgroundImage = `linear-gradient(${overlayColor}, ${overlayColor}), url(\"${bgUrl}\")`;\n }\n\n Object.assign(btn.style, styles);\n container.appendChild(btn);\n [\"touchstart\", \"touchend\", \"touchcancel\"].forEach((evtName) => {\n btn.addEventListener(evtName, (e) => e.preventDefault(), { passive: false });\n });\n\n return btn;\n };\n\n // 跳跃按钮\n this.jumpBtnEl = createBtn(14, 14, jumpIconModule);\n this.jumpBtnEl.addEventListener(\n \"touchstart\",\n (e) => {\n e.preventDefault();\n this.setInput({ jump: true });\n },\n { passive: false }\n );\n this.jumpBtnEl.addEventListener(\n \"touchend\",\n (e) => {\n e.preventDefault();\n this.setInput({ jump: false });\n },\n { passive: false }\n );\n this.jumpBtnEl.addEventListener(\n \"touchcancel\",\n (e) => {\n e.preventDefault();\n this.setInput({ jump: false });\n },\n { passive: false }\n );\n\n // 切换飞行按钮\n this.flyBtnEl = createBtn(14, 14 + 80, flyIconModule);\n this.flyBtnEl.addEventListener(\n \"touchstart\",\n (e) => {\n e.preventDefault();\n this.setInput({ toggleFly: true });\n },\n { passive: false }\n );\n\n // 切换视角按钮\n this.viewBtnEl = createBtn(14, 14 + 200, viewIconModule);\n this.viewBtnEl.addEventListener(\n \"touchstart\",\n (e) => {\n e.preventDefault();\n this.setInput({ toggleView: true });\n },\n { passive: false }\n );\n }\n\n /**\n * 销毁移动端摇杆控制\n */\n destroyMobileControls() {\n try {\n if (this.joystickManager && this.joystickManager.destroy) {\n this.joystickManager.destroy();\n this.joystickManager = null;\n }\n if (this.joystickZoneEl?.parentElement) {\n this.joystickZoneEl.parentElement.removeChild(this.joystickZoneEl);\n this.joystickZoneEl = null;\n }\n if (this.lookAreaEl?.parentElement) {\n this.lookAreaEl.parentElement.removeChild(this.lookAreaEl);\n this.lookAreaEl = null;\n }\n if (this.jumpBtnEl?.parentElement) {\n this.jumpBtnEl.parentElement.removeChild(this.jumpBtnEl);\n this.jumpBtnEl = null;\n }\n if (this.flyBtnEl?.parentElement) {\n this.flyBtnEl.parentElement.removeChild(this.flyBtnEl);\n this.flyBtnEl = null;\n }\n if (this.viewBtnEl?.parentElement) {\n this.viewBtnEl.parentElement.removeChild(this.viewBtnEl);\n this.viewBtnEl = null;\n }\n\n // 监听\n this.lookAreaEl?.removeEventListener(\"pointerdown\", this.onPointerDown);\n this.lookAreaEl?.removeEventListener(\"pointermove\", this.onPointerMove);\n this.lookAreaEl?.removeEventListener(\"pointerup\", this.onPointerUp);\n this.lookAreaEl?.removeEventListener(\"pointercancel\", this.onPointerUp);\n } catch (e) {\n console.warn(\"销毁移动端摇杆控制时出错:\", e);\n }\n }\n\n // ==================== 销毁 ====================\n\n /**\n * 销毁人物控制器\n */\n destroy() {\n this.offAllEvent();\n if (this.player) {\n this.player.remove(this.camera);\n this.scene.remove(this.player);\n }\n (this.player as any) = null;\n if (this.person) {\n this.scene.remove(this.person);\n this.person = null;\n }\n\n this.resetControls();\n\n // 清理 BVH 可视化\n if (this.visualizer) {\n this.scene.remove(this.visualizer);\n this.visualizer = null;\n }\n if (this.collider) {\n this.scene.remove(this.collider);\n this.collider = null;\n }\n\n this.destroyMobileControls();\n\n controllerInstance = null;\n }\n}\n\n// 导出API\nexport function playerController() {\n if (!controllerInstance) controllerInstance = new PlayerController();\n const c = controllerInstance;\n return {\n init: (opts: PlayerControllerOptions, callback?: () => void) => c.init(opts, callback),\n changeView: () => c.changeView(),\n reset: (pos?: THREE.Vector3) => c.reset(pos),\n update: (dt?: number) => c.update(dt),\n destroy: () => c.destroy(),\n setInput: (i: any) => c.setInput(i),\n getposition: () => c.getPosition(),\n loadVehicleModel: (params: {\n url: string;\n position: THREE.Vector3;\n scale?: number;\n animations: {\n openDoorAnim?: string;\n wheelsTurnAnim?: string;\n turnLeftAnim?: string;\n turnRightAnim?: string;\n };\n }) => c.loadVehicleModel(params),\n };\n}\n\n// 打开所有事件\nexport function onAllEvent(): void {\n if (!controllerInstance) controllerInstance = new PlayerController();\n controllerInstance.onAllEvent();\n}\n\n// 关闭所有事件\nexport function offAllEvent(): void {\n if (!controllerInstance) return;\n controllerInstance.offAllEvent();\n}\n"],"mappings":"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","names":["angle","intersects"]}
package/dist/index.mjs CHANGED
@@ -23,7 +23,7 @@ var PlayerController = class {
23
23
  constructor() {
24
24
  // ==================== 基本配置与参数 ====================
25
25
  this.loader = new GLTFLoader();
26
- // 0: 隐藏鼠标控制朝向及视角,1: 隐藏鼠标仅控制视角,2: 显示鼠标拖拽控制朝向及视角, 3: 显示鼠标拖拽仅控制视角
26
+ // 0: 普通 1: 飞行 2: 车辆
27
27
  // ==================== 玩家基本属性 ====================
28
28
  this.playerRadius = 45;
29
29
  this.playerHeight = 180;
@@ -37,6 +37,7 @@ var PlayerController = class {
37
37
  this.collider = null;
38
38
  this.visualizer = null;
39
39
  this.person = null;
40
+ this.vehicle = null;
40
41
  // ==================== 状态开关 ====================
41
42
  this.playerIsOnGround = false;
42
43
  this.isupdate = true;
@@ -199,6 +200,9 @@ var PlayerController = class {
199
200
  this.playPersonAnimationByName("jumping");
200
201
  }
201
202
  break;
203
+ case "KeyE":
204
+ this.setDrive();
205
+ break;
202
206
  }
203
207
  };
204
208
  /**
@@ -466,6 +470,50 @@ var PlayerController = class {
466
470
  this.reset();
467
471
  this.player.rotateY(this.playerModel.rotateY ?? 0);
468
472
  }
473
+ // ==================== 车辆模型相关 ====================
474
+ /**
475
+ * 加载车辆模型与动画
476
+ */
477
+ async loadVehicleModel(params) {
478
+ try {
479
+ const { url, position, scale = 1 } = params;
480
+ const gltf = await this.loader.loadAsync(url);
481
+ this.vehicle = gltf.scene;
482
+ this.vehicle.scale.set(scale, scale, scale);
483
+ this.vehicle.position.copy(position);
484
+ this.vehicle.traverse((child) => {
485
+ if (child.isMesh) {
486
+ child.castShadow = true;
487
+ child.receiveShadow = true;
488
+ }
489
+ });
490
+ this.scene.add(this.vehicle);
491
+ const animations = gltf.animations ?? [];
492
+ this.vehicleActions = /* @__PURE__ */ new Map();
493
+ this.vehicleMixer = new THREE.AnimationMixer(this.vehicle);
494
+ const animationMappings = [
495
+ [params.animations?.openDoorAnim ?? "", "open_door"],
496
+ [params.animations?.wheelsTurnAnim ?? "", "wheels_turn"],
497
+ [params.animations?.turnLeftAnim ?? "", "turn_left"],
498
+ [params.animations?.turnRightAnim ?? "", "turn_right"]
499
+ ];
500
+ const findClip = (name) => animations.find((a) => a.name === name);
501
+ for (const [clipName, actionName] of animationMappings) {
502
+ const clip = findClip(clipName);
503
+ if (!clip) continue;
504
+ const action = this.vehicleMixer.clipAction(clip);
505
+ action.setLoop(THREE.LoopOnce, 1);
506
+ action.clampWhenFinished = true;
507
+ action.setEffectiveTimeScale(2);
508
+ action.enabled = true;
509
+ action.setEffectiveWeight(0);
510
+ this.vehicleActions.set(actionName, action);
511
+ }
512
+ console.log("\u5F00\u95E8\u52A8\u753B", this.vehicleActions.get("open_door"));
513
+ } catch (error) {
514
+ console.error("\u52A0\u8F7D\u8F66\u8F86\u6A21\u578B\u5931\u8D25:", error);
515
+ }
516
+ }
469
517
  // ==================== 相机与视角控制 ====================
470
518
  /**
471
519
  * 第一/三人称视角切换
@@ -487,6 +535,10 @@ var PlayerController = class {
487
535
  }
488
536
  this.setPointerLock();
489
537
  }
538
+ setDrive() {
539
+ this.controllerMode = 2;
540
+ this.person?.attach(this.vehicle);
541
+ }
490
542
  /**
491
543
  * 设置指针锁定
492
544
  */
@@ -729,8 +781,12 @@ var PlayerController = class {
729
781
  this.player.position.addScaledVector(this.playerVelocity, delta);
730
782
  this.playerIsOnGround = true;
731
783
  } else {
732
- this.playerVelocity.set(0, 0, 0);
733
- this.playerIsOnGround = true;
784
+ if (this.spacePressed) {
785
+ this.playerVelocity.y += delta * this.gravity;
786
+ } else {
787
+ this.playerVelocity.set(0, 0, 0);
788
+ this.playerIsOnGround = true;
789
+ }
734
790
  }
735
791
  } else if (playerDistanceFromGround > minH && playerDistanceFromGround < h) {
736
792
  this.playerVelocity.set(0, 0, 0);
@@ -861,6 +917,7 @@ var PlayerController = class {
861
917
  */
862
918
  updateMixers(delta) {
863
919
  if (this.personMixer) this.personMixer.update(delta);
920
+ if (this.vehicleMixer) this.vehicleMixer.update(delta);
864
921
  }
865
922
  /**
866
923
  * 重置玩家位置
@@ -1183,7 +1240,8 @@ function playerController() {
1183
1240
  update: (dt) => c.update(dt),
1184
1241
  destroy: () => c.destroy(),
1185
1242
  setInput: (i) => c.setInput(i),
1186
- getposition: () => c.getPosition()
1243
+ getposition: () => c.getPosition(),
1244
+ loadVehicleModel: (params) => c.loadVehicleModel(params)
1187
1245
  };
1188
1246
  }
1189
1247
  function onAllEvent() {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/playerController.ts"],"sourcesContent":["import * as THREE from \"three\";\nimport { acceleratedRaycast, MeshBVH, MeshBVHHelper } from \"three-mesh-bvh\";\nimport type { GLTF } from \"three/examples/jsm/Addons.js\";\nimport { OrbitControls } from \"three/examples/jsm/controls/OrbitControls.js\";\nimport { RoundedBoxGeometry } from \"three/examples/jsm/geometries/RoundedBoxGeometry.js\";\nimport { DRACOLoader } from \"three/examples/jsm/loaders/DRACOLoader.js\";\nimport { GLTFLoader } from \"three/examples/jsm/loaders/GLTFLoader.js\";\nimport * as BufferGeometryUtils from \"three/examples/jsm/utils/BufferGeometryUtils.js\";\nimport flyIconModule from \"../assets/imgs/fly.png\";\nimport jumpIconModule from \"../assets/imgs/jump.png\";\nimport viewIconModule from \"../assets/imgs/view.png\";\n\nTHREE.Mesh.prototype.raycast = acceleratedRaycast; // 启用加速 raycast\n\nlet controllerInstance: PlayerController | null = null;\nconst clock = new THREE.Clock();\n\nexport type PlayerControllerOptions = {\n scene: THREE.Scene;\n camera: THREE.PerspectiveCamera;\n controls: OrbitControls;\n playerModel: {\n url: string;\n idleAnim: string;\n walkAnim: string;\n runAnim: string;\n jumpAnim: string;\n leftWalkAnim?: string;\n rightWalkAnim?: string;\n backwardAnim?: string;\n flyAnim?: string;\n flyIdleAnim?: string;\n scale: number;\n gravity?: number;\n jumpHeight?: number;\n speed?: number;\n rotateY?: number;\n };\n initPos?: THREE.Vector3;\n mouseSensity?: number;\n minCamDistance?: number;\n maxCamDistance?: number;\n colliderMeshUrl?: string;\n isShowMobileControls?: boolean;\n thirdMouseMode?: 0 | 1 | 2 | 3;\n};\n\nclass PlayerController {\n // ==================== 基本配置与参数 ====================\n loader: GLTFLoader = new GLTFLoader();\n scene!: THREE.Scene;\n camera!: THREE.PerspectiveCamera;\n controls!: OrbitControls;\n playerModel!: PlayerControllerOptions[\"playerModel\"];\n initPos!: THREE.Vector3;\n visualizeDepth!: number;\n gravity!: number;\n jumpHeight!: number;\n playerSpeed!: number;\n mouseSensity!: number;\n originPlayerSpeed!: number;\n colliderMeshUrl!: string;\n isShowMobileControls!: boolean;\n thirdMouseMode!: 0 | 1 | 2 | 3; // 0: 隐藏鼠标控制朝向及视角,1: 隐藏鼠标仅控制视角,2: 显示鼠标拖拽控制朝向及视角, 3: 显示鼠标拖拽仅控制视角\n\n // ==================== 玩家基本属性 ====================\n playerRadius: number = 45;\n playerHeight: number = 180;\n isFirstPerson: boolean = false;\n boundingBoxMinY: number = 0;\n\n // ==================== 测试参数 ====================\n displayPlayer: boolean = false;\n displayCollider: boolean = false;\n displayVisualizer: boolean = false;\n\n // ==================== 场景对象 ====================\n collider: THREE.Mesh | null = null;\n visualizer: MeshBVHHelper | null = null;\n player!: THREE.Mesh & { capsuleInfo?: any };\n person: THREE.Object3D | null = null;\n\n // ==================== 状态开关 ====================\n playerIsOnGround: boolean = false;\n isupdate: boolean = true;\n isFlying: boolean = false;\n\n // ==================== 输入状态 ====================\n fwdPressed: boolean = false;\n bkdPressed: boolean = false;\n lftPressed: boolean = false;\n rgtPressed: boolean = false;\n spacePressed: boolean = false;\n ctPressed: boolean = false;\n shiftPressed: boolean = false;\n\n // ==================== 移动端输入 ====================\n prevJoyState = { dirX: 0, dirY: 0, shift: false };\n nippleModule: any = null;\n joystickManager: any = null;\n joystickZoneEl: HTMLDivElement | null = null;\n lookAreaEl: HTMLDivElement | null = null;\n jumpBtnEl: HTMLButtonElement | null = null;\n flyBtnEl: HTMLButtonElement | null = null;\n viewBtnEl: HTMLButtonElement | null = null;\n lookPointerId: number | null = null;\n isLookDown = false;\n lastTouchX = 0;\n lastTouchY = 0;\n\n // ==================== 第三人称相机参数 ====================\n _camCollisionLerp: number = 0.18; // 平滑系数\n _camEpsilon: number = 0.35; // 摄像机与障碍物之间的安全距离\n _minCamDistance: number = 1.0; // 摄像机最小距离\n _maxCamDistance: number = 4.4; // 摄像机最大距离\n orginMaxCamDistance: number = 4.4;\n\n // ==================== 物理/运动 ====================\n playerVelocity = new THREE.Vector3(); // 玩家速度向量\n readonly upVector = new THREE.Vector3(0, 1, 0);\n\n // ==================== 临时复用向量/矩阵 ====================\n readonly tempVector = new THREE.Vector3();\n readonly tempVector2 = new THREE.Vector3();\n readonly tempBox = new THREE.Box3();\n readonly tempMat = new THREE.Matrix4();\n readonly tempSegment = new THREE.Line3();\n\n // ==================== 动画相关 ====================\n personMixer?: THREE.AnimationMixer;\n personActions?: Map<string, THREE.AnimationAction>;\n idleAction!: THREE.AnimationAction;\n walkAction!: THREE.AnimationAction;\n leftWalkAction!: THREE.AnimationAction;\n rightWalkAction!: THREE.AnimationAction;\n backwardAction!: THREE.AnimationAction;\n jumpAction!: THREE.AnimationAction;\n runAction!: THREE.AnimationAction;\n flyidleAction!: THREE.AnimationAction;\n flyAction!: THREE.AnimationAction;\n actionState!: THREE.AnimationAction;\n recheckAnimTimer: any | null = null;\n\n // ==================== 相机朝向/移动复用向量 ====================\n readonly camDir = new THREE.Vector3();\n readonly moveDir = new THREE.Vector3();\n readonly targetQuat = new THREE.Quaternion();\n readonly targetMat = new THREE.Matrix4();\n readonly rotationSpeed = 10;\n readonly DIR_FWD = new THREE.Vector3(0, 0, -1);\n readonly DIR_BKD = new THREE.Vector3(0, 0, 1);\n readonly DIR_LFT = new THREE.Vector3(-1, 0, 0);\n readonly DIR_RGT = new THREE.Vector3(1, 0, 0);\n readonly DIR_UP = new THREE.Vector3(0, 1, 0);\n\n // ==================== 射线检测 ====================\n readonly _personToCam = new THREE.Vector3();\n readonly _originTmp = new THREE.Vector3();\n readonly _raycaster = new THREE.Raycaster(new THREE.Vector3(), new THREE.Vector3(0, -1, 0));\n readonly _raycasterPersonToCam = new THREE.Raycaster(new THREE.Vector3(), new THREE.Vector3());\n\n constructor() {\n // 射线检测时只返回第一个碰撞\n (this._raycaster as any).firstHitOnly = true;\n (this._raycasterPersonToCam as any).firstHitOnly = true;\n }\n\n // ==================== 初始化相关方法 ====================\n\n /**\n * 初始化控制器\n */\n async init(opts: PlayerControllerOptions, callback?: () => void) {\n this.scene = opts.scene;\n this.camera = opts.camera;\n this.camera.rotation.order = \"YXZ\";\n this.controls = opts.controls;\n this.playerModel = opts.playerModel;\n this.initPos = opts.initPos ?? new THREE.Vector3(0, 0, 0);\n this.mouseSensity = opts.mouseSensity ?? 5;\n\n const s = this.playerModel.scale;\n this.visualizeDepth = 0 * s;\n this.gravity = (opts.playerModel.gravity ?? -2400) * s;\n this.jumpHeight = (opts.playerModel.jumpHeight ?? 800) * s;\n this.originPlayerSpeed = (opts.playerModel.speed ?? 400) * s;\n this.playerSpeed = this.originPlayerSpeed;\n this.playerModel.rotateY = opts.playerModel.rotateY ?? 0;\n\n this._camCollisionLerp = 0.18;\n this._camEpsilon = 35 * s;\n this._minCamDistance = (opts.minCamDistance ?? 100) * s;\n this._maxCamDistance = (opts.maxCamDistance ?? 440) * s;\n this.orginMaxCamDistance = this._maxCamDistance;\n this.thirdMouseMode = opts.thirdMouseMode ?? 1;\n\n // 判断是否移动端\n const isMobileDevice = () => (navigator.maxTouchPoints && navigator.maxTouchPoints > 0) || \"ontouchstart\" in window || /Mobi|Android|iPhone|iPad|iPod/i.test(navigator.userAgent);\n\n this.isShowMobileControls = (opts.isShowMobileControls ?? true) && isMobileDevice();\n if (this.isShowMobileControls) {\n await this.initMobileControls();\n }\n\n // 创建BVH碰撞体\n await this.createBVH(opts.colliderMeshUrl);\n\n // 创建玩家胶囊体\n this.createPlayer();\n\n // 加载玩家模型\n await this.loadPersonGLB();\n\n // 等待资源加载完毕再设置摄像机\n if (this.isFirstPerson && this.person) {\n this.person.add(this.camera);\n }\n\n this.onAllEvent();\n this.setCameraPos();\n this.setControls();\n if (callback) callback();\n }\n\n /**\n * 初始化加载器\n */\n async initLoader() {\n const dracoLoader = new DRACOLoader();\n dracoLoader.setDecoderPath(\"https://unpkg.com/three@0.180.0/examples/jsm/libs/draco/gltf/\");\n dracoLoader.setDecoderConfig({ type: \"js\" });\n this.loader.setDRACOLoader(dracoLoader);\n }\n\n // ==================== 玩家模型相关方法 ====================\n\n /**\n * 加载玩家模型与动画\n */\n async loadPersonGLB() {\n try {\n const gltf: GLTF = await this.loader.loadAsync(this.playerModel.url);\n this.person = gltf.scene;\n const sc = this.playerModel.scale;\n const h = this.playerHeight * sc;\n\n this.person.scale.set(sc, sc, sc);\n this.person.position.set(0, -h * 0.75, 0);\n this.person.traverse((child: any) => {\n if (child.isMesh) {\n child.castShadow = true;\n child.receiveShadow = true;\n }\n });\n\n this.player.add(this.person);\n this.reset();\n\n // 创建动画混合器\n this.personMixer = new THREE.AnimationMixer(this.person);\n const animations = gltf.animations ?? [];\n this.personActions = new Map<string, THREE.AnimationAction>();\n\n // 动画映射表\n const animationMappings: [string, string][] = [\n [this.playerModel.idleAnim, \"idle\"],\n [this.playerModel.walkAnim, \"walking\"],\n [this.playerModel.leftWalkAnim || this.playerModel.walkAnim, \"left_walking\"],\n [this.playerModel.rightWalkAnim || this.playerModel.walkAnim, \"right_walking\"],\n [this.playerModel.backwardAnim || this.playerModel.walkAnim, \"walking_backward\"],\n [this.playerModel.jumpAnim, \"jumping\"],\n [this.playerModel.runAnim, \"running\"],\n [this.playerModel.flyIdleAnim || this.playerModel.idleAnim, \"flyidle\"],\n [this.playerModel.flyAnim || this.playerModel.idleAnim, \"flying\"],\n ];\n\n // 注册动画动作\n const findClip = (name: string) => animations.find((a: any) => a.name === name);\n for (const [clipName, actionName] of animationMappings) {\n const clip = findClip(clipName);\n if (!clip) continue;\n\n const action = this.personMixer.clipAction(clip);\n\n if (actionName === \"jumping\") {\n action.setLoop(THREE.LoopOnce, 1);\n action.clampWhenFinished = true;\n action.setEffectiveTimeScale(1.2);\n } else {\n action.setLoop(THREE.LoopRepeat, Infinity);\n action.clampWhenFinished = false;\n action.setEffectiveTimeScale(1);\n }\n\n action.enabled = true;\n action.setEffectiveWeight(0);\n this.personActions.set(actionName, action);\n }\n\n // 获取动画动作引用\n this.idleAction = this.personActions.get(\"idle\")!;\n this.walkAction = this.personActions.get(\"walking\")!;\n this.leftWalkAction = this.personActions.get(\"left_walking\")!;\n this.rightWalkAction = this.personActions.get(\"right_walking\")!;\n this.backwardAction = this.personActions.get(\"walking_backward\")!;\n this.jumpAction = this.personActions.get(\"jumping\")!;\n this.runAction = this.personActions.get(\"running\")!;\n this.flyidleAction = this.personActions.get(\"flyidle\")!;\n this.flyAction = this.personActions.get(\"flying\")!;\n\n // 激活空闲动作\n this.idleAction.setEffectiveWeight(1);\n this.idleAction.play();\n this.actionState = this.idleAction;\n\n // 监听动画完成事件\n this.personMixer.addEventListener(\"finished\", (ev: any) => {\n const finishedAction: THREE.AnimationAction = ev.action;\n\n if (finishedAction === this.jumpAction) {\n if (this.fwdPressed) {\n this.playPersonAnimationByName(this.shiftPressed ? \"running\" : \"walking\");\n return;\n }\n if (this.bkdPressed) {\n this.playPersonAnimationByName(\"walking_backward\");\n return;\n }\n if (this.rgtPressed || this.lftPressed) {\n this.playPersonAnimationByName(\"walking\");\n return;\n }\n this.playPersonAnimationByName(\"idle\");\n }\n });\n } catch (error) {\n console.error(\"加载玩家模型失败:\", error);\n }\n }\n\n /**\n * 平滑切换人物动画\n */\n playPersonAnimationByName(name: string, fade = 0.18) {\n if (!this.personActions || this.ctPressed) return;\n\n const next = this.personActions.get(name);\n if (!next || this.actionState === next) return;\n\n const prev = this.actionState;\n\n next.reset();\n next.setEffectiveWeight(1);\n next.play();\n\n if (prev && prev !== next) {\n prev.fadeOut(fade);\n next.fadeIn(fade);\n } else {\n next.fadeIn(fade);\n }\n\n this.actionState = next;\n }\n\n /**\n * 创建玩家胶囊体\n */\n createPlayer() {\n const material = new THREE.MeshStandardMaterial({\n color: new THREE.Color(1, 0, 0),\n shadowSide: THREE.DoubleSide,\n depthTest: false,\n transparent: true,\n opacity: this.displayPlayer ? 0.5 : 0,\n wireframe: true,\n depthWrite: false,\n });\n\n const r = this.playerRadius * this.playerModel.scale;\n const h = this.playerHeight * this.playerModel.scale;\n this.player = new THREE.Mesh(new RoundedBoxGeometry(r * 2, h, r * 2, 1, 75), material) as typeof this.player;\n\n this.player.geometry.translate(0, -h * 0.25, 0);\n this.player.capsuleInfo = {\n radius: r,\n segment: new THREE.Line3(new THREE.Vector3(), new THREE.Vector3(0, -h * 0.5, 0)),\n };\n\n this.player.name = \"capsule\";\n this.scene.add(this.player);\n this.reset();\n\n // 设置初始朝向\n this.player.rotateY(this.playerModel.rotateY ?? 0);\n }\n\n // ==================== 相机与视角控制 ====================\n\n /**\n * 第一/三人称视角切换\n */\n changeView() {\n this.isFirstPerson = !this.isFirstPerson;\n\n if (this.isFirstPerson) {\n this.player.attach(this.camera);\n this.camera.position.set(0, 40 * this.playerModel.scale, 30 * this.playerModel.scale);\n this.camera.rotation.set(0, Math.PI, 0);\n } else {\n this.scene.attach(this.camera);\n const worldPos = this.player.position.clone();\n const dir = new THREE.Vector3(0, 0, -1).applyQuaternion(this.player.quaternion);\n const angle = Math.atan2(dir.z, dir.x);\n const offset = new THREE.Vector3(Math.cos(angle) * 400 * this.playerModel.scale, 200 * this.playerModel.scale, Math.sin(angle) * 400 * this.playerModel.scale);\n this.camera.position.copy(worldPos).add(offset);\n this.controls.target.copy(worldPos);\n }\n\n this.setPointerLock();\n }\n\n /**\n * 设置指针锁定\n */\n setPointerLock() {\n if (((this.thirdMouseMode === 0 || this.thirdMouseMode === 1) && !this.isFirstPerson) || this.isFirstPerson) {\n document.body.requestPointerLock();\n }\n }\n\n /**\n * 设置摄像机初始位置\n */\n setCameraPos() {\n if (this.isFirstPerson) {\n this.camera.position.set(0, 40 * this.playerModel.scale, 30 * this.playerModel.scale);\n } else {\n const worldPos = this.player.position.clone();\n const dir = new THREE.Vector3(0, 0, -1).applyQuaternion(this.player.quaternion);\n const angle = Math.atan2(dir.z, dir.x);\n const offset = new THREE.Vector3(Math.cos(angle) * 400 * this.playerModel.scale, -100 * this.playerModel.scale, Math.sin(angle) * 400 * this.playerModel.scale);\n this.camera.position.copy(worldPos).add(offset);\n }\n this.camera.updateProjectionMatrix();\n }\n\n /**\n * 设置控制器\n */\n setControls() {\n this.controls.enabled = !(this.thirdMouseMode === 0 || this.thirdMouseMode === 1);\n this.controls.rotateSpeed = this.mouseSensity * 0.05;\n this.controls.maxPolarAngle = Math.PI * (300 / 360);\n }\n\n /**\n * 重置控制器\n */\n resetControls() {\n if (!this.controls) return;\n this.controls.enabled = true;\n this.controls.enablePan = true;\n this.controls.maxPolarAngle = Math.PI / 2;\n this.controls.rotateSpeed = 1;\n this.controls.enableZoom = true;\n this.controls.mouseButtons = { LEFT: 0, MIDDLE: 1, RIGHT: 2 };\n }\n\n /**\n * 设置朝向\n */\n setToward(dx: number, dy: number, speed: number) {\n if (this.isFirstPerson) {\n const yaw = -dx * speed * this.mouseSensity;\n const pitch = -dy * speed * this.mouseSensity;\n this.player.rotateY(yaw);\n this.camera.rotation.x = THREE.MathUtils.clamp(this.camera.rotation.x + pitch, -1.1, 1.4);\n } else {\n const sensitivity = this.mouseSensity;\n const deltaX = -dx * speed * sensitivity;\n const deltaY = -dy * speed * sensitivity;\n\n const target = this.player.position.clone();\n const distance = this.camera.position.distanceTo(target);\n const currentPosition = this.camera.position.clone().sub(target);\n\n let theta = Math.atan2(currentPosition.x, currentPosition.z);\n let phi = Math.acos(currentPosition.y / distance);\n\n theta += deltaX;\n phi += deltaY;\n phi = Math.max(0.1, Math.min(Math.PI - 0.1, phi));\n\n const newX = distance * Math.sin(phi) * Math.sin(theta);\n const newY = distance * Math.cos(phi);\n const newZ = distance * Math.sin(phi) * Math.cos(theta);\n\n this.camera.position.set(target.x + newX, target.y + newY, target.z + newZ);\n this.camera.lookAt(target);\n }\n }\n\n // ==================== 物理与碰撞检测 ====================\n\n /**\n * BVH碰撞体构建\n */\n async createBVH(meshUrl: string = \"\"): Promise<void> {\n await this.initLoader();\n\n const ensureAttributesMinimal = (geom: THREE.BufferGeometry): THREE.BufferGeometry | null => {\n if (!geom.attributes.position) return null;\n if (!geom.attributes.normal) geom.computeVertexNormals();\n if (!geom.attributes.uv) {\n const count = geom.attributes.position.count;\n const dummyUV = new Float32Array(count * 2);\n geom.setAttribute(\"uv\", new THREE.BufferAttribute(dummyUV, 2));\n }\n return geom;\n };\n\n const collected: THREE.BufferGeometry[] = [];\n\n if (meshUrl === \"\") {\n // 从场景中收集几何体\n if (this.collider) {\n this.scene.remove(this.collider);\n this.collider = null;\n }\n\n this.scene.traverse((c) => {\n const mesh = c as THREE.Mesh;\n if (mesh?.isMesh && mesh.geometry && c.name !== \"capsule\") {\n try {\n let geom = (mesh.geometry as THREE.BufferGeometry).clone();\n geom.applyMatrix4(mesh.matrixWorld);\n if (geom.index) geom = geom.toNonIndexed();\n const safe = ensureAttributesMinimal(geom);\n if (safe) collected.push(safe);\n } catch (e) {\n console.warn(\"处理网格时出错:\", mesh, e);\n }\n }\n });\n\n if (!collected.length) return;\n\n // 统一属性集合\n type AttrMeta = { itemSize: number; arrayCtor: any; examples: number };\n const attrMap = new Map<string, AttrMeta>();\n const attrConflict = new Set<string>();\n\n for (const g of collected) {\n for (const name of Object.keys(g.attributes)) {\n const attr = g.attributes[name] as THREE.BufferAttribute;\n const ctor = (attr.array as any).constructor;\n const itemSize = attr.itemSize;\n\n if (!attrMap.has(name)) {\n attrMap.set(name, { itemSize, arrayCtor: ctor, examples: 1 });\n } else {\n const m = attrMap.get(name)!;\n if (m.itemSize !== itemSize || m.arrayCtor !== ctor) {\n attrConflict.add(name);\n } else {\n m.examples++;\n }\n }\n }\n }\n\n // 删除冲突属性\n if (attrConflict.size) {\n for (const g of collected) {\n for (const name of Array.from(attrConflict)) {\n if (g.attributes[name]) g.deleteAttribute(name);\n }\n }\n for (const name of attrConflict) attrMap.delete(name);\n }\n\n // 补全缺失属性\n const attrNames = Array.from(attrMap.keys());\n for (const g of collected) {\n const count = g.attributes.position.count;\n for (const name of attrNames) {\n if (!g.attributes[name]) {\n const meta = attrMap.get(name)!;\n const len = count * meta.itemSize;\n const array = new meta.arrayCtor(len);\n g.setAttribute(name, new THREE.BufferAttribute(array, meta.itemSize));\n }\n }\n }\n } else {\n // 从URL加载模型\n const gltf: GLTF = await this.loader.loadAsync(meshUrl);\n const mesh = gltf.scene.children[0] as THREE.Mesh;\n mesh.name = \"BVH加载模型\";\n\n let geom = mesh.geometry.clone();\n geom.applyMatrix4(mesh.matrixWorld);\n if (geom.index) geom = geom.toNonIndexed();\n const safe = ensureAttributesMinimal(geom);\n if (safe) collected.push(safe);\n }\n\n // 合并几何体\n const merged = BufferGeometryUtils.mergeGeometries(collected, false);\n if (!merged) {\n console.error(\"合并几何失败\");\n return;\n }\n\n // 构建BVH\n (merged as any).boundsTree = new MeshBVH(merged, { maxDepth: 100 });\n this.collider = new THREE.Mesh(\n merged,\n new THREE.MeshBasicMaterial({\n opacity: 0.5,\n transparent: true,\n wireframe: true,\n })\n );\n\n if (this.displayCollider) this.scene.add(this.collider);\n if (this.displayVisualizer) {\n if (this.visualizer) this.scene.remove(this.visualizer);\n this.visualizer = new MeshBVHHelper(this.collider, this.visualizeDepth);\n this.scene.add(this.visualizer);\n }\n\n this.boundingBoxMinY = (this.collider as any).geometry.boundingBox.min.y;\n }\n\n /**\n * 获取法线与Y轴的夹角\n */\n getAngleWithYAxis(normal: { x: number; y: number; z: number }): number {\n const yAxis = { x: 0, y: 1, z: 0 };\n const dotProduct = normal.x * yAxis.x + normal.y * yAxis.y + normal.z * yAxis.z;\n const normalMagnitude = Math.sqrt(normal.x * normal.x + normal.y * normal.y + normal.z * normal.z);\n const cosTheta = dotProduct / normalMagnitude;\n return Math.acos(cosTheta);\n }\n\n // ==================== 循环更新 ====================\n\n /**\n * 每帧更新\n */\n async update(delta: number = clock.getDelta()) {\n if (!this.isupdate || !this.player || !this.collider) return;\n delta = Math.min(delta, 1 / 30);\n\n // 应用速度\n if (!this.isFlying) {\n this.player.position.addScaledVector(this.playerVelocity, delta);\n }\n\n // 更新动画\n this.updateMixers(delta);\n\n // 计算移动方向\n this.camera.getWorldDirection(this.camDir);\n let angle = Math.atan2(this.camDir.z, this.camDir.x) + Math.PI / 2;\n angle = 2 * Math.PI - angle;\n\n this.moveDir.set(0, 0, 0);\n if (this.fwdPressed) this.moveDir.add(this.DIR_FWD);\n if (this.bkdPressed) this.moveDir.add(this.DIR_BKD);\n if (this.lftPressed) this.moveDir.add(this.DIR_LFT);\n if (this.rgtPressed) this.moveDir.add(this.DIR_RGT);\n\n if (this.isFlying) {\n if (this.fwdPressed) this.moveDir.y = this.camDir.y;\n else this.moveDir.y = 0;\n if (this.spacePressed) this.moveDir.add(this.DIR_UP);\n }\n\n // 设置速度\n if (this.isFlying && this.fwdPressed) {\n this.playerSpeed = this.shiftPressed ? this.originPlayerSpeed * 12 : this.originPlayerSpeed * 7;\n } else {\n this.playerSpeed = this.shiftPressed ? this.originPlayerSpeed * 2 : this.originPlayerSpeed;\n }\n\n this.moveDir.normalize().applyAxisAngle(this.upVector, angle);\n this.player.position.addScaledVector(this.moveDir, this.playerSpeed * delta);\n\n // 向下射线检测地面高度\n let playerDistanceFromGround = Infinity;\n this._originTmp.set(this.player.position.x, this.player.position.y, this.player.position.z);\n this._raycaster.ray.origin.copy(this._originTmp);\n const intersects = this._raycaster.intersectObject(this.collider as THREE.Object3D, false);\n\n if (intersects.length > 0) {\n playerDistanceFromGround = this.player.position.y - intersects[0].point.y;\n const normal = intersects[0].normal as THREE.Vector3;\n const angle = (this.getAngleWithYAxis(normal) * 180) / Math.PI;\n const maxH = this.playerHeight * this.playerModel.scale * 0.9; // 坡度高度阈值\n const h = this.playerHeight * this.playerModel.scale * 0.75; // 正常高度\n const minH = this.playerHeight * this.playerModel.scale * 0.7; // 最小高度\n\n if (!this.isFlying) {\n if (playerDistanceFromGround > maxH) {\n // 下落状态\n this.playerVelocity.y += delta * this.gravity;\n this.player.position.addScaledVector(this.playerVelocity, delta);\n this.playerIsOnGround = false;\n } else if (playerDistanceFromGround > h && playerDistanceFromGround < maxH) {\n if (angle >= 0 && angle < 5) {\n // 平地\n this.playerVelocity.y += delta * this.gravity;\n this.player.position.addScaledVector(this.playerVelocity, delta);\n this.playerIsOnGround = true;\n } else {\n // 坡地\n this.playerVelocity.set(0, 0, 0);\n this.playerIsOnGround = true;\n }\n } else if (playerDistanceFromGround > minH && playerDistanceFromGround < h) {\n // 误差范围内在平地\n this.playerVelocity.set(0, 0, 0);\n this.playerIsOnGround = true;\n } else if (playerDistanceFromGround < minH) {\n // 强行拉回\n this.playerVelocity.set(0, 0, 0);\n this.player.position.set(this.player.position.x, intersects[0].point.y + h, this.player.position.z);\n this.playerIsOnGround = true;\n }\n }\n }\n\n // 更新玩家矩阵\n this.player.updateMatrixWorld();\n\n // BVH碰撞检测\n const capsuleInfo = this.player.capsuleInfo;\n this.tempBox.makeEmpty();\n this.tempMat.copy(this.collider!.matrixWorld).invert();\n this.tempSegment.copy(capsuleInfo.segment);\n this.tempSegment.start.applyMatrix4(this.player.matrixWorld).applyMatrix4(this.tempMat);\n this.tempSegment.end.applyMatrix4(this.player.matrixWorld).applyMatrix4(this.tempMat);\n\n this.tempBox.expandByPoint(this.tempSegment.start);\n this.tempBox.expandByPoint(this.tempSegment.end);\n this.tempBox.expandByScalar(capsuleInfo.radius);\n\n const bvh = this.collider?.geometry as any;\n bvh?.boundsTree?.shapecast({\n // 检测包围盒碰撞\n intersectsBounds: (box: THREE.Box3) => box.intersectsBox(this.tempBox),\n // 检测三角形碰撞\n intersectsTriangle: (tri: any) => {\n const triPoint = this.tempVector;\n const capsulePoint = this.tempVector2;\n const distance = tri.closestPointToSegment(this.tempSegment, triPoint, capsulePoint);\n // 距离小于人物半径,发生碰撞\n if (distance < capsuleInfo.radius) {\n const depth = capsuleInfo.radius - distance;\n const direction = capsulePoint.sub(triPoint).normalize();\n this.tempSegment.start.addScaledVector(direction, depth);\n this.tempSegment.end.addScaledVector(direction, depth);\n }\n },\n });\n\n // 设置玩家位置\n const newPosition = this.tempVector.copy(this.tempSegment.start).applyMatrix4(this.collider!.matrixWorld);\n const deltaVector = this.tempVector2.subVectors(newPosition, this.player.position);\n const offset = Math.max(0, deltaVector.length() - 1e-5);\n deltaVector.normalize().multiplyScalar(offset);\n this.player.position.add(deltaVector);\n\n // 第三人称-朝向\n if (!this.isFirstPerson && !this.isFlying) {\n this.camDir.y = 0;\n this.camDir.normalize();\n this.camDir.negate();\n this.moveDir.normalize();\n this.moveDir.negate();\n\n let lookTarget: THREE.Vector3;\n if (this.thirdMouseMode === 0 || this.thirdMouseMode === 2) {\n if (this.moveDir.lengthSq() > 0) {\n lookTarget = this.player.position.clone().add(this.moveDir);\n } else {\n lookTarget = this.player.position.clone().add(this.camDir);\n }\n this.targetMat.lookAt(this.player.position, lookTarget, this.player.up);\n this.targetQuat.setFromRotationMatrix(this.targetMat);\n const alpha = Math.min(1, this.rotationSpeed * delta);\n this.player.quaternion.slerp(this.targetQuat, alpha);\n }\n if ((this.thirdMouseMode === 1 || this.thirdMouseMode === 3) && this.moveDir.lengthSq() > 0) {\n lookTarget = this.player.position.clone().add(this.moveDir);\n this.targetMat.lookAt(this.player.position, lookTarget, this.player.up);\n this.targetQuat.setFromRotationMatrix(this.targetMat);\n const alpha = Math.min(1, this.rotationSpeed * delta);\n this.player.quaternion.slerp(this.targetQuat, alpha);\n }\n }\n\n // 飞行模式朝向\n if (this.isFlying) {\n this.camDir.y = 0;\n this.camDir.normalize();\n this.camDir.negate();\n this.moveDir.normalize();\n this.moveDir.negate();\n const lookTarget = this.player.position.clone().add(this.fwdPressed ? this.moveDir : this.camDir);\n this.targetMat.lookAt(this.player.position, lookTarget, this.player.up);\n this.targetQuat.setFromRotationMatrix(this.targetMat);\n const alpha = Math.min(1, this.rotationSpeed * delta);\n this.player.quaternion.slerp(this.targetQuat, alpha);\n }\n\n // 第三人称-相机跟随\n if (!this.isFirstPerson) {\n const lookTarget = this.player.position.clone();\n lookTarget.y += 30 * this.playerModel.scale;\n this.camera.position.sub(this.controls.target);\n this.controls.target.copy(lookTarget);\n this.camera.position.add(lookTarget);\n this.controls.update();\n\n // 当视线被遮挡时的处理\n this._personToCam.subVectors(this.camera.position, this.player.position);\n const origin = this.player.position.clone().add(new THREE.Vector3(0, 0, 0));\n const direction = this._personToCam.clone().normalize();\n const desiredDist = this._personToCam.length();\n this._raycasterPersonToCam.set(origin, direction);\n this._raycasterPersonToCam.far = desiredDist;\n\n const intersects = this._raycasterPersonToCam.intersectObject(this.collider as THREE.Object3D, false);\n\n if (intersects.length > 0) {\n // 相机拉近\n const hit = intersects[0];\n const safeDist = Math.max(hit.distance - this._camEpsilon, this._minCamDistance);\n const targetCamPos = origin.clone().add(direction.clone().multiplyScalar(safeDist));\n this.camera.position.lerp(targetCamPos, this._camCollisionLerp);\n } else {\n // 相机恢复\n this._raycasterPersonToCam.far = this._maxCamDistance;\n const intersectsMaxDis = this._raycasterPersonToCam.intersectObject(this.collider as THREE.Object3D, false);\n\n let safeDist = this._maxCamDistance;\n if (intersectsMaxDis.length) {\n const hitMax = intersectsMaxDis[0];\n safeDist = hitMax.distance - this._camEpsilon;\n }\n const targetCamPos = origin.clone().add(direction.clone().multiplyScalar(safeDist));\n this.camera.position.lerp(targetCamPos, this._camCollisionLerp);\n }\n }\n\n // 掉出场景重置\n if (this.player.position.y < this.boundingBoxMinY - 1) {\n this._originTmp.set(this.player.position.x, 10000, this.player.position.z);\n this._raycaster.ray.origin.copy(this._originTmp);\n const intersects = this._raycaster.intersectObject(this.collider as THREE.Object3D, false);\n\n if (intersects.length > 0) {\n // 出现碰撞 说明玩家为bug意外掉落\n console.log(\"玩家为bug意外掉落\");\n this.reset(new THREE.Vector3(this.player.position.x, intersects[0].point.y + 5, this.player.position.z));\n } else {\n // 无碰撞 正常掉落\n console.log(\"玩家正常掉落\");\n this.reset(new THREE.Vector3(this.player.position.x, this.player.position.y + 15, this.player.position.z));\n }\n }\n }\n\n /**\n * 更新模型动画\n */\n private updateMixers(delta: number) {\n if (this.personMixer) this.personMixer.update(delta);\n }\n\n /**\n * 重置玩家位置\n */\n reset(position?: THREE.Vector3) {\n if (!this.player) return;\n this.playerVelocity.set(0, 0, 0);\n this.player.position.copy(position ?? this.initPos);\n }\n\n /**\n * 获取玩家位置\n */\n getPosition() {\n return this.player.position;\n }\n\n // ==================== 输入处理 ====================\n\n /**\n * 设置输入\n */\n setInput(\n input: Partial<{\n moveX: 1 | 0 | -1;\n moveY: 1 | 0 | -1;\n lookDeltaX: number;\n lookDeltaY: number;\n jump: boolean;\n shift: boolean;\n toggleView: boolean;\n toggleFly: boolean;\n }>\n ) {\n // 控制人物移动\n if (typeof input.moveX === \"number\") {\n this.lftPressed = input.moveX === -1;\n this.rgtPressed = input.moveX === 1;\n this.setAnimationByPressed();\n }\n if (typeof input.moveY === \"number\") {\n this.fwdPressed = input.moveY === 1;\n this.bkdPressed = input.moveY === -1;\n this.setAnimationByPressed();\n }\n\n // 控制朝向\n if (typeof input.lookDeltaX === \"number\" && typeof input.lookDeltaY === \"number\") {\n this.setToward(input.lookDeltaX, input.lookDeltaY, 0.002);\n }\n\n // 跳跃\n if (typeof input.jump === \"boolean\") {\n if (input.jump) {\n this.spacePressed = true;\n if (!this.playerIsOnGround || this.isFlying) return;\n this.playPersonAnimationByName(\"jumping\");\n this.playerVelocity.y = this.jumpHeight;\n this.playerIsOnGround = false;\n } else {\n this.spacePressed = false;\n }\n }\n\n // 加速\n if (typeof input.shift === \"boolean\") {\n this.shiftPressed = input.shift;\n }\n\n // 切换视角\n if (input.toggleView) {\n this.changeView();\n }\n\n // 切换飞行\n if (input.toggleFly) {\n this.isFlying = !this.isFlying;\n this.setAnimationByPressed();\n if (!this.isFlying && !this.playerIsOnGround) {\n this.playPersonAnimationByName(\"jumping\");\n }\n }\n }\n\n /**\n * 根据按键设置人物动画\n */\n private setAnimationByPressed = () => {\n this._maxCamDistance = this.orginMaxCamDistance;\n\n if (this.isFlying) {\n if (!this.fwdPressed) {\n this.playPersonAnimationByName(\"flyidle\");\n return;\n }\n this.playPersonAnimationByName(\"flying\");\n this._maxCamDistance = this.orginMaxCamDistance * 2;\n return;\n }\n\n if (this.playerIsOnGround) {\n if (!this.fwdPressed && !this.bkdPressed && !this.lftPressed && !this.rgtPressed) {\n this.playPersonAnimationByName(\"idle\");\n return;\n }\n\n if (this.fwdPressed) {\n this.playPersonAnimationByName(this.shiftPressed ? \"running\" : \"walking\");\n return;\n }\n\n // 第三人称下动画统一使用前进动画\n if (!this.isFirstPerson && (this.lftPressed || this.rgtPressed || this.bkdPressed)) {\n this.playPersonAnimationByName(this.shiftPressed ? \"running\" : \"walking\");\n return;\n }\n\n // 第一人称下根据方向播放不同动画\n if (this.lftPressed) {\n this.playPersonAnimationByName(\"left_walking\");\n return;\n }\n if (this.rgtPressed) {\n this.playPersonAnimationByName(\"right_walking\");\n return;\n }\n if (this.bkdPressed) {\n this.playPersonAnimationByName(\"walking_backward\");\n return;\n }\n }\n\n // 销毁旧的定时器\n if (this.recheckAnimTimer !== null) {\n clearTimeout(this.recheckAnimTimer);\n }\n\n // 200ms后重新检测动画\n this.recheckAnimTimer = setTimeout(() => {\n this.setAnimationByPressed();\n this.recheckAnimTimer = null;\n }, 200);\n };\n\n // ==================== 事件处理 ====================\n\n /**\n * 键盘按下事件\n */\n private _boundOnKeydown = async (e: KeyboardEvent) => {\n if (e.ctrlKey && [\"KeyW\", \"KeyA\", \"KeyS\", \"KeyD\"].includes(e.code)) {\n e.preventDefault();\n }\n\n switch (e.code) {\n case \"KeyW\":\n this.fwdPressed = true;\n this.setAnimationByPressed();\n break;\n case \"KeyS\":\n this.bkdPressed = true;\n this.setAnimationByPressed();\n break;\n case \"KeyD\":\n this.rgtPressed = true;\n this.setAnimationByPressed();\n break;\n case \"KeyA\":\n this.lftPressed = true;\n this.setAnimationByPressed();\n break;\n case \"ShiftLeft\":\n this.shiftPressed = true;\n this.setAnimationByPressed();\n this.controls.mouseButtons = { LEFT: 2, MIDDLE: 1, RIGHT: 0 };\n break;\n case \"Space\":\n this.spacePressed = true;\n if (!this.playerIsOnGround || this.isFlying) return;\n const next = this.personActions?.get(\"jumping\");\n if (next && this.actionState === next) return;\n this.playPersonAnimationByName(\"jumping\");\n this.playerVelocity.y = this.jumpHeight;\n this.playerIsOnGround = false;\n break;\n case \"ControlLeft\":\n this.ctPressed = true;\n break;\n case \"KeyV\":\n this.changeView();\n break;\n case \"KeyF\":\n this.isFlying = !this.isFlying;\n this.setAnimationByPressed();\n if (!this.isFlying && !this.playerIsOnGround) {\n this.playPersonAnimationByName(\"jumping\");\n }\n break;\n }\n };\n\n /**\n * 键盘抬起事件\n */\n private _boundOnKeyup = (e: KeyboardEvent) => {\n switch (e.code) {\n case \"KeyW\":\n this.fwdPressed = false;\n this.setAnimationByPressed();\n break;\n case \"KeyS\":\n this.bkdPressed = false;\n this.setAnimationByPressed();\n break;\n case \"KeyD\":\n this.rgtPressed = false;\n this.setAnimationByPressed();\n break;\n case \"KeyA\":\n this.lftPressed = false;\n this.setAnimationByPressed();\n break;\n case \"ShiftLeft\":\n this.shiftPressed = false;\n this.setAnimationByPressed();\n this.controls.mouseButtons = { LEFT: 0, MIDDLE: 1, RIGHT: 2 };\n break;\n case \"Space\":\n this.spacePressed = false;\n break;\n case \"ControlLeft\":\n this.ctPressed = false;\n break;\n }\n };\n\n /**\n * 鼠标移动事件\n */\n private _mouseMove = (e: MouseEvent) => {\n if (document.pointerLockElement !== document.body) return;\n this.setToward(e.movementX, e.movementY, 0.0001);\n };\n\n /**\n * 鼠标点击事件\n */\n private _mouseClick = (e: MouseEvent) => {\n this.setPointerLock();\n };\n\n /**\n * 事件绑定\n */\n onAllEvent() {\n this.isupdate = true;\n this.setPointerLock();\n\n window.addEventListener(\"keydown\", this._boundOnKeydown);\n window.addEventListener(\"keyup\", this._boundOnKeyup);\n window.addEventListener(\"mousemove\", this._mouseMove);\n window.addEventListener(\"click\", this._mouseClick);\n }\n\n /**\n * 事件解绑\n */\n offAllEvent() {\n this.isupdate = false;\n document.exitPointerLock();\n window.removeEventListener(\"keydown\", this._boundOnKeydown);\n window.removeEventListener(\"keyup\", this._boundOnKeyup);\n window.removeEventListener(\"mousemove\", this._mouseMove);\n window.removeEventListener(\"click\", this._mouseClick);\n }\n\n // ==================== 移动端控制 ====================\n\n /**\n * 指针按下事件\n */\n onPointerDown = (e: PointerEvent) => {\n if (e.pointerType !== \"touch\") return;\n this.isLookDown = true;\n this.lookPointerId = e.pointerId;\n this.lastTouchX = e.clientX;\n this.lastTouchY = e.clientY;\n\n this.lookAreaEl?.setPointerCapture?.(e.pointerId);\n e.preventDefault();\n };\n\n /**\n * 指针移动事件\n */\n onPointerMove = (e: PointerEvent) => {\n if (!this.isLookDown || e.pointerId !== this.lookPointerId) return;\n const dx = e.clientX - this.lastTouchX;\n const dy = e.clientY - this.lastTouchY;\n this.lastTouchX = e.clientX;\n this.lastTouchY = e.clientY;\n\n this.setInput({ lookDeltaX: dx, lookDeltaY: dy });\n e.preventDefault();\n };\n\n /**\n * 指针抬起事件\n */\n onPointerUp = (e: PointerEvent) => {\n if (e.pointerId !== this.lookPointerId) return;\n this.isLookDown = false;\n this.lookPointerId = null;\n this.lookAreaEl?.releasePointerCapture?.(e.pointerId);\n };\n\n /**\n * 初始化移动端摇杆控制\n */\n async initMobileControls() {\n this.controls.maxPolarAngle = Math.PI * (300 / 360);\n this.controls.touches = { ONE: null as any, TWO: null as any };\n this.nippleModule = await import(\"nipplejs\");\n const nipple = this.nippleModule?.default;\n const JOY_SIZE = 120;\n\n const container = document.body;\n\n // 摇杆容器\n this.joystickZoneEl = document.createElement(\"div\");\n this.joystickZoneEl.id = \"joy-zone\";\n Object.assign(this.joystickZoneEl.style, {\n position: \"absolute\",\n left: \"16px\",\n bottom: \"16px\",\n width: `${JOY_SIZE + 40}px`,\n height: `${JOY_SIZE + 40}px`,\n touchAction: \"none\",\n zIndex: \"999\",\n pointerEvents: \"auto\",\n WebkitUserSelect: \"none\",\n userSelect: \"none\",\n });\n container.appendChild(this.joystickZoneEl);\n\n // 阻止touch的默认行为\n [\"touchstart\", \"touchmove\", \"touchend\", \"touchcancel\"].forEach((evtName) => {\n this.joystickZoneEl?.addEventListener(evtName, (e) => e.preventDefault(), {\n passive: false,\n });\n });\n\n // 创建摇杆\n this.joystickManager = nipple.create({\n zone: this.joystickZoneEl,\n mode: \"static\",\n position: {\n left: `${(JOY_SIZE + 40) / 2}px`,\n bottom: `${(JOY_SIZE + 40) / 2}px`,\n },\n color: \"#ffffff\",\n size: JOY_SIZE,\n multitouch: true,\n maxNumberOfNipples: 1,\n });\n\n this.joystickManager.on(\"move\", (_evt: any, data: any) => {\n if (!data) return;\n\n const rawX = data.vector?.x ?? 0;\n const rawY = data.vector?.y ?? 0;\n const distance = data.distance ?? 0;\n const deadzone = 0.5;\n\n const dirX = rawX > deadzone ? 1 : rawX < -deadzone ? -1 : 0;\n const dirY = rawY > deadzone ? 1 : rawY < -deadzone ? -1 : 0;\n\n const sprintThreshold = JOY_SIZE / 2;\n const isSprinting = distance >= sprintThreshold;\n\n const prev = this.prevJoyState || { dirX: 0, dirY: 0, shift: false };\n if (dirX === prev.dirX && dirY === prev.dirY && isSprinting === prev.shift) {\n return;\n }\n\n this.prevJoyState = { dirX, dirY, shift: isSprinting };\n this.setInput({ moveX: dirX, moveY: dirY, shift: isSprinting });\n });\n\n this.joystickManager.on(\"end\", () => {\n const prev = this.prevJoyState || { dirX: 0, dirY: 0, shift: false };\n if (prev.dirX !== 0 || prev.dirY !== 0 || prev.shift !== false) {\n this.prevJoyState = { dirX: 0, dirY: 0, shift: false };\n this.setInput({ moveX: 0, moveY: 0, shift: false });\n }\n });\n\n // 右侧视角控制区域\n this.lookAreaEl = document.createElement(\"div\");\n Object.assign(this.lookAreaEl.style, {\n position: \"absolute\",\n right: \"0\",\n bottom: \"0\",\n width: \"50%\",\n height: \"100%\",\n zIndex: \"998\",\n touchAction: \"none\",\n WebkitUserSelect: \"none\",\n userSelect: \"none\",\n });\n container.appendChild(this.lookAreaEl);\n\n [\"touchstart\", \"touchmove\", \"touchend\", \"touchcancel\"].forEach((evtName) => {\n this.lookAreaEl?.addEventListener(evtName, (e) => e.preventDefault(), {\n passive: false,\n });\n });\n\n this.lookAreaEl.addEventListener(\"pointerdown\", this.onPointerDown, { passive: false });\n this.lookAreaEl.addEventListener(\"pointermove\", this.onPointerMove, { passive: false });\n this.lookAreaEl.addEventListener(\"pointerup\", this.onPointerUp, { passive: false });\n this.lookAreaEl.addEventListener(\"pointercancel\", this.onPointerUp, { passive: false });\n\n // 创建按钮\n const createBtn = (rightPx: number, bottomPx: number, bgUrl?: string) => {\n const btn = document.createElement(\"button\");\n const styles: Partial<CSSStyleDeclaration> = {\n position: \"absolute\",\n right: `${rightPx}px`,\n bottom: `${bottomPx}px`,\n width: \"56px\",\n height: \"56px\",\n zIndex: \"1000\",\n borderRadius: \"50%\",\n border: \"2px solid black\",\n background: \"rgba(0,0,0)\",\n padding: \"20px\",\n opacity: \"0.95\",\n touchAction: \"none\",\n fontSize: \"14px\",\n userSelect: \"none\",\n overflow: \"hidden\",\n boxSizing: \"border-box\",\n backgroundColor: \"transparent\",\n backgroundRepeat: \"no-repeat, no-repeat\",\n backgroundPosition: \"center center, center center\",\n backgroundSize: \"100% 100%, 80% 80%\",\n };\n\n if (bgUrl) {\n const overlayColor = \"rgba(0,0,0,0.5)\";\n styles.backgroundImage = `linear-gradient(${overlayColor}, ${overlayColor}), url(\"${bgUrl}\")`;\n }\n\n Object.assign(btn.style, styles);\n container.appendChild(btn);\n [\"touchstart\", \"touchend\", \"touchcancel\"].forEach((evtName) => {\n btn.addEventListener(evtName, (e) => e.preventDefault(), { passive: false });\n });\n\n return btn;\n };\n\n // 跳跃按钮\n this.jumpBtnEl = createBtn(14, 14, jumpIconModule);\n this.jumpBtnEl.addEventListener(\n \"touchstart\",\n (e) => {\n e.preventDefault();\n this.setInput({ jump: true });\n },\n { passive: false }\n );\n this.jumpBtnEl.addEventListener(\n \"touchend\",\n (e) => {\n e.preventDefault();\n this.setInput({ jump: false });\n },\n { passive: false }\n );\n this.jumpBtnEl.addEventListener(\n \"touchcancel\",\n (e) => {\n e.preventDefault();\n this.setInput({ jump: false });\n },\n { passive: false }\n );\n\n // 切换飞行按钮\n this.flyBtnEl = createBtn(14, 14 + 80, flyIconModule);\n this.flyBtnEl.addEventListener(\n \"touchstart\",\n (e) => {\n e.preventDefault();\n this.setInput({ toggleFly: true });\n },\n { passive: false }\n );\n\n // 切换视角按钮\n this.viewBtnEl = createBtn(14, 14 + 200, viewIconModule);\n this.viewBtnEl.addEventListener(\n \"touchstart\",\n (e) => {\n e.preventDefault();\n this.setInput({ toggleView: true });\n },\n { passive: false }\n );\n }\n\n /**\n * 销毁移动端摇杆控制\n */\n destroyMobileControls() {\n try {\n if (this.joystickManager && this.joystickManager.destroy) {\n this.joystickManager.destroy();\n this.joystickManager = null;\n }\n if (this.joystickZoneEl?.parentElement) {\n this.joystickZoneEl.parentElement.removeChild(this.joystickZoneEl);\n this.joystickZoneEl = null;\n }\n if (this.lookAreaEl?.parentElement) {\n this.lookAreaEl.parentElement.removeChild(this.lookAreaEl);\n this.lookAreaEl = null;\n }\n if (this.jumpBtnEl?.parentElement) {\n this.jumpBtnEl.parentElement.removeChild(this.jumpBtnEl);\n this.jumpBtnEl = null;\n }\n if (this.flyBtnEl?.parentElement) {\n this.flyBtnEl.parentElement.removeChild(this.flyBtnEl);\n this.flyBtnEl = null;\n }\n if (this.viewBtnEl?.parentElement) {\n this.viewBtnEl.parentElement.removeChild(this.viewBtnEl);\n this.viewBtnEl = null;\n }\n\n // 监听\n this.lookAreaEl?.removeEventListener(\"pointerdown\", this.onPointerDown);\n this.lookAreaEl?.removeEventListener(\"pointermove\", this.onPointerMove);\n this.lookAreaEl?.removeEventListener(\"pointerup\", this.onPointerUp);\n this.lookAreaEl?.removeEventListener(\"pointercancel\", this.onPointerUp);\n } catch (e) {\n console.warn(\"销毁移动端摇杆控制时出错:\", e);\n }\n }\n\n // ==================== 销毁 ====================\n\n /**\n * 销毁人物控制器\n */\n destroy() {\n this.offAllEvent();\n if (this.player) {\n this.player.remove(this.camera);\n this.scene.remove(this.player);\n }\n (this.player as any) = null;\n if (this.person) {\n this.scene.remove(this.person);\n this.person = null;\n }\n\n this.resetControls();\n\n // 清理 BVH 可视化\n if (this.visualizer) {\n this.scene.remove(this.visualizer);\n this.visualizer = null;\n }\n if (this.collider) {\n this.scene.remove(this.collider);\n this.collider = null;\n }\n\n this.destroyMobileControls();\n\n controllerInstance = null;\n }\n}\n\n// 导出API\nexport function playerController() {\n if (!controllerInstance) controllerInstance = new PlayerController();\n const c = controllerInstance;\n return {\n init: (opts: PlayerControllerOptions, callback?: () => void) => c.init(opts, callback),\n changeView: () => c.changeView(),\n reset: (pos?: THREE.Vector3) => c.reset(pos),\n update: (dt?: number) => c.update(dt),\n destroy: () => c.destroy(),\n setInput: (i: any) => c.setInput(i),\n getposition: () => c.getPosition(),\n };\n}\n\n// 打开所有事件\nexport function onAllEvent(): void {\n if (!controllerInstance) controllerInstance = new PlayerController();\n controllerInstance.onAllEvent();\n}\n\n// 关闭所有事件\nexport function offAllEvent(): void {\n if (!controllerInstance) return;\n controllerInstance.offAllEvent();\n}\n"],"mappings":"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","names":["angle","intersects"]}
1
+ {"version":3,"sources":["../src/playerController.ts"],"sourcesContent":["import * as THREE from \"three\";\nimport { acceleratedRaycast, MeshBVH, MeshBVHHelper } from \"three-mesh-bvh\";\nimport type { GLTF } from \"three/examples/jsm/Addons.js\";\nimport { OrbitControls } from \"three/examples/jsm/controls/OrbitControls.js\";\nimport { RoundedBoxGeometry } from \"three/examples/jsm/geometries/RoundedBoxGeometry.js\";\nimport { DRACOLoader } from \"three/examples/jsm/loaders/DRACOLoader.js\";\nimport { GLTFLoader } from \"three/examples/jsm/loaders/GLTFLoader.js\";\nimport * as BufferGeometryUtils from \"three/examples/jsm/utils/BufferGeometryUtils.js\";\nimport flyIconModule from \"../assets/imgs/fly.png\";\nimport jumpIconModule from \"../assets/imgs/jump.png\";\nimport viewIconModule from \"../assets/imgs/view.png\";\n\nTHREE.Mesh.prototype.raycast = acceleratedRaycast; // 启用加速 raycast\n\nlet controllerInstance: PlayerController | null = null;\nconst clock = new THREE.Clock();\n\nexport type PlayerControllerOptions = {\n scene: THREE.Scene;\n camera: THREE.PerspectiveCamera;\n controls: OrbitControls;\n playerModel: {\n url: string;\n idleAnim: string;\n walkAnim: string;\n runAnim: string;\n jumpAnim: string;\n leftWalkAnim?: string;\n rightWalkAnim?: string;\n backwardAnim?: string;\n flyAnim?: string;\n flyIdleAnim?: string;\n scale: number;\n gravity?: number;\n jumpHeight?: number;\n speed?: number;\n rotateY?: number;\n };\n initPos?: THREE.Vector3;\n mouseSensity?: number;\n minCamDistance?: number;\n maxCamDistance?: number;\n colliderMeshUrl?: string;\n isShowMobileControls?: boolean;\n thirdMouseMode?: 0 | 1 | 2 | 3;\n};\n\nclass PlayerController {\n // ==================== 基本配置与参数 ====================\n loader: GLTFLoader = new GLTFLoader();\n scene!: THREE.Scene;\n camera!: THREE.PerspectiveCamera;\n controls!: OrbitControls;\n playerModel!: PlayerControllerOptions[\"playerModel\"];\n initPos!: THREE.Vector3;\n visualizeDepth!: number;\n gravity!: number;\n jumpHeight!: number;\n playerSpeed!: number;\n mouseSensity!: number;\n originPlayerSpeed!: number;\n colliderMeshUrl!: string;\n isShowMobileControls!: boolean;\n thirdMouseMode!: 0 | 1 | 2 | 3; // 0: 隐藏鼠标控制朝向及视角,1: 隐藏鼠标仅控制视角,2: 显示鼠标拖拽控制朝向及视角, 3: 显示鼠标拖拽仅控制视角\n controllerMode!: 0 | 1 | 2; // 0: 普通 1: 飞行 2: 车辆\n\n // ==================== 玩家基本属性 ====================\n playerRadius: number = 45;\n playerHeight: number = 180;\n isFirstPerson: boolean = false;\n boundingBoxMinY: number = 0;\n\n // ==================== 测试参数 ====================\n displayPlayer: boolean = false;\n displayCollider: boolean = false;\n displayVisualizer: boolean = false;\n\n // ==================== 场景对象 ====================\n collider: THREE.Mesh | null = null;\n visualizer: MeshBVHHelper | null = null;\n player!: THREE.Mesh & { capsuleInfo?: any };\n person: THREE.Object3D | null = null;\n vehicle: THREE.Object3D | null = null;\n\n // ==================== 状态开关 ====================\n playerIsOnGround: boolean = false;\n isupdate: boolean = true;\n isFlying: boolean = false;\n\n // ==================== 输入状态 ====================\n fwdPressed: boolean = false;\n bkdPressed: boolean = false;\n lftPressed: boolean = false;\n rgtPressed: boolean = false;\n spacePressed: boolean = false;\n ctPressed: boolean = false;\n shiftPressed: boolean = false;\n\n // ==================== 移动端输入 ====================\n prevJoyState = { dirX: 0, dirY: 0, shift: false };\n nippleModule: any = null;\n joystickManager: any = null;\n joystickZoneEl: HTMLDivElement | null = null;\n lookAreaEl: HTMLDivElement | null = null;\n jumpBtnEl: HTMLButtonElement | null = null;\n flyBtnEl: HTMLButtonElement | null = null;\n viewBtnEl: HTMLButtonElement | null = null;\n lookPointerId: number | null = null;\n isLookDown = false;\n lastTouchX = 0;\n lastTouchY = 0;\n\n // ==================== 第三人称相机参数 ====================\n _camCollisionLerp: number = 0.18; // 平滑系数\n _camEpsilon: number = 0.35; // 摄像机与障碍物之间的安全距离\n _minCamDistance: number = 1.0; // 摄像机最小距离\n _maxCamDistance: number = 4.4; // 摄像机最大距离\n orginMaxCamDistance: number = 4.4;\n\n // ==================== 物理/运动 ====================\n playerVelocity = new THREE.Vector3(); // 玩家速度向量\n readonly upVector = new THREE.Vector3(0, 1, 0);\n\n // ==================== 临时复用向量/矩阵 ====================\n readonly tempVector = new THREE.Vector3();\n readonly tempVector2 = new THREE.Vector3();\n readonly tempBox = new THREE.Box3();\n readonly tempMat = new THREE.Matrix4();\n readonly tempSegment = new THREE.Line3();\n\n // ==================== 动画相关 ====================\n personMixer?: THREE.AnimationMixer;\n personActions?: Map<string, THREE.AnimationAction>;\n idleAction!: THREE.AnimationAction;\n walkAction!: THREE.AnimationAction;\n leftWalkAction!: THREE.AnimationAction;\n rightWalkAction!: THREE.AnimationAction;\n backwardAction!: THREE.AnimationAction;\n jumpAction!: THREE.AnimationAction;\n runAction!: THREE.AnimationAction;\n flyidleAction!: THREE.AnimationAction;\n flyAction!: THREE.AnimationAction;\n actionState!: THREE.AnimationAction;\n recheckAnimTimer: any | null = null;\n\n vehicleMixer?: THREE.AnimationMixer;\n vehicleActions?: Map<string, THREE.AnimationAction>;\n\n // ==================== 相机朝向/移动复用向量 ====================\n readonly camDir = new THREE.Vector3();\n readonly moveDir = new THREE.Vector3();\n readonly targetQuat = new THREE.Quaternion();\n readonly targetMat = new THREE.Matrix4();\n readonly rotationSpeed = 10;\n readonly DIR_FWD = new THREE.Vector3(0, 0, -1);\n readonly DIR_BKD = new THREE.Vector3(0, 0, 1);\n readonly DIR_LFT = new THREE.Vector3(-1, 0, 0);\n readonly DIR_RGT = new THREE.Vector3(1, 0, 0);\n readonly DIR_UP = new THREE.Vector3(0, 1, 0);\n\n // ==================== 射线检测 ====================\n readonly _personToCam = new THREE.Vector3();\n readonly _originTmp = new THREE.Vector3();\n readonly _raycaster = new THREE.Raycaster(new THREE.Vector3(), new THREE.Vector3(0, -1, 0));\n readonly _raycasterPersonToCam = new THREE.Raycaster(new THREE.Vector3(), new THREE.Vector3());\n\n constructor() {\n // 射线检测时只返回第一个碰撞\n (this._raycaster as any).firstHitOnly = true;\n (this._raycasterPersonToCam as any).firstHitOnly = true;\n }\n\n // ==================== 初始化相关方法 ====================\n\n /**\n * 初始化控制器\n */\n async init(opts: PlayerControllerOptions, callback?: () => void) {\n this.scene = opts.scene;\n this.camera = opts.camera;\n this.camera.rotation.order = \"YXZ\";\n this.controls = opts.controls;\n this.playerModel = opts.playerModel;\n this.initPos = opts.initPos ?? new THREE.Vector3(0, 0, 0);\n this.mouseSensity = opts.mouseSensity ?? 5;\n\n const s = this.playerModel.scale;\n this.visualizeDepth = 0 * s;\n this.gravity = (opts.playerModel.gravity ?? -2400) * s;\n this.jumpHeight = (opts.playerModel.jumpHeight ?? 800) * s;\n this.originPlayerSpeed = (opts.playerModel.speed ?? 400) * s;\n this.playerSpeed = this.originPlayerSpeed;\n this.playerModel.rotateY = opts.playerModel.rotateY ?? 0;\n\n this._camCollisionLerp = 0.18;\n this._camEpsilon = 35 * s;\n this._minCamDistance = (opts.minCamDistance ?? 100) * s;\n this._maxCamDistance = (opts.maxCamDistance ?? 440) * s;\n this.orginMaxCamDistance = this._maxCamDistance;\n this.thirdMouseMode = opts.thirdMouseMode ?? 1;\n\n // 判断是否移动端\n const isMobileDevice = () => (navigator.maxTouchPoints && navigator.maxTouchPoints > 0) || \"ontouchstart\" in window || /Mobi|Android|iPhone|iPad|iPod/i.test(navigator.userAgent);\n\n this.isShowMobileControls = (opts.isShowMobileControls ?? true) && isMobileDevice();\n if (this.isShowMobileControls) {\n await this.initMobileControls();\n }\n\n // 创建BVH碰撞体\n await this.createBVH(opts.colliderMeshUrl);\n\n // 创建玩家胶囊体\n this.createPlayer();\n\n // 加载玩家模型\n await this.loadPersonGLB();\n\n // 等待资源加载完毕再设置摄像机\n if (this.isFirstPerson && this.person) {\n this.person.add(this.camera);\n }\n\n this.onAllEvent();\n this.setCameraPos();\n this.setControls();\n if (callback) callback();\n }\n\n /**\n * 初始化加载器\n */\n async initLoader() {\n const dracoLoader = new DRACOLoader();\n dracoLoader.setDecoderPath(\"https://unpkg.com/three@0.180.0/examples/jsm/libs/draco/gltf/\");\n dracoLoader.setDecoderConfig({ type: \"js\" });\n this.loader.setDRACOLoader(dracoLoader);\n }\n\n // ==================== 玩家模型相关方法 ====================\n\n /**\n * 加载玩家模型与动画\n */\n async loadPersonGLB() {\n try {\n const gltf: GLTF = await this.loader.loadAsync(this.playerModel.url);\n this.person = gltf.scene;\n const sc = this.playerModel.scale;\n const h = this.playerHeight * sc;\n\n this.person.scale.set(sc, sc, sc);\n this.person.position.set(0, -h * 0.75, 0);\n this.person.traverse((child: any) => {\n if (child.isMesh) {\n child.castShadow = true;\n child.receiveShadow = true;\n }\n });\n\n this.player.add(this.person);\n this.reset();\n\n // 创建动画混合器\n this.personMixer = new THREE.AnimationMixer(this.person);\n const animations = gltf.animations ?? [];\n this.personActions = new Map<string, THREE.AnimationAction>();\n\n // 动画映射表\n const animationMappings: [string, string][] = [\n [this.playerModel.idleAnim, \"idle\"],\n [this.playerModel.walkAnim, \"walking\"],\n [this.playerModel.leftWalkAnim || this.playerModel.walkAnim, \"left_walking\"],\n [this.playerModel.rightWalkAnim || this.playerModel.walkAnim, \"right_walking\"],\n [this.playerModel.backwardAnim || this.playerModel.walkAnim, \"walking_backward\"],\n [this.playerModel.jumpAnim, \"jumping\"],\n [this.playerModel.runAnim, \"running\"],\n [this.playerModel.flyIdleAnim || this.playerModel.idleAnim, \"flyidle\"],\n [this.playerModel.flyAnim || this.playerModel.idleAnim, \"flying\"],\n ];\n\n // 注册动画动作\n const findClip = (name: string) => animations.find((a: any) => a.name === name);\n for (const [clipName, actionName] of animationMappings) {\n const clip = findClip(clipName);\n if (!clip) continue;\n\n const action = this.personMixer.clipAction(clip);\n\n if (actionName === \"jumping\") {\n action.setLoop(THREE.LoopOnce, 1);\n action.clampWhenFinished = true;\n action.setEffectiveTimeScale(1.2);\n } else {\n action.setLoop(THREE.LoopRepeat, Infinity);\n action.clampWhenFinished = false;\n action.setEffectiveTimeScale(1);\n }\n\n action.enabled = true;\n action.setEffectiveWeight(0);\n this.personActions.set(actionName, action);\n }\n\n // 获取动画动作引用\n this.idleAction = this.personActions.get(\"idle\")!;\n this.walkAction = this.personActions.get(\"walking\")!;\n this.leftWalkAction = this.personActions.get(\"left_walking\")!;\n this.rightWalkAction = this.personActions.get(\"right_walking\")!;\n this.backwardAction = this.personActions.get(\"walking_backward\")!;\n this.jumpAction = this.personActions.get(\"jumping\")!;\n this.runAction = this.personActions.get(\"running\")!;\n this.flyidleAction = this.personActions.get(\"flyidle\")!;\n this.flyAction = this.personActions.get(\"flying\")!;\n\n // 激活空闲动作\n this.idleAction.setEffectiveWeight(1);\n this.idleAction.play();\n this.actionState = this.idleAction;\n\n // 监听动画完成事件\n this.personMixer.addEventListener(\"finished\", (ev: any) => {\n const finishedAction: THREE.AnimationAction = ev.action;\n\n if (finishedAction === this.jumpAction) {\n if (this.fwdPressed) {\n this.playPersonAnimationByName(this.shiftPressed ? \"running\" : \"walking\");\n return;\n }\n if (this.bkdPressed) {\n this.playPersonAnimationByName(\"walking_backward\");\n return;\n }\n if (this.rgtPressed || this.lftPressed) {\n this.playPersonAnimationByName(\"walking\");\n return;\n }\n this.playPersonAnimationByName(\"idle\");\n }\n });\n } catch (error) {\n console.error(\"加载玩家模型失败:\", error);\n }\n }\n\n /**\n * 平滑切换人物动画\n */\n playPersonAnimationByName(name: string, fade = 0.18) {\n if (!this.personActions || this.ctPressed) return;\n\n const next = this.personActions.get(name);\n if (!next || this.actionState === next) return;\n\n const prev = this.actionState;\n\n next.reset();\n next.setEffectiveWeight(1);\n next.play();\n\n if (prev && prev !== next) {\n prev.fadeOut(fade);\n next.fadeIn(fade);\n } else {\n next.fadeIn(fade);\n }\n\n this.actionState = next;\n }\n\n /**\n * 创建玩家胶囊体\n */\n createPlayer() {\n const material = new THREE.MeshStandardMaterial({\n color: new THREE.Color(1, 0, 0),\n shadowSide: THREE.DoubleSide,\n depthTest: false,\n transparent: true,\n opacity: this.displayPlayer ? 0.5 : 0,\n wireframe: true,\n depthWrite: false,\n });\n\n const r = this.playerRadius * this.playerModel.scale;\n const h = this.playerHeight * this.playerModel.scale;\n this.player = new THREE.Mesh(new RoundedBoxGeometry(r * 2, h, r * 2, 1, 75), material) as typeof this.player;\n\n this.player.geometry.translate(0, -h * 0.25, 0);\n this.player.capsuleInfo = {\n radius: r,\n segment: new THREE.Line3(new THREE.Vector3(), new THREE.Vector3(0, -h * 0.5, 0)),\n };\n\n this.player.name = \"capsule\";\n this.scene.add(this.player);\n this.reset();\n\n // 设置初始朝向\n this.player.rotateY(this.playerModel.rotateY ?? 0);\n }\n\n // ==================== 车辆模型相关 ====================\n\n /**\n * 加载车辆模型与动画\n */\n async loadVehicleModel(params: {\n url: string;\n position: THREE.Vector3;\n scale?: number;\n animations?: {\n openDoorAnim?: string;\n wheelsTurnAnim?: string;\n turnLeftAnim?: string;\n turnRightAnim?: string;\n };\n }) {\n try {\n const { url, position, scale = 1 } = params;\n const gltf: GLTF = await this.loader.loadAsync(url);\n this.vehicle = gltf.scene;\n this.vehicle.scale.set(scale, scale, scale);\n this.vehicle.position.copy(position);\n this.vehicle.traverse((child: any) => {\n if (child.isMesh) {\n child.castShadow = true;\n child.receiveShadow = true;\n }\n });\n\n this.scene.add(this.vehicle);\n\n const animations = gltf.animations ?? [];\n // console.log(\"车辆所有动画\", animations);\n this.vehicleActions = new Map<string, THREE.AnimationAction>();\n this.vehicleMixer = new THREE.AnimationMixer(this.vehicle);\n\n // 动画映射表\n const animationMappings: [string, string][] = [\n [params.animations?.openDoorAnim ?? \"\", \"open_door\"],\n [params.animations?.wheelsTurnAnim ?? \"\", \"wheels_turn\"],\n [params.animations?.turnLeftAnim ?? \"\", \"turn_left\"],\n [params.animations?.turnRightAnim ?? \"\", \"turn_right\"],\n ];\n\n // 注册动画动作\n const findClip = (name: string) => animations.find((a: any) => a.name === name);\n for (const [clipName, actionName] of animationMappings) {\n const clip = findClip(clipName);\n if (!clip) continue;\n const action = this.vehicleMixer.clipAction(clip);\n action.setLoop(THREE.LoopOnce, 1);\n action.clampWhenFinished = true;\n action.setEffectiveTimeScale(2);\n action.enabled = true;\n action.setEffectiveWeight(0);\n this.vehicleActions.set(actionName, action);\n }\n\n console.log(\"开门动画\", this.vehicleActions.get(\"open_door\"));\n\n // const next = this.vehicleActions.get(\"open_door\") as THREE.AnimationAction;\n // next.setEffectiveWeight(1);\n // next.play();\n } catch (error) {\n console.error(\"加载车辆模型失败:\", error);\n }\n }\n\n // ==================== 相机与视角控制 ====================\n\n /**\n * 第一/三人称视角切换\n */\n changeView() {\n this.isFirstPerson = !this.isFirstPerson;\n\n if (this.isFirstPerson) {\n this.player.attach(this.camera);\n this.camera.position.set(0, 40 * this.playerModel.scale, 30 * this.playerModel.scale);\n this.camera.rotation.set(0, Math.PI, 0);\n } else {\n this.scene.attach(this.camera);\n const worldPos = this.player.position.clone();\n const dir = new THREE.Vector3(0, 0, -1).applyQuaternion(this.player.quaternion);\n const angle = Math.atan2(dir.z, dir.x);\n const offset = new THREE.Vector3(Math.cos(angle) * 400 * this.playerModel.scale, 200 * this.playerModel.scale, Math.sin(angle) * 400 * this.playerModel.scale);\n this.camera.position.copy(worldPos).add(offset);\n this.controls.target.copy(worldPos);\n }\n\n this.setPointerLock();\n }\n\n setDrive() {\n this.controllerMode = 2;\n this.person?.attach(this.vehicle as THREE.Object3D);\n }\n\n /**\n * 设置指针锁定\n */\n setPointerLock() {\n if (((this.thirdMouseMode === 0 || this.thirdMouseMode === 1) && !this.isFirstPerson) || this.isFirstPerson) {\n document.body.requestPointerLock();\n }\n }\n\n /**\n * 设置摄像机初始位置\n */\n setCameraPos() {\n if (this.isFirstPerson) {\n this.camera.position.set(0, 40 * this.playerModel.scale, 30 * this.playerModel.scale);\n } else {\n const worldPos = this.player.position.clone();\n const dir = new THREE.Vector3(0, 0, -1).applyQuaternion(this.player.quaternion);\n const angle = Math.atan2(dir.z, dir.x);\n const offset = new THREE.Vector3(Math.cos(angle) * 400 * this.playerModel.scale, -100 * this.playerModel.scale, Math.sin(angle) * 400 * this.playerModel.scale);\n this.camera.position.copy(worldPos).add(offset);\n }\n this.camera.updateProjectionMatrix();\n }\n\n /**\n * 设置控制器\n */\n setControls() {\n this.controls.enabled = !(this.thirdMouseMode === 0 || this.thirdMouseMode === 1);\n this.controls.rotateSpeed = this.mouseSensity * 0.05;\n this.controls.maxPolarAngle = Math.PI * (300 / 360);\n }\n\n /**\n * 重置控制器\n */\n resetControls() {\n if (!this.controls) return;\n this.controls.enabled = true;\n this.controls.enablePan = true;\n this.controls.maxPolarAngle = Math.PI / 2;\n this.controls.rotateSpeed = 1;\n this.controls.enableZoom = true;\n this.controls.mouseButtons = { LEFT: 0, MIDDLE: 1, RIGHT: 2 };\n }\n\n /**\n * 设置朝向\n */\n setToward(dx: number, dy: number, speed: number) {\n if (this.isFirstPerson) {\n const yaw = -dx * speed * this.mouseSensity;\n const pitch = -dy * speed * this.mouseSensity;\n this.player.rotateY(yaw);\n this.camera.rotation.x = THREE.MathUtils.clamp(this.camera.rotation.x + pitch, -1.1, 1.4);\n } else {\n const sensitivity = this.mouseSensity;\n const deltaX = -dx * speed * sensitivity;\n const deltaY = -dy * speed * sensitivity;\n\n const target = this.player.position.clone();\n const distance = this.camera.position.distanceTo(target);\n const currentPosition = this.camera.position.clone().sub(target);\n\n let theta = Math.atan2(currentPosition.x, currentPosition.z);\n let phi = Math.acos(currentPosition.y / distance);\n\n theta += deltaX;\n phi += deltaY;\n phi = Math.max(0.1, Math.min(Math.PI - 0.1, phi));\n\n const newX = distance * Math.sin(phi) * Math.sin(theta);\n const newY = distance * Math.cos(phi);\n const newZ = distance * Math.sin(phi) * Math.cos(theta);\n\n this.camera.position.set(target.x + newX, target.y + newY, target.z + newZ);\n this.camera.lookAt(target);\n }\n }\n\n // ==================== 物理与碰撞检测 ====================\n\n /**\n * BVH碰撞体构建\n */\n async createBVH(meshUrl: string = \"\"): Promise<void> {\n await this.initLoader();\n\n const ensureAttributesMinimal = (geom: THREE.BufferGeometry): THREE.BufferGeometry | null => {\n if (!geom.attributes.position) return null;\n if (!geom.attributes.normal) geom.computeVertexNormals();\n if (!geom.attributes.uv) {\n const count = geom.attributes.position.count;\n const dummyUV = new Float32Array(count * 2);\n geom.setAttribute(\"uv\", new THREE.BufferAttribute(dummyUV, 2));\n }\n return geom;\n };\n\n const collected: THREE.BufferGeometry[] = [];\n\n if (meshUrl === \"\") {\n // 从场景中收集几何体\n if (this.collider) {\n this.scene.remove(this.collider);\n this.collider = null;\n }\n\n this.scene.traverse((c) => {\n const mesh = c as THREE.Mesh;\n if (mesh?.isMesh && mesh.geometry && c.name !== \"capsule\") {\n try {\n let geom = (mesh.geometry as THREE.BufferGeometry).clone();\n geom.applyMatrix4(mesh.matrixWorld);\n if (geom.index) geom = geom.toNonIndexed();\n const safe = ensureAttributesMinimal(geom);\n if (safe) collected.push(safe);\n } catch (e) {\n console.warn(\"处理网格时出错:\", mesh, e);\n }\n }\n });\n\n if (!collected.length) return;\n\n // 统一属性集合\n type AttrMeta = { itemSize: number; arrayCtor: any; examples: number };\n const attrMap = new Map<string, AttrMeta>();\n const attrConflict = new Set<string>();\n\n for (const g of collected) {\n for (const name of Object.keys(g.attributes)) {\n const attr = g.attributes[name] as THREE.BufferAttribute;\n const ctor = (attr.array as any).constructor;\n const itemSize = attr.itemSize;\n\n if (!attrMap.has(name)) {\n attrMap.set(name, { itemSize, arrayCtor: ctor, examples: 1 });\n } else {\n const m = attrMap.get(name)!;\n if (m.itemSize !== itemSize || m.arrayCtor !== ctor) {\n attrConflict.add(name);\n } else {\n m.examples++;\n }\n }\n }\n }\n\n // 删除冲突属性\n if (attrConflict.size) {\n for (const g of collected) {\n for (const name of Array.from(attrConflict)) {\n if (g.attributes[name]) g.deleteAttribute(name);\n }\n }\n for (const name of attrConflict) attrMap.delete(name);\n }\n\n // 补全缺失属性\n const attrNames = Array.from(attrMap.keys());\n for (const g of collected) {\n const count = g.attributes.position.count;\n for (const name of attrNames) {\n if (!g.attributes[name]) {\n const meta = attrMap.get(name)!;\n const len = count * meta.itemSize;\n const array = new meta.arrayCtor(len);\n g.setAttribute(name, new THREE.BufferAttribute(array, meta.itemSize));\n }\n }\n }\n } else {\n // 从URL加载模型\n const gltf: GLTF = await this.loader.loadAsync(meshUrl);\n const mesh = gltf.scene.children[0] as THREE.Mesh;\n mesh.name = \"BVH加载模型\";\n\n let geom = mesh.geometry.clone();\n geom.applyMatrix4(mesh.matrixWorld);\n if (geom.index) geom = geom.toNonIndexed();\n const safe = ensureAttributesMinimal(geom);\n if (safe) collected.push(safe);\n }\n\n // 合并几何体\n const merged = BufferGeometryUtils.mergeGeometries(collected, false);\n if (!merged) {\n console.error(\"合并几何失败\");\n return;\n }\n\n // 构建BVH\n (merged as any).boundsTree = new MeshBVH(merged, { maxDepth: 100 });\n this.collider = new THREE.Mesh(\n merged,\n new THREE.MeshBasicMaterial({\n opacity: 0.5,\n transparent: true,\n wireframe: true,\n })\n );\n\n if (this.displayCollider) this.scene.add(this.collider);\n if (this.displayVisualizer) {\n if (this.visualizer) this.scene.remove(this.visualizer);\n this.visualizer = new MeshBVHHelper(this.collider, this.visualizeDepth);\n this.scene.add(this.visualizer);\n }\n\n this.boundingBoxMinY = (this.collider as any).geometry.boundingBox.min.y;\n }\n\n /**\n * 获取法线与Y轴的夹角\n */\n getAngleWithYAxis(normal: { x: number; y: number; z: number }): number {\n const yAxis = { x: 0, y: 1, z: 0 };\n const dotProduct = normal.x * yAxis.x + normal.y * yAxis.y + normal.z * yAxis.z;\n const normalMagnitude = Math.sqrt(normal.x * normal.x + normal.y * normal.y + normal.z * normal.z);\n const cosTheta = dotProduct / normalMagnitude;\n return Math.acos(cosTheta);\n }\n\n // ==================== 循环更新 ====================\n\n /**\n * 每帧更新\n */\n async update(delta: number = clock.getDelta()) {\n if (!this.isupdate || !this.player || !this.collider) return;\n delta = Math.min(delta, 1 / 30);\n\n // 应用速度\n if (!this.isFlying) {\n this.player.position.addScaledVector(this.playerVelocity, delta);\n }\n\n // 更新动画\n this.updateMixers(delta);\n\n // 计算移动方向\n this.camera.getWorldDirection(this.camDir);\n let angle = Math.atan2(this.camDir.z, this.camDir.x) + Math.PI / 2;\n angle = 2 * Math.PI - angle;\n\n this.moveDir.set(0, 0, 0);\n if (this.fwdPressed) this.moveDir.add(this.DIR_FWD);\n if (this.bkdPressed) this.moveDir.add(this.DIR_BKD);\n if (this.lftPressed) this.moveDir.add(this.DIR_LFT);\n if (this.rgtPressed) this.moveDir.add(this.DIR_RGT);\n\n if (this.isFlying) {\n if (this.fwdPressed) this.moveDir.y = this.camDir.y;\n else this.moveDir.y = 0;\n if (this.spacePressed) this.moveDir.add(this.DIR_UP);\n }\n\n // 设置速度\n if (this.isFlying && this.fwdPressed) {\n this.playerSpeed = this.shiftPressed ? this.originPlayerSpeed * 12 : this.originPlayerSpeed * 7;\n } else {\n this.playerSpeed = this.shiftPressed ? this.originPlayerSpeed * 2 : this.originPlayerSpeed;\n }\n\n this.moveDir.normalize().applyAxisAngle(this.upVector, angle);\n this.player.position.addScaledVector(this.moveDir, this.playerSpeed * delta);\n\n // 向下射线检测地面高度\n let playerDistanceFromGround = Infinity;\n this._originTmp.set(this.player.position.x, this.player.position.y, this.player.position.z);\n this._raycaster.ray.origin.copy(this._originTmp);\n const intersects = this._raycaster.intersectObject(this.collider as THREE.Object3D, false);\n\n if (intersects.length > 0) {\n playerDistanceFromGround = this.player.position.y - intersects[0].point.y;\n const normal = intersects[0].normal as THREE.Vector3;\n const angle = (this.getAngleWithYAxis(normal) * 180) / Math.PI;\n const maxH = this.playerHeight * this.playerModel.scale * 0.9; // 坡度高度阈值\n const h = this.playerHeight * this.playerModel.scale * 0.75; // 正常高度\n const minH = this.playerHeight * this.playerModel.scale * 0.7; // 最小高度\n\n // console.log(\"人物中心点距离地面高度\", playerDistanceFromGround, \"坡度高度阈值\", maxH, \"正常高度\", h, \"最小高度\", minH);\n // console.log(\"坡度角度\", angle);\n\n // console.log(\"this.playerVelocity.y\", this.playerVelocity.y);\n\n if (!this.isFlying) {\n if (playerDistanceFromGround > maxH) {\n // 下落状态\n this.playerVelocity.y += delta * this.gravity;\n this.player.position.addScaledVector(this.playerVelocity, delta);\n this.playerIsOnGround = false;\n // console.log(\"下落\");\n } else if (playerDistanceFromGround > h && playerDistanceFromGround < maxH) {\n if (angle >= 0 && angle < 5) {\n // 平地\n this.playerVelocity.y += delta * this.gravity;\n this.player.position.addScaledVector(this.playerVelocity, delta);\n this.playerIsOnGround = true;\n // console.log(\"平地\");\n } else {\n // 坡地\n if (this.spacePressed) {\n this.playerVelocity.y += delta * this.gravity;\n } else {\n // console.log(\"坡地\", this.spacePressed);\n this.playerVelocity.set(0, 0, 0);\n this.playerIsOnGround = true;\n }\n }\n } else if (playerDistanceFromGround > minH && playerDistanceFromGround < h) {\n // 误差范围内在平地\n this.playerVelocity.set(0, 0, 0);\n this.playerIsOnGround = true;\n } else if (playerDistanceFromGround < minH) {\n // 强行拉回\n this.playerVelocity.set(0, 0, 0);\n this.player.position.set(this.player.position.x, intersects[0].point.y + h, this.player.position.z);\n this.playerIsOnGround = true;\n }\n }\n\n // console.log(\"是否在地面\", this.playerIsOnGround);\n }\n\n // 更新玩家矩阵\n this.player.updateMatrixWorld();\n\n // BVH碰撞检测\n const capsuleInfo = this.player.capsuleInfo;\n this.tempBox.makeEmpty();\n this.tempMat.copy(this.collider!.matrixWorld).invert();\n this.tempSegment.copy(capsuleInfo.segment);\n this.tempSegment.start.applyMatrix4(this.player.matrixWorld).applyMatrix4(this.tempMat);\n this.tempSegment.end.applyMatrix4(this.player.matrixWorld).applyMatrix4(this.tempMat);\n\n this.tempBox.expandByPoint(this.tempSegment.start);\n this.tempBox.expandByPoint(this.tempSegment.end);\n this.tempBox.expandByScalar(capsuleInfo.radius);\n\n const bvh = this.collider?.geometry as any;\n bvh?.boundsTree?.shapecast({\n // 检测包围盒碰撞\n intersectsBounds: (box: THREE.Box3) => box.intersectsBox(this.tempBox),\n // 检测三角形碰撞\n intersectsTriangle: (tri: any) => {\n const triPoint = this.tempVector;\n const capsulePoint = this.tempVector2;\n const distance = tri.closestPointToSegment(this.tempSegment, triPoint, capsulePoint);\n // 距离小于人物半径,发生碰撞\n if (distance < capsuleInfo.radius) {\n const depth = capsuleInfo.radius - distance;\n const direction = capsulePoint.sub(triPoint).normalize();\n this.tempSegment.start.addScaledVector(direction, depth);\n this.tempSegment.end.addScaledVector(direction, depth);\n }\n },\n });\n\n // 设置玩家位置\n const newPosition = this.tempVector.copy(this.tempSegment.start).applyMatrix4(this.collider!.matrixWorld);\n const deltaVector = this.tempVector2.subVectors(newPosition, this.player.position);\n const offset = Math.max(0, deltaVector.length() - 1e-5);\n deltaVector.normalize().multiplyScalar(offset);\n this.player.position.add(deltaVector);\n\n // 第三人称-朝向\n if (!this.isFirstPerson && !this.isFlying) {\n this.camDir.y = 0;\n this.camDir.normalize();\n this.camDir.negate();\n this.moveDir.normalize();\n this.moveDir.negate();\n\n let lookTarget: THREE.Vector3;\n if (this.thirdMouseMode === 0 || this.thirdMouseMode === 2) {\n if (this.moveDir.lengthSq() > 0) {\n lookTarget = this.player.position.clone().add(this.moveDir);\n } else {\n lookTarget = this.player.position.clone().add(this.camDir);\n }\n this.targetMat.lookAt(this.player.position, lookTarget, this.player.up);\n this.targetQuat.setFromRotationMatrix(this.targetMat);\n const alpha = Math.min(1, this.rotationSpeed * delta);\n this.player.quaternion.slerp(this.targetQuat, alpha);\n }\n if ((this.thirdMouseMode === 1 || this.thirdMouseMode === 3) && this.moveDir.lengthSq() > 0) {\n lookTarget = this.player.position.clone().add(this.moveDir);\n this.targetMat.lookAt(this.player.position, lookTarget, this.player.up);\n this.targetQuat.setFromRotationMatrix(this.targetMat);\n const alpha = Math.min(1, this.rotationSpeed * delta);\n this.player.quaternion.slerp(this.targetQuat, alpha);\n }\n }\n\n // 飞行模式朝向\n if (this.isFlying) {\n this.camDir.y = 0;\n this.camDir.normalize();\n this.camDir.negate();\n this.moveDir.normalize();\n this.moveDir.negate();\n const lookTarget = this.player.position.clone().add(this.fwdPressed ? this.moveDir : this.camDir);\n this.targetMat.lookAt(this.player.position, lookTarget, this.player.up);\n this.targetQuat.setFromRotationMatrix(this.targetMat);\n const alpha = Math.min(1, this.rotationSpeed * delta);\n this.player.quaternion.slerp(this.targetQuat, alpha);\n }\n\n // 第三人称-相机跟随\n if (!this.isFirstPerson) {\n const lookTarget = this.player.position.clone();\n lookTarget.y += 30 * this.playerModel.scale;\n this.camera.position.sub(this.controls.target);\n this.controls.target.copy(lookTarget);\n this.camera.position.add(lookTarget);\n this.controls.update();\n\n // 当视线被遮挡时的处理\n this._personToCam.subVectors(this.camera.position, this.player.position);\n const origin = this.player.position.clone().add(new THREE.Vector3(0, 0, 0));\n const direction = this._personToCam.clone().normalize();\n const desiredDist = this._personToCam.length();\n this._raycasterPersonToCam.set(origin, direction);\n this._raycasterPersonToCam.far = desiredDist;\n\n const intersects = this._raycasterPersonToCam.intersectObject(this.collider as THREE.Object3D, false);\n\n if (intersects.length > 0) {\n // 相机拉近\n const hit = intersects[0];\n const safeDist = Math.max(hit.distance - this._camEpsilon, this._minCamDistance);\n const targetCamPos = origin.clone().add(direction.clone().multiplyScalar(safeDist));\n this.camera.position.lerp(targetCamPos, this._camCollisionLerp);\n } else {\n // 相机恢复\n this._raycasterPersonToCam.far = this._maxCamDistance;\n const intersectsMaxDis = this._raycasterPersonToCam.intersectObject(this.collider as THREE.Object3D, false);\n\n let safeDist = this._maxCamDistance;\n if (intersectsMaxDis.length) {\n const hitMax = intersectsMaxDis[0];\n safeDist = hitMax.distance - this._camEpsilon;\n }\n const targetCamPos = origin.clone().add(direction.clone().multiplyScalar(safeDist));\n this.camera.position.lerp(targetCamPos, this._camCollisionLerp);\n }\n }\n\n // 掉出场景重置\n if (this.player.position.y < this.boundingBoxMinY - 1) {\n this._originTmp.set(this.player.position.x, 10000, this.player.position.z);\n this._raycaster.ray.origin.copy(this._originTmp);\n const intersects = this._raycaster.intersectObject(this.collider as THREE.Object3D, false);\n\n if (intersects.length > 0) {\n // 出现碰撞 说明玩家为bug意外掉落\n console.log(\"玩家为bug意外掉落\");\n this.reset(new THREE.Vector3(this.player.position.x, intersects[0].point.y + 5, this.player.position.z));\n } else {\n // 无碰撞 正常掉落\n console.log(\"玩家正常掉落\");\n this.reset(new THREE.Vector3(this.player.position.x, this.player.position.y + 15, this.player.position.z));\n }\n }\n }\n\n /**\n * 更新模型动画\n */\n private updateMixers(delta: number) {\n if (this.personMixer) this.personMixer.update(delta);\n if (this.vehicleMixer) this.vehicleMixer.update(delta);\n }\n\n /**\n * 重置玩家位置\n */\n reset(position?: THREE.Vector3) {\n if (!this.player) return;\n this.playerVelocity.set(0, 0, 0);\n this.player.position.copy(position ?? this.initPos);\n }\n\n /**\n * 获取玩家位置\n */\n getPosition() {\n return this.player.position;\n }\n\n // ==================== 输入处理 ====================\n\n /**\n * 设置输入\n */\n setInput(\n input: Partial<{\n moveX: 1 | 0 | -1;\n moveY: 1 | 0 | -1;\n lookDeltaX: number;\n lookDeltaY: number;\n jump: boolean;\n shift: boolean;\n toggleView: boolean;\n toggleFly: boolean;\n }>\n ) {\n // 控制人物移动\n if (typeof input.moveX === \"number\") {\n this.lftPressed = input.moveX === -1;\n this.rgtPressed = input.moveX === 1;\n this.setAnimationByPressed();\n }\n if (typeof input.moveY === \"number\") {\n this.fwdPressed = input.moveY === 1;\n this.bkdPressed = input.moveY === -1;\n this.setAnimationByPressed();\n }\n\n // 控制朝向\n if (typeof input.lookDeltaX === \"number\" && typeof input.lookDeltaY === \"number\") {\n this.setToward(input.lookDeltaX, input.lookDeltaY, 0.002);\n }\n\n // 跳跃\n if (typeof input.jump === \"boolean\") {\n if (input.jump) {\n this.spacePressed = true;\n if (!this.playerIsOnGround || this.isFlying) return;\n this.playPersonAnimationByName(\"jumping\");\n this.playerVelocity.y = this.jumpHeight;\n this.playerIsOnGround = false;\n } else {\n this.spacePressed = false;\n }\n }\n\n // 加速\n if (typeof input.shift === \"boolean\") {\n this.shiftPressed = input.shift;\n }\n\n // 切换视角\n if (input.toggleView) {\n this.changeView();\n }\n\n // 切换飞行\n if (input.toggleFly) {\n this.isFlying = !this.isFlying;\n this.setAnimationByPressed();\n if (!this.isFlying && !this.playerIsOnGround) {\n this.playPersonAnimationByName(\"jumping\");\n }\n }\n }\n\n /**\n * 根据按键设置人物动画\n */\n private setAnimationByPressed = () => {\n this._maxCamDistance = this.orginMaxCamDistance;\n\n if (this.isFlying) {\n if (!this.fwdPressed) {\n this.playPersonAnimationByName(\"flyidle\");\n return;\n }\n this.playPersonAnimationByName(\"flying\");\n this._maxCamDistance = this.orginMaxCamDistance * 2;\n return;\n }\n\n if (this.playerIsOnGround) {\n if (!this.fwdPressed && !this.bkdPressed && !this.lftPressed && !this.rgtPressed) {\n this.playPersonAnimationByName(\"idle\");\n return;\n }\n\n if (this.fwdPressed) {\n this.playPersonAnimationByName(this.shiftPressed ? \"running\" : \"walking\");\n return;\n }\n\n // 第三人称下动画统一使用前进动画\n if (!this.isFirstPerson && (this.lftPressed || this.rgtPressed || this.bkdPressed)) {\n this.playPersonAnimationByName(this.shiftPressed ? \"running\" : \"walking\");\n return;\n }\n\n // 第一人称下根据方向播放不同动画\n if (this.lftPressed) {\n this.playPersonAnimationByName(\"left_walking\");\n return;\n }\n if (this.rgtPressed) {\n this.playPersonAnimationByName(\"right_walking\");\n return;\n }\n if (this.bkdPressed) {\n this.playPersonAnimationByName(\"walking_backward\");\n return;\n }\n }\n\n // 销毁旧的定时器\n if (this.recheckAnimTimer !== null) {\n clearTimeout(this.recheckAnimTimer);\n }\n\n // 200ms后重新检测动画\n this.recheckAnimTimer = setTimeout(() => {\n this.setAnimationByPressed();\n this.recheckAnimTimer = null;\n }, 200);\n };\n\n // ==================== 事件处理 ====================\n\n /**\n * 键盘按下事件\n */\n private _boundOnKeydown = async (e: KeyboardEvent) => {\n if (e.ctrlKey && [\"KeyW\", \"KeyA\", \"KeyS\", \"KeyD\"].includes(e.code)) {\n e.preventDefault();\n }\n\n switch (e.code) {\n case \"KeyW\":\n this.fwdPressed = true;\n this.setAnimationByPressed();\n break;\n case \"KeyS\":\n this.bkdPressed = true;\n this.setAnimationByPressed();\n break;\n case \"KeyD\":\n this.rgtPressed = true;\n this.setAnimationByPressed();\n break;\n case \"KeyA\":\n this.lftPressed = true;\n this.setAnimationByPressed();\n break;\n case \"ShiftLeft\":\n this.shiftPressed = true;\n this.setAnimationByPressed();\n this.controls.mouseButtons = { LEFT: 2, MIDDLE: 1, RIGHT: 0 };\n break;\n case \"Space\":\n this.spacePressed = true;\n // console.log(\"点击跳跃\", this.playerIsOnGround, this.isFlying);\n if (!this.playerIsOnGround || this.isFlying) return;\n const next = this.personActions?.get(\"jumping\");\n if (next && this.actionState === next) return;\n this.playPersonAnimationByName(\"jumping\");\n this.playerVelocity.y = this.jumpHeight;\n this.playerIsOnGround = false;\n break;\n case \"ControlLeft\":\n this.ctPressed = true;\n break;\n case \"KeyV\":\n this.changeView();\n break;\n case \"KeyF\":\n this.isFlying = !this.isFlying;\n this.setAnimationByPressed();\n if (!this.isFlying && !this.playerIsOnGround) {\n this.playPersonAnimationByName(\"jumping\");\n }\n break;\n case \"KeyE\":\n this.setDrive();\n break;\n }\n };\n\n /**\n * 键盘抬起事件\n */\n private _boundOnKeyup = (e: KeyboardEvent) => {\n switch (e.code) {\n case \"KeyW\":\n this.fwdPressed = false;\n this.setAnimationByPressed();\n break;\n case \"KeyS\":\n this.bkdPressed = false;\n this.setAnimationByPressed();\n break;\n case \"KeyD\":\n this.rgtPressed = false;\n this.setAnimationByPressed();\n break;\n case \"KeyA\":\n this.lftPressed = false;\n this.setAnimationByPressed();\n break;\n case \"ShiftLeft\":\n this.shiftPressed = false;\n this.setAnimationByPressed();\n this.controls.mouseButtons = { LEFT: 0, MIDDLE: 1, RIGHT: 2 };\n break;\n case \"Space\":\n this.spacePressed = false;\n break;\n case \"ControlLeft\":\n this.ctPressed = false;\n break;\n }\n };\n\n /**\n * 鼠标移动事件\n */\n private _mouseMove = (e: MouseEvent) => {\n if (document.pointerLockElement !== document.body) return;\n this.setToward(e.movementX, e.movementY, 0.0001);\n };\n\n /**\n * 鼠标点击事件\n */\n private _mouseClick = (e: MouseEvent) => {\n this.setPointerLock();\n };\n\n /**\n * 事件绑定\n */\n onAllEvent() {\n this.isupdate = true;\n this.setPointerLock();\n\n window.addEventListener(\"keydown\", this._boundOnKeydown);\n window.addEventListener(\"keyup\", this._boundOnKeyup);\n window.addEventListener(\"mousemove\", this._mouseMove);\n window.addEventListener(\"click\", this._mouseClick);\n }\n\n /**\n * 事件解绑\n */\n offAllEvent() {\n this.isupdate = false;\n document.exitPointerLock();\n window.removeEventListener(\"keydown\", this._boundOnKeydown);\n window.removeEventListener(\"keyup\", this._boundOnKeyup);\n window.removeEventListener(\"mousemove\", this._mouseMove);\n window.removeEventListener(\"click\", this._mouseClick);\n }\n\n // ==================== 移动端控制 ====================\n\n /**\n * 指针按下事件\n */\n onPointerDown = (e: PointerEvent) => {\n if (e.pointerType !== \"touch\") return;\n this.isLookDown = true;\n this.lookPointerId = e.pointerId;\n this.lastTouchX = e.clientX;\n this.lastTouchY = e.clientY;\n\n this.lookAreaEl?.setPointerCapture?.(e.pointerId);\n e.preventDefault();\n };\n\n /**\n * 指针移动事件\n */\n onPointerMove = (e: PointerEvent) => {\n if (!this.isLookDown || e.pointerId !== this.lookPointerId) return;\n const dx = e.clientX - this.lastTouchX;\n const dy = e.clientY - this.lastTouchY;\n this.lastTouchX = e.clientX;\n this.lastTouchY = e.clientY;\n\n this.setInput({ lookDeltaX: dx, lookDeltaY: dy });\n e.preventDefault();\n };\n\n /**\n * 指针抬起事件\n */\n onPointerUp = (e: PointerEvent) => {\n if (e.pointerId !== this.lookPointerId) return;\n this.isLookDown = false;\n this.lookPointerId = null;\n this.lookAreaEl?.releasePointerCapture?.(e.pointerId);\n };\n\n /**\n * 初始化移动端摇杆控制\n */\n async initMobileControls() {\n this.controls.maxPolarAngle = Math.PI * (300 / 360);\n this.controls.touches = { ONE: null as any, TWO: null as any };\n this.nippleModule = await import(\"nipplejs\");\n const nipple = this.nippleModule?.default;\n const JOY_SIZE = 120;\n\n const container = document.body;\n\n // 摇杆容器\n this.joystickZoneEl = document.createElement(\"div\");\n this.joystickZoneEl.id = \"joy-zone\";\n Object.assign(this.joystickZoneEl.style, {\n position: \"absolute\",\n left: \"16px\",\n bottom: \"16px\",\n width: `${JOY_SIZE + 40}px`,\n height: `${JOY_SIZE + 40}px`,\n touchAction: \"none\",\n zIndex: \"999\",\n pointerEvents: \"auto\",\n WebkitUserSelect: \"none\",\n userSelect: \"none\",\n });\n container.appendChild(this.joystickZoneEl);\n\n // 阻止touch的默认行为\n [\"touchstart\", \"touchmove\", \"touchend\", \"touchcancel\"].forEach((evtName) => {\n this.joystickZoneEl?.addEventListener(evtName, (e) => e.preventDefault(), {\n passive: false,\n });\n });\n\n // 创建摇杆\n this.joystickManager = nipple.create({\n zone: this.joystickZoneEl,\n mode: \"static\",\n position: {\n left: `${(JOY_SIZE + 40) / 2}px`,\n bottom: `${(JOY_SIZE + 40) / 2}px`,\n },\n color: \"#ffffff\",\n size: JOY_SIZE,\n multitouch: true,\n maxNumberOfNipples: 1,\n });\n\n this.joystickManager.on(\"move\", (_evt: any, data: any) => {\n if (!data) return;\n\n const rawX = data.vector?.x ?? 0;\n const rawY = data.vector?.y ?? 0;\n const distance = data.distance ?? 0;\n const deadzone = 0.5;\n\n const dirX = rawX > deadzone ? 1 : rawX < -deadzone ? -1 : 0;\n const dirY = rawY > deadzone ? 1 : rawY < -deadzone ? -1 : 0;\n\n const sprintThreshold = JOY_SIZE / 2;\n const isSprinting = distance >= sprintThreshold;\n\n const prev = this.prevJoyState || { dirX: 0, dirY: 0, shift: false };\n if (dirX === prev.dirX && dirY === prev.dirY && isSprinting === prev.shift) {\n return;\n }\n\n this.prevJoyState = { dirX, dirY, shift: isSprinting };\n this.setInput({ moveX: dirX, moveY: dirY, shift: isSprinting });\n });\n\n this.joystickManager.on(\"end\", () => {\n const prev = this.prevJoyState || { dirX: 0, dirY: 0, shift: false };\n if (prev.dirX !== 0 || prev.dirY !== 0 || prev.shift !== false) {\n this.prevJoyState = { dirX: 0, dirY: 0, shift: false };\n this.setInput({ moveX: 0, moveY: 0, shift: false });\n }\n });\n\n // 右侧视角控制区域\n this.lookAreaEl = document.createElement(\"div\");\n Object.assign(this.lookAreaEl.style, {\n position: \"absolute\",\n right: \"0\",\n bottom: \"0\",\n width: \"50%\",\n height: \"100%\",\n zIndex: \"998\",\n touchAction: \"none\",\n WebkitUserSelect: \"none\",\n userSelect: \"none\",\n });\n container.appendChild(this.lookAreaEl);\n\n [\"touchstart\", \"touchmove\", \"touchend\", \"touchcancel\"].forEach((evtName) => {\n this.lookAreaEl?.addEventListener(evtName, (e) => e.preventDefault(), {\n passive: false,\n });\n });\n\n this.lookAreaEl.addEventListener(\"pointerdown\", this.onPointerDown, { passive: false });\n this.lookAreaEl.addEventListener(\"pointermove\", this.onPointerMove, { passive: false });\n this.lookAreaEl.addEventListener(\"pointerup\", this.onPointerUp, { passive: false });\n this.lookAreaEl.addEventListener(\"pointercancel\", this.onPointerUp, { passive: false });\n\n // 创建按钮\n const createBtn = (rightPx: number, bottomPx: number, bgUrl?: string) => {\n const btn = document.createElement(\"button\");\n const styles: Partial<CSSStyleDeclaration> = {\n position: \"absolute\",\n right: `${rightPx}px`,\n bottom: `${bottomPx}px`,\n width: \"56px\",\n height: \"56px\",\n zIndex: \"1000\",\n borderRadius: \"50%\",\n border: \"2px solid black\",\n background: \"rgba(0,0,0)\",\n padding: \"20px\",\n opacity: \"0.95\",\n touchAction: \"none\",\n fontSize: \"14px\",\n userSelect: \"none\",\n overflow: \"hidden\",\n boxSizing: \"border-box\",\n backgroundColor: \"transparent\",\n backgroundRepeat: \"no-repeat, no-repeat\",\n backgroundPosition: \"center center, center center\",\n backgroundSize: \"100% 100%, 80% 80%\",\n };\n\n if (bgUrl) {\n const overlayColor = \"rgba(0,0,0,0.5)\";\n styles.backgroundImage = `linear-gradient(${overlayColor}, ${overlayColor}), url(\"${bgUrl}\")`;\n }\n\n Object.assign(btn.style, styles);\n container.appendChild(btn);\n [\"touchstart\", \"touchend\", \"touchcancel\"].forEach((evtName) => {\n btn.addEventListener(evtName, (e) => e.preventDefault(), { passive: false });\n });\n\n return btn;\n };\n\n // 跳跃按钮\n this.jumpBtnEl = createBtn(14, 14, jumpIconModule);\n this.jumpBtnEl.addEventListener(\n \"touchstart\",\n (e) => {\n e.preventDefault();\n this.setInput({ jump: true });\n },\n { passive: false }\n );\n this.jumpBtnEl.addEventListener(\n \"touchend\",\n (e) => {\n e.preventDefault();\n this.setInput({ jump: false });\n },\n { passive: false }\n );\n this.jumpBtnEl.addEventListener(\n \"touchcancel\",\n (e) => {\n e.preventDefault();\n this.setInput({ jump: false });\n },\n { passive: false }\n );\n\n // 切换飞行按钮\n this.flyBtnEl = createBtn(14, 14 + 80, flyIconModule);\n this.flyBtnEl.addEventListener(\n \"touchstart\",\n (e) => {\n e.preventDefault();\n this.setInput({ toggleFly: true });\n },\n { passive: false }\n );\n\n // 切换视角按钮\n this.viewBtnEl = createBtn(14, 14 + 200, viewIconModule);\n this.viewBtnEl.addEventListener(\n \"touchstart\",\n (e) => {\n e.preventDefault();\n this.setInput({ toggleView: true });\n },\n { passive: false }\n );\n }\n\n /**\n * 销毁移动端摇杆控制\n */\n destroyMobileControls() {\n try {\n if (this.joystickManager && this.joystickManager.destroy) {\n this.joystickManager.destroy();\n this.joystickManager = null;\n }\n if (this.joystickZoneEl?.parentElement) {\n this.joystickZoneEl.parentElement.removeChild(this.joystickZoneEl);\n this.joystickZoneEl = null;\n }\n if (this.lookAreaEl?.parentElement) {\n this.lookAreaEl.parentElement.removeChild(this.lookAreaEl);\n this.lookAreaEl = null;\n }\n if (this.jumpBtnEl?.parentElement) {\n this.jumpBtnEl.parentElement.removeChild(this.jumpBtnEl);\n this.jumpBtnEl = null;\n }\n if (this.flyBtnEl?.parentElement) {\n this.flyBtnEl.parentElement.removeChild(this.flyBtnEl);\n this.flyBtnEl = null;\n }\n if (this.viewBtnEl?.parentElement) {\n this.viewBtnEl.parentElement.removeChild(this.viewBtnEl);\n this.viewBtnEl = null;\n }\n\n // 监听\n this.lookAreaEl?.removeEventListener(\"pointerdown\", this.onPointerDown);\n this.lookAreaEl?.removeEventListener(\"pointermove\", this.onPointerMove);\n this.lookAreaEl?.removeEventListener(\"pointerup\", this.onPointerUp);\n this.lookAreaEl?.removeEventListener(\"pointercancel\", this.onPointerUp);\n } catch (e) {\n console.warn(\"销毁移动端摇杆控制时出错:\", e);\n }\n }\n\n // ==================== 销毁 ====================\n\n /**\n * 销毁人物控制器\n */\n destroy() {\n this.offAllEvent();\n if (this.player) {\n this.player.remove(this.camera);\n this.scene.remove(this.player);\n }\n (this.player as any) = null;\n if (this.person) {\n this.scene.remove(this.person);\n this.person = null;\n }\n\n this.resetControls();\n\n // 清理 BVH 可视化\n if (this.visualizer) {\n this.scene.remove(this.visualizer);\n this.visualizer = null;\n }\n if (this.collider) {\n this.scene.remove(this.collider);\n this.collider = null;\n }\n\n this.destroyMobileControls();\n\n controllerInstance = null;\n }\n}\n\n// 导出API\nexport function playerController() {\n if (!controllerInstance) controllerInstance = new PlayerController();\n const c = controllerInstance;\n return {\n init: (opts: PlayerControllerOptions, callback?: () => void) => c.init(opts, callback),\n changeView: () => c.changeView(),\n reset: (pos?: THREE.Vector3) => c.reset(pos),\n update: (dt?: number) => c.update(dt),\n destroy: () => c.destroy(),\n setInput: (i: any) => c.setInput(i),\n getposition: () => c.getPosition(),\n loadVehicleModel: (params: {\n url: string;\n position: THREE.Vector3;\n scale?: number;\n animations: {\n openDoorAnim?: string;\n wheelsTurnAnim?: string;\n turnLeftAnim?: string;\n turnRightAnim?: string;\n };\n }) => c.loadVehicleModel(params),\n };\n}\n\n// 打开所有事件\nexport function onAllEvent(): void {\n if (!controllerInstance) controllerInstance = new PlayerController();\n controllerInstance.onAllEvent();\n}\n\n// 关闭所有事件\nexport function offAllEvent(): void {\n if (!controllerInstance) return;\n controllerInstance.offAllEvent();\n}\n"],"mappings":"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","names":["angle","intersects"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "three-player-controller",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "Third-person / first-person player controller for three.js (three-mesh-bvh based)",
5
5
  "author": "",
6
6
  "license": "MIT",