@adatechnology/game-characters-three 0.4.1 → 0.5.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/README.md +5 -4
- package/dist/index.d.ts +25 -2
- package/dist/index.global.js +236 -47
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +85 -25
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
package/dist/index.js
CHANGED
|
@@ -4065,6 +4065,7 @@ function createCharactersTestModule(options = {}) {
|
|
|
4065
4065
|
return {
|
|
4066
4066
|
id: CHARACTERS_AREA_ID,
|
|
4067
4067
|
name: text.name,
|
|
4068
|
+
ground: { surface: "concrete_slab" },
|
|
4068
4069
|
group: text.group,
|
|
4069
4070
|
get entries() {
|
|
4070
4071
|
return entries;
|
|
@@ -4238,6 +4239,7 @@ var player_avatar_default = {
|
|
|
4238
4239
|
var TWO_PI = Math.PI * 2;
|
|
4239
4240
|
var MAX_GAIT = 1.4;
|
|
4240
4241
|
var CLIP_BLEND = 0.12;
|
|
4242
|
+
var CLIP_CASCADE = 5;
|
|
4241
4243
|
var FALL_SECONDS2 = 0.3;
|
|
4242
4244
|
var HIP_HEIGHT = 0.95;
|
|
4243
4245
|
var WALK_ARM = 0.28;
|
|
@@ -4277,6 +4279,7 @@ var createPlayerAvatar = (THREE, options = {}) => {
|
|
|
4277
4279
|
const blendDefault = options.blend ?? CLIP_BLEND;
|
|
4278
4280
|
const fallSeconds = options.fallSeconds ?? FALL_SECONDS2;
|
|
4279
4281
|
const smooth = options.cascade ?? true;
|
|
4282
|
+
const clipCascade = options.clipCascade ?? CLIP_CASCADE;
|
|
4280
4283
|
const root = new THREE.Group();
|
|
4281
4284
|
const tilt = new THREE.Group();
|
|
4282
4285
|
tilt.add(body);
|
|
@@ -4376,6 +4379,24 @@ var createPlayerAvatar = (THREE, options = {}) => {
|
|
|
4376
4379
|
});
|
|
4377
4380
|
return { armR: shoulder, armL: shoulder, armRz: AIMED.zRight, armLz: AIMED.zLeft, elbR: AIMED.elbowRight, elbL: AIMED.elbowLeft };
|
|
4378
4381
|
};
|
|
4382
|
+
const pushingPose = (push) => {
|
|
4383
|
+
const on = push.phase === "grip" ? Math.min(1, push.progress * 2.2) : 1;
|
|
4384
|
+
const strain = push.phase === "strain" ? 1 : 0;
|
|
4385
|
+
const shake = strain * Math.sin(time * 40) * 0.025;
|
|
4386
|
+
const raise = -1.5 * on;
|
|
4387
|
+
const elbow = -0.9 + 0.72 * (push.phase === "grip" ? push.progress : 1) + strain * 0.12;
|
|
4388
|
+
return {
|
|
4389
|
+
lean: (0.2 + 0.2 * strain) * on,
|
|
4390
|
+
headX: (0.05 + 0.08 * strain) * on,
|
|
4391
|
+
armR: raise + shake,
|
|
4392
|
+
armL: raise - shake,
|
|
4393
|
+
armRz: -0.08 * on,
|
|
4394
|
+
armLz: 0.08 * on,
|
|
4395
|
+
elbR: elbow,
|
|
4396
|
+
elbL: elbow,
|
|
4397
|
+
...strain ? { legL: -0.5, legR: 0.4, kneeL: 0.55, kneeR: 0.08, drop: -0.05 } : {}
|
|
4398
|
+
};
|
|
4399
|
+
};
|
|
4379
4400
|
const holdingPose = (gait, itemUse) => {
|
|
4380
4401
|
const bob = Math.sin(cycles * TWO_PI) * 0.05 * gait;
|
|
4381
4402
|
if (!itemUse) {
|
|
@@ -4503,7 +4524,7 @@ var createPlayerAvatar = (THREE, options = {}) => {
|
|
|
4503
4524
|
const fireClipEvents = (r, from, to) => {
|
|
4504
4525
|
for (const event of clipEventsBetween(r.clip, from, to)) emit({ ...event, clip: r.clip.id }, r.onEvent);
|
|
4505
4526
|
};
|
|
4506
|
-
const stepClip = (dt, down) => {
|
|
4527
|
+
const stepClip = (dt, down, crouch) => {
|
|
4507
4528
|
if (!run) return;
|
|
4508
4529
|
const r = run;
|
|
4509
4530
|
const from = r.time;
|
|
@@ -4523,7 +4544,9 @@ var createPlayerAvatar = (THREE, options = {}) => {
|
|
|
4523
4544
|
return;
|
|
4524
4545
|
}
|
|
4525
4546
|
if (down) return;
|
|
4526
|
-
const
|
|
4547
|
+
const keepsCrouch = crouch && !r.clip.events?.some((event) => event.data?.kind === "kick");
|
|
4548
|
+
const channels = r.clip.channels ?? "full";
|
|
4549
|
+
const sampled = filterPoseChannels(filterPoseChannels(samplePoseClip(r.clip, Math.min(r.time, duration)), channels), keepsCrouch ? "upper" : "full");
|
|
4527
4550
|
const current = readPose();
|
|
4528
4551
|
const blended = {};
|
|
4529
4552
|
for (const [name, value] of Object.entries(sampled)) if (name in current) blended[name] = current[name] + (value - current[name]) * r.weight;
|
|
@@ -4554,7 +4577,8 @@ var createPlayerAvatar = (THREE, options = {}) => {
|
|
|
4554
4577
|
else {
|
|
4555
4578
|
if (running) animator.setPose(rig, runningPose(gait, Boolean(state.armed || state.holding || state.itemUse)));
|
|
4556
4579
|
if (state.crouch) animator.setPose(rig, crouchPose(gait));
|
|
4557
|
-
if (state.
|
|
4580
|
+
if (state.push) animator.setPose(rig, pushingPose(state.push));
|
|
4581
|
+
else if (state.armed) animator.setPose(rig, armed(state.pitch ?? 0, gait, state.hip ?? 0));
|
|
4558
4582
|
else if (state.holding || state.itemUse) animator.setPose(rig, holdingPose(gait, state.itemUse));
|
|
4559
4583
|
else if (!running) {
|
|
4560
4584
|
animator.setPose(rig, {
|
|
@@ -4566,15 +4590,15 @@ var createPlayerAvatar = (THREE, options = {}) => {
|
|
|
4566
4590
|
}
|
|
4567
4591
|
}
|
|
4568
4592
|
placeBody(fall);
|
|
4569
|
-
stepClip(dt, down);
|
|
4570
|
-
if (smooth) animator.cascade(rig, dt);
|
|
4571
|
-
const
|
|
4593
|
+
stepClip(dt, down, Boolean(state.crouch));
|
|
4594
|
+
if (smooth) animator.cascade(rig, run && !run.clip.loop ? dt * clipCascade : dt);
|
|
4595
|
+
const blow = run?.clip.events?.find((event) => (event.type === "impact" || event.type === "grip") && event.data?.kind)?.data?.kind;
|
|
4572
4596
|
const ph = cycles * TWO_PI;
|
|
4573
4597
|
hands.forEach((hand) => {
|
|
4574
4598
|
const isRight = hand.side < 0;
|
|
4575
4599
|
const holdRight = isRight && (!!state.holding || !!state.itemUse);
|
|
4576
4600
|
const holdLeft = !isRight && (state.itemUse?.id === "open" || state.itemUse?.id === "close");
|
|
4577
|
-
const grip =
|
|
4601
|
+
const grip = blow === "punch" ? 1.4 : blow === "shove" ? 0.15 : state.armed || holdRight || holdLeft ? 1.22 : running ? 0.85 : 0.12;
|
|
4578
4602
|
const wristSwing = holdRight || state.armed || running ? 0 : -Math.min(1, gait) * Math.sin(ph - 0.6) * 0.12 * hand.side;
|
|
4579
4603
|
setHandGrip(hand, grip, wristSwing);
|
|
4580
4604
|
});
|
|
@@ -5003,10 +5027,11 @@ function createFirstPersonArms(THREE, options = {}) {
|
|
|
5003
5027
|
const palmAt = new THREE.Vector3();
|
|
5004
5028
|
const fingers = new THREE.Vector3();
|
|
5005
5029
|
const towards = new THREE.Vector3();
|
|
5006
|
-
const fromChannel = (channel, side, base, out) => {
|
|
5030
|
+
const fromChannel = (channel, side, base, out, from = side) => {
|
|
5007
5031
|
out.p.set(...channel.p);
|
|
5008
5032
|
out.q.copy(quaternionOf(channel.r));
|
|
5009
|
-
|
|
5033
|
+
const rightNumbers = from === "R" || channel.mirror;
|
|
5034
|
+
if (rightNumbers !== (side === "R")) {
|
|
5010
5035
|
out.p.x = -out.p.x;
|
|
5011
5036
|
out.q.copy(mirrorQuaternion(THREE, out.q));
|
|
5012
5037
|
}
|
|
@@ -5071,7 +5096,7 @@ function createFirstPersonArms(THREE, options = {}) {
|
|
|
5071
5096
|
play(id, options2) {
|
|
5072
5097
|
const clip = clips.get(id);
|
|
5073
5098
|
if (!clip) return false;
|
|
5074
|
-
run = { clip, time: 0, left: options2?.leg === "left" };
|
|
5099
|
+
run = { clip, time: 0, left: options2?.leg === "left", swap: options2?.hand === "left" };
|
|
5075
5100
|
fire(clip, -1e-9, 0);
|
|
5076
5101
|
return true;
|
|
5077
5102
|
},
|
|
@@ -5119,10 +5144,11 @@ function createFirstPersonArms(THREE, options = {}) {
|
|
|
5119
5144
|
arm.blend = blendSeconds <= 0 ? 1 : Math.min(1, arm.blend + dt / blendSeconds);
|
|
5120
5145
|
if (arm.blend >= 1) copyPose(arm.shown, desired);
|
|
5121
5146
|
else mixPose(THREE, arm.shown, arm.from, desired, ease(arm.blend));
|
|
5122
|
-
const
|
|
5147
|
+
const from = run?.swap ? side === "R" ? "L" : "R" : side;
|
|
5148
|
+
const channel = sample?.[from];
|
|
5123
5149
|
let pose;
|
|
5124
5150
|
if (channel && channel.w > 0) {
|
|
5125
|
-
fromChannel(channel, side, arm.shown, channelPose);
|
|
5151
|
+
fromChannel(channel, side, arm.shown, channelPose, from);
|
|
5126
5152
|
mixPose(THREE, mixed, arm.shown, channelPose, channel.w);
|
|
5127
5153
|
pose = mode === "target" ? mixed : keepOutside(mixed, handReach(mixed));
|
|
5128
5154
|
} else pose = mode === "target" ? arm.shown : keepOutside(arm.shown, handReach(arm.shown));
|
|
@@ -5178,6 +5204,8 @@ function createFirstPersonArms(THREE, options = {}) {
|
|
|
5178
5204
|
|
|
5179
5205
|
// src/player/room-avatar.ts
|
|
5180
5206
|
var impactOf = (clip) => clip.events?.find((event) => event.type === "impact")?.t ?? null;
|
|
5207
|
+
var isPunch = (clip) => clip.events?.some((event) => event.type === "impact" && event.data?.kind === "punch") ?? false;
|
|
5208
|
+
var GUARD_SPEED = 0.3;
|
|
5181
5209
|
var toRoomAvatar = (avatar, options = {}) => {
|
|
5182
5210
|
const arms = options.firstPerson === false ? null : createFirstPersonArms(avatar.three, {
|
|
5183
5211
|
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 },
|
|
@@ -5192,28 +5220,59 @@ var toRoomAvatar = (avatar, options = {}) => {
|
|
|
5192
5220
|
if (!found) mirrored.set(clip.id, found = mirrorPoseClip(clip, `${clip.id}_left`));
|
|
5193
5221
|
return found;
|
|
5194
5222
|
};
|
|
5223
|
+
const guard = options.guardClip === false ? void 0 : strikes.get(options.guardClip ?? "fight_guard");
|
|
5224
|
+
const guardHold = options.guardHold ?? 1.2;
|
|
5225
|
+
const punchBlend = options.punchBlend ?? 0.05;
|
|
5226
|
+
let strikeLeft = 0;
|
|
5227
|
+
let guardLeft = 0;
|
|
5228
|
+
let guarding = false;
|
|
5229
|
+
const stepGuard = (dt, state) => {
|
|
5230
|
+
if (!guard) return;
|
|
5231
|
+
const free = state.speed < GUARD_SPEED && !state.down && !state.armed && !state.holding && !state.push && !state.itemUse && !state.running;
|
|
5232
|
+
if (strikeLeft > 0) {
|
|
5233
|
+
strikeLeft -= dt;
|
|
5234
|
+
if (strikeLeft <= 0 && guardLeft > 0 && free) {
|
|
5235
|
+
avatar.play(guard);
|
|
5236
|
+
guarding = true;
|
|
5237
|
+
}
|
|
5238
|
+
return;
|
|
5239
|
+
}
|
|
5240
|
+
guardLeft = Math.max(0, guardLeft - dt);
|
|
5241
|
+
if (guarding && (guardLeft <= 0 || !free || avatar.playing !== guard.id)) {
|
|
5242
|
+
if (avatar.playing === guard.id) avatar.stop();
|
|
5243
|
+
guarding = false;
|
|
5244
|
+
}
|
|
5245
|
+
};
|
|
5195
5246
|
return {
|
|
5196
5247
|
root: avatar.root,
|
|
5197
5248
|
avatar,
|
|
5198
5249
|
arms,
|
|
5199
5250
|
...arms ? { firstPerson: { root: arms.root, update: (dt, state) => arms.update(dt, state) } } : {},
|
|
5200
|
-
update: (dt, state) =>
|
|
5201
|
-
|
|
5202
|
-
|
|
5203
|
-
|
|
5204
|
-
|
|
5205
|
-
|
|
5206
|
-
|
|
5207
|
-
|
|
5208
|
-
|
|
5209
|
-
|
|
5251
|
+
update: (dt, state) => {
|
|
5252
|
+
stepGuard(dt, state);
|
|
5253
|
+
avatar.update(dt, {
|
|
5254
|
+
speed: state.speed,
|
|
5255
|
+
running: state.running,
|
|
5256
|
+
crouch: state.crouch,
|
|
5257
|
+
down: state.down,
|
|
5258
|
+
armed: state.armed,
|
|
5259
|
+
pitch: -state.pitch,
|
|
5260
|
+
...state.holding !== void 0 ? { holding: state.holding } : {},
|
|
5261
|
+
...state.itemUse !== void 0 ? { itemUse: state.itemUse } : {},
|
|
5262
|
+
...state.push !== void 0 ? { push: state.push } : {}
|
|
5263
|
+
});
|
|
5264
|
+
},
|
|
5210
5265
|
hand: (side) => avatar.hand(side),
|
|
5211
5266
|
strike: (clipId, strikeOptions) => {
|
|
5212
5267
|
const clip = strikes.get(clipId);
|
|
5213
5268
|
if (!clip) return null;
|
|
5214
|
-
const left = strikeOptions?.leg === "left";
|
|
5215
|
-
|
|
5216
|
-
|
|
5269
|
+
const left = strikeOptions?.leg === "left" || strikeOptions?.hand === "left";
|
|
5270
|
+
const punch = guard !== void 0 && isPunch(clip);
|
|
5271
|
+
avatar.play(left ? leftOf(clip) : clip, punch ? { blend: punchBlend } : void 0);
|
|
5272
|
+
strikeLeft = punch ? clip.duration : 0;
|
|
5273
|
+
guardLeft = punch ? guardHold : 0;
|
|
5274
|
+
guarding = false;
|
|
5275
|
+
arms?.play(clipId, strikeOptions?.leg === "left" ? { leg: "left" } : strikeOptions?.hand === "left" ? { hand: "left" } : void 0);
|
|
5217
5276
|
return impactOf(clip);
|
|
5218
5277
|
}
|
|
5219
5278
|
};
|
|
@@ -5328,6 +5387,7 @@ function createAvatarTestModule(options) {
|
|
|
5328
5387
|
return {
|
|
5329
5388
|
id: AVATAR_AREA_ID,
|
|
5330
5389
|
name: textOf().name,
|
|
5390
|
+
ground: { surface: "concrete_slab" },
|
|
5331
5391
|
group: textOf().group,
|
|
5332
5392
|
state,
|
|
5333
5393
|
items: () => [],
|