@adatechnology/game-test-room 0.27.0 → 0.28.1

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();
@@ -5605,7 +5627,9 @@ function createTestRoom(options) {
5605
5627
  profile: quality,
5606
5628
  ...options.debris?.particles ? { sprites: { kinds: patchSpriteKinds(SPRITE_KINDS, options.debris.particles) } } : {},
5607
5629
  groundAt,
5608
- marklessAt: (x, z) => terrain.waterAt(x, z) !== null
5630
+ marklessAt: (x, z) => terrain.waterAt(x, z) !== null,
5631
+ // the dirt crater of the effects only where the ground is loose; rock, asphalt and a slab keep the soot and the bowl the terrain itself dug
5632
+ cratersAt: (x, z) => terrain.material(terrain.columnAt(x, z).material).reposeDegrees !== void 0
5609
5633
  })
5610
5634
  });
5611
5635
  const renderer = createDestructionRenderer(THREE, {
@@ -6590,10 +6614,21 @@ function createTestRoom(options) {
6590
6614
  return { ...pose, position: pose.at(camDistance), free: camDistance };
6591
6615
  };
6592
6616
  const thirdActive = () => cameraMode === "third" && avatar !== null;
6617
+ const firstPersonArms = options.firstPersonArms ?? null;
6618
+ if (firstPersonArms) {
6619
+ firstPersonArms.root.visible = cameraMode === "first";
6620
+ scene.add(firstPersonArms.root);
6621
+ }
6593
6622
  const syncAvatarVisible = () => {
6623
+ if (firstPersonArms) firstPersonArms.root.visible = cameraMode === "first";
6594
6624
  if (!avatar) return;
6595
6625
  avatar.root.visible = cameraMode === "third" || !!avatar.eye;
6596
- avatar.setView?.(cameraMode, camera);
6626
+ avatar.setView?.(cameraMode, camera, { arms: firstPersonArms !== null });
6627
+ };
6628
+ const updateFirstPersonArms = (dt) => {
6629
+ if (!firstPersonArms || cameraMode !== "first") return;
6630
+ firstPersonArms.update(dt, { camera, targets: lastHand.targets, stance: lastHand.stance, speed: player.speed, running: avatarState.running, crouch: avatarState.crouch });
6631
+ firstPersonArms.root.traverse((node) => node.layers.set(FIRST_PERSON_LAYER));
6597
6632
  };
6598
6633
  const setCameraMode = (mode) => {
6599
6634
  if (mode !== "first" && mode !== "third") return;
@@ -6677,6 +6712,39 @@ function createTestRoom(options) {
6677
6712
  };
6678
6713
  let handSource = null;
6679
6714
  let muzzleSource = null;
6715
+ let viewmodelFov = null;
6716
+ const firstPersonCamera = new THREE.PerspectiveCamera(72, 1, 0.01, 30);
6717
+ firstPersonCamera.layers.set(FIRST_PERSON_LAYER);
6718
+ let firstPersonPasses = 0;
6719
+ const drawFirstPersonLayer = () => {
6720
+ if (!firstPersonArms && viewmodelFov === null) return;
6721
+ const renderer2 = gl;
6722
+ if (typeof renderer2.clearDepth !== "function" || typeof renderer2.render !== "function") return;
6723
+ if (firstPersonPasses++ % 60 === 0) {
6724
+ scene.traverse((node) => {
6725
+ if (node.isLight) node.layers.enable(FIRST_PERSON_LAYER);
6726
+ });
6727
+ }
6728
+ firstPersonCamera.position.copy(camera.position);
6729
+ firstPersonCamera.quaternion.copy(camera.quaternion);
6730
+ const fov = viewmodelFov ?? camera.fov;
6731
+ if (firstPersonCamera.fov !== fov || firstPersonCamera.aspect !== camera.aspect) {
6732
+ firstPersonCamera.fov = fov;
6733
+ firstPersonCamera.aspect = camera.aspect;
6734
+ firstPersonCamera.updateProjectionMatrix();
6735
+ }
6736
+ firstPersonCamera.updateMatrixWorld();
6737
+ const { autoClear } = renderer2;
6738
+ const { background, fog } = scene;
6739
+ renderer2.autoClear = false;
6740
+ scene.background = null;
6741
+ scene.fog = null;
6742
+ renderer2.clearDepth();
6743
+ renderer2.render(scene, firstPersonCamera);
6744
+ scene.background = background;
6745
+ scene.fog = fog;
6746
+ renderer2.autoClear = autoClear ?? true;
6747
+ };
6680
6748
  let debugView = null;
6681
6749
  let lastHand = { stance: "relaxed", triggerFinger: null, targets: null };
6682
6750
  const strikeClips = options.strikeClips ?? DEFAULT_STRIKE_CLIPS;
@@ -6824,7 +6892,7 @@ function createTestRoom(options) {
6824
6892
  const line = new THREE.Line(g, tracerMat);
6825
6893
  line.frustumCulled = false;
6826
6894
  scene.add(line);
6827
- tr = { line, life: 0 };
6895
+ tr = { line, life: 0, follows: false };
6828
6896
  tracers.push(tr);
6829
6897
  }
6830
6898
  const attr = tr.line.geometry.getAttribute("position");
@@ -6833,6 +6901,7 @@ function createTestRoom(options) {
6833
6901
  attr.needsUpdate = true;
6834
6902
  tr.line.visible = true;
6835
6903
  tr.life = 0.07;
6904
+ tr.follows = muzzleSource !== null;
6836
6905
  };
6837
6906
  const fireZones = [];
6838
6907
  const burningStains = [];
@@ -8148,10 +8217,16 @@ function createTestRoom(options) {
8148
8217
  }
8149
8218
  };
8150
8219
  const simulateAfterModules = (dt) => {
8220
+ const drawn = tracers.some((tr) => tr.life > 0 && tr.follows) ? muzzleSource?.() ?? null : null;
8151
8221
  for (const tr of tracers) {
8152
8222
  if (tr.life > 0) {
8153
8223
  tr.life -= dt;
8154
8224
  if (tr.life <= 0) tr.line.visible = false;
8225
+ else if (tr.follows && drawn) {
8226
+ const attr = tr.line.geometry.getAttribute("position");
8227
+ attr.setXYZ(0, drawn.position[0], drawn.position[1], drawn.position[2]);
8228
+ attr.needsUpdate = true;
8229
+ }
8155
8230
  }
8156
8231
  }
8157
8232
  flush();
@@ -8185,6 +8260,7 @@ function createTestRoom(options) {
8185
8260
  };
8186
8261
  const updatePresent = (dt) => {
8187
8262
  reachAvatar();
8263
+ updateFirstPersonArms(dt);
8188
8264
  if (progress && simTime - progress.at > 0.25) progress = null;
8189
8265
  ui?.flushLog();
8190
8266
  hudAcc += dt;
@@ -8534,6 +8610,9 @@ function createTestRoom(options) {
8534
8610
  if (handSource === source) handSource = null;
8535
8611
  };
8536
8612
  },
8613
+ setViewmodelFov(degrees) {
8614
+ viewmodelFov = degrees;
8615
+ },
8537
8616
  setMuzzleSource(source) {
8538
8617
  muzzleSource = source;
8539
8618
  return () => {
@@ -9265,7 +9344,9 @@ function createTestRoom(options) {
9265
9344
  for (const batcher of batchers.values()) batcher.update();
9266
9345
  const restoreCamera = room.applyCamera();
9267
9346
  graphics?.beforeRender(camera);
9268
- gl.render(scene, debugView ?? moduleViews.main(camera));
9347
+ const view = debugView ?? moduleViews.main(camera);
9348
+ gl.render(scene, view);
9349
+ if (view === camera && cameraMode === "first") drawFirstPersonLayer();
9269
9350
  moduleViews.render(scene);
9270
9351
  graphics?.afterRender();
9271
9352
  restoreCamera();