three-player-controller 0.3.0 → 0.3.2
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/LICENSE +1 -1
- package/dist/index.d.mts +11 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +119 -44
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +119 -44
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/LICENSE
CHANGED
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:
|
|
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
|
*/
|
|
@@ -596,6 +648,61 @@ var PlayerController = class {
|
|
|
596
648
|
}
|
|
597
649
|
}
|
|
598
650
|
// ==================== 物理与碰撞检测 ====================
|
|
651
|
+
/**
|
|
652
|
+
* 统一属性集合
|
|
653
|
+
*/
|
|
654
|
+
unifiedAttribute(collected) {
|
|
655
|
+
const attrMap = /* @__PURE__ */ new Map();
|
|
656
|
+
const attrConflict = /* @__PURE__ */ new Set();
|
|
657
|
+
const requiredAttrs = /* @__PURE__ */ new Set(["position", "normal", "uv"]);
|
|
658
|
+
for (const g of collected) {
|
|
659
|
+
const attrNames2 = Object.keys(g.attributes);
|
|
660
|
+
for (const name of attrNames2) {
|
|
661
|
+
if (!requiredAttrs.has(name)) {
|
|
662
|
+
g.deleteAttribute(name);
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
for (const g of collected) {
|
|
667
|
+
for (const name of Object.keys(g.attributes)) {
|
|
668
|
+
const attr = g.attributes[name];
|
|
669
|
+
const ctor = attr.array.constructor;
|
|
670
|
+
const itemSize = attr.itemSize;
|
|
671
|
+
const normalized = attr.normalized;
|
|
672
|
+
if (!attrMap.has(name)) {
|
|
673
|
+
attrMap.set(name, { itemSize, arrayCtor: ctor, examples: 1, normalized });
|
|
674
|
+
} else {
|
|
675
|
+
const m = attrMap.get(name);
|
|
676
|
+
if (m.itemSize !== itemSize || m.arrayCtor !== ctor || m.normalized !== normalized) {
|
|
677
|
+
attrConflict.add(name);
|
|
678
|
+
} else {
|
|
679
|
+
m.examples++;
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
if (attrConflict.size) {
|
|
685
|
+
for (const g of collected) {
|
|
686
|
+
for (const name of Array.from(attrConflict)) {
|
|
687
|
+
if (g.attributes[name]) g.deleteAttribute(name);
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
for (const name of attrConflict) attrMap.delete(name);
|
|
691
|
+
}
|
|
692
|
+
const attrNames = Array.from(attrMap.keys());
|
|
693
|
+
for (const g of collected) {
|
|
694
|
+
const count = g.attributes.position.count;
|
|
695
|
+
for (const name of attrNames) {
|
|
696
|
+
if (!g.attributes[name]) {
|
|
697
|
+
const meta = attrMap.get(name);
|
|
698
|
+
const len = count * meta.itemSize;
|
|
699
|
+
const array = new meta.arrayCtor(len);
|
|
700
|
+
g.setAttribute(name, new THREE.BufferAttribute(array, meta.itemSize, meta.normalized));
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
return collected;
|
|
705
|
+
}
|
|
599
706
|
/**
|
|
600
707
|
* BVH碰撞体构建
|
|
601
708
|
*/
|
|
@@ -611,7 +718,7 @@ var PlayerController = class {
|
|
|
611
718
|
}
|
|
612
719
|
return geom;
|
|
613
720
|
};
|
|
614
|
-
|
|
721
|
+
let collected = [];
|
|
615
722
|
if (meshUrl === "") {
|
|
616
723
|
if (this.collider) {
|
|
617
724
|
this.scene.remove(this.collider);
|
|
@@ -632,45 +739,7 @@ var PlayerController = class {
|
|
|
632
739
|
}
|
|
633
740
|
});
|
|
634
741
|
if (!collected.length) return;
|
|
635
|
-
|
|
636
|
-
const attrConflict = /* @__PURE__ */ new Set();
|
|
637
|
-
for (const g of collected) {
|
|
638
|
-
for (const name of Object.keys(g.attributes)) {
|
|
639
|
-
const attr = g.attributes[name];
|
|
640
|
-
const ctor = attr.array.constructor;
|
|
641
|
-
const itemSize = attr.itemSize;
|
|
642
|
-
if (!attrMap.has(name)) {
|
|
643
|
-
attrMap.set(name, { itemSize, arrayCtor: ctor, examples: 1 });
|
|
644
|
-
} else {
|
|
645
|
-
const m = attrMap.get(name);
|
|
646
|
-
if (m.itemSize !== itemSize || m.arrayCtor !== ctor) {
|
|
647
|
-
attrConflict.add(name);
|
|
648
|
-
} else {
|
|
649
|
-
m.examples++;
|
|
650
|
-
}
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
}
|
|
654
|
-
if (attrConflict.size) {
|
|
655
|
-
for (const g of collected) {
|
|
656
|
-
for (const name of Array.from(attrConflict)) {
|
|
657
|
-
if (g.attributes[name]) g.deleteAttribute(name);
|
|
658
|
-
}
|
|
659
|
-
}
|
|
660
|
-
for (const name of attrConflict) attrMap.delete(name);
|
|
661
|
-
}
|
|
662
|
-
const attrNames = Array.from(attrMap.keys());
|
|
663
|
-
for (const g of collected) {
|
|
664
|
-
const count = g.attributes.position.count;
|
|
665
|
-
for (const name of attrNames) {
|
|
666
|
-
if (!g.attributes[name]) {
|
|
667
|
-
const meta = attrMap.get(name);
|
|
668
|
-
const len = count * meta.itemSize;
|
|
669
|
-
const array = new meta.arrayCtor(len);
|
|
670
|
-
g.setAttribute(name, new THREE.BufferAttribute(array, meta.itemSize));
|
|
671
|
-
}
|
|
672
|
-
}
|
|
673
|
-
}
|
|
742
|
+
collected = this.unifiedAttribute(collected);
|
|
674
743
|
} else {
|
|
675
744
|
const gltf = await this.loader.loadAsync(meshUrl);
|
|
676
745
|
const mesh = gltf.scene.children[0];
|
|
@@ -766,8 +835,12 @@ var PlayerController = class {
|
|
|
766
835
|
this.player.position.addScaledVector(this.playerVelocity, delta);
|
|
767
836
|
this.playerIsOnGround = true;
|
|
768
837
|
} else {
|
|
769
|
-
this.
|
|
770
|
-
|
|
838
|
+
if (this.spacePressed) {
|
|
839
|
+
this.playerVelocity.y += delta * this.gravity;
|
|
840
|
+
} else {
|
|
841
|
+
this.playerVelocity.set(0, 0, 0);
|
|
842
|
+
this.playerIsOnGround = true;
|
|
843
|
+
}
|
|
771
844
|
}
|
|
772
845
|
} else if (playerDistanceFromGround > minH && playerDistanceFromGround < h) {
|
|
773
846
|
this.playerVelocity.set(0, 0, 0);
|
|
@@ -898,6 +971,7 @@ var PlayerController = class {
|
|
|
898
971
|
*/
|
|
899
972
|
updateMixers(delta) {
|
|
900
973
|
if (this.personMixer) this.personMixer.update(delta);
|
|
974
|
+
if (this.vehicleMixer) this.vehicleMixer.update(delta);
|
|
901
975
|
}
|
|
902
976
|
/**
|
|
903
977
|
* 重置玩家位置
|
|
@@ -1220,7 +1294,8 @@ function playerController() {
|
|
|
1220
1294
|
update: (dt) => c.update(dt),
|
|
1221
1295
|
destroy: () => c.destroy(),
|
|
1222
1296
|
setInput: (i) => c.setInput(i),
|
|
1223
|
-
getposition: () => c.getPosition()
|
|
1297
|
+
getposition: () => c.getPosition(),
|
|
1298
|
+
loadVehicleModel: (params) => c.loadVehicleModel(params)
|
|
1224
1299
|
};
|
|
1225
1300
|
}
|
|
1226
1301
|
function onAllEvent() {
|