three-player-controller 0.1.8 → 0.2.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 +24 -23
- package/dist/index.d.mts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +182 -45
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +183 -46
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,28 +1,29 @@
|
|
|
1
1
|
# three-player-controller
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
轻量的第三人称 / 第一人称玩家控制器,开箱即用,基于 three.js 和 three-mesh-bvh 实现人物胶囊体碰撞、BVH 碰撞检测、人物动画、第一/三人称切换与相机避障。此仓库包含库源码、example 演示。
|
|
4
4
|
|
|
5
|
-
#
|
|
5
|
+
# 安装
|
|
6
6
|
|
|
7
7
|
npm install three-player-controller
|
|
8
8
|
|
|
9
|
-
#
|
|
9
|
+
# 示例
|
|
10
10
|
|
|
11
11
|
[Player Controller](https://hh-hang.github.io/three-player-controller/)
|
|
12
12
|
|
|
13
|
-
###
|
|
13
|
+
### 控制
|
|
14
14
|
|
|
15
|
-

|
|
16
16
|
|
|
17
|
-
###
|
|
17
|
+
### 飞行
|
|
18
18
|
|
|
19
|
-

|
|
20
20
|
|
|
21
|
-
###
|
|
21
|
+
### 3DTiles 漫游
|
|
22
22
|
|
|
23
|
-

|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
|
|
26
|
+
# 使用
|
|
26
27
|
|
|
27
28
|
```js
|
|
28
29
|
import * as THREE from "three";
|
|
@@ -30,27 +31,27 @@ import { playerController } from "three-player-controller";
|
|
|
30
31
|
|
|
31
32
|
const player = playerController();
|
|
32
33
|
|
|
33
|
-
//
|
|
34
|
+
// 初始化玩家控制器
|
|
34
35
|
player.init({
|
|
35
|
-
scene, // three.js
|
|
36
|
-
camera, // three.js
|
|
37
|
-
controls, // three.js
|
|
36
|
+
scene, // three.js 场景
|
|
37
|
+
camera, // three.js 相机
|
|
38
|
+
controls, // three.js 控制器
|
|
38
39
|
playerModel: {
|
|
39
|
-
url: "./glb/person.glb", //
|
|
40
|
-
scale: 0.001, //
|
|
41
|
-
idleAnim: "Idle_2", //
|
|
42
|
-
walkAnim: "Walking_11", //
|
|
43
|
-
runAnim: "Running_9", //
|
|
44
|
-
jumpAnim: "Jump_3", //
|
|
40
|
+
url: "./glb/person.glb", // 模型路径
|
|
41
|
+
scale: 0.001, // 模型缩放
|
|
42
|
+
idleAnim: "Idle_2", // 默认 Idle 动画名字
|
|
43
|
+
walkAnim: "Walking_11", // 默认 Walk 动画名字
|
|
44
|
+
runAnim: "Running_9", // 默认 Run 动画名字
|
|
45
|
+
jumpAnim: "Jump_3", // 默认 Jump 动画名字
|
|
45
46
|
},
|
|
46
|
-
initPos: pos, //
|
|
47
|
+
initPos: pos, // 初始位置
|
|
47
48
|
});
|
|
48
49
|
|
|
49
|
-
//
|
|
50
|
+
// 渲染循环调用
|
|
50
51
|
player.update();
|
|
51
52
|
```
|
|
52
53
|
|
|
53
|
-
#
|
|
54
|
+
# 感谢
|
|
54
55
|
|
|
55
56
|
[three-mesh-bvh](https://github.com/gkjohnson/three-mesh-bvh)
|
|
56
57
|
|
package/dist/index.d.mts
CHANGED
|
@@ -24,6 +24,8 @@ declare function playerController(): {
|
|
|
24
24
|
};
|
|
25
25
|
initPos?: THREE.Vector3;
|
|
26
26
|
mouseSensity?: number;
|
|
27
|
+
minCamDistance?: number;
|
|
28
|
+
maxCamDistance?: number;
|
|
27
29
|
}, callback?: () => void) => Promise<void>;
|
|
28
30
|
changeView: () => void;
|
|
29
31
|
createBVH: (url?: string) => Promise<void>;
|
package/dist/index.d.ts
CHANGED
|
@@ -24,6 +24,8 @@ declare function playerController(): {
|
|
|
24
24
|
};
|
|
25
25
|
initPos?: THREE.Vector3;
|
|
26
26
|
mouseSensity?: number;
|
|
27
|
+
minCamDistance?: number;
|
|
28
|
+
maxCamDistance?: number;
|
|
27
29
|
}, callback?: () => void) => Promise<void>;
|
|
28
30
|
changeView: () => void;
|
|
29
31
|
createBVH: (url?: string) => Promise<void>;
|
package/dist/index.js
CHANGED
|
@@ -42,6 +42,7 @@ var import_RoundedBoxGeometry = require("three/examples/jsm/geometries/RoundedBo
|
|
|
42
42
|
var import_DRACOLoader = require("three/examples/jsm/loaders/DRACOLoader.js");
|
|
43
43
|
var import_GLTFLoader = require("three/examples/jsm/loaders/GLTFLoader.js");
|
|
44
44
|
var BufferGeometryUtils = __toESM(require("three/examples/jsm/utils/BufferGeometryUtils.js"));
|
|
45
|
+
THREE.Mesh.prototype.raycast = import_three_mesh_bvh.acceleratedRaycast;
|
|
45
46
|
var controllerInstance = null;
|
|
46
47
|
var clock = new THREE.Clock();
|
|
47
48
|
var PlayerController = class {
|
|
@@ -81,6 +82,7 @@ var PlayerController = class {
|
|
|
81
82
|
// 摄像机最小距离
|
|
82
83
|
this._maxCamDistance = 4.4;
|
|
83
84
|
// 摄像机最大距离
|
|
85
|
+
this.orginMaxCamDistance = 4.4;
|
|
84
86
|
// 物理/运动
|
|
85
87
|
this.playerVelocity = new THREE.Vector3();
|
|
86
88
|
// 玩家速度向量
|
|
@@ -101,11 +103,17 @@ var PlayerController = class {
|
|
|
101
103
|
this.DIR_BKD = new THREE.Vector3(0, 0, 1);
|
|
102
104
|
this.DIR_LFT = new THREE.Vector3(-1, 0, 0);
|
|
103
105
|
this.DIR_RGT = new THREE.Vector3(1, 0, 0);
|
|
104
|
-
this.
|
|
106
|
+
this.DIR_UP = new THREE.Vector3(0, 1, 0);
|
|
105
107
|
this._personToCam = new THREE.Vector3();
|
|
106
108
|
this._originTmp = new THREE.Vector3();
|
|
107
|
-
this._raycaster = new THREE.Raycaster(
|
|
108
|
-
|
|
109
|
+
this._raycaster = new THREE.Raycaster(
|
|
110
|
+
new THREE.Vector3(),
|
|
111
|
+
new THREE.Vector3(0, -1, 0)
|
|
112
|
+
);
|
|
113
|
+
this._raycasterPersonToCam = new THREE.Raycaster(
|
|
114
|
+
new THREE.Vector3(),
|
|
115
|
+
new THREE.Vector3()
|
|
116
|
+
);
|
|
109
117
|
// 键盘按下事件
|
|
110
118
|
this._boundOnKeydown = async (e) => {
|
|
111
119
|
if (e.ctrlKey && (e.code === "KeyW" || e.code === "KeyA" || e.code === "KeyS" || e.code === "KeyD")) {
|
|
@@ -133,8 +141,8 @@ var PlayerController = class {
|
|
|
133
141
|
this.setAnimationByPressed();
|
|
134
142
|
break;
|
|
135
143
|
case "Space":
|
|
136
|
-
if (!this.playerIsOnGround || this.isFlying) return;
|
|
137
144
|
this.spacePressed = true;
|
|
145
|
+
if (!this.playerIsOnGround || this.isFlying) return;
|
|
138
146
|
this.playPersonAnimationByName("jumping");
|
|
139
147
|
this.playerVelocity.y = this.jumpHeight;
|
|
140
148
|
this.playerIsOnGround = false;
|
|
@@ -175,6 +183,7 @@ var PlayerController = class {
|
|
|
175
183
|
this.setAnimationByPressed();
|
|
176
184
|
break;
|
|
177
185
|
case "Space":
|
|
186
|
+
this.spacePressed = false;
|
|
178
187
|
break;
|
|
179
188
|
case "ControlLeft":
|
|
180
189
|
this.ctPressed = false;
|
|
@@ -183,14 +192,14 @@ var PlayerController = class {
|
|
|
183
192
|
};
|
|
184
193
|
// 根据按键设置人物动画
|
|
185
194
|
this.setAnimationByPressed = () => {
|
|
186
|
-
this._maxCamDistance =
|
|
195
|
+
this._maxCamDistance = this.orginMaxCamDistance;
|
|
187
196
|
if (this.isFlying) {
|
|
188
197
|
if (!this.fwdPressed) {
|
|
189
198
|
this.playPersonAnimationByName("flyidle");
|
|
190
199
|
return;
|
|
191
200
|
}
|
|
192
201
|
this.playPersonAnimationByName("flying");
|
|
193
|
-
this._maxCamDistance =
|
|
202
|
+
this._maxCamDistance = this.orginMaxCamDistance * 2;
|
|
194
203
|
return;
|
|
195
204
|
}
|
|
196
205
|
if (this.playerIsOnGround) {
|
|
@@ -237,7 +246,11 @@ var PlayerController = class {
|
|
|
237
246
|
const yaw = -e.movementX * 1e-4 * this.mouseSensity;
|
|
238
247
|
const pitch = -e.movementY * 1e-4 * this.mouseSensity;
|
|
239
248
|
this.player.rotateY(yaw);
|
|
240
|
-
this.camera.rotation.x = THREE.MathUtils.clamp(
|
|
249
|
+
this.camera.rotation.x = THREE.MathUtils.clamp(
|
|
250
|
+
this.camera.rotation.x + pitch,
|
|
251
|
+
-1.3,
|
|
252
|
+
1.4
|
|
253
|
+
);
|
|
241
254
|
} else {
|
|
242
255
|
const sensitivity = 1e-4 * this.mouseSensity;
|
|
243
256
|
const deltaX = -e.movementX * sensitivity;
|
|
@@ -253,12 +266,17 @@ var PlayerController = class {
|
|
|
253
266
|
const newX = distance * Math.sin(phi) * Math.sin(theta);
|
|
254
267
|
const newY = distance * Math.cos(phi);
|
|
255
268
|
const newZ = distance * Math.sin(phi) * Math.cos(theta);
|
|
256
|
-
this.camera.position.set(
|
|
269
|
+
this.camera.position.set(
|
|
270
|
+
target.x + newX,
|
|
271
|
+
target.y + newY,
|
|
272
|
+
target.z + newZ
|
|
273
|
+
);
|
|
257
274
|
this.camera.lookAt(target);
|
|
258
275
|
}
|
|
259
276
|
};
|
|
260
277
|
this._mouseClick = (e) => {
|
|
261
|
-
if (document.pointerLockElement !== document.body)
|
|
278
|
+
if (document.pointerLockElement !== document.body)
|
|
279
|
+
document.body.requestPointerLock();
|
|
262
280
|
};
|
|
263
281
|
this._raycaster.firstHitOnly = true;
|
|
264
282
|
this._raycasterPersonToCam.firstHitOnly = true;
|
|
@@ -278,8 +296,9 @@ var PlayerController = class {
|
|
|
278
296
|
this.playerSpeed = opts.playerModel.speed ? opts.playerModel.speed * s : 400 * s;
|
|
279
297
|
this._camCollisionLerp = 0.18;
|
|
280
298
|
this._camEpsilon = 35 * s;
|
|
281
|
-
this._minCamDistance = 100 * s;
|
|
282
|
-
this._maxCamDistance = 440 * s;
|
|
299
|
+
this._minCamDistance = opts.minCamDistance ? opts.minCamDistance * s : 100 * s;
|
|
300
|
+
this._maxCamDistance = opts.maxCamDistance ? opts.maxCamDistance * s : 440 * s;
|
|
301
|
+
this.orginMaxCamDistance = this._maxCamDistance;
|
|
283
302
|
await this.createBVH();
|
|
284
303
|
this.createPlayer();
|
|
285
304
|
await this.loadPersonGLB();
|
|
@@ -296,15 +315,25 @@ var PlayerController = class {
|
|
|
296
315
|
this.isFirstPerson = !this.isFirstPerson;
|
|
297
316
|
if (this.isFirstPerson) {
|
|
298
317
|
this.player.attach(this.camera);
|
|
299
|
-
this.camera.position.set(
|
|
318
|
+
this.camera.position.set(
|
|
319
|
+
0,
|
|
320
|
+
40 * this.playerModel.scale,
|
|
321
|
+
30 * this.playerModel.scale
|
|
322
|
+
);
|
|
300
323
|
this.camera.rotation.set(0, Math.PI, 0);
|
|
301
324
|
document.body.requestPointerLock();
|
|
302
325
|
} else {
|
|
303
326
|
this.scene.attach(this.camera);
|
|
304
327
|
const worldPos = this.player.position.clone();
|
|
305
|
-
const dir = new THREE.Vector3(0, 0, -1).applyQuaternion(
|
|
328
|
+
const dir = new THREE.Vector3(0, 0, -1).applyQuaternion(
|
|
329
|
+
this.player.quaternion
|
|
330
|
+
);
|
|
306
331
|
const angle = Math.atan2(dir.z, dir.x);
|
|
307
|
-
const offset = new THREE.Vector3(
|
|
332
|
+
const offset = new THREE.Vector3(
|
|
333
|
+
Math.cos(angle) * 400 * this.playerModel.scale,
|
|
334
|
+
200 * this.playerModel.scale,
|
|
335
|
+
Math.sin(angle) * 400 * this.playerModel.scale
|
|
336
|
+
);
|
|
308
337
|
this.camera.position.copy(worldPos).add(offset);
|
|
309
338
|
this.controls.target.copy(worldPos);
|
|
310
339
|
document.body.requestPointerLock();
|
|
@@ -313,12 +342,22 @@ var PlayerController = class {
|
|
|
313
342
|
// 摄像机/控制器设置
|
|
314
343
|
setCameraPos() {
|
|
315
344
|
if (this.isFirstPerson) {
|
|
316
|
-
this.camera.position.set(
|
|
345
|
+
this.camera.position.set(
|
|
346
|
+
0,
|
|
347
|
+
40 * this.playerModel.scale,
|
|
348
|
+
30 * this.playerModel.scale
|
|
349
|
+
);
|
|
317
350
|
} else {
|
|
318
351
|
const worldPos = this.player.position.clone();
|
|
319
|
-
const dir = new THREE.Vector3(0, 0, -1).applyQuaternion(
|
|
352
|
+
const dir = new THREE.Vector3(0, 0, -1).applyQuaternion(
|
|
353
|
+
this.player.quaternion
|
|
354
|
+
);
|
|
320
355
|
const angle = Math.atan2(dir.z, dir.x);
|
|
321
|
-
const offset = new THREE.Vector3(
|
|
356
|
+
const offset = new THREE.Vector3(
|
|
357
|
+
Math.cos(angle) * 400 * this.playerModel.scale,
|
|
358
|
+
200 * this.playerModel.scale,
|
|
359
|
+
Math.sin(angle) * 400 * this.playerModel.scale
|
|
360
|
+
);
|
|
322
361
|
this.camera.position.copy(worldPos).add(offset);
|
|
323
362
|
}
|
|
324
363
|
this.camera.updateProjectionMatrix();
|
|
@@ -330,6 +369,7 @@ var PlayerController = class {
|
|
|
330
369
|
}
|
|
331
370
|
// 重置控制器
|
|
332
371
|
resetControls() {
|
|
372
|
+
if (!this.controls) return;
|
|
333
373
|
this.controls.enabled = true;
|
|
334
374
|
this.controls.enablePan = true;
|
|
335
375
|
this.controls.maxPolarAngle = Math.PI / 2;
|
|
@@ -344,7 +384,9 @@ var PlayerController = class {
|
|
|
344
384
|
// 初始化加载器
|
|
345
385
|
async initLoader() {
|
|
346
386
|
const dracoLoader = new import_DRACOLoader.DRACOLoader();
|
|
347
|
-
dracoLoader.setDecoderPath(
|
|
387
|
+
dracoLoader.setDecoderPath(
|
|
388
|
+
"https://unpkg.com/three@0.180.0/examples/jsm/libs/draco/gltf/"
|
|
389
|
+
);
|
|
348
390
|
dracoLoader.setDecoderConfig({ type: "js" });
|
|
349
391
|
this.loader.setDRACOLoader(dracoLoader);
|
|
350
392
|
}
|
|
@@ -360,21 +402,34 @@ var PlayerController = class {
|
|
|
360
402
|
this.person.traverse((child) => {
|
|
361
403
|
if (child.isMesh) {
|
|
362
404
|
child.castShadow = true;
|
|
405
|
+
const mat = child.material;
|
|
406
|
+
if (!mat) return;
|
|
407
|
+
const mats = Array.isArray(mat) ? mat : [mat];
|
|
408
|
+
mats.forEach((m) => {
|
|
409
|
+
});
|
|
363
410
|
}
|
|
364
411
|
});
|
|
365
412
|
this.player.add(this.person);
|
|
366
413
|
this.reset();
|
|
367
414
|
this.personMixer = new THREE.AnimationMixer(this.person);
|
|
368
415
|
const animations = gltf.animations ?? [];
|
|
369
|
-
console.log("animations", animations);
|
|
370
416
|
this.personActions = /* @__PURE__ */ new Map();
|
|
371
417
|
const findClip = (name) => animations.find((a) => a.name === name);
|
|
372
418
|
const regs = [
|
|
373
419
|
[this.playerModel.idleAnim, "idle"],
|
|
374
420
|
[this.playerModel.walkAnim, "walking"],
|
|
375
|
-
[
|
|
376
|
-
|
|
377
|
-
|
|
421
|
+
[
|
|
422
|
+
this.playerModel.leftWalkAnim || this.playerModel.walkAnim,
|
|
423
|
+
"left_walking"
|
|
424
|
+
],
|
|
425
|
+
[
|
|
426
|
+
this.playerModel.rightWalkAnim || this.playerModel.walkAnim,
|
|
427
|
+
"right_walking"
|
|
428
|
+
],
|
|
429
|
+
[
|
|
430
|
+
this.playerModel.backwardAnim || this.playerModel.walkAnim,
|
|
431
|
+
"walking_backward"
|
|
432
|
+
],
|
|
378
433
|
[this.playerModel.jumpAnim, "jumping"],
|
|
379
434
|
[this.playerModel.runAnim, "running"],
|
|
380
435
|
[this.playerModel.flyIdleAnim || this.playerModel.idleAnim, "flyidle"],
|
|
@@ -463,20 +518,29 @@ var PlayerController = class {
|
|
|
463
518
|
material.depthWrite = false;
|
|
464
519
|
const r = this.playerRadius * this.playerModel.scale;
|
|
465
520
|
const h = this.playerHeight * this.playerModel.scale;
|
|
466
|
-
this.player = new THREE.Mesh(
|
|
521
|
+
this.player = new THREE.Mesh(
|
|
522
|
+
new import_RoundedBoxGeometry.RoundedBoxGeometry(r * 2, h, r * 2, 1, 75),
|
|
523
|
+
material
|
|
524
|
+
);
|
|
467
525
|
this.player.geometry.translate(0, -h * 0.25, 0);
|
|
468
526
|
this.player.capsuleInfo = {
|
|
469
527
|
radius: r,
|
|
470
|
-
segment: new THREE.Line3(
|
|
528
|
+
segment: new THREE.Line3(
|
|
529
|
+
new THREE.Vector3(),
|
|
530
|
+
new THREE.Vector3(0, -h * 0.5, 0)
|
|
531
|
+
)
|
|
471
532
|
};
|
|
472
533
|
this.player.name = "capsule";
|
|
473
534
|
this.scene.add(this.player);
|
|
474
535
|
this.reset();
|
|
475
536
|
}
|
|
537
|
+
// 获取法线与Y轴的夹角
|
|
476
538
|
getAngleWithYAxis(normal) {
|
|
477
539
|
const yAxis = { x: 0, y: 1, z: 0 };
|
|
478
540
|
const dotProduct = normal.x * yAxis.x + normal.y * yAxis.y + normal.z * yAxis.z;
|
|
479
|
-
const normalMagnitude = Math.sqrt(
|
|
541
|
+
const normalMagnitude = Math.sqrt(
|
|
542
|
+
normal.x * normal.x + normal.y * normal.y + normal.z * normal.z
|
|
543
|
+
);
|
|
480
544
|
const yAxisMagnitude = 1;
|
|
481
545
|
const cosTheta = dotProduct / (normalMagnitude * yAxisMagnitude);
|
|
482
546
|
return Math.acos(cosTheta);
|
|
@@ -484,8 +548,9 @@ var PlayerController = class {
|
|
|
484
548
|
// 每帧更新
|
|
485
549
|
async update(delta = clock.getDelta()) {
|
|
486
550
|
if (!this.isupdate || !this.player || !this.collider) return;
|
|
487
|
-
delta = Math.min(delta, 1 /
|
|
488
|
-
if (!this.isFlying)
|
|
551
|
+
delta = Math.min(delta, 1 / 30);
|
|
552
|
+
if (!this.isFlying)
|
|
553
|
+
this.player.position.addScaledVector(this.playerVelocity, delta);
|
|
489
554
|
this.updateMixers(delta);
|
|
490
555
|
this.camera.getWorldDirection(this.camDir);
|
|
491
556
|
let angle = Math.atan2(this.camDir.z, this.camDir.x) + Math.PI / 2;
|
|
@@ -495,8 +560,15 @@ var PlayerController = class {
|
|
|
495
560
|
if (this.bkdPressed) this.moveDir.add(this.DIR_BKD);
|
|
496
561
|
if (this.lftPressed) this.moveDir.add(this.DIR_LFT);
|
|
497
562
|
if (this.rgtPressed) this.moveDir.add(this.DIR_RGT);
|
|
498
|
-
if (this.isFlying
|
|
499
|
-
this.
|
|
563
|
+
if (this.isFlying) {
|
|
564
|
+
if (this.fwdPressed) {
|
|
565
|
+
this.moveDir.y = this.camDir.y;
|
|
566
|
+
} else {
|
|
567
|
+
this.moveDir.y = 0;
|
|
568
|
+
}
|
|
569
|
+
if (this.spacePressed) {
|
|
570
|
+
this.moveDir.add(this.DIR_UP);
|
|
571
|
+
}
|
|
500
572
|
}
|
|
501
573
|
if (this.isFlying && this.fwdPressed) {
|
|
502
574
|
this.playerSpeed = this.shiftPressed ? 4e3 * this.playerModel.scale : 3e3 * this.playerModel.scale;
|
|
@@ -504,11 +576,21 @@ var PlayerController = class {
|
|
|
504
576
|
this.playerSpeed = this.shiftPressed ? 900 * this.playerModel.scale : 400 * this.playerModel.scale;
|
|
505
577
|
}
|
|
506
578
|
this.moveDir.normalize().applyAxisAngle(this.upVector, angle);
|
|
507
|
-
this.player.position.addScaledVector(
|
|
579
|
+
this.player.position.addScaledVector(
|
|
580
|
+
this.moveDir,
|
|
581
|
+
this.playerSpeed * delta
|
|
582
|
+
);
|
|
508
583
|
let playerDistanceFromGround = Infinity;
|
|
509
|
-
this._originTmp.set(
|
|
584
|
+
this._originTmp.set(
|
|
585
|
+
this.player.position.x,
|
|
586
|
+
this.player.position.y,
|
|
587
|
+
this.player.position.z
|
|
588
|
+
);
|
|
510
589
|
this._raycaster.ray.origin.copy(this._originTmp);
|
|
511
|
-
const intersects = this._raycaster.intersectObject(
|
|
590
|
+
const intersects = this._raycaster.intersectObject(
|
|
591
|
+
this.collider,
|
|
592
|
+
false
|
|
593
|
+
);
|
|
512
594
|
if (intersects.length > 0) {
|
|
513
595
|
playerDistanceFromGround = this.player.position.y - intersects[0].point.y;
|
|
514
596
|
const normal = intersects[0].normal;
|
|
@@ -536,7 +618,11 @@ var PlayerController = class {
|
|
|
536
618
|
this.playerIsOnGround = true;
|
|
537
619
|
} else if (playerDistanceFromGround < minH) {
|
|
538
620
|
this.playerVelocity.set(0, 0, 0);
|
|
539
|
-
this.player.position.set(
|
|
621
|
+
this.player.position.set(
|
|
622
|
+
this.player.position.x,
|
|
623
|
+
intersects[0].point.y + h,
|
|
624
|
+
this.player.position.z
|
|
625
|
+
);
|
|
540
626
|
this.playerIsOnGround = true;
|
|
541
627
|
}
|
|
542
628
|
}
|
|
@@ -559,7 +645,11 @@ var PlayerController = class {
|
|
|
559
645
|
intersectsTriangle: (tri) => {
|
|
560
646
|
const triPoint = this.tempVector;
|
|
561
647
|
const capsulePoint = this.tempVector2;
|
|
562
|
-
const distance = tri.closestPointToSegment(
|
|
648
|
+
const distance = tri.closestPointToSegment(
|
|
649
|
+
this.tempSegment,
|
|
650
|
+
triPoint,
|
|
651
|
+
capsulePoint
|
|
652
|
+
);
|
|
563
653
|
if (distance < capsuleInfo.radius) {
|
|
564
654
|
const depth = capsuleInfo.radius - distance;
|
|
565
655
|
const direction = capsulePoint.sub(triPoint).normalize();
|
|
@@ -569,11 +659,14 @@ var PlayerController = class {
|
|
|
569
659
|
}
|
|
570
660
|
});
|
|
571
661
|
const newPosition = this.tempVector.copy(this.tempSegment.start).applyMatrix4(this.collider.matrixWorld);
|
|
572
|
-
const deltaVector = this.tempVector2.subVectors(
|
|
662
|
+
const deltaVector = this.tempVector2.subVectors(
|
|
663
|
+
newPosition,
|
|
664
|
+
this.player.position
|
|
665
|
+
);
|
|
573
666
|
const offset = Math.max(0, deltaVector.length() - 1e-5);
|
|
574
667
|
deltaVector.normalize().multiplyScalar(offset);
|
|
575
668
|
this.player.position.add(deltaVector);
|
|
576
|
-
if (!this.isFirstPerson && this.moveDir.lengthSq() > 0) {
|
|
669
|
+
if (!this.isFirstPerson && this.moveDir.lengthSq() > 0 && !this.isFlying) {
|
|
577
670
|
this.camDir.y = 0;
|
|
578
671
|
this.camDir.normalize();
|
|
579
672
|
this.camDir.negate();
|
|
@@ -585,6 +678,18 @@ var PlayerController = class {
|
|
|
585
678
|
const alpha = Math.min(1, this.rotationSpeed * delta);
|
|
586
679
|
this.player.quaternion.slerp(this.targetQuat, alpha);
|
|
587
680
|
}
|
|
681
|
+
if (this.isFlying) {
|
|
682
|
+
this.camDir.y = 0;
|
|
683
|
+
this.camDir.normalize();
|
|
684
|
+
this.camDir.negate();
|
|
685
|
+
this.moveDir.normalize();
|
|
686
|
+
this.moveDir.negate();
|
|
687
|
+
const lookTarget = this.player.position.clone().add(this.fwdPressed ? this.moveDir : this.camDir);
|
|
688
|
+
this.targetMat.lookAt(this.player.position, lookTarget, this.player.up);
|
|
689
|
+
this.targetQuat.setFromRotationMatrix(this.targetMat);
|
|
690
|
+
const alpha = Math.min(1, this.rotationSpeed * delta);
|
|
691
|
+
this.player.quaternion.slerp(this.targetQuat, alpha);
|
|
692
|
+
}
|
|
588
693
|
if (!this.isFirstPerson) {
|
|
589
694
|
const lookTarget = this.player.position.clone();
|
|
590
695
|
lookTarget.y += 30 * this.playerModel.scale;
|
|
@@ -598,15 +703,24 @@ var PlayerController = class {
|
|
|
598
703
|
const desiredDist = this._personToCam.length();
|
|
599
704
|
this._raycasterPersonToCam.set(origin, direction);
|
|
600
705
|
this._raycasterPersonToCam.far = desiredDist;
|
|
601
|
-
const intersects2 = this._raycasterPersonToCam.intersectObject(
|
|
706
|
+
const intersects2 = this._raycasterPersonToCam.intersectObject(
|
|
707
|
+
this.collider,
|
|
708
|
+
false
|
|
709
|
+
);
|
|
602
710
|
if (intersects2.length > 0) {
|
|
603
711
|
const hit = intersects2[0];
|
|
604
|
-
const safeDist = Math.max(
|
|
712
|
+
const safeDist = Math.max(
|
|
713
|
+
hit.distance - this._camEpsilon,
|
|
714
|
+
this._minCamDistance
|
|
715
|
+
);
|
|
605
716
|
const targetCamPos = origin.clone().add(direction.clone().multiplyScalar(safeDist));
|
|
606
717
|
this.camera.position.lerp(targetCamPos, this._camCollisionLerp);
|
|
607
718
|
} else {
|
|
608
719
|
this._raycasterPersonToCam.far = this._maxCamDistance;
|
|
609
|
-
const intersectsMaxDis = this._raycasterPersonToCam.intersectObject(
|
|
720
|
+
const intersectsMaxDis = this._raycasterPersonToCam.intersectObject(
|
|
721
|
+
this.collider,
|
|
722
|
+
false
|
|
723
|
+
);
|
|
610
724
|
let safeDist = this._maxCamDistance;
|
|
611
725
|
if (intersectsMaxDis.length) {
|
|
612
726
|
const hitMax = intersectsMaxDis[0];
|
|
@@ -617,15 +731,34 @@ var PlayerController = class {
|
|
|
617
731
|
}
|
|
618
732
|
}
|
|
619
733
|
if (this.player.position.y < this.boundingBoxMinY - 1) {
|
|
620
|
-
this._originTmp.set(
|
|
734
|
+
this._originTmp.set(
|
|
735
|
+
this.player.position.x,
|
|
736
|
+
1e4,
|
|
737
|
+
this.player.position.z
|
|
738
|
+
);
|
|
621
739
|
this._raycaster.ray.origin.copy(this._originTmp);
|
|
622
|
-
const intersects2 = this._raycaster.intersectObject(
|
|
740
|
+
const intersects2 = this._raycaster.intersectObject(
|
|
741
|
+
this.collider,
|
|
742
|
+
false
|
|
743
|
+
);
|
|
623
744
|
if (intersects2.length > 0) {
|
|
624
745
|
console.log("\u73A9\u5BB6\u4E3Abug\u610F\u5916\u6389\u843D");
|
|
625
|
-
this.reset(
|
|
746
|
+
this.reset(
|
|
747
|
+
new THREE.Vector3(
|
|
748
|
+
this.player.position.x,
|
|
749
|
+
intersects2[0].point.y + 5,
|
|
750
|
+
this.player.position.z
|
|
751
|
+
)
|
|
752
|
+
);
|
|
626
753
|
} else {
|
|
627
754
|
console.log("\u73A9\u5BB6\u6B63\u5E38\u6389\u843D");
|
|
628
|
-
this.reset(
|
|
755
|
+
this.reset(
|
|
756
|
+
new THREE.Vector3(
|
|
757
|
+
this.player.position.x,
|
|
758
|
+
this.player.position.y + 15,
|
|
759
|
+
this.player.position.z
|
|
760
|
+
)
|
|
761
|
+
);
|
|
629
762
|
}
|
|
630
763
|
}
|
|
631
764
|
}
|
|
@@ -729,7 +862,8 @@ var PlayerController = class {
|
|
|
729
862
|
attrMap.set(name, { itemSize, arrayCtor: ctor, examples: 1 });
|
|
730
863
|
} else {
|
|
731
864
|
const m = attrMap.get(name);
|
|
732
|
-
if (m.itemSize !== itemSize || m.arrayCtor !== ctor)
|
|
865
|
+
if (m.itemSize !== itemSize || m.arrayCtor !== ctor)
|
|
866
|
+
attrConflict.add(name);
|
|
733
867
|
else m.examples++;
|
|
734
868
|
}
|
|
735
869
|
}
|
|
@@ -750,7 +884,10 @@ var PlayerController = class {
|
|
|
750
884
|
const meta = attrMap.get(name);
|
|
751
885
|
const len = count * meta.itemSize;
|
|
752
886
|
const array = new meta.arrayCtor(len);
|
|
753
|
-
g.setAttribute(
|
|
887
|
+
g.setAttribute(
|
|
888
|
+
name,
|
|
889
|
+
new THREE.BufferAttribute(array, meta.itemSize)
|
|
890
|
+
);
|
|
754
891
|
}
|
|
755
892
|
}
|
|
756
893
|
}
|