@adatechnology/game-characters-three 0.6.0 → 0.7.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/README.md +1 -1
- package/dist/index.d.ts +164 -105
- package/dist/index.global.js +604 -331
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +522 -333
- package/dist/index.js.map +1 -1
- package/package.json +9 -9
package/dist/index.js
CHANGED
|
@@ -993,7 +993,7 @@ var createBestBuilder = (host, { types, random = Math.random }) => {
|
|
|
993
993
|
});
|
|
994
994
|
}
|
|
995
995
|
const neckLen = 0.14 + Math.max(0, P.neck);
|
|
996
|
-
|
|
996
|
+
const neck = cut.head ? void 0 : add(U, CYL(0.058, 0.068, neckLen, SEG), skinM, 0, 1.63 + Math.max(0, P.neck) / 2, 0);
|
|
997
997
|
const headG = new THREE.Group();
|
|
998
998
|
headG.position.set(0, 1.64 + P.neck, P.headFwd || 0);
|
|
999
999
|
headG.rotation.x = P.headX;
|
|
@@ -1200,6 +1200,7 @@ var createBestBuilder = (host, { types, random = Math.random }) => {
|
|
|
1200
1200
|
if (o.userData.flap) flaps.push(o);
|
|
1201
1201
|
});
|
|
1202
1202
|
const rig = { flaps, dangles: arms.filter((a) => a.el.userData.dangle), type: spec.type || "Lento", fig, upper, headG, arms, legs, P, ph: spec.phase ?? options.random() * 6, dropBase: fig.position.y, leanBase: P.lean, hxBase: P.headX };
|
|
1203
|
+
if (neck) Object.defineProperty(rig, "neck", { value: neck });
|
|
1203
1204
|
if (spec.lying) {
|
|
1204
1205
|
root.rotation.x = -PI / 2;
|
|
1205
1206
|
root.position.set(0, 0.16 * P.s, 0.9 * P.s);
|
|
@@ -2674,6 +2675,7 @@ var ringWound = (three, materials, parent, radius, y = 0) => {
|
|
|
2674
2675
|
};
|
|
2675
2676
|
|
|
2676
2677
|
// src/wounds/flying.ts
|
|
2678
|
+
import { discardObject3D } from "@adatechnology/game-shapes-three";
|
|
2677
2679
|
var GRAVITY2 = 9.8;
|
|
2678
2680
|
var FLOOR_OFFSET = 0.08;
|
|
2679
2681
|
var BOUNCE_LIMIT = 1.2;
|
|
@@ -2686,7 +2688,10 @@ var createFlyingPieces = (three, { random, groundAt = () => 0, onRest, max = 40
|
|
|
2686
2688
|
const quaternion = new three.Quaternion();
|
|
2687
2689
|
const euler = new three.Euler();
|
|
2688
2690
|
const trim = () => {
|
|
2689
|
-
while (pieces.length > max)
|
|
2691
|
+
while (pieces.length > max) {
|
|
2692
|
+
const piece = pieces.shift();
|
|
2693
|
+
if (piece) discardObject3D(piece.object);
|
|
2694
|
+
}
|
|
2690
2695
|
};
|
|
2691
2696
|
const add = (object, velocity, spin, tag) => {
|
|
2692
2697
|
const piece = { object, velocity, spin, rest: false, ...tag ? { tag } : {} };
|
|
@@ -2735,7 +2740,7 @@ var createFlyingPieces = (three, { random, groundAt = () => 0, onRest, max = 40
|
|
|
2735
2740
|
}
|
|
2736
2741
|
},
|
|
2737
2742
|
clear() {
|
|
2738
|
-
pieces.splice(0).
|
|
2743
|
+
discardObject3D(pieces.splice(0).map((piece) => piece.object));
|
|
2739
2744
|
}
|
|
2740
2745
|
};
|
|
2741
2746
|
};
|
|
@@ -3751,7 +3756,8 @@ function createCharactersTestModule(options = {}) {
|
|
|
3751
3756
|
const makeKit = () => options.createKit ? options.createKit({ penetration: settings.penetration, deathRule: settings.deathRule }) : createCharacters({ ...options.packs ? { packs: options.packs } : {}, penetration: settings.penetration, damage: { deathRule: settings.deathRule } });
|
|
3752
3757
|
let kit = makeKit();
|
|
3753
3758
|
let undead = options.createUndead ? options.createUndead(kit) : null;
|
|
3754
|
-
|
|
3759
|
+
let stream = createRng3(options.seed ?? 1);
|
|
3760
|
+
const random = () => stream();
|
|
3755
3761
|
let seedCounter = 100;
|
|
3756
3762
|
let host = null;
|
|
3757
3763
|
let three = null;
|
|
@@ -4131,6 +4137,14 @@ function createCharactersTestModule(options = {}) {
|
|
|
4131
4137
|
wounds = createWounds(lent.THREE, { random, scene: scene2, groundAt: (x, z) => lent.groundAt(x, z), ...bridge ? { bridge } : {}, ...sound ? { sound } : {} });
|
|
4132
4138
|
for (const entry of entries.values()) trackEntry(entry);
|
|
4133
4139
|
const stopChange = lent.bench?.onChange(onChange);
|
|
4140
|
+
const stopReset = lent.onReset?.(() => {
|
|
4141
|
+
stream = createRng3(options.seed ?? 1);
|
|
4142
|
+
seedCounter = 100;
|
|
4143
|
+
time = 0;
|
|
4144
|
+
selected = null;
|
|
4145
|
+
lastCrossed = 0;
|
|
4146
|
+
lastEnergy = 1;
|
|
4147
|
+
});
|
|
4134
4148
|
const stopEvents = lent.on((event) => {
|
|
4135
4149
|
if (event.type !== "explosion") return;
|
|
4136
4150
|
for (const entry of entries.values()) {
|
|
@@ -4144,6 +4158,8 @@ function createCharactersTestModule(options = {}) {
|
|
|
4144
4158
|
time += dt;
|
|
4145
4159
|
for (const [id, entry] of entries) {
|
|
4146
4160
|
if (!entry.root.parent) {
|
|
4161
|
+
if (entry.body) wounds?.untrack(entry.body);
|
|
4162
|
+
if (selected === entry) selected = null;
|
|
4147
4163
|
entries.delete(id);
|
|
4148
4164
|
continue;
|
|
4149
4165
|
}
|
|
@@ -4155,6 +4171,7 @@ function createCharactersTestModule(options = {}) {
|
|
|
4155
4171
|
});
|
|
4156
4172
|
return () => {
|
|
4157
4173
|
stopChange?.();
|
|
4174
|
+
stopReset?.();
|
|
4158
4175
|
stopEvents();
|
|
4159
4176
|
stopFrame();
|
|
4160
4177
|
clearOverlays();
|
|
@@ -4201,6 +4218,7 @@ import {
|
|
|
4201
4218
|
filterPoseChannels,
|
|
4202
4219
|
samplePoseClip,
|
|
4203
4220
|
walkCadence,
|
|
4221
|
+
stepCascade as stepCascade2,
|
|
4204
4222
|
walkGait
|
|
4205
4223
|
} from "@adatechnology/game-characters";
|
|
4206
4224
|
|
|
@@ -4276,8 +4294,22 @@ var ARM_REACH = {
|
|
|
4276
4294
|
slack: 0.96,
|
|
4277
4295
|
/** Where the elbow points: down and out from the body, a little back (body space, x outward). */
|
|
4278
4296
|
elbowPole: [0.55, -1, -0.25],
|
|
4297
|
+
/** The support arm's elbow: under the gun, hardly out of the body (the first-person arms' `elbowPoleLeft`), so the forearm meets the handguard nearer the aim's line. */
|
|
4298
|
+
elbowPoleSupport: [0.1, -1, -0.2],
|
|
4279
4299
|
/** From the wrist joint to the middle of the palm, metres of the body. */
|
|
4280
|
-
palm: 0.042
|
|
4300
|
+
palm: 0.042,
|
|
4301
|
+
/** In a view the elbow keeps at least this interior bend where a hand is out of reach, right then left (the first-person arms' numbers). */
|
|
4302
|
+
viewBend: [1.35, 0.95],
|
|
4303
|
+
/** In a view a hand stays this far before a surface, metres. */
|
|
4304
|
+
contactMargin: 5e-3,
|
|
4305
|
+
/** In a view a hand is never nearer than this to the eye, metres. */
|
|
4306
|
+
contactNearest: 0.12,
|
|
4307
|
+
/** How far in front of the eye a surface is looked for, metres. */
|
|
4308
|
+
contactProbe: 1.4,
|
|
4309
|
+
/** How far a hand reaches forward of its middle at least (the thickness of the palm), and per metre of fingers pointing ahead. */
|
|
4310
|
+
contactPalm: 0.03,
|
|
4311
|
+
/** From the middle of the palm to the fingertips. */
|
|
4312
|
+
contactFingers: 0.085
|
|
4281
4313
|
};
|
|
4282
4314
|
var createArmReach = (THREE, rig, hands) => {
|
|
4283
4315
|
const arms = {
|
|
@@ -4298,11 +4330,17 @@ var createArmReach = (THREE, rig, hands) => {
|
|
|
4298
4330
|
const v = { shoulder: new THREE.Vector3(), elbow: new THREE.Vector3(), wrist: new THREE.Vector3(), palm: new THREE.Vector3(), target: new THREE.Vector3(), pole: new THREE.Vector3(), a: new THREE.Vector3(), b: new THREE.Vector3(), c: new THREE.Vector3() };
|
|
4299
4331
|
const q = { hand: new THREE.Quaternion(), parent: new THREE.Quaternion(), body: new THREE.Quaternion(), local: new THREE.Quaternion(), swing: new THREE.Quaternion(), twist: new THREE.Quaternion(), rest: new THREE.Quaternion() };
|
|
4300
4332
|
const basis = new THREE.Matrix4();
|
|
4333
|
+
const camera = { position: new THREE.Vector3(), quaternion: new THREE.Quaternion(), inverse: new THREE.Quaternion(), probe: new THREE.Vector3(), forward: new THREE.Vector3(), fingers: new THREE.Vector3(), hand: new THREE.Quaternion() };
|
|
4334
|
+
let bendLimit = null;
|
|
4301
4335
|
const yAxis = new THREE.Vector3(0, 1, 0);
|
|
4302
4336
|
const lengthsOf = (arm) => {
|
|
4303
4337
|
const scale = arm.g.getWorldScale(v.a).y;
|
|
4304
4338
|
return { upper: arm.el.position.length() * scale, fore: arm.hand.position.length() * scale, palm: ARM_REACH.palm * scale };
|
|
4305
4339
|
};
|
|
4340
|
+
const limitOf = (side, upperLength, fore) => {
|
|
4341
|
+
if (!bendLimit) return (upperLength + fore) * ARM_REACH.slack;
|
|
4342
|
+
return Math.sqrt(upperLength * upperLength + fore * fore + 2 * upperLength * fore * Math.cos(bendLimit[side === "R" ? 0 : 1]));
|
|
4343
|
+
};
|
|
4306
4344
|
const wristOf = (side, pose, palm) => {
|
|
4307
4345
|
q.hand.set(...pose.quaternion).multiply(handBasis[side]);
|
|
4308
4346
|
v.palm.set(...pose.position);
|
|
@@ -4311,14 +4349,14 @@ var createArmReach = (THREE, rig, hands) => {
|
|
|
4311
4349
|
const turnChest = (pose) => {
|
|
4312
4350
|
const { upper: up, fore, palm } = lengthsOf(arms.L);
|
|
4313
4351
|
wristOf("L", pose, palm);
|
|
4314
|
-
const excess = arms.L.g.getWorldPosition(v.shoulder).distanceTo(v.wrist) - (up
|
|
4352
|
+
const excess = arms.L.g.getWorldPosition(v.shoulder).distanceTo(v.wrist) - limitOf("L", up, fore);
|
|
4315
4353
|
if (excess <= 0) return;
|
|
4316
4354
|
const chestRadius = Math.hypot(arms.L.g.position.x, arms.L.g.position.z) * arms.L.g.getWorldScale(v.a).y;
|
|
4317
4355
|
upper.rotation.y -= Math.min(ARM_REACH.chestTurn, excess / Math.max(0.05, chestRadius));
|
|
4318
4356
|
upper.updateMatrixWorld(true);
|
|
4319
4357
|
};
|
|
4320
|
-
const protract = (arm,
|
|
4321
|
-
const excess = arm.g.getWorldPosition(v.shoulder).distanceTo(v.wrist) -
|
|
4358
|
+
const protract = (arm, limit) => {
|
|
4359
|
+
const excess = arm.g.getWorldPosition(v.shoulder).distanceTo(v.wrist) - limit;
|
|
4322
4360
|
if (excess <= 0) return;
|
|
4323
4361
|
const parent = arm.g.parent;
|
|
4324
4362
|
v.b.copy(v.wrist).sub(v.shoulder).normalize().multiplyScalar(Math.min(excess, ARM_REACH.protraction)).add(v.shoulder);
|
|
@@ -4339,11 +4377,13 @@ var createArmReach = (THREE, rig, hands) => {
|
|
|
4339
4377
|
const arm = arms[side];
|
|
4340
4378
|
const { upper: up, fore, palm } = lengthsOf(arm);
|
|
4341
4379
|
wristOf(side, pose, palm);
|
|
4342
|
-
protract(arm, up
|
|
4380
|
+
protract(arm, limitOf(side, up, fore));
|
|
4343
4381
|
arm.g.getWorldPosition(v.shoulder);
|
|
4344
4382
|
upper.getWorldQuaternion(q.body);
|
|
4345
|
-
|
|
4346
|
-
|
|
4383
|
+
const pole = side === "L" ? ARM_REACH.elbowPoleSupport : ARM_REACH.elbowPole;
|
|
4384
|
+
v.pole.set(pole[0] * arm.outward, pole[1], pole[2]).applyQuaternion(q.body);
|
|
4385
|
+
const lockLimit = Math.sqrt(up * up + fore * fore + 2 * up * fore * Math.cos(ARM_REACH.elbowMin));
|
|
4386
|
+
const most = bendLimit ? Math.min(lockLimit, limitOf(side, up, fore)) : lockLimit;
|
|
4347
4387
|
const least = Math.sqrt(up * up + fore * fore + 2 * up * fore * Math.cos(ARM_REACH.elbowMax));
|
|
4348
4388
|
const line = v.c.copy(v.wrist).sub(v.shoulder);
|
|
4349
4389
|
const distance2 = Math.min(most, Math.max(least, line.length()));
|
|
@@ -4368,6 +4408,20 @@ var createArmReach = (THREE, rig, hands) => {
|
|
|
4368
4408
|
arm.el.getWorldQuaternion(q.parent);
|
|
4369
4409
|
arm.hand.quaternion.copy(limitWrist(q.local.copy(q.parent.invert()).multiply(q.hand)));
|
|
4370
4410
|
};
|
|
4411
|
+
const keepOutside = (pose, outside) => {
|
|
4412
|
+
const place = v.a.set(...pose.position).sub(camera.position).applyQuaternion(camera.inverse);
|
|
4413
|
+
camera.probe.set(place.x, place.y, 0).applyQuaternion(camera.quaternion).add(camera.position);
|
|
4414
|
+
camera.forward.set(0, 0, -1).applyQuaternion(camera.quaternion);
|
|
4415
|
+
const distance2 = outside.contact([camera.probe.x, camera.probe.y, camera.probe.z], [camera.forward.x, camera.forward.y, camera.forward.z], ARM_REACH.contactProbe);
|
|
4416
|
+
if (distance2 === null) return pose;
|
|
4417
|
+
camera.hand.set(...pose.quaternion).premultiply(camera.inverse);
|
|
4418
|
+
const ahead = Math.max(ARM_REACH.contactPalm, -camera.fingers.set(1, 0, 0).applyQuaternion(camera.hand).z * ARM_REACH.contactFingers);
|
|
4419
|
+
const limit = Math.max(outside.nearest ?? ARM_REACH.contactNearest, distance2 - ahead - (outside.margin ?? ARM_REACH.contactMargin));
|
|
4420
|
+
if (-place.z <= limit) return pose;
|
|
4421
|
+
place.z = -limit;
|
|
4422
|
+
place.applyQuaternion(camera.quaternion).add(camera.position);
|
|
4423
|
+
return { ...pose, position: [place.x, place.y, place.z] };
|
|
4424
|
+
};
|
|
4371
4425
|
const save = () => {
|
|
4372
4426
|
saved.twist = upper.rotation.y;
|
|
4373
4427
|
for (const side of ["R", "L"]) {
|
|
@@ -4380,14 +4434,24 @@ var createArmReach = (THREE, rig, hands) => {
|
|
|
4380
4434
|
}
|
|
4381
4435
|
};
|
|
4382
4436
|
return {
|
|
4383
|
-
apply(targets) {
|
|
4437
|
+
apply(targets, view) {
|
|
4384
4438
|
if (!targets || !targets.R && !targets.L) return;
|
|
4385
4439
|
save();
|
|
4386
4440
|
applied = true;
|
|
4387
4441
|
upper.updateWorldMatrix(true, true);
|
|
4388
|
-
|
|
4389
|
-
|
|
4390
|
-
if (
|
|
4442
|
+
let { R, L } = targets;
|
|
4443
|
+
bendLimit = view ? view.reachBend ?? ARM_REACH.viewBend : null;
|
|
4444
|
+
if (view?.keepOutside) {
|
|
4445
|
+
view.camera.updateWorldMatrix(true, false);
|
|
4446
|
+
view.camera.matrixWorld.decompose(camera.position, camera.quaternion, v.a);
|
|
4447
|
+
camera.inverse.copy(camera.quaternion).invert();
|
|
4448
|
+
if (R) R = keepOutside(R, view.keepOutside);
|
|
4449
|
+
if (L) L = keepOutside(L, view.keepOutside);
|
|
4450
|
+
}
|
|
4451
|
+
if (L && R) turnChest(L);
|
|
4452
|
+
if (R) reach("R", R);
|
|
4453
|
+
if (L) reach("L", L);
|
|
4454
|
+
bendLimit = null;
|
|
4391
4455
|
},
|
|
4392
4456
|
restore() {
|
|
4393
4457
|
if (!applied) return;
|
|
@@ -4405,12 +4469,56 @@ var createArmReach = (THREE, rig, hands) => {
|
|
|
4405
4469
|
};
|
|
4406
4470
|
};
|
|
4407
4471
|
|
|
4472
|
+
// src/player/head-hiding.ts
|
|
4473
|
+
var isDrawable = (object) => {
|
|
4474
|
+
const flagged = object;
|
|
4475
|
+
return Boolean(flagged.isMesh || flagged.isSprite || flagged.isPoints);
|
|
4476
|
+
};
|
|
4477
|
+
var createHeadHider = (roots) => {
|
|
4478
|
+
let isHiding = false;
|
|
4479
|
+
let viewCamera = null;
|
|
4480
|
+
const drawables = [];
|
|
4481
|
+
for (const root of roots) root.traverse((object) => isDrawable(object) && drawables.push(object));
|
|
4482
|
+
for (const drawable of drawables) {
|
|
4483
|
+
const previousBefore = drawable.onBeforeRender;
|
|
4484
|
+
const previousAfter = drawable.onAfterRender;
|
|
4485
|
+
let saved = [];
|
|
4486
|
+
drawable.onBeforeRender = (renderer, scene2, camera, geometry, material, group) => {
|
|
4487
|
+
previousBefore.call(drawable, renderer, scene2, camera, geometry, material, group);
|
|
4488
|
+
if (!isHiding || camera !== viewCamera) return;
|
|
4489
|
+
const drawn = Array.isArray(drawable.material) ? drawable.material : [material];
|
|
4490
|
+
saved = drawn.map((entry) => ({ material: entry, colorWrite: entry.colorWrite, depthWrite: entry.depthWrite }));
|
|
4491
|
+
for (const entry of drawn) {
|
|
4492
|
+
entry.colorWrite = false;
|
|
4493
|
+
entry.depthWrite = false;
|
|
4494
|
+
}
|
|
4495
|
+
};
|
|
4496
|
+
drawable.onAfterRender = (renderer, scene2, camera, geometry, material, group) => {
|
|
4497
|
+
previousAfter.call(drawable, renderer, scene2, camera, geometry, material, group);
|
|
4498
|
+
for (const flags of saved) {
|
|
4499
|
+
flags.material.colorWrite = flags.colorWrite;
|
|
4500
|
+
flags.material.depthWrite = flags.depthWrite;
|
|
4501
|
+
}
|
|
4502
|
+
saved = [];
|
|
4503
|
+
};
|
|
4504
|
+
}
|
|
4505
|
+
return {
|
|
4506
|
+
setView(mode, camera) {
|
|
4507
|
+
isHiding = mode === "first" && camera !== null;
|
|
4508
|
+
viewCamera = camera;
|
|
4509
|
+
}
|
|
4510
|
+
};
|
|
4511
|
+
};
|
|
4512
|
+
|
|
4408
4513
|
// src/player/avatar.ts
|
|
4409
4514
|
var TWO_PI = Math.PI * 2;
|
|
4410
4515
|
var MAX_GAIT = 1.4;
|
|
4411
4516
|
var CLIP_BLEND = 0.12;
|
|
4412
4517
|
var CLIP_CASCADE = 5;
|
|
4413
4518
|
var FALL_SECONDS2 = 0.3;
|
|
4519
|
+
var BUILDER_EYE = [0, 1.815, 0.16];
|
|
4520
|
+
var EYE_OFFSET = [0, -0.068, 0];
|
|
4521
|
+
var EYE_BOB = 0.5;
|
|
4414
4522
|
var HIP_HEIGHT = 0.95;
|
|
4415
4523
|
var WALK_ARM = 0.28;
|
|
4416
4524
|
var WALK_BOB = 0.035;
|
|
@@ -4420,7 +4528,11 @@ var RUN_BOB = 0.05;
|
|
|
4420
4528
|
var REST_ARM_Z = 0.18;
|
|
4421
4529
|
var CROUCH = { thigh: -0.95, thighWalk: 0.3, shin: 1.9, lean: 0.25, drop: -0.35 };
|
|
4422
4530
|
var AIMED = { shoulder: -1.42, perAim: 0.85, swing: 0.02, zRight: -0.54, zLeft: 0.36, elbowRight: -0.04, elbowLeft: -0.12 };
|
|
4531
|
+
var SIT = { thigh: -1.5, lean: -0.08, arm: -0.45, armZ: 0.12, elbow: -0.75 };
|
|
4532
|
+
var LIE = { knee: 0.08, armZ: 0.12, elbow: -0.1 };
|
|
4423
4533
|
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 };
|
|
4534
|
+
var DOOR_SHOULDER = 1.42;
|
|
4535
|
+
var DOOR_ARM = 0.62;
|
|
4424
4536
|
var HAND_OFFSET = { x: 0, y: -0.33, z: 0.04 };
|
|
4425
4537
|
var hexOf = (value) => typeof value === "string" ? Number.parseInt(value, 16) : value;
|
|
4426
4538
|
var clamp = (value, min, max) => Math.min(max, Math.max(min, value));
|
|
@@ -4450,6 +4562,8 @@ var createPlayerAvatar = (THREE, options = {}) => {
|
|
|
4450
4562
|
const fallSeconds = options.fallSeconds ?? FALL_SECONDS2;
|
|
4451
4563
|
const smooth = options.cascade ?? true;
|
|
4452
4564
|
const clipCascade = options.clipCascade ?? CLIP_CASCADE;
|
|
4565
|
+
const eyeBob = options.eyeBob ?? EYE_BOB;
|
|
4566
|
+
const eyeOffset = options.eyeOffset ?? EYE_OFFSET;
|
|
4453
4567
|
const root = new THREE.Group();
|
|
4454
4568
|
const tilt = new THREE.Group();
|
|
4455
4569
|
tilt.add(body);
|
|
@@ -4509,7 +4623,23 @@ var createPlayerAvatar = (THREE, options = {}) => {
|
|
|
4509
4623
|
if (hand.th) hand.th.rotation.z = -hand.side * (0.32 + grip * 0.25);
|
|
4510
4624
|
hand.hg.rotation.x = wristX;
|
|
4511
4625
|
};
|
|
4626
|
+
const eyeSocket = new THREE.Object3D();
|
|
4627
|
+
eyeSocket.name = "eye";
|
|
4628
|
+
eyeSocket.position.set(BUILDER_EYE[0] + eyeOffset[0], BUILDER_EYE[1] + eyeOffset[1], BUILDER_EYE[2] + eyeOffset[2]);
|
|
4629
|
+
rig.headG.children[0].add(eyeSocket);
|
|
4630
|
+
const headHider = createHeadHider([rig.headG, ...rig.neck ? [rig.neck] : []]);
|
|
4631
|
+
const eyeLocal = new THREE.Vector3();
|
|
4632
|
+
let bob = 0;
|
|
4633
|
+
let hipWithoutBob = null;
|
|
4512
4634
|
const legRestX = rig.legs.map((leg) => leg.g.position.x);
|
|
4635
|
+
const legLengths = (() => {
|
|
4636
|
+
const thigh = rig.legs[0].g;
|
|
4637
|
+
const shin = rig.legs[0].kn;
|
|
4638
|
+
root.updateMatrixWorld(true);
|
|
4639
|
+
const hipY = thigh.getWorldPosition(new THREE.Vector3()).y;
|
|
4640
|
+
const kneeY = shin.getWorldPosition(new THREE.Vector3()).y;
|
|
4641
|
+
return { hipBelowTrunk: HIP_HEIGHT - hipY, thigh: hipY - kneeY, shin: kneeY - new THREE.Box3().setFromObject(shin).min.y };
|
|
4642
|
+
})();
|
|
4513
4643
|
const legSide = (index) => index === 0 ? 1 : -1;
|
|
4514
4644
|
let cycles = 0;
|
|
4515
4645
|
let time = 0;
|
|
@@ -4568,10 +4698,29 @@ var createPlayerAvatar = (THREE, options = {}) => {
|
|
|
4568
4698
|
...strain ? { legL: -0.5, legR: 0.4, kneeL: 0.55, kneeR: 0.08, drop: -0.05 } : {}
|
|
4569
4699
|
};
|
|
4570
4700
|
};
|
|
4701
|
+
const doorPose = (door) => {
|
|
4702
|
+
const { phase, progress } = door;
|
|
4703
|
+
const on = phase === "reach" ? progress : phase === "release" ? 1 - progress : 1;
|
|
4704
|
+
const swing = phase === "swing" ? progress : phase === "release" ? 1 : 0;
|
|
4705
|
+
const shake = phase === "rattle" ? Math.sin(time * 55) * 0.06 * (1 - progress) : 0;
|
|
4706
|
+
const drop = clamp((DOOR_SHOULDER - door.height) / DOOR_ARM, -0.9, 1);
|
|
4707
|
+
const low = clamp((0.75 - door.height) / 0.5, 0, 1);
|
|
4708
|
+
const raise = -Math.acos(clamp(drop, -1, 1)) * on - 0.35 * low * on;
|
|
4709
|
+
const elbow = door.pull ? -0.35 - 0.75 * swing : -0.95 + 0.75 * swing;
|
|
4710
|
+
return {
|
|
4711
|
+
armR: raise + shake,
|
|
4712
|
+
armRz: REST_ARM_Z * (1 - on) + 0.05 * on,
|
|
4713
|
+
elbR: -0.12 + (elbow + 0.12) * on,
|
|
4714
|
+
armLz: -REST_ARM_Z,
|
|
4715
|
+
elbL: -0.12,
|
|
4716
|
+
lean: ((door.pull ? -0.06 : 0.1) * swing + 0.35 * low) * on,
|
|
4717
|
+
headX: 0.06 * on + 0.2 * low * on
|
|
4718
|
+
};
|
|
4719
|
+
};
|
|
4571
4720
|
const holdingPose = (gait, itemUse) => {
|
|
4572
|
-
const
|
|
4721
|
+
const bob2 = Math.sin(cycles * TWO_PI) * 0.05 * gait;
|
|
4573
4722
|
if (!itemUse) {
|
|
4574
|
-
return { armL: -0.45 +
|
|
4723
|
+
return { armL: -0.45 + bob2, armLz: 0.22, elbL: -1.05 };
|
|
4575
4724
|
}
|
|
4576
4725
|
const { id, position, rotation } = itemUse;
|
|
4577
4726
|
if (id === "drink" || id === "sip" || id === "chug") {
|
|
@@ -4584,7 +4733,7 @@ var createPlayerAvatar = (THREE, options = {}) => {
|
|
|
4584
4733
|
headX: -0.26 * tilt3
|
|
4585
4734
|
};
|
|
4586
4735
|
}
|
|
4587
|
-
if (id === "open" || id === "close") {
|
|
4736
|
+
if (id === "open" || id === "close" || itemUse.gripL !== void 0) {
|
|
4588
4737
|
const reach = clamp((0.22 - position[0]) / 0.12, 0, 1);
|
|
4589
4738
|
return {
|
|
4590
4739
|
armL: -0.45 - 0.35 * reach,
|
|
@@ -4683,6 +4832,31 @@ var createPlayerAvatar = (THREE, options = {}) => {
|
|
|
4683
4832
|
drop: Math.abs(Math.sin(ph)) * WALK_BOB * gait
|
|
4684
4833
|
};
|
|
4685
4834
|
};
|
|
4835
|
+
const sitPose = (hip) => {
|
|
4836
|
+
const knee = hip - legLengths.hipBelowTrunk - legLengths.thigh * Math.cos(SIT.thigh);
|
|
4837
|
+
const shinFromVertical = Math.acos(clamp(knee / legLengths.shin, 0, 1));
|
|
4838
|
+
const bend = -SIT.thigh - shinFromVertical;
|
|
4839
|
+
return {
|
|
4840
|
+
legL: SIT.thigh,
|
|
4841
|
+
legR: SIT.thigh,
|
|
4842
|
+
kneeL: bend,
|
|
4843
|
+
kneeR: bend,
|
|
4844
|
+
lean: SIT.lean,
|
|
4845
|
+
drop: hip - HIP_HEIGHT,
|
|
4846
|
+
armR: SIT.arm,
|
|
4847
|
+
armL: SIT.arm,
|
|
4848
|
+
armRz: SIT.armZ,
|
|
4849
|
+
armLz: -SIT.armZ,
|
|
4850
|
+
elbR: SIT.elbow,
|
|
4851
|
+
elbL: SIT.elbow
|
|
4852
|
+
};
|
|
4853
|
+
};
|
|
4854
|
+
const liePose = () => ({ legL: 0, legR: 0, kneeL: LIE.knee, kneeR: LIE.knee, lean: 0, drop: 0, armR: 0, armL: 0, armRz: LIE.armZ, armLz: -LIE.armZ, elbR: LIE.elbow, elbL: LIE.elbow });
|
|
4855
|
+
const layBody = (hip) => {
|
|
4856
|
+
tilt.rotation.set(-Math.PI / 2, 0, 0, "XYZ");
|
|
4857
|
+
const pivot = new THREE.Vector3(0, HIP_HEIGHT, 0).applyEuler(tilt.rotation);
|
|
4858
|
+
tilt.position.set(0, hip, 0).sub(pivot);
|
|
4859
|
+
};
|
|
4686
4860
|
const placeBody = (progress) => {
|
|
4687
4861
|
const fk = progress * progress * (3 - 2 * progress);
|
|
4688
4862
|
const flip = fract(cycles * 1.7) >= 0.5 ? 1 : 0;
|
|
@@ -4743,13 +4917,27 @@ var createPlayerAvatar = (THREE, options = {}) => {
|
|
|
4743
4917
|
profile.bob = (running ? RUN_BOB : WALK_BOB) * gait;
|
|
4744
4918
|
time = cycles / (walkCadence(Math.max(speed, 0)) * (running ? 1.3 : 1));
|
|
4745
4919
|
animator.animate(body, time, { speed });
|
|
4920
|
+
bob = rig.fig.position.y - rig.dropBase;
|
|
4746
4921
|
fall = fallSeconds <= 0 ? down ? 1 : 0 : clamp(fall + (down ? dt : -dt) / fallSeconds, 0, 1);
|
|
4747
4922
|
resetLegYaw();
|
|
4748
|
-
|
|
4749
|
-
|
|
4750
|
-
|
|
4751
|
-
|
|
4923
|
+
const seat = down ? null : state.seat ?? null;
|
|
4924
|
+
if (down) {
|
|
4925
|
+
animator.setPose(rig, downPose());
|
|
4926
|
+
bob = rig.fig.position.y - rig.dropBase;
|
|
4927
|
+
} else if (seat) {
|
|
4928
|
+
animator.setPose(rig, seat.pose === "lie" ? liePose() : sitPose(seat.hip));
|
|
4929
|
+
bob = 0;
|
|
4930
|
+
} else {
|
|
4931
|
+
if (running) {
|
|
4932
|
+
animator.setPose(rig, runningPose(gait, Boolean(state.armed || state.holding || state.itemUse)));
|
|
4933
|
+
bob = rig.fig.position.y - rig.dropBase;
|
|
4934
|
+
}
|
|
4935
|
+
if (state.crouch) {
|
|
4936
|
+
animator.setPose(rig, crouchPose(gait));
|
|
4937
|
+
bob = rig.fig.position.y - rig.dropBase - CROUCH.drop;
|
|
4938
|
+
}
|
|
4752
4939
|
if (state.push) animator.setPose(rig, pushingPose(state.push));
|
|
4940
|
+
else if (state.door) animator.setPose(rig, doorPose(state.door));
|
|
4753
4941
|
else if (state.armed) animator.setPose(rig, armed(state.pitch ?? 0, gait, state.hip ?? 0));
|
|
4754
4942
|
else if (state.holding || state.itemUse) animator.setPose(rig, holdingPose(gait, state.itemUse));
|
|
4755
4943
|
else if (!running) {
|
|
@@ -4761,20 +4949,33 @@ var createPlayerAvatar = (THREE, options = {}) => {
|
|
|
4761
4949
|
});
|
|
4762
4950
|
}
|
|
4763
4951
|
}
|
|
4764
|
-
|
|
4765
|
-
|
|
4766
|
-
|
|
4952
|
+
if (seat?.pose === "lie") layBody(seat.hip);
|
|
4953
|
+
else placeBody(fall);
|
|
4954
|
+
stepClip(dt, down, Boolean(state.crouch || seat));
|
|
4955
|
+
const cascadeDt = run && !run.clip.loop ? dt * clipCascade : dt;
|
|
4956
|
+
const targetWithoutBob = rig.fig.position.y - bob;
|
|
4957
|
+
if (smooth) animator.cascade(rig, cascadeDt);
|
|
4958
|
+
hipWithoutBob = smooth && hipWithoutBob !== null ? stepCascade2(hipWithoutBob, targetWithoutBob, cascadeDt, "hip") : targetWithoutBob;
|
|
4959
|
+
bob = rig.fig.position.y - hipWithoutBob;
|
|
4767
4960
|
const blow = run?.clip.events?.find((event) => (event.type === "impact" || event.type === "grip") && event.data?.kind)?.data?.kind;
|
|
4768
4961
|
const ph = cycles * TWO_PI;
|
|
4769
4962
|
hands.forEach((hand) => {
|
|
4770
4963
|
const isRight = hand.side < 0;
|
|
4771
4964
|
const holdRight = isRight && (!!state.holding || !!state.itemUse);
|
|
4772
|
-
const holdLeft = !isRight && (state.itemUse?.id === "open" || state.itemUse?.id === "close");
|
|
4773
|
-
const grip = blow === "punch" ? 1.4 : blow === "shove" ? 0.15 : state.armed || holdRight || holdLeft ? 1.22 : running ? 0.85 : 0.12;
|
|
4965
|
+
const holdLeft = !isRight && (state.itemUse?.id === "open" || state.itemUse?.id === "close" || state.itemUse?.gripL !== void 0);
|
|
4966
|
+
const grip = !isRight && state.itemUse?.gripL !== void 0 ? 1.22 * state.itemUse.gripL : blow === "punch" ? 1.4 : blow === "shove" ? 0.15 : state.armed || holdRight || holdLeft ? 1.22 : running ? 0.85 : 0.12;
|
|
4774
4967
|
const wristSwing = holdRight || state.armed || running ? 0 : -Math.min(1, gait) * Math.sin(ph - 0.6) * 0.12 * hand.side;
|
|
4775
4968
|
setHandGrip(hand, grip, wristSwing);
|
|
4776
4969
|
});
|
|
4970
|
+
root.updateMatrixWorld(true);
|
|
4971
|
+
root.worldToLocal(eyeSocket.getWorldPosition(eyeLocal));
|
|
4972
|
+
eyeLocal.y -= (1 - eyeBob) * bob;
|
|
4777
4973
|
},
|
|
4974
|
+
eye(out = new THREE.Vector3()) {
|
|
4975
|
+
root.updateWorldMatrix(true, false);
|
|
4976
|
+
return root.localToWorld(out.copy(eyeLocal));
|
|
4977
|
+
},
|
|
4978
|
+
setView: (mode, camera) => headHider.setView(mode, camera),
|
|
4778
4979
|
play(clip, playOptions = {}) {
|
|
4779
4980
|
const found = typeof clip === "string" ? clips.get(clip) : clip;
|
|
4780
4981
|
if (!found) throw new Error(`Unknown pose clip: ${String(clip)}`);
|
|
@@ -4786,10 +4987,11 @@ var createPlayerAvatar = (THREE, options = {}) => {
|
|
|
4786
4987
|
if (run) run.target = 0;
|
|
4787
4988
|
},
|
|
4788
4989
|
hand: (side) => sockets[side],
|
|
4789
|
-
|
|
4990
|
+
shoulder: (side) => armOf[side].g,
|
|
4991
|
+
reach(targets, view) {
|
|
4790
4992
|
if (run || fall > 0) return;
|
|
4791
4993
|
root.updateMatrixWorld(true);
|
|
4792
|
-
armReach.apply(targets);
|
|
4994
|
+
armReach.apply(targets, view);
|
|
4793
4995
|
},
|
|
4794
4996
|
on(_type, listener) {
|
|
4795
4997
|
listeners.add(listener);
|
|
@@ -4811,8 +5013,236 @@ var createPlayerAvatar = (THREE, options = {}) => {
|
|
|
4811
5013
|
};
|
|
4812
5014
|
|
|
4813
5015
|
// src/player/room-avatar.ts
|
|
4814
|
-
import { ATTACK_CLIPS
|
|
5016
|
+
import { ATTACK_CLIPS } from "@adatechnology/game-characters-people";
|
|
4815
5017
|
import { mirrorPoseClip } from "@adatechnology/game-characters";
|
|
5018
|
+
var impactOf = (clip) => clip.events?.find((event) => event.type === "impact")?.t ?? null;
|
|
5019
|
+
var isPunch = (clip) => clip.events?.some((event) => event.type === "impact" && event.data?.kind === "punch") ?? false;
|
|
5020
|
+
var GUARD_SPEED = 0.3;
|
|
5021
|
+
var toRoomAvatar = (avatar, options = {}) => {
|
|
5022
|
+
const strikes = new Map((options.strikeClips ?? ATTACK_CLIPS).map((clip) => [clip.id, clip]));
|
|
5023
|
+
const mirrored = /* @__PURE__ */ new Map();
|
|
5024
|
+
const leftOf = (clip) => {
|
|
5025
|
+
let found = mirrored.get(clip.id);
|
|
5026
|
+
if (!found) mirrored.set(clip.id, found = mirrorPoseClip(clip, `${clip.id}_left`));
|
|
5027
|
+
return found;
|
|
5028
|
+
};
|
|
5029
|
+
const guard = options.guardClip === false ? void 0 : strikes.get(options.guardClip ?? "fight_guard");
|
|
5030
|
+
const guardHold = options.guardHold ?? 1.2;
|
|
5031
|
+
const punchBlend = options.punchBlend ?? 0.05;
|
|
5032
|
+
let strikeLeft = 0;
|
|
5033
|
+
let guardLeft = 0;
|
|
5034
|
+
let guarding = false;
|
|
5035
|
+
const stepGuard = (dt, state) => {
|
|
5036
|
+
if (!guard) return;
|
|
5037
|
+
const free = state.speed < GUARD_SPEED && !state.down && !state.armed && !state.holding && !state.push && !state.door && !state.itemUse && !state.running;
|
|
5038
|
+
if (strikeLeft > 0) {
|
|
5039
|
+
strikeLeft -= dt;
|
|
5040
|
+
if (strikeLeft <= 0 && guardLeft > 0 && free) {
|
|
5041
|
+
avatar.play(guard);
|
|
5042
|
+
guarding = true;
|
|
5043
|
+
}
|
|
5044
|
+
return;
|
|
5045
|
+
}
|
|
5046
|
+
guardLeft = Math.max(0, guardLeft - dt);
|
|
5047
|
+
if (guarding && (guardLeft <= 0 || !free || avatar.playing !== guard.id)) {
|
|
5048
|
+
if (avatar.playing === guard.id) avatar.stop();
|
|
5049
|
+
guarding = false;
|
|
5050
|
+
}
|
|
5051
|
+
};
|
|
5052
|
+
return {
|
|
5053
|
+
root: avatar.root,
|
|
5054
|
+
avatar,
|
|
5055
|
+
eye: (out) => avatar.eye(out),
|
|
5056
|
+
setView: (mode, camera) => avatar.setView(mode, camera),
|
|
5057
|
+
update: (dt, state) => {
|
|
5058
|
+
stepGuard(dt, state);
|
|
5059
|
+
avatar.update(dt, {
|
|
5060
|
+
speed: state.speed,
|
|
5061
|
+
running: state.running,
|
|
5062
|
+
crouch: state.crouch,
|
|
5063
|
+
down: state.down,
|
|
5064
|
+
armed: state.armed,
|
|
5065
|
+
pitch: -state.pitch,
|
|
5066
|
+
...state.holding !== void 0 ? { holding: state.holding } : {},
|
|
5067
|
+
...state.itemUse !== void 0 ? { itemUse: state.itemUse } : {},
|
|
5068
|
+
...state.push !== void 0 ? { push: state.push } : {},
|
|
5069
|
+
...state.seat !== void 0 ? { seat: state.seat } : {},
|
|
5070
|
+
...state.door !== void 0 ? { door: state.door } : {}
|
|
5071
|
+
});
|
|
5072
|
+
},
|
|
5073
|
+
hand: (side) => avatar.hand(side),
|
|
5074
|
+
shoulder: (side) => avatar.shoulder(side),
|
|
5075
|
+
reach: (targets, view) => avatar.reach(targets, view),
|
|
5076
|
+
strike: (clipId, strikeOptions) => {
|
|
5077
|
+
const clip = strikes.get(clipId);
|
|
5078
|
+
if (!clip) return null;
|
|
5079
|
+
const left = strikeOptions?.leg === "left" || strikeOptions?.hand === "left";
|
|
5080
|
+
const punch = guard !== void 0 && isPunch(clip);
|
|
5081
|
+
avatar.play(left ? leftOf(clip) : clip, punch ? { blend: punchBlend } : void 0);
|
|
5082
|
+
strikeLeft = punch ? clip.duration : 0;
|
|
5083
|
+
guardLeft = punch ? guardHold : 0;
|
|
5084
|
+
guarding = false;
|
|
5085
|
+
return impactOf(clip);
|
|
5086
|
+
}
|
|
5087
|
+
};
|
|
5088
|
+
};
|
|
5089
|
+
|
|
5090
|
+
// src/player/test-module.ts
|
|
5091
|
+
import { POSE_CLIPS as POSE_CLIPS2, POSE_CLIP_LOCALES } from "@adatechnology/game-characters";
|
|
5092
|
+
|
|
5093
|
+
// src/player/test-text.ts
|
|
5094
|
+
var AVATAR_TEXT = {
|
|
5095
|
+
en: {
|
|
5096
|
+
group: "Avatar",
|
|
5097
|
+
name: "Player body",
|
|
5098
|
+
actions: {
|
|
5099
|
+
camera_first: "Camera: 1st person",
|
|
5100
|
+
camera_third: "Camera: 3rd person",
|
|
5101
|
+
crouch: "Crouch",
|
|
5102
|
+
stand: "Stand up",
|
|
5103
|
+
fall: "Fall down",
|
|
5104
|
+
get_up: "Get up",
|
|
5105
|
+
armed_on: "Armed: on",
|
|
5106
|
+
armed_off: "Armed: off",
|
|
5107
|
+
stop_clip: "Stop clip"
|
|
5108
|
+
},
|
|
5109
|
+
play: "Play",
|
|
5110
|
+
metrics: { camera: "Camera", clip: "Clip playing", last_event: "Last clip event", state: "State", joints: "Joints" },
|
|
5111
|
+
none: "none"
|
|
5112
|
+
},
|
|
5113
|
+
"pt-BR": {
|
|
5114
|
+
group: "Avatar",
|
|
5115
|
+
name: "Corpo do jogador",
|
|
5116
|
+
actions: {
|
|
5117
|
+
camera_first: "C\xE2mera: 1\xAA pessoa",
|
|
5118
|
+
camera_third: "C\xE2mera: 3\xAA pessoa",
|
|
5119
|
+
crouch: "Agachar",
|
|
5120
|
+
stand: "Levantar",
|
|
5121
|
+
fall: "Cair",
|
|
5122
|
+
get_up: "Levantar do ch\xE3o",
|
|
5123
|
+
armed_on: "Armado: ligado",
|
|
5124
|
+
armed_off: "Armado: desligado",
|
|
5125
|
+
stop_clip: "Parar clipe"
|
|
5126
|
+
},
|
|
5127
|
+
play: "Tocar",
|
|
5128
|
+
metrics: { camera: "C\xE2mera", clip: "Clipe tocando", last_event: "\xDAltimo evento do clipe", state: "Estado", joints: "Juntas" },
|
|
5129
|
+
none: "nenhum"
|
|
5130
|
+
}
|
|
5131
|
+
};
|
|
5132
|
+
|
|
5133
|
+
// src/player/test-module.ts
|
|
5134
|
+
var AVATAR_AREA_ID = "avatar_area";
|
|
5135
|
+
var round = (value) => (Math.round(value * 100) / 100).toString();
|
|
5136
|
+
function createAvatarTestModule(options) {
|
|
5137
|
+
const clips = options.clips ?? POSE_CLIPS2;
|
|
5138
|
+
const textOf = (locale) => AVATAR_TEXT[locale ?? options.locale ?? "pt-BR"] ?? AVATAR_TEXT["pt-BR"];
|
|
5139
|
+
const phaseLabel = (label, locale) => {
|
|
5140
|
+
const id = locale ?? options.locale ?? "pt-BR";
|
|
5141
|
+
const table = { ...POSE_CLIP_LOCALES[id] ?? POSE_CLIP_LOCALES["pt-BR"], ...options.clipLocales?.[id] ?? options.clipLocales?.["pt-BR"] };
|
|
5142
|
+
return typeof label === "string" ? table[label] ?? label : "";
|
|
5143
|
+
};
|
|
5144
|
+
const state = { crouch: false, down: false, armed: null };
|
|
5145
|
+
let host = null;
|
|
5146
|
+
let lastEvent = "";
|
|
5147
|
+
const log = (action, extra = {}) => {
|
|
5148
|
+
const entry = { type: "avatar", action, ...extra };
|
|
5149
|
+
host?.log(JSON.stringify(entry), entry);
|
|
5150
|
+
};
|
|
5151
|
+
const push = (action, patch, extra = {}) => {
|
|
5152
|
+
Object.assign(state, patch);
|
|
5153
|
+
options.state?.set(patch);
|
|
5154
|
+
log(action, { crouch: state.crouch, down: state.down, armed: state.armed, ...extra });
|
|
5155
|
+
};
|
|
5156
|
+
const setCamera = (mode) => {
|
|
5157
|
+
options.camera?.set(mode);
|
|
5158
|
+
log(`camera_${mode}`, { mode: options.camera?.mode() ?? null });
|
|
5159
|
+
};
|
|
5160
|
+
const onChange = (change) => {
|
|
5161
|
+
if (change.kind !== "action") return;
|
|
5162
|
+
switch (change.id) {
|
|
5163
|
+
case "camera_first":
|
|
5164
|
+
return setCamera("first");
|
|
5165
|
+
case "camera_third":
|
|
5166
|
+
return setCamera("third");
|
|
5167
|
+
case "crouch":
|
|
5168
|
+
return push("crouch", { crouch: true });
|
|
5169
|
+
case "stand":
|
|
5170
|
+
return push("stand", { crouch: false });
|
|
5171
|
+
case "fall":
|
|
5172
|
+
return push("fall", { down: true });
|
|
5173
|
+
case "get_up":
|
|
5174
|
+
return push("get_up", { down: false });
|
|
5175
|
+
case "armed_on":
|
|
5176
|
+
return push("armed_on", { armed: true });
|
|
5177
|
+
case "armed_off":
|
|
5178
|
+
return push("armed_off", { armed: false });
|
|
5179
|
+
case "stop_clip":
|
|
5180
|
+
options.avatar.stop();
|
|
5181
|
+
return log("stop_clip", { playing: options.avatar.playing });
|
|
5182
|
+
default: {
|
|
5183
|
+
const clip = clips.find((item) => `play_${item.id}` === change.id);
|
|
5184
|
+
if (!clip) return;
|
|
5185
|
+
options.avatar.play(clip);
|
|
5186
|
+
log("play_clip", { clip: clip.id, duration: clip.duration, loop: clip.loop ?? false, channels: clip.channels ?? "full" });
|
|
5187
|
+
}
|
|
5188
|
+
}
|
|
5189
|
+
};
|
|
5190
|
+
const joints = () => {
|
|
5191
|
+
const rig = options.avatar.rig;
|
|
5192
|
+
const [armA, armB] = rig.arms;
|
|
5193
|
+
const [legA, legB] = rig.legs;
|
|
5194
|
+
return `arms ${round(armA.g.rotation.x)}/${round(armB.g.rotation.x)} elbows ${round(armA.el.rotation.x)}/${round(armB.el.rotation.x)} legs ${round(legA.g.rotation.x)}/${round(legB.g.rotation.x)} knees ${round(legA.kn.rotation.x)}/${round(legB.kn.rotation.x)} lean ${round(rig.upper.rotation.x)}`;
|
|
5195
|
+
};
|
|
5196
|
+
return {
|
|
5197
|
+
id: AVATAR_AREA_ID,
|
|
5198
|
+
name: textOf().name,
|
|
5199
|
+
ground: { surface: "concrete_slab" },
|
|
5200
|
+
group: textOf().group,
|
|
5201
|
+
state,
|
|
5202
|
+
items: () => [],
|
|
5203
|
+
area: () => ({ placements: [], view: { eye: [0, 1.7, 6], target: [0, 1.2, 0] } }),
|
|
5204
|
+
controls: (locale) => {
|
|
5205
|
+
const text = textOf(locale);
|
|
5206
|
+
const action = (id, name, hint) => ({ kind: "action", id, name, ...hint ? { hint } : {} });
|
|
5207
|
+
return [
|
|
5208
|
+
action("camera_first", text.actions.camera_first),
|
|
5209
|
+
action("camera_third", text.actions.camera_third),
|
|
5210
|
+
action("crouch", text.actions.crouch),
|
|
5211
|
+
action("stand", text.actions.stand),
|
|
5212
|
+
action("fall", text.actions.fall),
|
|
5213
|
+
action("get_up", text.actions.get_up),
|
|
5214
|
+
action("armed_on", text.actions.armed_on),
|
|
5215
|
+
action("armed_off", text.actions.armed_off),
|
|
5216
|
+
...clips.map((clip) => action(`play_${clip.id}`, `${text.play}: ${clip.id}`)),
|
|
5217
|
+
action("stop_clip", text.actions.stop_clip)
|
|
5218
|
+
];
|
|
5219
|
+
},
|
|
5220
|
+
metrics: (locale) => {
|
|
5221
|
+
const text = textOf(locale);
|
|
5222
|
+
return [
|
|
5223
|
+
{ id: "camera", name: text.metrics.camera, read: () => options.camera?.mode() ?? text.none },
|
|
5224
|
+
{ id: "clip", name: text.metrics.clip, read: () => options.avatar.playing ?? text.none },
|
|
5225
|
+
{ id: "last_event", name: text.metrics.last_event, read: () => lastEvent || text.none },
|
|
5226
|
+
{ id: "state", name: text.metrics.state, read: () => `${state.crouch ? "crouch " : ""}${state.down ? "down " : ""}${state.armed === null ? "" : state.armed ? "armed" : "unarmed"}`.trim() || text.none },
|
|
5227
|
+
{ id: "joints", name: text.metrics.joints, read: joints }
|
|
5228
|
+
];
|
|
5229
|
+
},
|
|
5230
|
+
attach(lent) {
|
|
5231
|
+
host = lent;
|
|
5232
|
+
const stopChange = lent.bench?.onChange(onChange);
|
|
5233
|
+
const stopEvents = options.avatar.on("event", (event) => {
|
|
5234
|
+
lastEvent = `${event.clip} ${event.type} ${round(event.t)}s${event.data && "label" in event.data ? ` ${phaseLabel(event.data.label)}` : ""}`;
|
|
5235
|
+
log("clip_event", { clip: event.clip, event: event.type, t: event.t, data: event.data ?? null });
|
|
5236
|
+
if (event.type === "impact") log("impact", { clip: event.clip, t: event.t, kind: event.data?.kind ?? null });
|
|
5237
|
+
});
|
|
5238
|
+
return () => {
|
|
5239
|
+
stopChange?.();
|
|
5240
|
+
stopEvents();
|
|
5241
|
+
host = null;
|
|
5242
|
+
};
|
|
5243
|
+
}
|
|
5244
|
+
};
|
|
5245
|
+
}
|
|
4816
5246
|
|
|
4817
5247
|
// src/first-person/arms.ts
|
|
4818
5248
|
import { clipEventsBetween as clipEventsBetween2, sampleFirstPersonClip } from "@adatechnology/game-characters";
|
|
@@ -4827,7 +5257,9 @@ var first_person_arms_default = {
|
|
|
4827
5257
|
shoulder: [0.16, -0.36, 0.18],
|
|
4828
5258
|
upper: 0.32,
|
|
4829
5259
|
fore: 0.3,
|
|
4830
|
-
reachShift: 0.
|
|
5260
|
+
reachShift: 0.42,
|
|
5261
|
+
reachBend: [1.35, 0.95],
|
|
5262
|
+
elbowView: [[0.96, -0.26, -0.06], null],
|
|
4831
5263
|
wrist: 0.07,
|
|
4832
5264
|
elbowPole: [0.45, -1, 0.2],
|
|
4833
5265
|
shoulderLeft: [-0.07, -0.46, 0.18],
|
|
@@ -4854,22 +5286,14 @@ var first_person_arms_default = {
|
|
|
4854
5286
|
};
|
|
4855
5287
|
|
|
4856
5288
|
// src/first-person/hand.ts
|
|
4857
|
-
var
|
|
4858
|
-
|
|
4859
|
-
|
|
4860
|
-
{ z: 9e-3, lengths: [0.035, 0.025, 0.02], width: 0.0155 },
|
|
4861
|
-
{ z: 0.027, lengths: [0.029, 0.02, 0.018], width: 0.0135 }
|
|
4862
|
-
];
|
|
4863
|
-
var PALM = { length: 0.09, thick: 0.026, width: 0.09, wristWidth: 0.066 };
|
|
4864
|
-
var FINGER_THICK = 0.0135;
|
|
4865
|
-
var CURL = { near: 1.05, mid: 1.25, far: 0.85, spread: 0.06 };
|
|
4866
|
-
var THUMB = { base: [5e-3, -6e-3, -0.044], near: 0.034, far: 0.028, width: 0.019 };
|
|
5289
|
+
var PALM = { radius: 0.048, scale: [0.6, 1.05, 1], down: 0.035 };
|
|
5290
|
+
var CURL = { closed: 1.25, near: 0.9, far: 1.1 };
|
|
5291
|
+
var THUMB = { open: 0.32, closed: 0.25 };
|
|
4867
5292
|
var createHandMesh = (THREE, skin, wristSkin = skin) => {
|
|
4868
5293
|
const root = new THREE.Group();
|
|
4869
5294
|
root.name = "first-person-hand";
|
|
4870
5295
|
const geometries = [];
|
|
4871
|
-
const
|
|
4872
|
-
const geometry = new THREE.BoxGeometry(sx, sy, sz);
|
|
5296
|
+
const add = (parent, geometry, material, x = 0, y = 0, z = 0) => {
|
|
4873
5297
|
geometries.push(geometry);
|
|
4874
5298
|
const mesh = new THREE.Mesh(geometry, material);
|
|
4875
5299
|
mesh.position.set(x, y, z);
|
|
@@ -4877,64 +5301,26 @@ var createHandMesh = (THREE, skin, wristSkin = skin) => {
|
|
|
4877
5301
|
parent.add(mesh);
|
|
4878
5302
|
return mesh;
|
|
4879
5303
|
};
|
|
4880
|
-
const
|
|
4881
|
-
|
|
4882
|
-
|
|
4883
|
-
|
|
4884
|
-
|
|
4885
|
-
|
|
4886
|
-
|
|
4887
|
-
const palm = new THREE.Mesh(palmGeometry, skin);
|
|
4888
|
-
palm.frustumCulled = false;
|
|
4889
|
-
root.add(palm);
|
|
4890
|
-
const wristGeometry = new THREE.CylinderGeometry(0.03, 0.033, 0.05, 8);
|
|
5304
|
+
const group = new THREE.Group();
|
|
5305
|
+
group.quaternion.setFromRotationMatrix(new THREE.Matrix4().makeBasis(new THREE.Vector3(0, -1, 0), new THREE.Vector3(-1, 0, 0), new THREE.Vector3(0, 0, -1)));
|
|
5306
|
+
group.position.set(-PALM.down, 0, 0);
|
|
5307
|
+
root.add(group);
|
|
5308
|
+
add(group, new THREE.SphereGeometry(PALM.radius, 14, 10), skin, 0, -PALM.down, 0).scale.set(...PALM.scale);
|
|
5309
|
+
const built = buildHand({ THREE, add, hg: group, handM: skin, s: -1, detailed: true });
|
|
5310
|
+
const wristGeometry = new THREE.CylinderGeometry(0.03, 0.033, 0.05, 10);
|
|
4891
5311
|
wristGeometry.rotateZ(Math.PI / 2);
|
|
4892
|
-
|
|
4893
|
-
const wrist = new THREE.Mesh(wristGeometry, wristSkin);
|
|
4894
|
-
wrist.position.set(-PALM.length / 2 - 0.018, 0, 0);
|
|
4895
|
-
wrist.frustumCulled = false;
|
|
4896
|
-
root.add(wrist);
|
|
4897
|
-
const joints = [];
|
|
4898
|
-
FINGERS.forEach((finger, index) => {
|
|
4899
|
-
const segments = [];
|
|
4900
|
-
let parent = root;
|
|
4901
|
-
let at = PALM.length / 2;
|
|
4902
|
-
finger.lengths.forEach((length, k) => {
|
|
4903
|
-
const group = new THREE.Group();
|
|
4904
|
-
group.position.set(at, k === 0 ? 2e-3 : 0, k === 0 ? finger.z : 0);
|
|
4905
|
-
const taper = 1 - k * 0.07;
|
|
4906
|
-
box(group, length, FINGER_THICK * taper, finger.width * taper, length / 2, 0, 0);
|
|
4907
|
-
parent.add(group);
|
|
4908
|
-
segments.push(group);
|
|
4909
|
-
parent = group;
|
|
4910
|
-
at = length;
|
|
4911
|
-
});
|
|
4912
|
-
joints.push({ segments, weight: 1 + index * (CURL.spread / CURL.near) });
|
|
4913
|
-
});
|
|
4914
|
-
const thumbNear = new THREE.Group();
|
|
4915
|
-
thumbNear.rotation.order = "YZX";
|
|
4916
|
-
thumbNear.position.set(...THUMB.base);
|
|
4917
|
-
box(thumbNear, THUMB.near, FINGER_THICK * 1.1, THUMB.width, THUMB.near / 2, 0, 0);
|
|
4918
|
-
const thumbFar = new THREE.Group();
|
|
4919
|
-
thumbFar.position.set(THUMB.near, 0, 0);
|
|
4920
|
-
box(thumbFar, THUMB.far, FINGER_THICK, THUMB.width * 0.9, THUMB.far / 2, 0, 0);
|
|
4921
|
-
thumbNear.add(thumbFar);
|
|
4922
|
-
root.add(thumbNear);
|
|
5312
|
+
add(root, wristGeometry, wristSkin, -PALM.down - 0.03, 0, 0);
|
|
4923
5313
|
let lastGrip = 0;
|
|
4924
5314
|
let indexCurl;
|
|
4925
|
-
const
|
|
4926
|
-
|
|
4927
|
-
|
|
4928
|
-
if (!finger) return;
|
|
4929
|
-
const k = indexCurl === void 0 ? lastGrip : Math.min(1, Math.max(0, indexCurl));
|
|
4930
|
-
finger.segments.forEach((segment, i) => segment.rotation.z = -curl[i] * k * finger.weight);
|
|
5315
|
+
const curlFinger = (finger, k) => {
|
|
5316
|
+
built.fingers[finger * 2].rotation.z = k * CURL.closed * CURL.near;
|
|
5317
|
+
built.fingers[finger * 2 + 1].rotation.z = k * CURL.closed * CURL.far;
|
|
4931
5318
|
};
|
|
5319
|
+
const applyIndex = () => curlFinger(0, indexCurl === void 0 ? lastGrip : Math.min(1, Math.max(0, indexCurl)));
|
|
4932
5320
|
const setGrip = (grip) => {
|
|
4933
|
-
|
|
4934
|
-
|
|
4935
|
-
|
|
4936
|
-
thumbNear.rotation.set(0, 0.55 - 1.45 * k, -0.1 - 0.75 * k);
|
|
4937
|
-
thumbFar.rotation.z = -0.1 - 0.7 * k;
|
|
5321
|
+
lastGrip = Math.min(1, Math.max(0, grip));
|
|
5322
|
+
for (let finger = 1; finger < 4; finger++) curlFinger(finger, lastGrip);
|
|
5323
|
+
if (built.th) built.th.rotation.z = THUMB.open + lastGrip * THUMB.closed;
|
|
4938
5324
|
applyIndex();
|
|
4939
5325
|
};
|
|
4940
5326
|
const setIndex = (value) => {
|
|
@@ -4956,6 +5342,8 @@ var createHandMesh = (THREE, skin, wristSkin = skin) => {
|
|
|
4956
5342
|
var DEFAULT_BLEND = 0.18;
|
|
4957
5343
|
var ELBOW_SEGMENTS = 8;
|
|
4958
5344
|
var REACH_SLACK = 0.97;
|
|
5345
|
+
var ELBOW_VIEW_MARGIN = 0.86;
|
|
5346
|
+
var ELBOW_VIEW_PASSES = 4;
|
|
4959
5347
|
var CONTACT_PROBE = 1.4;
|
|
4960
5348
|
var CONTACT_MIN = 0.12;
|
|
4961
5349
|
var CONTACT_MARGIN = 5e-3;
|
|
@@ -5104,6 +5492,11 @@ function createFirstPersonArms(THREE, options = {}) {
|
|
|
5104
5492
|
const shoulderOf = (sign, out) => sign === -1 && rig.shoulderLeft ? out.set(...rig.shoulderLeft) : out.set(rig.shoulder[0] * sign, rig.shoulder[1], rig.shoulder[2]);
|
|
5105
5493
|
const poleOf = (sign) => sign === -1 && rig.elbowPoleLeft ? new THREE.Vector3(...rig.elbowPoleLeft) : new THREE.Vector3(rig.elbowPole[0] * sign, rig.elbowPole[1], rig.elbowPole[2]);
|
|
5106
5494
|
const kneePole = new THREE.Vector3(...rig.kneePole);
|
|
5495
|
+
const reachOf = (sign) => {
|
|
5496
|
+
const bend = rig.reachBend?.[sign === 1 ? 0 : 1];
|
|
5497
|
+
if (bend === void 0) return (rig.upper + rig.fore) * REACH_SLACK;
|
|
5498
|
+
return Math.sqrt(rig.upper * rig.upper + rig.fore * rig.fore + 2 * rig.upper * rig.fore * Math.cos(bend));
|
|
5499
|
+
};
|
|
5107
5500
|
const hip = new THREE.Vector3(...rig.hip);
|
|
5108
5501
|
const euler = new THREE.Euler(0, 0, 0, "YZX");
|
|
5109
5502
|
const quaternionOf = (r) => new THREE.Quaternion().setFromEuler(euler.set(r[0], r[1], r[2], "YZX"));
|
|
@@ -5193,15 +5586,45 @@ function createFirstPersonArms(THREE, options = {}) {
|
|
|
5193
5586
|
out.scale = base.scale;
|
|
5194
5587
|
return out;
|
|
5195
5588
|
};
|
|
5196
|
-
const
|
|
5589
|
+
const elbowAt = new THREE.Vector3();
|
|
5590
|
+
const viewOf = (camera) => {
|
|
5591
|
+
const lens = camera;
|
|
5592
|
+
if (!lens.isPerspectiveCamera) return null;
|
|
5593
|
+
const tanV = Math.tan(lens.fov * Math.PI / 360);
|
|
5594
|
+
return { tanV, tanH: tanV * lens.aspect };
|
|
5595
|
+
};
|
|
5596
|
+
const placeElbowInView = (sign, view) => {
|
|
5597
|
+
const way = rig.elbowView?.[sign === 1 ? 0 : 1];
|
|
5598
|
+
if (!way) return false;
|
|
5599
|
+
elbowAt.set(way[0], way[1], way[2]).setLength(rig.fore).add(wristAt);
|
|
5600
|
+
for (let pass = 0; pass < ELBOW_VIEW_PASSES; pass++) {
|
|
5601
|
+
const depth = Math.max(0.05, -elbowAt.z);
|
|
5602
|
+
const high = view.tanV * ELBOW_VIEW_MARGIN * depth;
|
|
5603
|
+
const wide = view.tanH * ELBOW_VIEW_MARGIN * depth;
|
|
5604
|
+
elbowAt.y = Math.max(elbowAt.y, -high);
|
|
5605
|
+
elbowAt.x = Math.min(wide, Math.max(-wide, elbowAt.x));
|
|
5606
|
+
elbowAt.sub(wristAt).setLength(rig.fore).add(wristAt);
|
|
5607
|
+
}
|
|
5608
|
+
shoulder.sub(elbowAt).setLength(rig.upper).add(elbowAt);
|
|
5609
|
+
return true;
|
|
5610
|
+
};
|
|
5611
|
+
const drawArm = (arm, pose, view) => {
|
|
5197
5612
|
copyPose(arm.drawn, pose);
|
|
5198
5613
|
const scale = pose.scale;
|
|
5199
5614
|
fingers.set(1, 0, 0).applyQuaternion(pose.q);
|
|
5200
5615
|
wristAt.copy(pose.p).addScaledVector(fingers, -rig.wrist * scale);
|
|
5201
5616
|
shoulderOf(arm.sign, shoulder).add(bobOffset);
|
|
5202
|
-
|
|
5617
|
+
if (view && placeElbowInView(arm.sign, view)) {
|
|
5618
|
+
solveTwoBone(shoulder, wristAt, rig.upper, rig.fore, towards.copy(elbowAt).sub(shoulder).add(elbowAt).sub(wristAt), bone);
|
|
5619
|
+
finishArm(arm, pose, scale);
|
|
5620
|
+
return;
|
|
5621
|
+
}
|
|
5622
|
+
const excess = shoulder.distanceTo(wristAt) - reachOf(arm.sign);
|
|
5203
5623
|
if (excess > 0 && rig.reachShift > 0) shoulder.addScaledVector(towards.subVectors(wristAt, shoulder).normalize(), Math.min(excess, rig.reachShift));
|
|
5204
5624
|
solveTwoBone(shoulder, wristAt, rig.upper, rig.fore, poleOf(arm.sign), bone);
|
|
5625
|
+
finishArm(arm, pose, scale);
|
|
5626
|
+
};
|
|
5627
|
+
const finishArm = (arm, pose, scale) => {
|
|
5205
5628
|
palmAt.copy(bone.end).addScaledVector(fingers, rig.wrist * scale);
|
|
5206
5629
|
arm.drawn.p.copy(palmAt);
|
|
5207
5630
|
arm.anchor.position.copy(palmAt);
|
|
@@ -5313,7 +5736,7 @@ function createFirstPersonArms(THREE, options = {}) {
|
|
|
5313
5736
|
dropped.p.y -= AWAY_DROP * ease(arm.away);
|
|
5314
5737
|
pose = dropped;
|
|
5315
5738
|
}
|
|
5316
|
-
drawArm(arm, pose);
|
|
5739
|
+
drawArm(arm, pose, mode === "target" && targets?.elbows !== "body" ? viewOf(state.camera) : null);
|
|
5317
5740
|
const shown = arm.away < AWAY_HIDDEN;
|
|
5318
5741
|
for (const part of [arm.anchor, arm.upper, arm.fore, arm.cuff, arm.elbow]) part.visible = shown;
|
|
5319
5742
|
}
|
|
@@ -5355,240 +5778,6 @@ function createFirstPersonArms(THREE, options = {}) {
|
|
|
5355
5778
|
}
|
|
5356
5779
|
};
|
|
5357
5780
|
}
|
|
5358
|
-
|
|
5359
|
-
// src/player/room-avatar.ts
|
|
5360
|
-
var impactOf = (clip) => clip.events?.find((event) => event.type === "impact")?.t ?? null;
|
|
5361
|
-
var isPunch = (clip) => clip.events?.some((event) => event.type === "impact" && event.data?.kind === "punch") ?? false;
|
|
5362
|
-
var GUARD_SPEED = 0.3;
|
|
5363
|
-
var toRoomAvatar = (avatar, options = {}) => {
|
|
5364
|
-
const arms = options.firstPerson === false ? null : createFirstPersonArms(avatar.three, {
|
|
5365
|
-
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 },
|
|
5366
|
-
clips: options.firstPersonClips ?? FIRST_PERSON_CLIPS,
|
|
5367
|
-
hideWhenIdle: true,
|
|
5368
|
-
...options.firstPerson
|
|
5369
|
-
});
|
|
5370
|
-
const strikes = new Map((options.strikeClips ?? ATTACK_CLIPS).map((clip) => [clip.id, clip]));
|
|
5371
|
-
const mirrored = /* @__PURE__ */ new Map();
|
|
5372
|
-
const leftOf = (clip) => {
|
|
5373
|
-
let found = mirrored.get(clip.id);
|
|
5374
|
-
if (!found) mirrored.set(clip.id, found = mirrorPoseClip(clip, `${clip.id}_left`));
|
|
5375
|
-
return found;
|
|
5376
|
-
};
|
|
5377
|
-
const guard = options.guardClip === false ? void 0 : strikes.get(options.guardClip ?? "fight_guard");
|
|
5378
|
-
const guardHold = options.guardHold ?? 1.2;
|
|
5379
|
-
const punchBlend = options.punchBlend ?? 0.05;
|
|
5380
|
-
let strikeLeft = 0;
|
|
5381
|
-
let guardLeft = 0;
|
|
5382
|
-
let guarding = false;
|
|
5383
|
-
const stepGuard = (dt, state) => {
|
|
5384
|
-
if (!guard) return;
|
|
5385
|
-
const free = state.speed < GUARD_SPEED && !state.down && !state.armed && !state.holding && !state.push && !state.itemUse && !state.running;
|
|
5386
|
-
if (strikeLeft > 0) {
|
|
5387
|
-
strikeLeft -= dt;
|
|
5388
|
-
if (strikeLeft <= 0 && guardLeft > 0 && free) {
|
|
5389
|
-
avatar.play(guard);
|
|
5390
|
-
guarding = true;
|
|
5391
|
-
}
|
|
5392
|
-
return;
|
|
5393
|
-
}
|
|
5394
|
-
guardLeft = Math.max(0, guardLeft - dt);
|
|
5395
|
-
if (guarding && (guardLeft <= 0 || !free || avatar.playing !== guard.id)) {
|
|
5396
|
-
if (avatar.playing === guard.id) avatar.stop();
|
|
5397
|
-
guarding = false;
|
|
5398
|
-
}
|
|
5399
|
-
};
|
|
5400
|
-
return {
|
|
5401
|
-
root: avatar.root,
|
|
5402
|
-
avatar,
|
|
5403
|
-
arms,
|
|
5404
|
-
...arms ? { firstPerson: { root: arms.root, update: (dt, state) => arms.update(dt, state) } } : {},
|
|
5405
|
-
update: (dt, state) => {
|
|
5406
|
-
stepGuard(dt, state);
|
|
5407
|
-
avatar.update(dt, {
|
|
5408
|
-
speed: state.speed,
|
|
5409
|
-
running: state.running,
|
|
5410
|
-
crouch: state.crouch,
|
|
5411
|
-
down: state.down,
|
|
5412
|
-
armed: state.armed,
|
|
5413
|
-
pitch: -state.pitch,
|
|
5414
|
-
...state.holding !== void 0 ? { holding: state.holding } : {},
|
|
5415
|
-
...state.itemUse !== void 0 ? { itemUse: state.itemUse } : {},
|
|
5416
|
-
...state.push !== void 0 ? { push: state.push } : {}
|
|
5417
|
-
});
|
|
5418
|
-
},
|
|
5419
|
-
hand: (side) => avatar.hand(side),
|
|
5420
|
-
reach: (targets) => avatar.reach(targets),
|
|
5421
|
-
strike: (clipId, strikeOptions) => {
|
|
5422
|
-
const clip = strikes.get(clipId);
|
|
5423
|
-
if (!clip) return null;
|
|
5424
|
-
const left = strikeOptions?.leg === "left" || strikeOptions?.hand === "left";
|
|
5425
|
-
const punch = guard !== void 0 && isPunch(clip);
|
|
5426
|
-
avatar.play(left ? leftOf(clip) : clip, punch ? { blend: punchBlend } : void 0);
|
|
5427
|
-
strikeLeft = punch ? clip.duration : 0;
|
|
5428
|
-
guardLeft = punch ? guardHold : 0;
|
|
5429
|
-
guarding = false;
|
|
5430
|
-
arms?.play(clipId, strikeOptions?.leg === "left" ? { leg: "left" } : strikeOptions?.hand === "left" ? { hand: "left" } : void 0);
|
|
5431
|
-
return impactOf(clip);
|
|
5432
|
-
}
|
|
5433
|
-
};
|
|
5434
|
-
};
|
|
5435
|
-
|
|
5436
|
-
// src/player/test-module.ts
|
|
5437
|
-
import { POSE_CLIPS as POSE_CLIPS2, POSE_CLIP_LOCALES } from "@adatechnology/game-characters";
|
|
5438
|
-
|
|
5439
|
-
// src/player/test-text.ts
|
|
5440
|
-
var AVATAR_TEXT = {
|
|
5441
|
-
en: {
|
|
5442
|
-
group: "Avatar",
|
|
5443
|
-
name: "Player body",
|
|
5444
|
-
actions: {
|
|
5445
|
-
camera_first: "Camera: 1st person",
|
|
5446
|
-
camera_third: "Camera: 3rd person",
|
|
5447
|
-
crouch: "Crouch",
|
|
5448
|
-
stand: "Stand up",
|
|
5449
|
-
fall: "Fall down",
|
|
5450
|
-
get_up: "Get up",
|
|
5451
|
-
armed_on: "Armed: on",
|
|
5452
|
-
armed_off: "Armed: off",
|
|
5453
|
-
stop_clip: "Stop clip"
|
|
5454
|
-
},
|
|
5455
|
-
play: "Play",
|
|
5456
|
-
metrics: { camera: "Camera", clip: "Clip playing", last_event: "Last clip event", state: "State", joints: "Joints" },
|
|
5457
|
-
none: "none"
|
|
5458
|
-
},
|
|
5459
|
-
"pt-BR": {
|
|
5460
|
-
group: "Avatar",
|
|
5461
|
-
name: "Corpo do jogador",
|
|
5462
|
-
actions: {
|
|
5463
|
-
camera_first: "C\xE2mera: 1\xAA pessoa",
|
|
5464
|
-
camera_third: "C\xE2mera: 3\xAA pessoa",
|
|
5465
|
-
crouch: "Agachar",
|
|
5466
|
-
stand: "Levantar",
|
|
5467
|
-
fall: "Cair",
|
|
5468
|
-
get_up: "Levantar do ch\xE3o",
|
|
5469
|
-
armed_on: "Armado: ligado",
|
|
5470
|
-
armed_off: "Armado: desligado",
|
|
5471
|
-
stop_clip: "Parar clipe"
|
|
5472
|
-
},
|
|
5473
|
-
play: "Tocar",
|
|
5474
|
-
metrics: { camera: "C\xE2mera", clip: "Clipe tocando", last_event: "\xDAltimo evento do clipe", state: "Estado", joints: "Juntas" },
|
|
5475
|
-
none: "nenhum"
|
|
5476
|
-
}
|
|
5477
|
-
};
|
|
5478
|
-
|
|
5479
|
-
// src/player/test-module.ts
|
|
5480
|
-
var AVATAR_AREA_ID = "avatar_area";
|
|
5481
|
-
var round = (value) => (Math.round(value * 100) / 100).toString();
|
|
5482
|
-
function createAvatarTestModule(options) {
|
|
5483
|
-
const clips = options.clips ?? POSE_CLIPS2;
|
|
5484
|
-
const textOf = (locale) => AVATAR_TEXT[locale ?? options.locale ?? "pt-BR"] ?? AVATAR_TEXT["pt-BR"];
|
|
5485
|
-
const phaseLabel = (label, locale) => {
|
|
5486
|
-
const id = locale ?? options.locale ?? "pt-BR";
|
|
5487
|
-
const table = { ...POSE_CLIP_LOCALES[id] ?? POSE_CLIP_LOCALES["pt-BR"], ...options.clipLocales?.[id] ?? options.clipLocales?.["pt-BR"] };
|
|
5488
|
-
return typeof label === "string" ? table[label] ?? label : "";
|
|
5489
|
-
};
|
|
5490
|
-
const state = { crouch: false, down: false, armed: null };
|
|
5491
|
-
let host = null;
|
|
5492
|
-
let lastEvent = "";
|
|
5493
|
-
const log = (action, extra = {}) => {
|
|
5494
|
-
const entry = { type: "avatar", action, ...extra };
|
|
5495
|
-
host?.log(JSON.stringify(entry), entry);
|
|
5496
|
-
};
|
|
5497
|
-
const push = (action, patch, extra = {}) => {
|
|
5498
|
-
Object.assign(state, patch);
|
|
5499
|
-
options.state?.set(patch);
|
|
5500
|
-
log(action, { crouch: state.crouch, down: state.down, armed: state.armed, ...extra });
|
|
5501
|
-
};
|
|
5502
|
-
const setCamera = (mode) => {
|
|
5503
|
-
options.camera?.set(mode);
|
|
5504
|
-
log(`camera_${mode}`, { mode: options.camera?.mode() ?? null });
|
|
5505
|
-
};
|
|
5506
|
-
const onChange = (change) => {
|
|
5507
|
-
if (change.kind !== "action") return;
|
|
5508
|
-
switch (change.id) {
|
|
5509
|
-
case "camera_first":
|
|
5510
|
-
return setCamera("first");
|
|
5511
|
-
case "camera_third":
|
|
5512
|
-
return setCamera("third");
|
|
5513
|
-
case "crouch":
|
|
5514
|
-
return push("crouch", { crouch: true });
|
|
5515
|
-
case "stand":
|
|
5516
|
-
return push("stand", { crouch: false });
|
|
5517
|
-
case "fall":
|
|
5518
|
-
return push("fall", { down: true });
|
|
5519
|
-
case "get_up":
|
|
5520
|
-
return push("get_up", { down: false });
|
|
5521
|
-
case "armed_on":
|
|
5522
|
-
return push("armed_on", { armed: true });
|
|
5523
|
-
case "armed_off":
|
|
5524
|
-
return push("armed_off", { armed: false });
|
|
5525
|
-
case "stop_clip":
|
|
5526
|
-
options.avatar.stop();
|
|
5527
|
-
return log("stop_clip", { playing: options.avatar.playing });
|
|
5528
|
-
default: {
|
|
5529
|
-
const clip = clips.find((item) => `play_${item.id}` === change.id);
|
|
5530
|
-
if (!clip) return;
|
|
5531
|
-
options.avatar.play(clip);
|
|
5532
|
-
log("play_clip", { clip: clip.id, duration: clip.duration, loop: clip.loop ?? false, channels: clip.channels ?? "full" });
|
|
5533
|
-
}
|
|
5534
|
-
}
|
|
5535
|
-
};
|
|
5536
|
-
const joints = () => {
|
|
5537
|
-
const rig = options.avatar.rig;
|
|
5538
|
-
const [armA, armB] = rig.arms;
|
|
5539
|
-
const [legA, legB] = rig.legs;
|
|
5540
|
-
return `arms ${round(armA.g.rotation.x)}/${round(armB.g.rotation.x)} elbows ${round(armA.el.rotation.x)}/${round(armB.el.rotation.x)} legs ${round(legA.g.rotation.x)}/${round(legB.g.rotation.x)} knees ${round(legA.kn.rotation.x)}/${round(legB.kn.rotation.x)} lean ${round(rig.upper.rotation.x)}`;
|
|
5541
|
-
};
|
|
5542
|
-
return {
|
|
5543
|
-
id: AVATAR_AREA_ID,
|
|
5544
|
-
name: textOf().name,
|
|
5545
|
-
ground: { surface: "concrete_slab" },
|
|
5546
|
-
group: textOf().group,
|
|
5547
|
-
state,
|
|
5548
|
-
items: () => [],
|
|
5549
|
-
area: () => ({ placements: [], view: { eye: [0, 1.7, 6], target: [0, 1.2, 0] } }),
|
|
5550
|
-
controls: (locale) => {
|
|
5551
|
-
const text = textOf(locale);
|
|
5552
|
-
const action = (id, name, hint) => ({ kind: "action", id, name, ...hint ? { hint } : {} });
|
|
5553
|
-
return [
|
|
5554
|
-
action("camera_first", text.actions.camera_first),
|
|
5555
|
-
action("camera_third", text.actions.camera_third),
|
|
5556
|
-
action("crouch", text.actions.crouch),
|
|
5557
|
-
action("stand", text.actions.stand),
|
|
5558
|
-
action("fall", text.actions.fall),
|
|
5559
|
-
action("get_up", text.actions.get_up),
|
|
5560
|
-
action("armed_on", text.actions.armed_on),
|
|
5561
|
-
action("armed_off", text.actions.armed_off),
|
|
5562
|
-
...clips.map((clip) => action(`play_${clip.id}`, `${text.play}: ${clip.id}`)),
|
|
5563
|
-
action("stop_clip", text.actions.stop_clip)
|
|
5564
|
-
];
|
|
5565
|
-
},
|
|
5566
|
-
metrics: (locale) => {
|
|
5567
|
-
const text = textOf(locale);
|
|
5568
|
-
return [
|
|
5569
|
-
{ id: "camera", name: text.metrics.camera, read: () => options.camera?.mode() ?? text.none },
|
|
5570
|
-
{ id: "clip", name: text.metrics.clip, read: () => options.avatar.playing ?? text.none },
|
|
5571
|
-
{ id: "last_event", name: text.metrics.last_event, read: () => lastEvent || text.none },
|
|
5572
|
-
{ id: "state", name: text.metrics.state, read: () => `${state.crouch ? "crouch " : ""}${state.down ? "down " : ""}${state.armed === null ? "" : state.armed ? "armed" : "unarmed"}`.trim() || text.none },
|
|
5573
|
-
{ id: "joints", name: text.metrics.joints, read: joints }
|
|
5574
|
-
];
|
|
5575
|
-
},
|
|
5576
|
-
attach(lent) {
|
|
5577
|
-
host = lent;
|
|
5578
|
-
const stopChange = lent.bench?.onChange(onChange);
|
|
5579
|
-
const stopEvents = options.avatar.on("event", (event) => {
|
|
5580
|
-
lastEvent = `${event.clip} ${event.type} ${round(event.t)}s${event.data && "label" in event.data ? ` ${phaseLabel(event.data.label)}` : ""}`;
|
|
5581
|
-
log("clip_event", { clip: event.clip, event: event.type, t: event.t, data: event.data ?? null });
|
|
5582
|
-
if (event.type === "impact") log("impact", { clip: event.clip, t: event.t, kind: event.data?.kind ?? null });
|
|
5583
|
-
});
|
|
5584
|
-
return () => {
|
|
5585
|
-
stopChange?.();
|
|
5586
|
-
stopEvents();
|
|
5587
|
-
host = null;
|
|
5588
|
-
};
|
|
5589
|
-
}
|
|
5590
|
-
};
|
|
5591
|
-
}
|
|
5592
5781
|
export {
|
|
5593
5782
|
AVATAR_AREA_ID,
|
|
5594
5783
|
BAKE_NEUTRAL_POSE,
|