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/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
  */
@@ -559,6 +611,61 @@ var PlayerController = class {
559
611
  }
560
612
  }
561
613
  // ==================== 物理与碰撞检测 ====================
614
+ /**
615
+ * 统一属性集合
616
+ */
617
+ unifiedAttribute(collected) {
618
+ const attrMap = /* @__PURE__ */ new Map();
619
+ const attrConflict = /* @__PURE__ */ new Set();
620
+ const requiredAttrs = /* @__PURE__ */ new Set(["position", "normal", "uv"]);
621
+ for (const g of collected) {
622
+ const attrNames2 = Object.keys(g.attributes);
623
+ for (const name of attrNames2) {
624
+ if (!requiredAttrs.has(name)) {
625
+ g.deleteAttribute(name);
626
+ }
627
+ }
628
+ }
629
+ for (const g of collected) {
630
+ for (const name of Object.keys(g.attributes)) {
631
+ const attr = g.attributes[name];
632
+ const ctor = attr.array.constructor;
633
+ const itemSize = attr.itemSize;
634
+ const normalized = attr.normalized;
635
+ if (!attrMap.has(name)) {
636
+ attrMap.set(name, { itemSize, arrayCtor: ctor, examples: 1, normalized });
637
+ } else {
638
+ const m = attrMap.get(name);
639
+ if (m.itemSize !== itemSize || m.arrayCtor !== ctor || m.normalized !== normalized) {
640
+ attrConflict.add(name);
641
+ } else {
642
+ m.examples++;
643
+ }
644
+ }
645
+ }
646
+ }
647
+ if (attrConflict.size) {
648
+ for (const g of collected) {
649
+ for (const name of Array.from(attrConflict)) {
650
+ if (g.attributes[name]) g.deleteAttribute(name);
651
+ }
652
+ }
653
+ for (const name of attrConflict) attrMap.delete(name);
654
+ }
655
+ const attrNames = Array.from(attrMap.keys());
656
+ for (const g of collected) {
657
+ const count = g.attributes.position.count;
658
+ for (const name of attrNames) {
659
+ if (!g.attributes[name]) {
660
+ const meta = attrMap.get(name);
661
+ const len = count * meta.itemSize;
662
+ const array = new meta.arrayCtor(len);
663
+ g.setAttribute(name, new THREE.BufferAttribute(array, meta.itemSize, meta.normalized));
664
+ }
665
+ }
666
+ }
667
+ return collected;
668
+ }
562
669
  /**
563
670
  * BVH碰撞体构建
564
671
  */
@@ -574,7 +681,7 @@ var PlayerController = class {
574
681
  }
575
682
  return geom;
576
683
  };
577
- const collected = [];
684
+ let collected = [];
578
685
  if (meshUrl === "") {
579
686
  if (this.collider) {
580
687
  this.scene.remove(this.collider);
@@ -595,45 +702,7 @@ var PlayerController = class {
595
702
  }
596
703
  });
597
704
  if (!collected.length) return;
598
- const attrMap = /* @__PURE__ */ new Map();
599
- const attrConflict = /* @__PURE__ */ new Set();
600
- for (const g of collected) {
601
- for (const name of Object.keys(g.attributes)) {
602
- const attr = g.attributes[name];
603
- const ctor = attr.array.constructor;
604
- const itemSize = attr.itemSize;
605
- if (!attrMap.has(name)) {
606
- attrMap.set(name, { itemSize, arrayCtor: ctor, examples: 1 });
607
- } else {
608
- const m = attrMap.get(name);
609
- if (m.itemSize !== itemSize || m.arrayCtor !== ctor) {
610
- attrConflict.add(name);
611
- } else {
612
- m.examples++;
613
- }
614
- }
615
- }
616
- }
617
- if (attrConflict.size) {
618
- for (const g of collected) {
619
- for (const name of Array.from(attrConflict)) {
620
- if (g.attributes[name]) g.deleteAttribute(name);
621
- }
622
- }
623
- for (const name of attrConflict) attrMap.delete(name);
624
- }
625
- const attrNames = Array.from(attrMap.keys());
626
- for (const g of collected) {
627
- const count = g.attributes.position.count;
628
- for (const name of attrNames) {
629
- if (!g.attributes[name]) {
630
- const meta = attrMap.get(name);
631
- const len = count * meta.itemSize;
632
- const array = new meta.arrayCtor(len);
633
- g.setAttribute(name, new THREE.BufferAttribute(array, meta.itemSize));
634
- }
635
- }
636
- }
705
+ collected = this.unifiedAttribute(collected);
637
706
  } else {
638
707
  const gltf = await this.loader.loadAsync(meshUrl);
639
708
  const mesh = gltf.scene.children[0];
@@ -729,8 +798,12 @@ var PlayerController = class {
729
798
  this.player.position.addScaledVector(this.playerVelocity, delta);
730
799
  this.playerIsOnGround = true;
731
800
  } else {
732
- this.playerVelocity.set(0, 0, 0);
733
- this.playerIsOnGround = true;
801
+ if (this.spacePressed) {
802
+ this.playerVelocity.y += delta * this.gravity;
803
+ } else {
804
+ this.playerVelocity.set(0, 0, 0);
805
+ this.playerIsOnGround = true;
806
+ }
734
807
  }
735
808
  } else if (playerDistanceFromGround > minH && playerDistanceFromGround < h) {
736
809
  this.playerVelocity.set(0, 0, 0);
@@ -861,6 +934,7 @@ var PlayerController = class {
861
934
  */
862
935
  updateMixers(delta) {
863
936
  if (this.personMixer) this.personMixer.update(delta);
937
+ if (this.vehicleMixer) this.vehicleMixer.update(delta);
864
938
  }
865
939
  /**
866
940
  * 重置玩家位置
@@ -1183,7 +1257,8 @@ function playerController() {
1183
1257
  update: (dt) => c.update(dt),
1184
1258
  destroy: () => c.destroy(),
1185
1259
  setInput: (i) => c.setInput(i),
1186
- getposition: () => c.getPosition()
1260
+ getposition: () => c.getPosition(),
1261
+ loadVehicleModel: (params) => c.loadVehicleModel(params)
1187
1262
  };
1188
1263
  }
1189
1264
  function onAllEvent() {