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/README.md +4 -8
- package/dist/index.d.mts +15 -5
- package/dist/index.d.ts +15 -5
- package/dist/index.js +33 -20
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +32 -20
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -8,11 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
# 示例
|
|
10
10
|
|
|
11
|
-
- [
|
|
12
|
-
|
|
13
|
-
- [3dtiles 场景](https://hh-hang.github.io/three-player-controller/3dtilesScene.html)
|
|
14
|
-
|
|
15
|
-
- [3dtiles 自定义](https://hh-hang.github.io/three-player-controller/3dtilesCustomize.html)
|
|
11
|
+
- [示例](https://hh-hang.github.io/three-player-controller/index.html)
|
|
16
12
|
|
|
17
13
|
### 普通控制
|
|
18
14
|
|
|
@@ -256,7 +252,7 @@ type PlayerControllerOptions = {
|
|
|
256
252
|
gravity?: number;
|
|
257
253
|
jumpHeight?: number;
|
|
258
254
|
speed?: number;
|
|
259
|
-
|
|
255
|
+
flySpeed?: number;
|
|
260
256
|
rotateY?: number;
|
|
261
257
|
headObjName?: string;
|
|
262
258
|
flyEnabled?: boolean;
|
|
@@ -299,7 +295,7 @@ type PlayerControllerOptions = {
|
|
|
299
295
|
| `playerModel.speed` | `number` | 否 | `300` | 移动速度基准值 |
|
|
300
296
|
| `playerModel.gravity` | `number` | 否 | `-2400` | 重力加速度基准值 |
|
|
301
297
|
| `playerModel.jumpHeight` | `number` | 否 | `600` | 跳跃高度基准值 |
|
|
302
|
-
| `playerModel.
|
|
298
|
+
| `playerModel.flySpeed` | `number` | 否 | `2100` | 飞行速度基准值 |
|
|
303
299
|
| `playerModel.flyEnabled` | `boolean` | 否 | `true` | 是否允许飞行模式 |
|
|
304
300
|
| `initPos` | `THREE.Vector3` | 否 | `(0,0,0)` | 初始位置 |
|
|
305
301
|
| `mouseSensity` | `number` | 否 | `5` | 鼠标灵敏度 |
|
|
@@ -416,4 +412,4 @@ player.playAnimation("attack", { force: true });
|
|
|
416
412
|
[three](https://github.com/mrdoob/three.js)
|
|
417
413
|
|
|
418
414
|
[npm]: https://img.shields.io/npm/v/three-player-controller
|
|
419
|
-
[npm-url]: https://www.npmjs.com/package/three-player-controller
|
|
415
|
+
[npm-url]: https://www.npmjs.com/package/three-player-controller
|
package/dist/index.d.mts
CHANGED
|
@@ -109,13 +109,23 @@ declare function playerController(): {
|
|
|
109
109
|
update: (dt?: number) => Promise<void>;
|
|
110
110
|
destroy: () => void;
|
|
111
111
|
reset: (pos?: THREE.Vector3) => void;
|
|
112
|
-
setInput: (i:
|
|
112
|
+
setInput: (i: Parameters<(input: Partial<{
|
|
113
|
+
moveX: 1 | 0 | -1;
|
|
114
|
+
moveY: 1 | 0 | -1;
|
|
115
|
+
lookDeltaX: number;
|
|
116
|
+
lookDeltaY: number;
|
|
117
|
+
jump: boolean;
|
|
118
|
+
shift: boolean;
|
|
119
|
+
toggleView: boolean;
|
|
120
|
+
toggleFly: boolean;
|
|
121
|
+
toggleVehicle: boolean;
|
|
122
|
+
}>) => void>[0]) => void;
|
|
113
123
|
changeView: () => void;
|
|
114
124
|
getPosition: () => THREE.Vector3;
|
|
115
|
-
getCenterScreenRaycastHit: () => THREE.Intersection<THREE.Object3D<THREE.Object3DEventMap
|
|
116
|
-
getCurrentPersonAnimationName: () => string;
|
|
117
|
-
getPerson: () => THREE.Object3D<THREE.Object3DEventMap
|
|
118
|
-
getActiveVehicle: () => VehicleInstance;
|
|
125
|
+
getCenterScreenRaycastHit: () => THREE.Intersection<THREE.Object3D<THREE.Object3DEventMap>> | undefined;
|
|
126
|
+
getCurrentPersonAnimationName: () => string | null;
|
|
127
|
+
getPerson: () => THREE.Object3D<THREE.Object3DEventMap> | null;
|
|
128
|
+
getActiveVehicle: () => VehicleInstance | null;
|
|
119
129
|
getAllVehicles: () => VehicleInstance[];
|
|
120
130
|
switchPlayerModel: (model: PlayerModelOptions) => Promise<void>;
|
|
121
131
|
setPlayerScale: (scale: number) => void;
|
package/dist/index.d.ts
CHANGED
|
@@ -109,13 +109,23 @@ declare function playerController(): {
|
|
|
109
109
|
update: (dt?: number) => Promise<void>;
|
|
110
110
|
destroy: () => void;
|
|
111
111
|
reset: (pos?: THREE.Vector3) => void;
|
|
112
|
-
setInput: (i:
|
|
112
|
+
setInput: (i: Parameters<(input: Partial<{
|
|
113
|
+
moveX: 1 | 0 | -1;
|
|
114
|
+
moveY: 1 | 0 | -1;
|
|
115
|
+
lookDeltaX: number;
|
|
116
|
+
lookDeltaY: number;
|
|
117
|
+
jump: boolean;
|
|
118
|
+
shift: boolean;
|
|
119
|
+
toggleView: boolean;
|
|
120
|
+
toggleFly: boolean;
|
|
121
|
+
toggleVehicle: boolean;
|
|
122
|
+
}>) => void>[0]) => void;
|
|
113
123
|
changeView: () => void;
|
|
114
124
|
getPosition: () => THREE.Vector3;
|
|
115
|
-
getCenterScreenRaycastHit: () => THREE.Intersection<THREE.Object3D<THREE.Object3DEventMap
|
|
116
|
-
getCurrentPersonAnimationName: () => string;
|
|
117
|
-
getPerson: () => THREE.Object3D<THREE.Object3DEventMap
|
|
118
|
-
getActiveVehicle: () => VehicleInstance;
|
|
125
|
+
getCenterScreenRaycastHit: () => THREE.Intersection<THREE.Object3D<THREE.Object3DEventMap>> | undefined;
|
|
126
|
+
getCurrentPersonAnimationName: () => string | null;
|
|
127
|
+
getPerson: () => THREE.Object3D<THREE.Object3DEventMap> | null;
|
|
128
|
+
getActiveVehicle: () => VehicleInstance | null;
|
|
119
129
|
getAllVehicles: () => VehicleInstance[];
|
|
120
130
|
switchPlayerModel: (model: PlayerModelOptions) => Promise<void>;
|
|
121
131
|
setPlayerScale: (scale: number) => void;
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -1037,13 +1038,12 @@ var PlayerController = class {
|
|
|
1037
1038
|
}
|
|
1038
1039
|
const w = window.innerWidth;
|
|
1039
1040
|
const h = window.innerHeight;
|
|
1040
|
-
this.camera.setViewOffset(w, h,
|
|
1041
|
+
this.camera.setViewOffset(w, h, w * 0.15, 0, w, h);
|
|
1041
1042
|
}
|
|
1042
1043
|
// 初始化加载器
|
|
1043
1044
|
async initLoader() {
|
|
1044
1045
|
const dracoLoader = new import_DRACOLoader.DRACOLoader();
|
|
1045
|
-
dracoLoader.setDecoderPath("https://unpkg.com/three@0.
|
|
1046
|
-
dracoLoader.setDecoderConfig({ type: "js" });
|
|
1046
|
+
dracoLoader.setDecoderPath("https://unpkg.com/three@0.182.0/examples/jsm/libs/draco/gltf/");
|
|
1047
1047
|
this.loader.setDRACOLoader(dracoLoader);
|
|
1048
1048
|
}
|
|
1049
1049
|
// 初始化物理引擎
|
|
@@ -1116,12 +1116,12 @@ var PlayerController = class {
|
|
|
1116
1116
|
action.setEffectiveWeight(0);
|
|
1117
1117
|
this.personActions.set(actionName, action);
|
|
1118
1118
|
}
|
|
1119
|
-
this.personActions.get("idle")
|
|
1120
|
-
this.personActions.get("idle")
|
|
1119
|
+
this.personActions.get("idle")?.setEffectiveWeight(1);
|
|
1120
|
+
this.personActions.get("idle")?.play();
|
|
1121
1121
|
this.actionState = this.personActions.get("idle");
|
|
1122
|
-
this.
|
|
1122
|
+
this.personMixerFinishedCb = (ev) => {
|
|
1123
1123
|
const done = ev.action;
|
|
1124
|
-
if (done === this.personActions
|
|
1124
|
+
if (done === this.personActions?.get("jumping")) {
|
|
1125
1125
|
if (this.fwdPressed) {
|
|
1126
1126
|
this.playPersonAnimationByName(this.shiftPressed ? "running" : "walking");
|
|
1127
1127
|
return;
|
|
@@ -1137,7 +1137,8 @@ var PlayerController = class {
|
|
|
1137
1137
|
this.playPersonAnimationByName("idle");
|
|
1138
1138
|
}
|
|
1139
1139
|
if (done === this.personActions?.get("enterCar")) this.onEnterCarAnimFinished();
|
|
1140
|
-
}
|
|
1140
|
+
};
|
|
1141
|
+
this.personMixer.addEventListener("finished", this.personMixerFinishedCb);
|
|
1141
1142
|
this.personMixer.update(0);
|
|
1142
1143
|
this.person.updateMatrixWorld(true);
|
|
1143
1144
|
const { size } = this.getBbox(this.person);
|
|
@@ -1192,6 +1193,10 @@ var PlayerController = class {
|
|
|
1192
1193
|
this.personHead = null;
|
|
1193
1194
|
}
|
|
1194
1195
|
if (this.personMixer) {
|
|
1196
|
+
if (this.personMixerFinishedCb) {
|
|
1197
|
+
this.personMixer.removeEventListener("finished", this.personMixerFinishedCb);
|
|
1198
|
+
this.personMixerFinishedCb = void 0;
|
|
1199
|
+
}
|
|
1195
1200
|
this.personMixer.stopAllAction();
|
|
1196
1201
|
this.personMixer.uncacheRoot(this.personMixer.getRoot());
|
|
1197
1202
|
this.personMixer = void 0;
|
|
@@ -1442,15 +1447,13 @@ var PlayerController = class {
|
|
|
1442
1447
|
changeView() {
|
|
1443
1448
|
this.isFirstPerson = !this.isFirstPerson;
|
|
1444
1449
|
if (this.isFirstPerson) {
|
|
1445
|
-
const
|
|
1446
|
-
|
|
1447
|
-
const flatDir = new THREE4.Vector3(camWorldDir.x, 0, camWorldDir.z).normalize();
|
|
1450
|
+
const playerFwd = new THREE4.Vector3(0, 0, 1).applyQuaternion(this.player.quaternion);
|
|
1451
|
+
const flatDir = new THREE4.Vector3(playerFwd.x, 0, playerFwd.z).normalize();
|
|
1448
1452
|
if (flatDir.lengthSq() > 1e-3) {
|
|
1449
1453
|
const yAngle = Math.atan2(flatDir.x, flatDir.z);
|
|
1450
|
-
this.player.rotation.set(0, yAngle
|
|
1454
|
+
this.player.rotation.set(0, yAngle, 0);
|
|
1451
1455
|
}
|
|
1452
|
-
|
|
1453
|
-
this.setFirstPersonCamera(vertAngle);
|
|
1456
|
+
this.setFirstPersonCamera();
|
|
1454
1457
|
this.setOverShoulderView(false);
|
|
1455
1458
|
} else {
|
|
1456
1459
|
this.controls.enabled = true;
|
|
@@ -1648,7 +1651,7 @@ var PlayerController = class {
|
|
|
1648
1651
|
return;
|
|
1649
1652
|
}
|
|
1650
1653
|
merged.boundsTree = new import_three_mesh_bvh.MeshBVH(merged, { maxDepth: 100 });
|
|
1651
|
-
this.collider = new THREE4.Mesh(merged, new THREE4.MeshBasicMaterial({ opacity: 0.5, transparent: true, wireframe: true, depthTest: true }));
|
|
1654
|
+
this.collider = new THREE4.Mesh(merged, new THREE4.MeshBasicMaterial({ opacity: 0.5, transparent: true, wireframe: true, depthTest: true, side: THREE4.DoubleSide }));
|
|
1652
1655
|
if (this.displayCollider) this.scene.add(this.collider);
|
|
1653
1656
|
if (this.displayVisualizer) {
|
|
1654
1657
|
if (this.visualizer) this.scene.remove(this.visualizer);
|
|
@@ -1686,7 +1689,7 @@ var PlayerController = class {
|
|
|
1686
1689
|
return;
|
|
1687
1690
|
}
|
|
1688
1691
|
merged.boundsTree = new import_three_mesh_bvh.MeshBVH(merged);
|
|
1689
|
-
this.dynamicCollider = new THREE4.Mesh(merged, new THREE4.MeshBasicMaterial({ opacity: 0.5, transparent: true, wireframe: true, depthTest: true }));
|
|
1692
|
+
this.dynamicCollider = new THREE4.Mesh(merged, new THREE4.MeshBasicMaterial({ opacity: 0.5, transparent: true, wireframe: true, depthTest: true, side: THREE4.DoubleSide }));
|
|
1690
1693
|
if (this.displayCollider) this.scene.add(this.dynamicCollider);
|
|
1691
1694
|
}
|
|
1692
1695
|
// ==================== 控制器过渡 ====================
|
|
@@ -1921,16 +1924,17 @@ var PlayerController = class {
|
|
|
1921
1924
|
if (!this.spacePressed) {
|
|
1922
1925
|
this.playerVelocity.set(0, 0, 0);
|
|
1923
1926
|
this.playerIsOnGround = true;
|
|
1924
|
-
this.player.position.y = hits[0].point.y + h;
|
|
1927
|
+
this.player.position.y = THREE4.MathUtils.lerp(this.player.position.y, hits[0].point.y + h, Math.min(1, 15 * delta));
|
|
1925
1928
|
}
|
|
1926
1929
|
} else if (dist >= minH) {
|
|
1927
1930
|
this.playerVelocity.set(0, 0, 0);
|
|
1928
1931
|
this.playerIsOnGround = true;
|
|
1929
1932
|
this.player.position.y = hits[0].point.y + h;
|
|
1930
1933
|
} else {
|
|
1934
|
+
const targetY = hits[0].point.y + h;
|
|
1931
1935
|
this.playerVelocity.set(0, 0, 0);
|
|
1932
|
-
this.player.position.y = hits[0].point.y + h;
|
|
1933
1936
|
this.playerIsOnGround = true;
|
|
1937
|
+
this.player.position.y = THREE4.MathUtils.lerp(this.player.position.y, targetY, Math.min(1, 15 * delta));
|
|
1934
1938
|
}
|
|
1935
1939
|
}
|
|
1936
1940
|
this.player.updateMatrixWorld();
|
|
@@ -1951,7 +1955,14 @@ var PlayerController = class {
|
|
|
1951
1955
|
const distance = tri.closestPointToSegment(this.tempSegment, this.tempVector, this.tempVector2);
|
|
1952
1956
|
if (distance < capsuleInfo.radius) {
|
|
1953
1957
|
const normal = tri.getNormal(new THREE4.Vector3());
|
|
1954
|
-
if (normal.y > 0.5
|
|
1958
|
+
if (!this.isFlying && Math.abs(normal.y) > 0.5) return;
|
|
1959
|
+
if (!this.isFlying && Math.abs(normal.y) <= 0.5) {
|
|
1960
|
+
const e = this.collider.matrixWorld.elements;
|
|
1961
|
+
const contactWorldY = e[1] * this.tempVector.x + e[5] * this.tempVector.y + e[9] * this.tempVector.z + e[13];
|
|
1962
|
+
const s = this.playerModel.scale;
|
|
1963
|
+
const feetY = this.player.position.y - this.playerCapsuleHeight * s * 0.75;
|
|
1964
|
+
if (contactWorldY < feetY + this.playerCapsuleHeight * s * 0.25) return;
|
|
1965
|
+
}
|
|
1955
1966
|
const dir = this.tempVector2.sub(this.tempVector).normalize();
|
|
1956
1967
|
const depth = capsuleInfo.radius - distance;
|
|
1957
1968
|
this.tempSegment.start.addScaledVector(dir, depth);
|
|
@@ -2046,13 +2057,14 @@ var PlayerController = class {
|
|
|
2046
2057
|
}
|
|
2047
2058
|
// 屏幕中心射线
|
|
2048
2059
|
getCenterScreenRaycastHit() {
|
|
2060
|
+
if (!this.collider) return void 0;
|
|
2049
2061
|
this.camera.updateMatrixWorld();
|
|
2050
2062
|
this.centerRay.setFromCamera(this.centerMouse, this.camera);
|
|
2051
2063
|
return this.centerRay.intersectObject(this.collider, false)[0];
|
|
2052
2064
|
}
|
|
2053
2065
|
// 获取当前人物动画名称
|
|
2054
2066
|
getCurrentPersonAnimationName() {
|
|
2055
|
-
return this.actionState
|
|
2067
|
+
return this.actionState?.getClip()?.name ?? null;
|
|
2056
2068
|
}
|
|
2057
2069
|
// 更新动画混合器
|
|
2058
2070
|
updateMixers(delta) {
|
|
@@ -2219,6 +2231,7 @@ var PlayerController = class {
|
|
|
2219
2231
|
for (const v of this.vehicles) {
|
|
2220
2232
|
this.scene.remove(v.vehicleGroup);
|
|
2221
2233
|
v.pathPlanner?.dispose();
|
|
2234
|
+
v.vehicleController?.destroy?.();
|
|
2222
2235
|
}
|
|
2223
2236
|
this.vehicles = [];
|
|
2224
2237
|
this.activeVehicle = null;
|