@adatechnology/game-test-room 0.26.0 → 0.28.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.js CHANGED
@@ -1,8 +1,9 @@
1
1
  // src/room.ts
2
2
  import { createDestruction, JOINT_DEFAULTS, resolveStrings as resolveDestructionStrings } from "@adatechnology/game-destruction";
3
3
  import { createAudioEngine, createAudioSink, loadKitSamples, loadUserSamples } from "@adatechnology/game-audio";
4
- import { createDestructionRenderer, createDestructionSound, dragSoundKey, impactKey, impactSoundKeys, specFromObject3D } from "@adatechnology/game-destruction-three";
5
- import { bodyMass, KNOCK_CHEST, KNOCK_DOWN_SPEED, knockOf, surfaceOfMaterial } from "@adatechnology/game-contracts";
4
+ import { registerFittedSounds } from "@adatechnology/game-audio/fitted";
5
+ import { createDestructionRenderer, createDestructionSound, dragSoundKey, impactKey, impactSoundIds, impactSoundKeys, specFromObject3D } from "@adatechnology/game-destruction-three";
6
+ import { bodyMass, FIRST_PERSON_LAYER, KNOCK_CHEST, KNOCK_DOWN_SPEED, knockOf, surfaceOfMaterial } from "@adatechnology/game-contracts";
6
7
 
7
8
  // src/body-sounds.ts
8
9
  import { BODY_FOLEY_BANK } from "@adatechnology/game-audio";
@@ -2153,6 +2154,7 @@ function createNarrator(c) {
2153
2154
 
2154
2155
  // src/player.ts
2155
2156
  import { stepKnock } from "@adatechnology/game-contracts";
2157
+ var RECOIL_RETURN = { share: 0.7, seconds: 0.25 };
2156
2158
  var SLAM_MIN_SPEED = 1.5;
2157
2159
  var LANDING_MIN_SPEED = 1;
2158
2160
  var EYE = 1.7;
@@ -2182,6 +2184,18 @@ function createPlayer(THREE, o) {
2182
2184
  const cam = o.camera;
2183
2185
  let yaw = 0;
2184
2186
  let pitch = 0;
2187
+ const recoilReturn = o.recoilReturn ?? RECOIL_RETURN;
2188
+ const recoilDebt = { pitch: 0, yaw: 0 };
2189
+ const returnRecoil = (dt) => {
2190
+ if (Math.abs(recoilDebt.pitch) + Math.abs(recoilDebt.yaw) < 1e-6) return;
2191
+ const k = 1 - Math.exp(-3 * dt / Math.max(1e-3, recoilReturn.seconds));
2192
+ const back = { pitch: recoilDebt.pitch * k, yaw: recoilDebt.yaw * k };
2193
+ recoilDebt.pitch -= back.pitch;
2194
+ recoilDebt.yaw -= back.yaw;
2195
+ pitch = Math.max(-1.5, Math.min(1.5, pitch - back.pitch));
2196
+ yaw -= back.yaw;
2197
+ apply();
2198
+ };
2185
2199
  let y = 0;
2186
2200
  let eye = EYE;
2187
2201
  let crouch = 0;
@@ -2523,6 +2537,7 @@ function createPlayer(THREE, o) {
2523
2537
  return stunLeft;
2524
2538
  },
2525
2539
  update(dt) {
2540
+ returnRecoil(dt);
2526
2541
  if (stunLeft > 0) {
2527
2542
  stunLeft = Math.max(0, stunLeft - dt);
2528
2543
  stunPhase += dt * 2.4;
@@ -2571,6 +2586,8 @@ function createPlayer(THREE, o) {
2571
2586
  },
2572
2587
  setPose(position, yw, pt) {
2573
2588
  knocked = null;
2589
+ recoilDebt.pitch = 0;
2590
+ recoilDebt.yaw = 0;
2574
2591
  px.x = position[0];
2575
2592
  px.z = position[2];
2576
2593
  floorLevel = floorHere();
@@ -2583,6 +2600,8 @@ function createPlayer(THREE, o) {
2583
2600
  },
2584
2601
  look(position, target) {
2585
2602
  knocked = null;
2603
+ recoilDebt.pitch = 0;
2604
+ recoilDebt.yaw = 0;
2586
2605
  px.x = position[0];
2587
2606
  px.z = position[2];
2588
2607
  floorLevel = floorHere();
@@ -2597,8 +2616,11 @@ function createPlayer(THREE, o) {
2597
2616
  apply();
2598
2617
  },
2599
2618
  kick(pitchDeg, yawDeg) {
2619
+ const before = pitch;
2600
2620
  pitch = Math.max(-1.5, Math.min(1.5, pitch + pitchDeg * Math.PI / 180));
2601
2621
  yaw += yawDeg * Math.PI / 180;
2622
+ recoilDebt.pitch += (pitch - before) * recoilReturn.share;
2623
+ recoilDebt.yaw += yawDeg * Math.PI / 180 * recoilReturn.share;
2602
2624
  apply();
2603
2625
  },
2604
2626
  moveBy(dx, dz) {
@@ -5498,6 +5520,7 @@ function createTestRoom(options) {
5498
5520
  const scene = options.scene ?? new THREE.Scene();
5499
5521
  const camera = options.camera ?? new THREE.PerspectiveCamera(72, width() / height(), 0.05, 140);
5500
5522
  if (!options.camera) scene.add(camera);
5523
+ camera.layers.disable(FIRST_PERSON_LAYER);
5501
5524
  const resize = () => {
5502
5525
  const w = width();
5503
5526
  const h = height();
@@ -5577,13 +5600,14 @@ function createTestRoom(options) {
5577
5600
  const preload = () => {
5578
5601
  window.removeEventListener("keydown", preload, true);
5579
5602
  window.removeEventListener("pointerdown", preload, true);
5580
- void audio.loadSamples([...HAND_RECORDED_IDS]).catch(() => void 0);
5603
+ void audio.loadSamples([...HAND_RECORDED_IDS, ...impactSoundIds()]).catch(() => void 0);
5581
5604
  };
5582
5605
  window.addEventListener("keydown", preload, true);
5583
5606
  window.addEventListener("pointerdown", preload, true);
5584
5607
  });
5585
5608
  }
5586
5609
  const bodySounds = createBodySounds(audio);
5610
+ if (audio && options.fittedSounds !== false) registerFittedSounds(audio);
5587
5611
  const playSound = (key2, point, volume, detail) => {
5588
5612
  destructionSound?.onSound(key2, point, volume, detail);
5589
5613
  if (detail) options.onSound?.(key2, point, volume, detail);
@@ -6588,10 +6612,21 @@ function createTestRoom(options) {
6588
6612
  return { ...pose, position: pose.at(camDistance), free: camDistance };
6589
6613
  };
6590
6614
  const thirdActive = () => cameraMode === "third" && avatar !== null;
6615
+ const firstPersonArms = options.firstPersonArms ?? null;
6616
+ if (firstPersonArms) {
6617
+ firstPersonArms.root.visible = cameraMode === "first";
6618
+ scene.add(firstPersonArms.root);
6619
+ }
6591
6620
  const syncAvatarVisible = () => {
6621
+ if (firstPersonArms) firstPersonArms.root.visible = cameraMode === "first";
6592
6622
  if (!avatar) return;
6593
6623
  avatar.root.visible = cameraMode === "third" || !!avatar.eye;
6594
- avatar.setView?.(cameraMode, camera);
6624
+ avatar.setView?.(cameraMode, camera, { arms: firstPersonArms !== null });
6625
+ };
6626
+ const updateFirstPersonArms = (dt) => {
6627
+ if (!firstPersonArms || cameraMode !== "first") return;
6628
+ firstPersonArms.update(dt, { camera, targets: lastHand.targets, stance: lastHand.stance, speed: player.speed, running: avatarState.running, crouch: avatarState.crouch });
6629
+ firstPersonArms.root.traverse((node) => node.layers.set(FIRST_PERSON_LAYER));
6595
6630
  };
6596
6631
  const setCameraMode = (mode) => {
6597
6632
  if (mode !== "first" && mode !== "third") return;
@@ -6675,6 +6710,39 @@ function createTestRoom(options) {
6675
6710
  };
6676
6711
  let handSource = null;
6677
6712
  let muzzleSource = null;
6713
+ let viewmodelFov = null;
6714
+ const firstPersonCamera = new THREE.PerspectiveCamera(72, 1, 0.01, 30);
6715
+ firstPersonCamera.layers.set(FIRST_PERSON_LAYER);
6716
+ let firstPersonPasses = 0;
6717
+ const drawFirstPersonLayer = () => {
6718
+ if (!firstPersonArms && viewmodelFov === null) return;
6719
+ const renderer2 = gl;
6720
+ if (typeof renderer2.clearDepth !== "function" || typeof renderer2.render !== "function") return;
6721
+ if (firstPersonPasses++ % 60 === 0) {
6722
+ scene.traverse((node) => {
6723
+ if (node.isLight) node.layers.enable(FIRST_PERSON_LAYER);
6724
+ });
6725
+ }
6726
+ firstPersonCamera.position.copy(camera.position);
6727
+ firstPersonCamera.quaternion.copy(camera.quaternion);
6728
+ const fov = viewmodelFov ?? camera.fov;
6729
+ if (firstPersonCamera.fov !== fov || firstPersonCamera.aspect !== camera.aspect) {
6730
+ firstPersonCamera.fov = fov;
6731
+ firstPersonCamera.aspect = camera.aspect;
6732
+ firstPersonCamera.updateProjectionMatrix();
6733
+ }
6734
+ firstPersonCamera.updateMatrixWorld();
6735
+ const { autoClear } = renderer2;
6736
+ const { background, fog } = scene;
6737
+ renderer2.autoClear = false;
6738
+ scene.background = null;
6739
+ scene.fog = null;
6740
+ renderer2.clearDepth();
6741
+ renderer2.render(scene, firstPersonCamera);
6742
+ scene.background = background;
6743
+ scene.fog = fog;
6744
+ renderer2.autoClear = autoClear ?? true;
6745
+ };
6678
6746
  let debugView = null;
6679
6747
  let lastHand = { stance: "relaxed", triggerFinger: null, targets: null };
6680
6748
  const strikeClips = options.strikeClips ?? DEFAULT_STRIKE_CLIPS;
@@ -6822,7 +6890,7 @@ function createTestRoom(options) {
6822
6890
  const line = new THREE.Line(g, tracerMat);
6823
6891
  line.frustumCulled = false;
6824
6892
  scene.add(line);
6825
- tr = { line, life: 0 };
6893
+ tr = { line, life: 0, follows: false };
6826
6894
  tracers.push(tr);
6827
6895
  }
6828
6896
  const attr = tr.line.geometry.getAttribute("position");
@@ -6831,6 +6899,7 @@ function createTestRoom(options) {
6831
6899
  attr.needsUpdate = true;
6832
6900
  tr.line.visible = true;
6833
6901
  tr.life = 0.07;
6902
+ tr.follows = muzzleSource !== null;
6834
6903
  };
6835
6904
  const fireZones = [];
6836
6905
  const burningStains = [];
@@ -8146,10 +8215,16 @@ function createTestRoom(options) {
8146
8215
  }
8147
8216
  };
8148
8217
  const simulateAfterModules = (dt) => {
8218
+ const drawn = tracers.some((tr) => tr.life > 0 && tr.follows) ? muzzleSource?.() ?? null : null;
8149
8219
  for (const tr of tracers) {
8150
8220
  if (tr.life > 0) {
8151
8221
  tr.life -= dt;
8152
8222
  if (tr.life <= 0) tr.line.visible = false;
8223
+ else if (tr.follows && drawn) {
8224
+ const attr = tr.line.geometry.getAttribute("position");
8225
+ attr.setXYZ(0, drawn.position[0], drawn.position[1], drawn.position[2]);
8226
+ attr.needsUpdate = true;
8227
+ }
8153
8228
  }
8154
8229
  }
8155
8230
  flush();
@@ -8183,6 +8258,7 @@ function createTestRoom(options) {
8183
8258
  };
8184
8259
  const updatePresent = (dt) => {
8185
8260
  reachAvatar();
8261
+ updateFirstPersonArms(dt);
8186
8262
  if (progress && simTime - progress.at > 0.25) progress = null;
8187
8263
  ui?.flushLog();
8188
8264
  hudAcc += dt;
@@ -8532,6 +8608,9 @@ function createTestRoom(options) {
8532
8608
  if (handSource === source) handSource = null;
8533
8609
  };
8534
8610
  },
8611
+ setViewmodelFov(degrees) {
8612
+ viewmodelFov = degrees;
8613
+ },
8535
8614
  setMuzzleSource(source) {
8536
8615
  muzzleSource = source;
8537
8616
  return () => {
@@ -9263,7 +9342,9 @@ function createTestRoom(options) {
9263
9342
  for (const batcher of batchers.values()) batcher.update();
9264
9343
  const restoreCamera = room.applyCamera();
9265
9344
  graphics?.beforeRender(camera);
9266
- gl.render(scene, debugView ?? moduleViews.main(camera));
9345
+ const view = debugView ?? moduleViews.main(camera);
9346
+ gl.render(scene, view);
9347
+ if (view === camera && cameraMode === "first") drawFirstPersonLayer();
9267
9348
  moduleViews.render(scene);
9268
9349
  graphics?.afterRender();
9269
9350
  restoreCamera();