@adatechnology/game-characters-three

中文文档
0.9.5发布于 2026/11/06MITTypeScriptES Module构建来源已验证近 30 天下载 3548

three.js presentation for @adatechnology/game-characters: the instanced crowd body (GPU animation, LOD, baking, variants, flying limbs) and the rich bodies (the Bestiário v17 builder, survivors with accessories and hands, the animator, wounds, eyes).

原始使用文档

@adatechnology/game-characters-three

three.js presentation for @adatechnology/game-characters. three.js is passed in by the host (import * as THREE from 'three'), so the same code runs from a bundler or from a plain script (dist/index.global.js exposes the GameCharactersThree global).

Instanced crowd body (literal port of the game's, G 65336-65541):

  • buildInstancedBody(THREE, { segments, body? }): the merged geometry (torso, head, hair, jaw, eyes, arms, legs) tagged with bone, pivot and material; 16, 10 and 5 segments are the three levels of detail. body defaults to TEAM_GAME; any BodySpec moves the joints.
  • BODY_CHUNK / createBodyChunk: the GPU pose chunk, byte for byte from the game (only the hip joint is a parameter). createBodyMaterial adds the tints and glowing eyes.
  • createBodyBatch: begin, push per body, end; one draw call for a whole variant.
  • bakeBody and bakeVariants: bake a rich body into an instanceable geometry; the three variants rule of the game (7000 + c·101 + v·13).
  • createFlyingLimbs: 40 torn-off pieces that fly, bounce and stay, with injected blood effects.
import * as THREE from 'three'
import { buildInstancedBody, createBodyBatch } from '@adatechnology/game-characters-three'

const time = { value: 0 }
const batch = createBodyBatch(THREE, buildInstancedBody(THREE, { segments: 10 }), { max: 700, time })
scene.add(batch.mesh)
batch.begin()
batch.push({ a: [x, z, yaw, phase], b: [1.8, 1, stride, 0], c: [missingMask, infection, 1, skinTone], color: { r: 0.3, g: 0.4, b: 0.5 }, eye: { r: 1, g: 0.2, b: 0.1 } })
batch.end()
time.value += dt

Sound and blood of the bodies (on @adatechnology/game-audio and the running film of @adatechnology/game-fluids-three):

  • createCharacterSound(host.audio, { style? }): voice(typeId, 'idle' | 'alert' | 'special', position) for the 13 undead types (UNDEAD_VOICES: the game's groans and scream, the art scene's voice groan, scream and leap, with the class rule of the page for the types it does not have), body(event, position) (wound = flesh, cut = sever, burst or split = gore), player('grab' | 'bite' | 'hurt'). The 16 recipes (CHARACTER_SOUND_BANK) leave the same trace as the team code.
  • createFluidsBridge({ sink, film }) and bloodLookOfAge(age): a body event throws drops of blood into the film, in the fresh and dry colours of the infection age (ages.json), old_blood for the thin ones.

Player avatar. createPlayerAvatar(THREE, options?) is the team game's player body: the rich human of the Bestiário/Elenco built from presets/player-avatar.json ({ type: 'Lento', human: true, seed: 4242, skin, hs: 'short', hair }, shirt 0x3d5a73), overridable with { spec, shirtColor, clips, blend, fallSeconds, cascade, clipCascade } (clipCascade, default 5: how many times faster the joints follow while a clip that does not loop plays, so a strike reaches its pose by its impact).

const player = createPlayerAvatar(THREE)
scene.add(player.root)
player.update(dt, { speed, crouch, down, armed, pitch, hip }) // the gait is tied to the ground speed (cadence and swing from `walkCadence`/`walkGait`)
player.hand('R').add(weaponMesh) // a socket at the weapon hand
player.play('grabbed_bitten_human', { onEvent: (event) => event.type === 'impact' && applyBlow() }) // or player.play(myClip); player.on('event', fn); player.stop()

Crouch, down and the aimed arms are derived literally from the game's GPU pose code (BODY_CHUNK, lines quoted in src/player/avatar.ts): crouch is thigh -0.95, knee 1.9, trunk +0.25, hip -0.35; down turns the body about the hip (±1.5 rad, face up or down by the phase) with the limbs of pose 2; armed follows (pitch + 1) / 3. play overlays a PoseClip of @adatechnology/game-characters (channels: 'upper' leaves the legs to the gait; while crouched only a kick takes the legs, so a punch or the guard stays low) with a 0.12 s blend, and fires its events (impact, phase) once through onEvent and on('event'). hand('R') is the weapon hand (the puppet's right, at -x). A pose clip's armL/legL channels move that side (arms[1]/legs[0]), so punch_right and front_kick of ATTACK_CLIPS drive armL and legL, the same arm and leg the first-person view shows.

In the test room. room.setAvatar(toRoomAvatar(player, { strikeClips: ATTACK_CLIPS })) (or defaultCharacterClips() of game-kit-defaults, which also has the first-person clips) shows the body at the player's feet (toRoomAvatar only flips the pitch: the room counts a look up as positive, the team game a look down) and V switches between the first and the third person of @adatechnology/game-test-room. createAvatarTestModule({ avatar, camera, state }) is the module of the area avatar_area (AVATAR_AREA_ID): bench buttons for the view (1st/3rd person), crouch, stand, fall, get up, armed on/off, one button per registered clip (Tocar: grabbed_bitten_human, grab_bite_zombie, and with clips: [...POSE_CLIPS, ...ATTACK_CLIPS] the punch, shove, kick and the recoils; clipLocales gives the phase texts) and stop; metrics for the camera, the clip playing, the last clip event and the joints. Every action is a JSON line in the room log ({"type":"avatar","action":"play_clip","clip":...}), clip events included, and an impact event also gets its own {"action":"impact","clip":...,"t":...} line. The module takes the body, the view (camera: { mode, set }) and the state (state: { set }) by option and imports only @adatechnology/game-contracts.

toRoomAvatar also gives the room strike(clipId), which plays the attack clip on the body (the only source of a strike, first and third person) and answers the seconds to the impact read from that clip (the same in both views). strike(clip, { leg: 'left' }) kicks with the left leg and strike(clip, { hand: 'left' }) punches with the left hand: the mirror of the clip on the body (mirrorPoseClip, id <clip>_left). After a punch (an impact of kind punch) the body holds the guard (guardClip, default 'fight_guard', false for none) for guardHold seconds (default 1.2) while it stands still, so a combo goes guard, punch, guard; the punch blends in over punchBlend (default 0.05 s). Walking, running, a weapon or a held item drop the guard.

First-person arms. createFirstPersonArms(THREE, { colors?, rig?, stances?, clips?, blend?, bob? }) builds sleeves (upper arm, forearm, elbow, cuff) and hands of skin (palm, four fingers of three segments, a thumb that close on a grip) drawn in the camera's space, plus the right leg that only shows during a kick. arms.update(dt, { camera, targets, stance, speed, running, crouch, contact? }): the relaxed and fists stances are rest poses (FIRST_PERSON_STANCES, from presets/first-person-arms.json), hold follows the HandTargets of game-contracts (world space) with a two-bone IK from fixed shoulders, the elbow bending down and out; a target out of reach is clamped (the shoulder moves reachShift toward it first). arms.play('punch_right' | 'shove_two_hands' | 'front_kick') overlays a FirstPersonClip (FIRST_PERSON_CLIPS of game-characters-people, same durations and impact seconds as the attack clips); arms.on('event', fn) gives its impact; arms.handPose(side) reads where a hand is drawn. contact(origin, direction, maxDistance) (optional; distance to the first surface or null) makes the hands and the kick foot stop a few millimetres before a surface along the camera forward (the elbow bends); arms.play('front_kick', { leg: 'left' }) kicks with the left leg and arms.play('punch_right', { hand: 'left' }) punches with the left hand (the hands of the clip in a mirror). Hand frame: x wrist to knuckles, y back of the hand, z little-finger side; a left hand is the right one mirrored.

Geometry

The builders (createPersonBuilder, createBestBuilder, bakeBody, buildInstancedBody, createFlyingLimbs, createEye) draw with shapeGeometries(host) of game-shapes-three: boxes, cylinders, cones, spheres, circles, rings, lathes and tori come from game-shapes with the same bytes; dodecahedron, shape and capsule geometries are three's. tests/exact-golden.test.ts holds every bit as the old path made them.

版本与发布记录

@adatechnology/game-characters-three 共发布 27 个版本,首次发布于 2026/10/24;过去 12 个月发布了 27 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.9.5latest2026/11/06今天
0.9.42026/11/042 天前
0.9.32026/11/042 天前
0.9.22026/11/042 天前
0.9.12026/11/042 天前
0.9.02026/11/042 天前

关于 @adatechnology/game-characters-three 的常见问题

@adatechnology/game-characters-three 是什么?

three.js presentation for @adatechnology/game-characters: the instanced crowd body (GPU animation, LOD, baking, variants, flying limbs) and the rich bodies (the Bestiário v17 builder, survivors with accessories and hands, the animator, wounds, eyes).

如何安装 @adatechnology/game-characters-three?

在项目目录运行 npm install @adatechnology/game-characters-three,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:three(^0.160.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@adatechnology/game-characters-three 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@adatechnology/game-characters-three 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@adatechnology/game-characters-three 可以商用吗?

@adatechnology/game-characters-three 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@adatechnology/game-characters-three 的下载量有多少?

根据 npm 官方下载统计,@adatechnology/game-characters-three 在 2026/10/05 – 2026/11/03 这 30 天内被下载 3,548 次,日均约 118 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@adatechnology/game-characters-three 还在维护吗?

最新版本 0.9.5 发布于 2026/11/06(今天);至今共发布 27 个版本,其中过去 12 个月发布了 27 个;首次发布于 2026/10/24。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。