@adatechnology/game-characters-three 0.3.0 → 0.3.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
@@ -4212,7 +4212,17 @@ var player_avatar_default = {
4212
4212
  fem: false,
4213
4213
  life: 1,
4214
4214
  hs: "short",
4215
- hair: "2a1e16"
4215
+ hair: "2a1e16",
4216
+ pose: {
4217
+ armL: 0,
4218
+ armR: 0,
4219
+ elbL: -0.12,
4220
+ elbR: -0.12,
4221
+ armOut: 0.11,
4222
+ lean: 0.04,
4223
+ headX: 0,
4224
+ headZ: 0
4225
+ }
4216
4226
  },
4217
4227
  shirtColor: "3d5a73"
4218
4228
  };
@@ -4223,9 +4233,12 @@ var MAX_GAIT = 1.4;
4223
4233
  var CLIP_BLEND = 0.12;
4224
4234
  var FALL_SECONDS2 = 0.3;
4225
4235
  var HIP_HEIGHT = 0.95;
4226
- var WALK_ARM = 0.45;
4236
+ var WALK_ARM = 0.28;
4227
4237
  var WALK_BOB = 0.035;
4228
4238
  var WALK_LEAN = 0.04;
4239
+ var RUN_LEAN = 0.16;
4240
+ var RUN_BOB = 0.05;
4241
+ var REST_ARM_Z = 0.18;
4229
4242
  var CROUCH = { thigh: -0.95, thighWalk: 0.3, shin: 1.9, lean: 0.25, drop: -0.35 };
4230
4243
  var AIMED = { shoulder: -1.42, perAim: 0.85, swing: 0.02, zRight: -0.54, zLeft: 0.36, elbowRight: -0.04, elbowLeft: -0.12 };
4231
4244
  var DOWN = { thighWalk: 0.5, shinSwing: 0.85, shinBend: 1.3, armHigh: -2.8, armLow: -0.35, armWave: 0.3, armZ: 0.5, armZWave: 0.3, tilt: 1.5, roll: 0.3, hipY: 0.16, hipZ: 0.6, hipZFlip: 1.2 };
@@ -4234,7 +4247,18 @@ var hexOf = (value) => typeof value === "string" ? Number.parseInt(value, 16) :
4234
4247
  var clamp = (value, min, max) => Math.min(max, Math.max(min, value));
4235
4248
  var fract = (value) => value - Math.floor(value);
4236
4249
  var createPlayerAvatar = (THREE, options = {}) => {
4237
- const spec = { ...player_avatar_default.spec, ...options.spec };
4250
+ const pose = {
4251
+ armL: 0,
4252
+ armR: 0,
4253
+ elbL: -0.08,
4254
+ elbR: -0.08,
4255
+ lean: 0.04,
4256
+ headX: 0,
4257
+ headZ: 0,
4258
+ ...player_avatar_default.spec.pose,
4259
+ ...options.spec?.pose
4260
+ };
4261
+ const spec = { ...player_avatar_default.spec, ...options.spec, pose };
4238
4262
  for (const key of ["skin", "hair"]) if (typeof spec[key] === "string") spec[key] = hexOf(spec[key]);
4239
4263
  const best = createBestBuilder(THREE, { types: [{ name: String(spec.type), eye: 0 }], random: createRng4(Number(spec.seed ?? 1)) });
4240
4264
  const body = best.build(spec);
@@ -4269,6 +4293,41 @@ var createPlayerAvatar = (THREE, options = {}) => {
4269
4293
  sockets[side].position.set(HAND_OFFSET.x, HAND_OFFSET.y, HAND_OFFSET.z);
4270
4294
  armOf[side].el.add(sockets[side]);
4271
4295
  }
4296
+ const addMesh = (parent, geometry, material, x = 0, y = 0, z = 0, rx = 0, ry = 0, rz = 0) => {
4297
+ const mesh = new THREE.Mesh(geometry, material);
4298
+ mesh.position.set(x, y, z);
4299
+ if (rx || ry || rz) mesh.rotation.set(rx, ry, rz);
4300
+ mesh.castShadow = true;
4301
+ mesh.receiveShadow = true;
4302
+ parent.add(mesh);
4303
+ return mesh;
4304
+ };
4305
+ const hands = [];
4306
+ rig.arms.forEach((arm, index) => {
4307
+ const el = arm.el;
4308
+ const side = index === 0 ? 1 : -1;
4309
+ const oldHand = meshesOf(el).find((mesh) => Math.abs(mesh.position.y + 0.33) < 0.025);
4310
+ const handMaterial = oldHand?.material ?? new THREE.MeshLambertMaterial({ color: colors.skin });
4311
+ if (oldHand) {
4312
+ oldHand.geometry?.dispose();
4313
+ el.remove(oldHand);
4314
+ }
4315
+ const hg = new THREE.Group();
4316
+ hg.name = side > 0 ? "hand_group_L" : "hand_group_R";
4317
+ hg.position.set(side * 0.02, -0.3, 0.01);
4318
+ el.add(hg);
4319
+ const palm = addMesh(hg, new THREE.SphereGeometry(0.048, 14, 10), handMaterial, 0, -0.035, 0);
4320
+ palm.scale.set(0.6, 1.05, 1);
4321
+ const built = buildHand({ THREE, add: addMesh, hg, handM: handMaterial, s: side, detailed: true });
4322
+ hands.push({ side, hg, fingers: built.fingers, th: built.th });
4323
+ });
4324
+ const setHandGrip = (hand, grip, wristX = 0) => {
4325
+ hand.fingers.forEach((finger, j) => {
4326
+ finger.rotation.z = -hand.side * grip * (j % 2 ? 1.1 : 0.9);
4327
+ });
4328
+ if (hand.th) hand.th.rotation.z = -hand.side * (0.32 + grip * 0.25);
4329
+ hand.hg.rotation.x = wristX;
4330
+ };
4272
4331
  const legRestX = rig.legs.map((leg) => leg.g.position.x);
4273
4332
  const legSide = (index) => index === 0 ? 1 : -1;
4274
4333
  let cycles = 0;
@@ -4310,6 +4369,42 @@ var createPlayerAvatar = (THREE, options = {}) => {
4310
4369
  });
4311
4370
  return { armR: shoulder, armL: shoulder, armRz: AIMED.zRight, armLz: AIMED.zLeft, elbR: AIMED.elbowRight, elbL: AIMED.elbowLeft };
4312
4371
  };
4372
+ const holdingPose = (gait, itemUse) => {
4373
+ const bob = Math.sin(cycles * TWO_PI) * 0.05 * gait;
4374
+ if (!itemUse) {
4375
+ return { armL: -0.45 + bob, armLz: 0.22, elbL: -1.05 };
4376
+ }
4377
+ const { id, position, rotation } = itemUse;
4378
+ if (id === "drink" || id === "sip" || id === "chug") {
4379
+ const raise2 = clamp((position[1] + 0.2) / 0.22, 0, 1);
4380
+ const tilt3 = clamp(Math.abs(rotation[0]) / 1.22, 0, 1.15);
4381
+ return {
4382
+ armL: -0.45 - 0.95 * raise2 - 0.22 * tilt3,
4383
+ armLz: 0.22 + 0.44 * raise2,
4384
+ elbL: -1.05 - 0.85 * raise2 + 0.12 * tilt3,
4385
+ headX: -0.26 * tilt3
4386
+ };
4387
+ }
4388
+ if (id === "open" || id === "close") {
4389
+ const reach = clamp((0.22 - position[0]) / 0.12, 0, 1);
4390
+ return {
4391
+ armL: -0.45 - 0.35 * reach,
4392
+ armLz: 0.22 + 0.28 * reach,
4393
+ elbL: -1.05 - 0.25 * reach,
4394
+ armR: -0.78 * reach,
4395
+ armRz: -0.48 * reach,
4396
+ elbR: -1.25 * reach
4397
+ };
4398
+ }
4399
+ const raise = clamp((position[1] + 0.2) / 0.25, 0, 1);
4400
+ const tilt2 = clamp(Math.abs(rotation[0]) / 1.75, 0, 1.2);
4401
+ const ext = Math.max(raise, tilt2 * 0.75);
4402
+ return {
4403
+ armL: -0.45 - 0.48 * ext,
4404
+ armLz: 0.22 + 0.08 * ext,
4405
+ elbL: -1.05 + 0.38 * ext
4406
+ };
4407
+ };
4313
4408
  const resetLegYaw = () => {
4314
4409
  rig.legs.forEach((leg, index) => {
4315
4410
  leg.g.rotation.y = 0;
@@ -4317,6 +4412,32 @@ var createPlayerAvatar = (THREE, options = {}) => {
4317
4412
  leg.g.position.z = 0;
4318
4413
  });
4319
4414
  };
4415
+ const runningPose = (gait, busyHands = false) => {
4416
+ const ph = cycles * TWO_PI;
4417
+ const sine = Math.sin(ph);
4418
+ const cosine = Math.cos(ph);
4419
+ const legL = sine * 0.65 * gait;
4420
+ const legR = -sine * 0.65 * gait;
4421
+ const kneeL = Math.max(0, -cosine) * 1.15 * gait;
4422
+ const kneeR = Math.max(0, cosine) * 1.15 * gait;
4423
+ const targets = {
4424
+ lean: RUN_LEAN * Math.min(1, gait),
4425
+ drop: Math.abs(cosine) * RUN_BOB * gait,
4426
+ legL,
4427
+ legR,
4428
+ kneeL,
4429
+ kneeR
4430
+ };
4431
+ if (!busyHands) {
4432
+ targets.armR = -0.32 - sine * 0.65 * gait;
4433
+ targets.armL = -0.32 + sine * 0.65 * gait;
4434
+ targets.elbR = -1.25 + Math.max(0, sine) * 0.3 * gait;
4435
+ targets.elbL = -1.25 + Math.max(0, -sine) * 0.3 * gait;
4436
+ targets.armRz = 0.22;
4437
+ targets.armLz = -0.22;
4438
+ }
4439
+ return targets;
4440
+ };
4320
4441
  const crouchPose = (gait) => {
4321
4442
  const swing = (leg) => {
4322
4443
  const legS = legSide(leg);
@@ -4412,23 +4533,44 @@ var createPlayerAvatar = (THREE, options = {}) => {
4412
4533
  update(dt, state = {}) {
4413
4534
  const speed = state.speed ?? 0;
4414
4535
  const moving = speed >= 0.05;
4415
- if (moving) cycles += dt * walkCadence(speed);
4536
+ const down = !!state.down;
4537
+ const running = Boolean(state.running && moving && !down && !state.crouch);
4538
+ if (moving) cycles += dt * (running ? walkCadence(speed) * 1.3 : walkCadence(speed));
4416
4539
  const gait = Math.min(MAX_GAIT, walkGait(speed));
4417
- profile.arm = WALK_ARM * gait;
4418
- profile.bob = WALK_BOB * gait;
4419
- time = cycles / walkCadence(Math.max(speed, 0));
4540
+ profile.arm = (running ? 0.55 : WALK_ARM) * gait;
4541
+ profile.bob = (running ? RUN_BOB : WALK_BOB) * gait;
4542
+ time = cycles / (walkCadence(Math.max(speed, 0)) * (running ? 1.3 : 1));
4420
4543
  animator.animate(body, time, { speed });
4421
- const down = !!state.down;
4422
4544
  fall = fallSeconds <= 0 ? down ? 1 : 0 : clamp(fall + (down ? dt : -dt) / fallSeconds, 0, 1);
4423
4545
  resetLegYaw();
4424
4546
  if (down) animator.setPose(rig, downPose());
4425
4547
  else {
4548
+ if (running) animator.setPose(rig, runningPose(gait, Boolean(state.armed || state.holding || state.itemUse)));
4426
4549
  if (state.crouch) animator.setPose(rig, crouchPose(gait));
4427
4550
  if (state.armed) animator.setPose(rig, armed(state.pitch ?? 0, gait, state.hip ?? 0));
4551
+ else if (state.holding || state.itemUse) animator.setPose(rig, holdingPose(gait, state.itemUse));
4552
+ else if (!running) {
4553
+ animator.setPose(rig, {
4554
+ armRz: REST_ARM_Z,
4555
+ armLz: -REST_ARM_Z,
4556
+ elbR: -0.12,
4557
+ elbL: -0.12
4558
+ });
4559
+ }
4428
4560
  }
4429
4561
  placeBody(fall);
4430
4562
  stepClip(dt, down);
4431
4563
  if (smooth) animator.cascade(rig, dt);
4564
+ const clipId = run ? run.clip.id : null;
4565
+ const ph = cycles * TWO_PI;
4566
+ hands.forEach((hand) => {
4567
+ const isRight = hand.side < 0;
4568
+ const holdRight = isRight && (!!state.holding || !!state.itemUse);
4569
+ const holdLeft = !isRight && (state.itemUse?.id === "open" || state.itemUse?.id === "close");
4570
+ const grip = clipId === "punch_right" ? 1.4 : clipId === "shove_two_hands" ? 0.15 : state.armed || holdRight || holdLeft ? 1.22 : running ? 0.85 : 0.12;
4571
+ const wristSwing = holdRight || state.armed || running ? 0 : -Math.min(1, gait) * Math.sin(ph - 0.6) * 0.12 * hand.side;
4572
+ setHandGrip(hand, grip, wristSwing);
4573
+ });
4432
4574
  },
4433
4575
  play(clip, playOptions = {}) {
4434
4576
  const found = typeof clip === "string" ? clips.get(clip) : clip;
@@ -4490,7 +4632,7 @@ var first_person_arms_default = {
4490
4632
  },
4491
4633
  stances: {
4492
4634
  relaxed: {
4493
- R: { p: [0.2, -0.2, -0.36], r: [0.2, 1.45, -0.4], grip: 0.35 },
4635
+ R: { p: [0.2, -0.22, -0.36], r: [0.05, 1.57, -0.05], grip: 0.2 },
4494
4636
  L: "mirror"
4495
4637
  },
4496
4638
  fists: {
@@ -4634,6 +4776,10 @@ var CONTACT_MARGIN = 5e-3;
4634
4776
  var CONTACT_PALM = 0.03;
4635
4777
  var FOOT_LENGTH = 0.24;
4636
4778
  var FOOT_SHOWN = 1e-3;
4779
+ var AWAY_DROP = 0.55;
4780
+ var AWAY_OUT = 7;
4781
+ var AWAY_IN = 20;
4782
+ var AWAY_HIDDEN = 0.97;
4637
4783
  var FILL = 0.3;
4638
4784
  var FIRST_PERSON_STANCES = first_person_arms_default.stances;
4639
4785
  var FIRST_PERSON_RIG = first_person_arms_default.rig;
@@ -4747,7 +4893,7 @@ function createFirstPersonArms(THREE, options = {}) {
4747
4893
  const cuff = limb(root, rig.radius.cuff, rig.radius.cuff, 0.03, materials.cuff);
4748
4894
  const elbow = ball(root, rig.radius.elbow * 1.02, materials.sleeve);
4749
4895
  elbow.name = `first-person-elbow-${side}`;
4750
- arms[side] = { side, sign, hand, anchor, upper, fore, cuff, elbow, shown: newPose(THREE), from: newPose(THREE), mode: null, blend: 1, drawn: newPose(THREE), joints: { shoulder: new THREE.Vector3(), elbow: new THREE.Vector3(), wrist: new THREE.Vector3() } };
4896
+ arms[side] = { side, sign, hand, anchor, upper, fore, cuff, elbow, shown: newPose(THREE), from: newPose(THREE), mode: null, blend: 1, drawn: newPose(THREE), joints: { shoulder: new THREE.Vector3(), elbow: new THREE.Vector3(), wrist: new THREE.Vector3() }, away: options.hideWhenIdle ? 1 : 0 };
4751
4897
  }
4752
4898
  const leg = new THREE.Group();
4753
4899
  leg.name = "first-person-leg";
@@ -4841,6 +4987,7 @@ function createFirstPersonArms(THREE, options = {}) {
4841
4987
  const desired = newPose(THREE);
4842
4988
  const channelPose = newPose(THREE);
4843
4989
  const mixed = newPose(THREE);
4990
+ const dropped = newPose(THREE);
4844
4991
  let indexCurl;
4845
4992
  const bone = createTwoBone(THREE);
4846
4993
  const shoulder = new THREE.Vector3();
@@ -4965,11 +5112,22 @@ function createFirstPersonArms(THREE, options = {}) {
4965
5112
  if (arm.blend >= 1) copyPose(arm.shown, desired);
4966
5113
  else mixPose(THREE, arm.shown, arm.from, desired, ease(arm.blend));
4967
5114
  const channel = sample?.[side];
5115
+ let pose;
4968
5116
  if (channel && channel.w > 0) {
4969
5117
  fromChannel(channel, side, arm.shown, channelPose);
4970
5118
  mixPose(THREE, mixed, arm.shown, channelPose, channel.w);
4971
- drawArm(arm, mode === "target" ? mixed : keepOutside(mixed, handReach(mixed)));
4972
- } else drawArm(arm, mode === "target" ? arm.shown : keepOutside(arm.shown, handReach(arm.shown)));
5119
+ pose = mode === "target" ? mixed : keepOutside(mixed, handReach(mixed));
5120
+ } else pose = mode === "target" ? arm.shown : keepOutside(arm.shown, handReach(arm.shown));
5121
+ const idle = options.hideWhenIdle === true && mode === "rest:relaxed" && !(channel && channel.w > 0);
5122
+ arm.away = options.hideWhenIdle ? Math.min(1, Math.max(0, arm.away + ((idle ? 1 : 0) - arm.away) * Math.min(1, dt * (idle ? AWAY_OUT : AWAY_IN)))) : 0;
5123
+ if (arm.away > 0) {
5124
+ copyPose(dropped, pose);
5125
+ dropped.p.y -= AWAY_DROP * ease(arm.away);
5126
+ pose = dropped;
5127
+ }
5128
+ drawArm(arm, pose);
5129
+ const shown = arm.away < AWAY_HIDDEN;
5130
+ for (const part of [arm.anchor, arm.upper, arm.fore, arm.cuff, arm.elbow]) part.visible = shown;
4973
5131
  }
4974
5132
  const foot = sample?.F;
4975
5133
  leg.visible = !!foot && foot.w > FOOT_SHOWN;
@@ -5016,6 +5174,7 @@ var toRoomAvatar = (avatar, options = {}) => {
5016
5174
  const arms = options.firstPerson === false ? null : createFirstPersonArms(avatar.three, {
5017
5175
  colors: { skin: avatar.colors.skin, sleeve: avatar.colors.longSleeves ? avatar.colors.shirt : avatar.colors.skin, trouser: avatar.colors.trousers, shoe: avatar.colors.shoes, ...options.firstPerson?.colors },
5018
5176
  clips: options.firstPersonClips ?? FIRST_PERSON_CLIPS,
5177
+ hideWhenIdle: true,
5019
5178
  ...options.firstPerson
5020
5179
  });
5021
5180
  const strikes = new Map((options.strikeClips ?? ATTACK_CLIPS).map((clip) => [clip.id, clip]));
@@ -5030,7 +5189,16 @@ var toRoomAvatar = (avatar, options = {}) => {
5030
5189
  avatar,
5031
5190
  arms,
5032
5191
  ...arms ? { firstPerson: { root: arms.root, update: (dt, state) => arms.update(dt, state) } } : {},
5033
- update: (dt, state) => avatar.update(dt, { speed: state.speed, running: state.running, crouch: state.crouch, down: state.down, armed: state.armed, pitch: -state.pitch }),
5192
+ update: (dt, state) => avatar.update(dt, {
5193
+ speed: state.speed,
5194
+ running: state.running,
5195
+ crouch: state.crouch,
5196
+ down: state.down,
5197
+ armed: state.armed,
5198
+ pitch: -state.pitch,
5199
+ ...state.holding !== void 0 ? { holding: state.holding } : {},
5200
+ ...state.itemUse !== void 0 ? { itemUse: state.itemUse } : {}
5201
+ }),
5034
5202
  hand: (side) => avatar.hand(side),
5035
5203
  strike: (clipId, strikeOptions) => {
5036
5204
  const clip = strikes.get(clipId);