three-player-controller 0.3.8 → 0.4.0

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.mjs CHANGED
@@ -1000,13 +1000,12 @@ var PlayerController = class {
1000
1000
  }
1001
1001
  const w = window.innerWidth;
1002
1002
  const h = window.innerHeight;
1003
- this.camera.setViewOffset(w, h, -w * -0.15, 0, w, h);
1003
+ this.camera.setViewOffset(w, h, w * 0.15, 0, w, h);
1004
1004
  }
1005
1005
  // 初始化加载器
1006
1006
  async initLoader() {
1007
1007
  const dracoLoader = new DRACOLoader();
1008
- dracoLoader.setDecoderPath("https://unpkg.com/three@0.180.0/examples/jsm/libs/draco/gltf/");
1009
- dracoLoader.setDecoderConfig({ type: "js" });
1008
+ dracoLoader.setDecoderPath("https://unpkg.com/three@0.182.0/examples/jsm/libs/draco/gltf/");
1010
1009
  this.loader.setDRACOLoader(dracoLoader);
1011
1010
  }
1012
1011
  // 初始化物理引擎
@@ -1079,12 +1078,12 @@ var PlayerController = class {
1079
1078
  action.setEffectiveWeight(0);
1080
1079
  this.personActions.set(actionName, action);
1081
1080
  }
1082
- this.personActions.get("idle").setEffectiveWeight(1);
1083
- this.personActions.get("idle").play();
1081
+ this.personActions.get("idle")?.setEffectiveWeight(1);
1082
+ this.personActions.get("idle")?.play();
1084
1083
  this.actionState = this.personActions.get("idle");
1085
- this.personMixer.addEventListener("finished", (ev) => {
1084
+ this.personMixerFinishedCb = (ev) => {
1086
1085
  const done = ev.action;
1087
- if (done === this.personActions.get("jumping")) {
1086
+ if (done === this.personActions?.get("jumping")) {
1088
1087
  if (this.fwdPressed) {
1089
1088
  this.playPersonAnimationByName(this.shiftPressed ? "running" : "walking");
1090
1089
  return;
@@ -1100,7 +1099,8 @@ var PlayerController = class {
1100
1099
  this.playPersonAnimationByName("idle");
1101
1100
  }
1102
1101
  if (done === this.personActions?.get("enterCar")) this.onEnterCarAnimFinished();
1103
- });
1102
+ };
1103
+ this.personMixer.addEventListener("finished", this.personMixerFinishedCb);
1104
1104
  this.personMixer.update(0);
1105
1105
  this.person.updateMatrixWorld(true);
1106
1106
  const { size } = this.getBbox(this.person);
@@ -1155,6 +1155,10 @@ var PlayerController = class {
1155
1155
  this.personHead = null;
1156
1156
  }
1157
1157
  if (this.personMixer) {
1158
+ if (this.personMixerFinishedCb) {
1159
+ this.personMixer.removeEventListener("finished", this.personMixerFinishedCb);
1160
+ this.personMixerFinishedCb = void 0;
1161
+ }
1158
1162
  this.personMixer.stopAllAction();
1159
1163
  this.personMixer.uncacheRoot(this.personMixer.getRoot());
1160
1164
  this.personMixer = void 0;
@@ -1405,15 +1409,13 @@ var PlayerController = class {
1405
1409
  changeView() {
1406
1410
  this.isFirstPerson = !this.isFirstPerson;
1407
1411
  if (this.isFirstPerson) {
1408
- const camWorldDir = new THREE4.Vector3();
1409
- this.camera.getWorldDirection(camWorldDir);
1410
- const flatDir = new THREE4.Vector3(camWorldDir.x, 0, camWorldDir.z).normalize();
1412
+ const playerFwd = new THREE4.Vector3(0, 0, 1).applyQuaternion(this.player.quaternion);
1413
+ const flatDir = new THREE4.Vector3(playerFwd.x, 0, playerFwd.z).normalize();
1411
1414
  if (flatDir.lengthSq() > 1e-3) {
1412
1415
  const yAngle = Math.atan2(flatDir.x, flatDir.z);
1413
- this.player.rotation.set(0, yAngle + Math.PI, 0);
1416
+ this.player.rotation.set(0, yAngle, 0);
1414
1417
  }
1415
- const vertAngle = Math.asin(THREE4.MathUtils.clamp(-camWorldDir.y, -1, 1));
1416
- this.setFirstPersonCamera(vertAngle);
1418
+ this.setFirstPersonCamera();
1417
1419
  this.setOverShoulderView(false);
1418
1420
  } else {
1419
1421
  this.controls.enabled = true;
@@ -1611,7 +1613,7 @@ var PlayerController = class {
1611
1613
  return;
1612
1614
  }
1613
1615
  merged.boundsTree = new MeshBVH(merged, { maxDepth: 100 });
1614
- this.collider = new THREE4.Mesh(merged, new THREE4.MeshBasicMaterial({ opacity: 0.5, transparent: true, wireframe: true, depthTest: true }));
1616
+ this.collider = new THREE4.Mesh(merged, new THREE4.MeshBasicMaterial({ opacity: 0.5, transparent: true, wireframe: true, depthTest: true, side: THREE4.DoubleSide }));
1615
1617
  if (this.displayCollider) this.scene.add(this.collider);
1616
1618
  if (this.displayVisualizer) {
1617
1619
  if (this.visualizer) this.scene.remove(this.visualizer);
@@ -1649,7 +1651,7 @@ var PlayerController = class {
1649
1651
  return;
1650
1652
  }
1651
1653
  merged.boundsTree = new MeshBVH(merged);
1652
- this.dynamicCollider = new THREE4.Mesh(merged, new THREE4.MeshBasicMaterial({ opacity: 0.5, transparent: true, wireframe: true, depthTest: true }));
1654
+ this.dynamicCollider = new THREE4.Mesh(merged, new THREE4.MeshBasicMaterial({ opacity: 0.5, transparent: true, wireframe: true, depthTest: true, side: THREE4.DoubleSide }));
1653
1655
  if (this.displayCollider) this.scene.add(this.dynamicCollider);
1654
1656
  }
1655
1657
  // ==================== 控制器过渡 ====================
@@ -1884,16 +1886,17 @@ var PlayerController = class {
1884
1886
  if (!this.spacePressed) {
1885
1887
  this.playerVelocity.set(0, 0, 0);
1886
1888
  this.playerIsOnGround = true;
1887
- this.player.position.y = hits[0].point.y + h;
1889
+ this.player.position.y = THREE4.MathUtils.lerp(this.player.position.y, hits[0].point.y + h, Math.min(1, 15 * delta));
1888
1890
  }
1889
1891
  } else if (dist >= minH) {
1890
1892
  this.playerVelocity.set(0, 0, 0);
1891
1893
  this.playerIsOnGround = true;
1892
1894
  this.player.position.y = hits[0].point.y + h;
1893
1895
  } else {
1896
+ const targetY = hits[0].point.y + h;
1894
1897
  this.playerVelocity.set(0, 0, 0);
1895
- this.player.position.y = hits[0].point.y + h;
1896
1898
  this.playerIsOnGround = true;
1899
+ this.player.position.y = THREE4.MathUtils.lerp(this.player.position.y, targetY, Math.min(1, 15 * delta));
1897
1900
  }
1898
1901
  }
1899
1902
  this.player.updateMatrixWorld();
@@ -1914,7 +1917,14 @@ var PlayerController = class {
1914
1917
  const distance = tri.closestPointToSegment(this.tempSegment, this.tempVector, this.tempVector2);
1915
1918
  if (distance < capsuleInfo.radius) {
1916
1919
  const normal = tri.getNormal(new THREE4.Vector3());
1917
- if (normal.y > 0.5 && !this.isFlying) return;
1920
+ if (!this.isFlying && Math.abs(normal.y) > 0.5) return;
1921
+ if (!this.isFlying && Math.abs(normal.y) <= 0.5) {
1922
+ const e = this.collider.matrixWorld.elements;
1923
+ const contactWorldY = e[1] * this.tempVector.x + e[5] * this.tempVector.y + e[9] * this.tempVector.z + e[13];
1924
+ const s = this.playerModel.scale;
1925
+ const feetY = this.player.position.y - this.playerCapsuleHeight * s * 0.75;
1926
+ if (contactWorldY < feetY + this.playerCapsuleHeight * s * 0.25) return;
1927
+ }
1918
1928
  const dir = this.tempVector2.sub(this.tempVector).normalize();
1919
1929
  const depth = capsuleInfo.radius - distance;
1920
1930
  this.tempSegment.start.addScaledVector(dir, depth);
@@ -2009,13 +2019,14 @@ var PlayerController = class {
2009
2019
  }
2010
2020
  // 屏幕中心射线
2011
2021
  getCenterScreenRaycastHit() {
2022
+ if (!this.collider) return void 0;
2012
2023
  this.camera.updateMatrixWorld();
2013
2024
  this.centerRay.setFromCamera(this.centerMouse, this.camera);
2014
2025
  return this.centerRay.intersectObject(this.collider, false)[0];
2015
2026
  }
2016
2027
  // 获取当前人物动画名称
2017
2028
  getCurrentPersonAnimationName() {
2018
- return this.actionState._clip.name;
2029
+ return this.actionState?.getClip()?.name ?? null;
2019
2030
  }
2020
2031
  // 更新动画混合器
2021
2032
  updateMixers(delta) {
@@ -2182,6 +2193,7 @@ var PlayerController = class {
2182
2193
  for (const v of this.vehicles) {
2183
2194
  this.scene.remove(v.vehicleGroup);
2184
2195
  v.pathPlanner?.dispose();
2196
+ v.vehicleController?.destroy?.();
2185
2197
  }
2186
2198
  this.vehicles = [];
2187
2199
  this.activeVehicle = null;