@adatechnology/game-test-room 0.27.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
@@ -3,7 +3,7 @@ import { createDestruction, JOINT_DEFAULTS, resolveStrings as resolveDestruction
3
3
  import { createAudioEngine, createAudioSink, loadKitSamples, loadUserSamples } from "@adatechnology/game-audio";
4
4
  import { registerFittedSounds } from "@adatechnology/game-audio/fitted";
5
5
  import { createDestructionRenderer, createDestructionSound, dragSoundKey, impactKey, impactSoundIds, impactSoundKeys, specFromObject3D } from "@adatechnology/game-destruction-three";
6
- import { bodyMass, KNOCK_CHEST, KNOCK_DOWN_SPEED, knockOf, surfaceOfMaterial } from "@adatechnology/game-contracts";
6
+ import { bodyMass, FIRST_PERSON_LAYER, KNOCK_CHEST, KNOCK_DOWN_SPEED, knockOf, surfaceOfMaterial } from "@adatechnology/game-contracts";
7
7
 
8
8
  // src/body-sounds.ts
9
9
  import { BODY_FOLEY_BANK } from "@adatechnology/game-audio";
@@ -2154,6 +2154,7 @@ function createNarrator(c) {
2154
2154
 
2155
2155
  // src/player.ts
2156
2156
  import { stepKnock } from "@adatechnology/game-contracts";
2157
+ var RECOIL_RETURN = { share: 0.7, seconds: 0.25 };
2157
2158
  var SLAM_MIN_SPEED = 1.5;
2158
2159
  var LANDING_MIN_SPEED = 1;
2159
2160
  var EYE = 1.7;
@@ -2183,6 +2184,18 @@ function createPlayer(THREE, o) {
2183
2184
  const cam = o.camera;
2184
2185
  let yaw = 0;
2185
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
+ };
2186
2199
  let y = 0;
2187
2200
  let eye = EYE;
2188
2201
  let crouch = 0;
@@ -2524,6 +2537,7 @@ function createPlayer(THREE, o) {
2524
2537
  return stunLeft;
2525
2538
  },
2526
2539
  update(dt) {
2540
+ returnRecoil(dt);
2527
2541
  if (stunLeft > 0) {
2528
2542
  stunLeft = Math.max(0, stunLeft - dt);
2529
2543
  stunPhase += dt * 2.4;
@@ -2572,6 +2586,8 @@ function createPlayer(THREE, o) {
2572
2586
  },
2573
2587
  setPose(position, yw, pt) {
2574
2588
  knocked = null;
2589
+ recoilDebt.pitch = 0;
2590
+ recoilDebt.yaw = 0;
2575
2591
  px.x = position[0];
2576
2592
  px.z = position[2];
2577
2593
  floorLevel = floorHere();
@@ -2584,6 +2600,8 @@ function createPlayer(THREE, o) {
2584
2600
  },
2585
2601
  look(position, target) {
2586
2602
  knocked = null;
2603
+ recoilDebt.pitch = 0;
2604
+ recoilDebt.yaw = 0;
2587
2605
  px.x = position[0];
2588
2606
  px.z = position[2];
2589
2607
  floorLevel = floorHere();
@@ -2598,8 +2616,11 @@ function createPlayer(THREE, o) {
2598
2616
  apply();
2599
2617
  },
2600
2618
  kick(pitchDeg, yawDeg) {
2619
+ const before = pitch;
2601
2620
  pitch = Math.max(-1.5, Math.min(1.5, pitch + pitchDeg * Math.PI / 180));
2602
2621
  yaw += yawDeg * Math.PI / 180;
2622
+ recoilDebt.pitch += (pitch - before) * recoilReturn.share;
2623
+ recoilDebt.yaw += yawDeg * Math.PI / 180 * recoilReturn.share;
2603
2624
  apply();
2604
2625
  },
2605
2626
  moveBy(dx, dz) {
@@ -5499,6 +5520,7 @@ function createTestRoom(options) {
5499
5520
  const scene = options.scene ?? new THREE.Scene();
5500
5521
  const camera = options.camera ?? new THREE.PerspectiveCamera(72, width() / height(), 0.05, 140);
5501
5522
  if (!options.camera) scene.add(camera);
5523
+ camera.layers.disable(FIRST_PERSON_LAYER);
5502
5524
  const resize = () => {
5503
5525
  const w = width();
5504
5526
  const h = height();
@@ -6590,10 +6612,21 @@ function createTestRoom(options) {
6590
6612
  return { ...pose, position: pose.at(camDistance), free: camDistance };
6591
6613
  };
6592
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
+ }
6593
6620
  const syncAvatarVisible = () => {
6621
+ if (firstPersonArms) firstPersonArms.root.visible = cameraMode === "first";
6594
6622
  if (!avatar) return;
6595
6623
  avatar.root.visible = cameraMode === "third" || !!avatar.eye;
6596
- 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));
6597
6630
  };
6598
6631
  const setCameraMode = (mode) => {
6599
6632
  if (mode !== "first" && mode !== "third") return;
@@ -6677,6 +6710,39 @@ function createTestRoom(options) {
6677
6710
  };
6678
6711
  let handSource = null;
6679
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
+ };
6680
6746
  let debugView = null;
6681
6747
  let lastHand = { stance: "relaxed", triggerFinger: null, targets: null };
6682
6748
  const strikeClips = options.strikeClips ?? DEFAULT_STRIKE_CLIPS;
@@ -6824,7 +6890,7 @@ function createTestRoom(options) {
6824
6890
  const line = new THREE.Line(g, tracerMat);
6825
6891
  line.frustumCulled = false;
6826
6892
  scene.add(line);
6827
- tr = { line, life: 0 };
6893
+ tr = { line, life: 0, follows: false };
6828
6894
  tracers.push(tr);
6829
6895
  }
6830
6896
  const attr = tr.line.geometry.getAttribute("position");
@@ -6833,6 +6899,7 @@ function createTestRoom(options) {
6833
6899
  attr.needsUpdate = true;
6834
6900
  tr.line.visible = true;
6835
6901
  tr.life = 0.07;
6902
+ tr.follows = muzzleSource !== null;
6836
6903
  };
6837
6904
  const fireZones = [];
6838
6905
  const burningStains = [];
@@ -8148,10 +8215,16 @@ function createTestRoom(options) {
8148
8215
  }
8149
8216
  };
8150
8217
  const simulateAfterModules = (dt) => {
8218
+ const drawn = tracers.some((tr) => tr.life > 0 && tr.follows) ? muzzleSource?.() ?? null : null;
8151
8219
  for (const tr of tracers) {
8152
8220
  if (tr.life > 0) {
8153
8221
  tr.life -= dt;
8154
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
+ }
8155
8228
  }
8156
8229
  }
8157
8230
  flush();
@@ -8185,6 +8258,7 @@ function createTestRoom(options) {
8185
8258
  };
8186
8259
  const updatePresent = (dt) => {
8187
8260
  reachAvatar();
8261
+ updateFirstPersonArms(dt);
8188
8262
  if (progress && simTime - progress.at > 0.25) progress = null;
8189
8263
  ui?.flushLog();
8190
8264
  hudAcc += dt;
@@ -8534,6 +8608,9 @@ function createTestRoom(options) {
8534
8608
  if (handSource === source) handSource = null;
8535
8609
  };
8536
8610
  },
8611
+ setViewmodelFov(degrees) {
8612
+ viewmodelFov = degrees;
8613
+ },
8537
8614
  setMuzzleSource(source) {
8538
8615
  muzzleSource = source;
8539
8616
  return () => {
@@ -9265,7 +9342,9 @@ function createTestRoom(options) {
9265
9342
  for (const batcher of batchers.values()) batcher.update();
9266
9343
  const restoreCamera = room.applyCamera();
9267
9344
  graphics?.beforeRender(camera);
9268
- 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();
9269
9348
  moduleViews.render(scene);
9270
9349
  graphics?.afterRender();
9271
9350
  restoreCamera();