@adatechnology/game-crowd 0.0.0-stage → 0.2.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/LICENSE +21 -0
- package/README.md +95 -2
- package/dist/index.d.ts +1128 -0
- package/dist/index.global.js +3282 -0
- package/dist/index.global.js.map +1 -0
- package/dist/index.js +2308 -0
- package/dist/index.js.map +1 -0
- package/package.json +58 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Anderson Fernandes
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,96 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @adatechnology/game-crowd
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Any crowd as a struct of arrays, pure and seeded: a horde, but also a street of people or a herd. Relevance bands with hysteresis, perception by sight,
|
|
4
|
+
hearing and smell, a sliced flow field, a spatial hash and separation, six attack slots, chain alerts, doors that take blows, piles of bodies against
|
|
5
|
+
walls, special moves as type traits, corpses, a blood trail, the population and migrations. No three.js, no audio, no game content: it emits events
|
|
6
|
+
(`sound`, `effect`, `message`, `kill`...) and the game plays, draws and shows them.
|
|
7
|
+
|
|
8
|
+
It is a literal port of the team game's horde (`jogo.js` G 66714-67430: `hordeUpdate` and everything it calls, with the doors of G 63796-64050). Every
|
|
9
|
+
number is in `src/data/defaults.json` with its source line, and the golden `game-crowd.json` (8 scripted scenes of the game code in `node:vm`, recorded by
|
|
10
|
+
`tools/characters-catalog`) is replayed frame by frame by the tests.
|
|
11
|
+
|
|
12
|
+
- **The pack is data.** Types (health, speeds, damage, bite, multipliers, perception, size), ages, outfits, segments and the clothes palette come in
|
|
13
|
+
`pack`. `@adatechnology/game-characters-undead` gives the undead one (`undeadCrowdPack()`, the game's 13 types); any game writes its own.
|
|
14
|
+
- **Special moves are traits** of a type (`vaultsLow`, `pounce`, `heavySwing`, `soundSeeker`, `caller`, `burns`, `waterWeak`, `submerged`, `ambush`,
|
|
15
|
+
`burst`, `eatsCorpses`, `tracker`...). A type without traits only walks, hears, sees and hits. `plugins` add moves without touching the core.
|
|
16
|
+
- **The normal world comes first.** With no target (`target: null`) nobody chases: agents wander and pause. The target is anything with the
|
|
17
|
+
`CrowdTarget` shape; `game-player`'s `Player` is one as it is.
|
|
18
|
+
- **The world** is a `NavGrid` (`createNavGrid`, the game's 0.5 m grid with occupancy codes and heights) and `water(x, z)`; doors are `createDoors`.
|
|
19
|
+
- **Every draw is in the game's order** on the stream you pass (`random`); the flow field's time budget reads `flow.clock` (pass `() => 0` to finish
|
|
20
|
+
each field in one frame, as the golden does).
|
|
21
|
+
|
|
22
|
+
## Install
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
pnpm add @adatechnology/game-crowd
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Browser without a bundler (the global is `GameCrowd`):
|
|
29
|
+
|
|
30
|
+
```html
|
|
31
|
+
<script src="https://unpkg.com/@adatechnology/game-crowd/dist/index.global.js"></script>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Usage
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
import { createCrowd, createNavGrid } from '@adatechnology/game-crowd'
|
|
38
|
+
import { undeadCrowdPack } from '@adatechnology/game-characters-undead'
|
|
39
|
+
|
|
40
|
+
const grid = createNavGrid() // 768 m, 0.5 m cells, a solid border
|
|
41
|
+
grid.fillRect(x0, z0, x1, z1, 1, 3) // a wall 3 m tall
|
|
42
|
+
const crowd = createCrowd({ pack: undeadCrowdPack(), seed: 7, grid, water: (x, z) => pool.contains(x, z) })
|
|
43
|
+
crowd.doors.add(0, -2.1, 'x', 1.2)
|
|
44
|
+
crowd.on('sound', (s) => host.audio?.play({ sound: s.sound, volume: s.volume, position: s.position }))
|
|
45
|
+
crowd.on('effect', (e) => host.effects?.play({ effect: e.effect, point: e.point }))
|
|
46
|
+
crowd.on('message', ({ id, seconds }) => hud.show(id, seconds))
|
|
47
|
+
|
|
48
|
+
crowd.target = player // game-player's Player, or { state, grab, hurt, knock, release }
|
|
49
|
+
player.setWorld({ ...world, crowd: crowd.asPlayerCrowd() })
|
|
50
|
+
player.on('noise', ({ x, z, radius }) => crowd.emitNoise(x, z, radius))
|
|
51
|
+
|
|
52
|
+
// every frame, in the game's order
|
|
53
|
+
crowd.updateTrail(dt)
|
|
54
|
+
crowd.update(dt, { nightFactor, viewYaw: camera.yaw })
|
|
55
|
+
crowd.updatePopulation(dt, { x: camera.x, z: camera.z, yaw: camera.yaw, far: fog.far }, { target: 1200, migration })
|
|
56
|
+
crowd.updateCorpses(dt)
|
|
57
|
+
|
|
58
|
+
crowd.damage(i, { region: 0, amount: 35, distance: 12, caliber: { id: '9x19', class: 'pistol', skull: 1 } })
|
|
59
|
+
crowd.store.x[i] // the struct of arrays: x, z, y, yaw, state, hp, missing, band, variant...
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Civilians, herds, flocks and the region model
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
import { HERD_ROLES, bindInfection, carrionCenter, createCivilians, createFlock, createHerd } from '@adatechnology/game-crowd'
|
|
66
|
+
|
|
67
|
+
// people with a routine by the hour; agents that are closer to them than to the target hunt them
|
|
68
|
+
const civilians = createCivilians(crowd, { people: [{ id: 'ana', home: 'house_2', routine: [[19, 'market']] }], buildings, hour: () => clock.hour })
|
|
69
|
+
civilians.on('bitten', ({ id, near }) => diary(id, near))
|
|
70
|
+
civilians.join('ana') // follows the target
|
|
71
|
+
civilians.flee('ana', path) // leaves; `gone` at the end
|
|
72
|
+
|
|
73
|
+
// animals: wander, rest, flee, call; their calls are noises the crowd hears
|
|
74
|
+
const herd = createHerd(crowd, { blocked: insideABuilding })
|
|
75
|
+
herd.add({ ...HERD_ROLES.cow, species: 'cow', x, z, walkHz: cow.walkHz, runHz: cow.runHz, size: quadrupedLayout(cow.body).size })
|
|
76
|
+
const vultures = createFlock({ count: 3, mode: 'carrion' })
|
|
77
|
+
// every frame, after crowd.updateTrail and before crowd.update
|
|
78
|
+
civilians.update(dt)
|
|
79
|
+
herd.update(dt)
|
|
80
|
+
vultures.update(herd.time, dt, carrionCenter(crowd.corpses.entries.map((e) => e.data), carcass), [camera.x, camera.z])
|
|
81
|
+
|
|
82
|
+
// the region model of game-infection: numbers become agents near the player and go back when far
|
|
83
|
+
const binding = bindInfection(crowd, infection, { place: (region, seed, k) => spotIn(region, seed, k), civilians, regionOf })
|
|
84
|
+
binding.materialize('downtown', 40)
|
|
85
|
+
binding.giveBack()
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Civilians are a literal port of the game's survivors on the block (`jogo.js` G 69960-70175: `pontos`, `rota`, `npcZombies`, `zChaseNpc`, `npcMorre`,
|
|
89
|
+
`npcVira`, `npcMove`, `npcUpdate`) without their names, lines, radio and diary; the herd of `bichoLivre`, `zumbiPerto` and `bichosUpdate` (G 66601-66700)
|
|
90
|
+
without the rig; the vultures of G 66700-66708 and the live map's ring of birds of the Bancada de Hordas (G 53609-53615). Two goldens replay them
|
|
91
|
+
with the horde: `game-crowd-civilians.json` (3 scenes) and `game-crowd-herd.json`.
|
|
92
|
+
|
|
93
|
+
## What is not here yet
|
|
94
|
+
|
|
95
|
+
The drawing and the test area are in `@adatechnology/game-crowd-three`. The game's multi-floor houses (`ANDARES`) and the roof (`ROOF`) are not ported: the crowd walks one
|
|
96
|
+
ground grid (`floor` is kept on each agent for a game that adds floors).
|