incanto 0.1.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 +30 -0
- package/README.md +36 -0
- package/THIRD-PARTY-NOTICES.md +88 -0
- package/assets/audio/attacked.mp3 +0 -0
- package/assets/audio/explosion.mp3 +0 -0
- package/assets/audio/gold_loot.mp3 +0 -0
- package/assets/audio/heal.mp3 +0 -0
- package/assets/audio/hit_metal_bang.mp3 +0 -0
- package/assets/audio/ice_spear.mp3 +0 -0
- package/assets/audio/monster_died.mp3 +0 -0
- package/assets/audio/slash.mp3 +0 -0
- package/assets/audio/smite.mp3 +0 -0
- package/assets/audio/spells_cast.mp3 +0 -0
- package/assets/audio/ui_click.wav +0 -0
- package/assets/audio/walk.mp3 +0 -0
- package/assets/catalog.json +390 -0
- package/assets/characters/2dbasic.json +41 -0
- package/assets/characters/2dbasic.png +0 -0
- package/assets/characters/ghost.json +46 -0
- package/assets/characters/ghost.png +0 -0
- package/assets/characters/goblin.json +40 -0
- package/assets/characters/goblin.png +0 -0
- package/assets/characters/medieval-knight.json +41 -0
- package/assets/characters/medieval-knight.png +0 -0
- package/assets/effects/swoosh.png +0 -0
- package/assets/items/box.png +0 -0
- package/assets/items/buff_potion.png +0 -0
- package/assets/items/coin.png +0 -0
- package/assets/items/gem.png +0 -0
- package/assets/items/gold.png +0 -0
- package/assets/items/hp_potion.png +0 -0
- package/assets/items/locked_item_box.png +0 -0
- package/assets/items/map.png +0 -0
- package/assets/items/resurrection_potion.png +0 -0
- package/assets/items/super_box.png +0 -0
- package/assets/items/trap.png +0 -0
- package/assets/tiles/floor00.jpg +0 -0
- package/assets/tiles/minecraft-tiles.png +0 -0
- package/assets/tiles/wall00.jpg +0 -0
- package/assets/vegetation/ash_color.png +0 -0
- package/assets/vegetation/aspen_color.png +0 -0
- package/assets/vegetation/bark/birch_color_1k.jpg +0 -0
- package/assets/vegetation/bark/birch_normal_1k.jpg +0 -0
- package/assets/vegetation/bark/birch_roughness_1k.jpg +0 -0
- package/assets/vegetation/bark/oak_color_1k.jpg +0 -0
- package/assets/vegetation/bark/oak_normal_1k.jpg +0 -0
- package/assets/vegetation/bark/oak_roughness_1k.jpg +0 -0
- package/assets/vegetation/bark/pine_color_1k.jpg +0 -0
- package/assets/vegetation/bark/pine_normal_1k.jpg +0 -0
- package/assets/vegetation/bark/pine_roughness_1k.jpg +0 -0
- package/assets/vegetation/ground/dirt_color.jpg +0 -0
- package/assets/vegetation/ground/dirt_normal.jpg +0 -0
- package/assets/vegetation/ground/grass.jpg +0 -0
- package/assets/vegetation/oak_color.png +0 -0
- package/assets/vegetation/pine_color.png +0 -0
- package/bin/incanto-assets.mjs +107 -0
- package/bin/incanto-check.mjs +107 -0
- package/bin/incanto-editor.mjs +343 -0
- package/bin/incanto-env.mjs +144 -0
- package/bin/incanto-model.mjs +296 -0
- package/bin/incanto-play.mjs +219 -0
- package/bin/incanto-skills.mjs +71 -0
- package/dist/2d.d.ts +642 -0
- package/dist/2d.js +44 -0
- package/dist/3d.d.ts +1860 -0
- package/dist/3d.js +5 -0
- package/dist/agent8-DzU2fFyH.js +129 -0
- package/dist/audio-player-DqUR3XFs.d.ts +110 -0
- package/dist/behavior-BAQq7HGM.d.ts +851 -0
- package/dist/create-game-BdjpTHrW.js +1725 -0
- package/dist/create-game-CZHROKcT.js +527 -0
- package/dist/debug-draw-CZmOYjL2.js +13 -0
- package/dist/debug.d.ts +66 -0
- package/dist/debug.js +658 -0
- package/dist/duplicate-DP2WPYom.js +22 -0
- package/dist/env.d.ts +430 -0
- package/dist/env.js +3152 -0
- package/dist/errors-BMFaY68Q.d.ts +33 -0
- package/dist/errors-BpWbnbb_.js +13 -0
- package/dist/gameplay-Ccruc3Wd.js +1501 -0
- package/dist/gameplay.d.ts +543 -0
- package/dist/gameplay.js +2 -0
- package/dist/heightmap-CroQPEER.js +185 -0
- package/dist/index.d.ts +305 -0
- package/dist/index.js +62 -0
- package/dist/json-BLk7H2Qa.js +30 -0
- package/dist/loader-CGs_G-r0.js +919 -0
- package/dist/loader-Mo0KghCv.d.ts +41 -0
- package/dist/net.d.ts +427 -0
- package/dist/net.js +772 -0
- package/dist/noise-CGUMx44x.js +82 -0
- package/dist/particle-sim-CbN4YUuH.d.ts +63 -0
- package/dist/particle-sim-DYuSUxvK.js +1319 -0
- package/dist/physics-2d-KuMWPTf6.js +288 -0
- package/dist/physics-3d-Dl67vOLT.js +434 -0
- package/dist/react.d.ts +65 -0
- package/dist/react.js +209 -0
- package/dist/register-BuUV1_KB.js +561 -0
- package/dist/register-CNlYAS1_.js +10634 -0
- package/dist/register-DPEV9_9t.js +851 -0
- package/dist/register-Dasmnurl.js +374 -0
- package/dist/registry-BVJ2HbCn.js +132 -0
- package/dist/rng-DP-SR7eg.js +38 -0
- package/dist/rolldown-runtime-D7D4PA-g.js +13 -0
- package/dist/schema-CcoWb32N.d.ts +104 -0
- package/dist/test.d.ts +158 -0
- package/dist/test.js +275 -0
- package/dist/touch-031PxtCR.js +208 -0
- package/dist/vite.d.ts +26 -0
- package/dist/vite.js +57 -0
- package/editor/assets/GameServer-C56iOUgF.js +1 -0
- package/editor/assets/agent8-Bp7QFI7v.js +1 -0
- package/editor/assets/index-DF3tMeKJ.css +1 -0
- package/editor/assets/index-Dl2pjA8e.js +7365 -0
- package/editor/assets/rapier-CEuLKeCu.js +1 -0
- package/editor/assets/rapier-DE6a0vmv.js +1 -0
- package/editor/index.html +169 -0
- package/package.json +97 -0
- package/schemas/scene.schema.json +4254 -0
- package/skills/README.md +9 -0
- package/skills/incanto-3d-character.md +229 -0
- package/skills/incanto-3d-models.md +151 -0
- package/skills/incanto-assets.md +118 -0
- package/skills/incanto-audio.md +309 -0
- package/skills/incanto-behaviors-and-scripts.md +169 -0
- package/skills/incanto-building-2d-games.md +242 -0
- package/skills/incanto-building-3d-games.md +245 -0
- package/skills/incanto-editor.md +163 -0
- package/skills/incanto-environment.md +743 -0
- package/skills/incanto-gameplay-behaviors.md +707 -0
- package/skills/incanto-multiplayer.md +264 -0
- package/skills/incanto-node-reference.md +797 -0
- package/skills/incanto-physics-and-input.md +164 -0
- package/skills/incanto-scene-json-authoring.md +325 -0
- package/skills/incanto-verifying-your-game.md +191 -0
- package/skills/incanto-web-integration.md +96 -0
- package/templates/agent8-server.js +84 -0
- package/templates/agent8-server.ts +138 -0
|
@@ -0,0 +1,543 @@
|
|
|
1
|
+
import { c as JsonValue } from "./schema-CcoWb32N.js";
|
|
2
|
+
import { T as Node, l as PropSchema, n as BehaviorCtor, t as Behavior } from "./behavior-BAQq7HGM.js";
|
|
3
|
+
|
|
4
|
+
//#region src/gameplay/chase.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Home in on a target node — the workhorse enemy AI. Each frame moves toward
|
|
7
|
+
* `target.position` at `speed`, stopping once within `stopRange` (melee reach).
|
|
8
|
+
* Dimension-agnostic.
|
|
9
|
+
*
|
|
10
|
+
* - `reachedTarget` fires once when it first enters `stopRange` (re-arms after
|
|
11
|
+
* it leaves), so wire it to an attack.
|
|
12
|
+
* - `loseRange` (>0) gives up the chase when the target gets that far away,
|
|
13
|
+
* emitting `lostTarget` once.
|
|
14
|
+
* - `moveParent` (default false) moves the parent node instead of this one.
|
|
15
|
+
* A node carries ONE behavior, so an enemy whose ROOT must hold `Health`
|
|
16
|
+
* (e.g. for `Health.freeOnDeath` clone-safe cleanup) puts `Chase` on a CHILD
|
|
17
|
+
* and sets `moveParent:true` — the AI child drives the whole entity. Distance
|
|
18
|
+
* is measured from the moved node (the parent).
|
|
19
|
+
*/
|
|
20
|
+
declare class Chase extends Behavior {
|
|
21
|
+
static readonly props: PropSchema;
|
|
22
|
+
static readonly signals: readonly string[];
|
|
23
|
+
target: string;
|
|
24
|
+
speed: number;
|
|
25
|
+
stopRange: number;
|
|
26
|
+
loseRange: number;
|
|
27
|
+
moveParent: boolean;
|
|
28
|
+
private inRange;
|
|
29
|
+
private lost;
|
|
30
|
+
override onReady(): void;
|
|
31
|
+
override update(dt: number): void;
|
|
32
|
+
}
|
|
33
|
+
//#endregion
|
|
34
|
+
//#region src/gameplay/collector.d.ts
|
|
35
|
+
/**
|
|
36
|
+
* A tally for the "collect N things" pattern, living on the collector itself
|
|
37
|
+
* (usually the player). Adds its node to `group` at ready so Pickups whose
|
|
38
|
+
* `collectorGroup` matches will count it as a collector.
|
|
39
|
+
*
|
|
40
|
+
* Wire a Pickup's `collected(value, other) → Collector.collect` (the value is
|
|
41
|
+
* the first arg) — `total` accumulates and `totalChanged(total)` fires.
|
|
42
|
+
* (Pickup also notifies a global ScoreKeeper; Collector is the per-actor tally,
|
|
43
|
+
* e.g. for split-screen or "each player's coins".)
|
|
44
|
+
*/
|
|
45
|
+
declare class Collector extends Behavior {
|
|
46
|
+
static readonly props: PropSchema;
|
|
47
|
+
static readonly signals: readonly string[];
|
|
48
|
+
group: string;
|
|
49
|
+
/** Running sum of collected values. */
|
|
50
|
+
total: number;
|
|
51
|
+
override onReady(): void;
|
|
52
|
+
/** Add `value` to the tally and emit `totalChanged`. */
|
|
53
|
+
collect(value: number): void;
|
|
54
|
+
}
|
|
55
|
+
//#endregion
|
|
56
|
+
//#region src/gameplay/health.d.ts
|
|
57
|
+
/**
|
|
58
|
+
* Hit points with regeneration and post-hit invulnerability (i-frames) —
|
|
59
|
+
* the universal "this thing can be hurt and can die" behavior.
|
|
60
|
+
*
|
|
61
|
+
* Other behaviors hurt it through `damage(n)` (e.g. `DamageOnContact` finds a
|
|
62
|
+
* target's Health and calls it); games heal/kill via `heal(n)` / `kill()`.
|
|
63
|
+
* Wire its `died` signal to a `ScoreKeeper.loseLife`, a respawn, etc.
|
|
64
|
+
*
|
|
65
|
+
* `freeOnDeath` (default false) `queueFree()`s the Health node itself when it
|
|
66
|
+
* dies. Because it is NODE-LOCAL it clones perfectly — this is THE way to free
|
|
67
|
+
* dying SPAWNED entities. Scene-level `connections` (e.g. `died → queueFree`)
|
|
68
|
+
* are NOT copied onto Spawner/WaveSpawner clones, so a `died` connection only
|
|
69
|
+
* ever wires the template, never the live clones; `freeOnDeath` needs no
|
|
70
|
+
* connection and so works on every clone.
|
|
71
|
+
*
|
|
72
|
+
* Dimension-agnostic: no node geometry, just numbers — testable headlessly.
|
|
73
|
+
*/
|
|
74
|
+
declare class Health extends Behavior {
|
|
75
|
+
static readonly props: PropSchema;
|
|
76
|
+
static readonly signals: readonly string[];
|
|
77
|
+
max: number;
|
|
78
|
+
regenPerSec: number;
|
|
79
|
+
invulnerableFor: number;
|
|
80
|
+
freeOnDeath: boolean;
|
|
81
|
+
/** Current hit points (set to `max` on ready). */
|
|
82
|
+
current: number;
|
|
83
|
+
private invulnTimer;
|
|
84
|
+
private dead;
|
|
85
|
+
/** True once `current` has hit 0 — `died` fires at most once per life. */
|
|
86
|
+
get isDead(): boolean;
|
|
87
|
+
/** Seconds of i-frames remaining (0 = vulnerable). */
|
|
88
|
+
get invulnerableRemaining(): number;
|
|
89
|
+
override onReady(): void;
|
|
90
|
+
override update(dt: number): void;
|
|
91
|
+
/** Apply `n` damage. No-op while invulnerable or already dead. Emits `damaged`. */
|
|
92
|
+
damage(n: number): void;
|
|
93
|
+
/** Restore `n` hit points (clamped to `max`). No-op when dead. Emits `healed`. */
|
|
94
|
+
heal(n: number): void;
|
|
95
|
+
/** Drop to 0 and die immediately (ignores i-frames). */
|
|
96
|
+
kill(): void;
|
|
97
|
+
private setCurrent;
|
|
98
|
+
private die;
|
|
99
|
+
}
|
|
100
|
+
//#endregion
|
|
101
|
+
//#region src/gameplay/damage-on-contact.d.ts
|
|
102
|
+
/**
|
|
103
|
+
* Deals damage to whatever it touches — projectiles, spikes, lava, enemy
|
|
104
|
+
* hitboxes. Must sit on an Area2D/Area3D (listens to `triggerEnter`).
|
|
105
|
+
*
|
|
106
|
+
* On overlap it finds the contacted entity's `Health` behavior (see
|
|
107
|
+
* `findHealth` for the exact search order) and calls `damage(amount)`, then
|
|
108
|
+
* emits `dealtDamage(amount, targetNode)`.
|
|
109
|
+
*
|
|
110
|
+
* - `targetGroup` (default '' = anything) gates who can be hurt: only a target
|
|
111
|
+
* whose Health-owner node is in that group takes damage. This is how you stop
|
|
112
|
+
* enemies killing each other — give the player's weapon `targetGroup:'enemy'`
|
|
113
|
+
* and each enemy's contact hitbox `targetGroup:'player'`.
|
|
114
|
+
* - `oncePerTarget` (default) prevents re-hitting the same node (a stationary
|
|
115
|
+
* hazard would otherwise drain a resting body every frame).
|
|
116
|
+
* - `destroySelf` frees the hazard after a hit (single-use projectiles).
|
|
117
|
+
*
|
|
118
|
+
* SCORING PATTERN (clone-safe): wire the KILLER's `dealtDamage` →
|
|
119
|
+
* `ScoreKeeper.addScore`. The weapon is usually a non-cloned node (it lives on
|
|
120
|
+
* the player), so a scene connection on it survives — unlike a connection on a
|
|
121
|
+
* spawned enemy, which never clones.
|
|
122
|
+
*/
|
|
123
|
+
declare class DamageOnContact extends Behavior {
|
|
124
|
+
static readonly props: PropSchema;
|
|
125
|
+
static readonly signals: readonly string[];
|
|
126
|
+
amount: number;
|
|
127
|
+
targetGroup: string;
|
|
128
|
+
oncePerTarget: boolean;
|
|
129
|
+
destroySelf: boolean;
|
|
130
|
+
private readonly hit;
|
|
131
|
+
override onReady(): void;
|
|
132
|
+
private tryDamage;
|
|
133
|
+
}
|
|
134
|
+
//#endregion
|
|
135
|
+
//#region src/gameplay/follow-camera.d.ts
|
|
136
|
+
/**
|
|
137
|
+
* Make the node it sits on chase a target's position — THE camera-follow
|
|
138
|
+
* behavior. Put it on a `Camera2D`/`Camera3D` (whose `position` is the view
|
|
139
|
+
* center/eye) and point `target` at the player; every frame the camera lerps
|
|
140
|
+
* toward `target.position + offset`.
|
|
141
|
+
*
|
|
142
|
+
* Dimension-agnostic: works on `[x,y]` (2D) and `[x,y,z]` (3D) positions.
|
|
143
|
+
*
|
|
144
|
+
* - `smoothing` (0..1) is a per-frame retention factor: 0 = instant snap,
|
|
145
|
+
* 0.85–0.95 = smooth drag (frame-rate independent at a 60fps reference).
|
|
146
|
+
* - `deadzone` keeps the camera still until the target drifts that far from the
|
|
147
|
+
* desired point — no jitter when the player makes tiny moves.
|
|
148
|
+
*/
|
|
149
|
+
declare class FollowCamera extends Behavior {
|
|
150
|
+
static readonly props: PropSchema;
|
|
151
|
+
static readonly signals: readonly string[];
|
|
152
|
+
target: string;
|
|
153
|
+
offset: number[];
|
|
154
|
+
smoothing: number;
|
|
155
|
+
deadzone: number;
|
|
156
|
+
override onReady(): void;
|
|
157
|
+
override update(dt: number): void;
|
|
158
|
+
}
|
|
159
|
+
//#endregion
|
|
160
|
+
//#region src/gameplay/interactable.d.ts
|
|
161
|
+
/**
|
|
162
|
+
* A proximity-gated "press to use" — doors, levers, chests, NPCs. Each frame,
|
|
163
|
+
* if an actor in `actorGroup` is within `range` (distance on `position` arrays,
|
|
164
|
+
* 2D or 3D) and the `action` input was just pressed, emits
|
|
165
|
+
* `interacted(actor)` (the nearest in-range actor).
|
|
166
|
+
*
|
|
167
|
+
* Wire `interacted → YourBehavior.someMethod`, or read it from a connection.
|
|
168
|
+
*/
|
|
169
|
+
declare class Interactable extends Behavior {
|
|
170
|
+
static readonly props: PropSchema;
|
|
171
|
+
static readonly signals: readonly string[];
|
|
172
|
+
action: string;
|
|
173
|
+
range: number;
|
|
174
|
+
actorGroup: string;
|
|
175
|
+
override update(): void;
|
|
176
|
+
}
|
|
177
|
+
//#endregion
|
|
178
|
+
//#region src/gameplay/lifetime.d.ts
|
|
179
|
+
/**
|
|
180
|
+
* Self-destruct after a fixed time — bullets, particles, temporary spawns,
|
|
181
|
+
* pickups that vanish. Accumulates `dt`; on elapse emits `expired` then
|
|
182
|
+
* `queueFree()`s its node.
|
|
183
|
+
*
|
|
184
|
+
* With `startOnSignal: true` the countdown is armed manually via `startTimer()`
|
|
185
|
+
* (wire a signal → `startTimer`), so the lifetime begins on an event rather
|
|
186
|
+
* than at spawn.
|
|
187
|
+
*/
|
|
188
|
+
declare class Lifetime extends Behavior {
|
|
189
|
+
static readonly props: PropSchema;
|
|
190
|
+
static readonly signals: readonly string[];
|
|
191
|
+
seconds: number;
|
|
192
|
+
startOnSignal: boolean;
|
|
193
|
+
private elapsed;
|
|
194
|
+
private running;
|
|
195
|
+
private fired;
|
|
196
|
+
override onReady(): void;
|
|
197
|
+
/** Arm (or re-arm) the countdown from zero. */
|
|
198
|
+
startTimer(): void;
|
|
199
|
+
override update(dt: number): void;
|
|
200
|
+
}
|
|
201
|
+
//#endregion
|
|
202
|
+
//#region src/gameplay/tween.d.ts
|
|
203
|
+
/** Easing curves shared by the tween behaviors (MoveTo, …). Pure math. */
|
|
204
|
+
type EaseName = "linear" | "easeIn" | "easeOut" | "easeInOut";
|
|
205
|
+
//#endregion
|
|
206
|
+
//#region src/gameplay/move-to.d.ts
|
|
207
|
+
/**
|
|
208
|
+
* Tween the node from where it starts to a fixed `to` position over `duration`
|
|
209
|
+
* seconds, through an easing curve — opening doors, sliding platforms, UI
|
|
210
|
+
* pop-ins, scripted moves. Emits `arrived` once at the end.
|
|
211
|
+
*
|
|
212
|
+
* `startOnSignal: true` arms it manually via `start()` (wire a signal → `start`)
|
|
213
|
+
* so the move plays on an event; otherwise it begins at ready. Dimension-
|
|
214
|
+
* agnostic (`[x,y]` / `[x,y,z]`).
|
|
215
|
+
*/
|
|
216
|
+
declare class MoveTo extends Behavior {
|
|
217
|
+
static readonly props: PropSchema;
|
|
218
|
+
static readonly signals: readonly string[];
|
|
219
|
+
to: number[];
|
|
220
|
+
duration: number;
|
|
221
|
+
ease: EaseName;
|
|
222
|
+
startOnSignal: boolean;
|
|
223
|
+
private from;
|
|
224
|
+
private elapsed;
|
|
225
|
+
private running;
|
|
226
|
+
private arrivedFired;
|
|
227
|
+
override onReady(): void;
|
|
228
|
+
/** Begin (or restart) the move from the node's CURRENT position. */
|
|
229
|
+
start(): void;
|
|
230
|
+
override update(dt: number): void;
|
|
231
|
+
}
|
|
232
|
+
//#endregion
|
|
233
|
+
//#region src/gameplay/oscillate.d.ts
|
|
234
|
+
declare const AXES: readonly ["x", "y", "z"];
|
|
235
|
+
type Axis = (typeof AXES)[number];
|
|
236
|
+
declare const MODES: readonly ["position", "rotation", "scale"];
|
|
237
|
+
type Mode = (typeof MODES)[number];
|
|
238
|
+
/**
|
|
239
|
+
* Continuous sine motion around a value — floating platforms, bobbing pickups,
|
|
240
|
+
* spinning/pulsing coins. Drives one `axis` of the node's `position`, `rotation`
|
|
241
|
+
* (`mode: 'rotation'` — a "spin" when on z), or `scale` (a "pulse"):
|
|
242
|
+
*
|
|
243
|
+
* value = start + amplitude · sin(2π · frequency · t)
|
|
244
|
+
*
|
|
245
|
+
* The baseline (`start`) is captured at ready, so it layers on top of authored
|
|
246
|
+
* transforms. Dimension-agnostic; on a 2D node `rotation` is the scalar spin
|
|
247
|
+
* (use `axis: 'z'`).
|
|
248
|
+
*/
|
|
249
|
+
declare class Oscillate extends Behavior {
|
|
250
|
+
static readonly props: PropSchema;
|
|
251
|
+
static readonly signals: readonly string[];
|
|
252
|
+
axis: Axis;
|
|
253
|
+
amplitude: number;
|
|
254
|
+
frequency: number;
|
|
255
|
+
mode: Mode;
|
|
256
|
+
private base;
|
|
257
|
+
private time;
|
|
258
|
+
override onReady(): void;
|
|
259
|
+
override update(dt: number): void;
|
|
260
|
+
/** Whether the target channel is the node's scalar 2D rotation. */
|
|
261
|
+
private isScalarRotation;
|
|
262
|
+
private readChannel;
|
|
263
|
+
private writeChannel;
|
|
264
|
+
}
|
|
265
|
+
//#endregion
|
|
266
|
+
//#region src/gameplay/patrol.d.ts
|
|
267
|
+
/**
|
|
268
|
+
* Walk the node along a fixed list of waypoints at constant speed — guards,
|
|
269
|
+
* platforms, moving hazards. `points` are positions (`[x,y]` / `[x,y,z]`) OR
|
|
270
|
+
* node paths whose `position` is read each frame (so you can author markers in
|
|
271
|
+
* the scene). On arrival emits `reachedPoint(index)`; `pauseAt` holds at each
|
|
272
|
+
* point before moving on.
|
|
273
|
+
*
|
|
274
|
+
* - `loop` (default) — after the last point, head back to the first.
|
|
275
|
+
* - `mode: 'pingpong'` — reverse direction at each end instead of wrapping.
|
|
276
|
+
*/
|
|
277
|
+
declare class Patrol extends Behavior {
|
|
278
|
+
static readonly props: PropSchema;
|
|
279
|
+
static readonly signals: readonly string[];
|
|
280
|
+
points: JsonValue[];
|
|
281
|
+
speed: number;
|
|
282
|
+
loop: boolean;
|
|
283
|
+
mode: string;
|
|
284
|
+
pauseAt: number;
|
|
285
|
+
private index;
|
|
286
|
+
private direction;
|
|
287
|
+
private pauseTimer;
|
|
288
|
+
override onReady(): void;
|
|
289
|
+
override update(dt: number): void;
|
|
290
|
+
/** Resolve waypoint `i` to a position, reading node paths live. */
|
|
291
|
+
private pointAt;
|
|
292
|
+
private advance;
|
|
293
|
+
}
|
|
294
|
+
//#endregion
|
|
295
|
+
//#region src/gameplay/pickup.d.ts
|
|
296
|
+
/**
|
|
297
|
+
* A collectible that vanishes when a collector overlaps it. Must sit on an
|
|
298
|
+
* Area2D/Area3D (it listens to the unified `triggerEnter`).
|
|
299
|
+
*
|
|
300
|
+
* On overlap with a node in `collectorGroup`, emits `collected(value, other)`
|
|
301
|
+
* then `queueFree()`s itself. Wire `collected → ScoreKeeper.addScore` (the
|
|
302
|
+
* value is the first arg) or `collected → Collector.collect`.
|
|
303
|
+
*/
|
|
304
|
+
declare class Pickup extends Behavior {
|
|
305
|
+
static readonly props: PropSchema;
|
|
306
|
+
static readonly signals: readonly string[];
|
|
307
|
+
value: number;
|
|
308
|
+
kind: string;
|
|
309
|
+
collectorGroup: string;
|
|
310
|
+
private collectedAlready;
|
|
311
|
+
override onReady(): void;
|
|
312
|
+
private tryCollect;
|
|
313
|
+
}
|
|
314
|
+
//#endregion
|
|
315
|
+
//#region src/gameplay/projectile.d.ts
|
|
316
|
+
/**
|
|
317
|
+
* Constant-velocity motion in a straight line — bullets, arrows, thrown rocks.
|
|
318
|
+
* Pure movement by design: pair it with `DamageOnContact` (deal damage on hit),
|
|
319
|
+
* `Lifetime` (auto-despawn), and an Area collider on the same node. Compose,
|
|
320
|
+
* don't conflate.
|
|
321
|
+
*
|
|
322
|
+
* `direction` is either an explicit vector (`[x,y]` / `[x,y,z]`, normalized) or
|
|
323
|
+
* the string `'forward'`, derived from the node's `rotation` (2D: degrees
|
|
324
|
+
* clockwise, +x at 0). It is a union-typed prop, so its schema default is
|
|
325
|
+
* `null` (the engine's "any JSON" escape hatch) and `null` means `'forward'`.
|
|
326
|
+
* `gravity` adds a constant downward (+y, the 2D y-down convention) pull, for
|
|
327
|
+
* lobbed/arcing shots.
|
|
328
|
+
*/
|
|
329
|
+
declare class Projectile extends Behavior {
|
|
330
|
+
static readonly props: PropSchema;
|
|
331
|
+
static readonly signals: readonly string[];
|
|
332
|
+
speed: number;
|
|
333
|
+
direction: JsonValue;
|
|
334
|
+
gravity: number;
|
|
335
|
+
private velocity;
|
|
336
|
+
override onReady(): void;
|
|
337
|
+
override update(dt: number): void;
|
|
338
|
+
/** Resolve `direction` to a unit vector, deriving 'forward' from rotation. */
|
|
339
|
+
private resolveDirection;
|
|
340
|
+
private forwardFromRotation;
|
|
341
|
+
}
|
|
342
|
+
//#endregion
|
|
343
|
+
//#region src/gameplay/score-keeper.d.ts
|
|
344
|
+
/**
|
|
345
|
+
* The game's state hub — score, lives, and win/lose detection. Put it on the
|
|
346
|
+
* Root/Game node and wire gameplay signals into its methods (e.g. a Pickup's
|
|
347
|
+
* `collected → addScore`, a Health's `died → loseLife`).
|
|
348
|
+
*
|
|
349
|
+
* - `score` rises via `addScore` / `setScore`; reaching `scoreToWin` (>0)
|
|
350
|
+
* emits `won` once.
|
|
351
|
+
* - `lives` (>0) shrinks via `loseLife`; reaching 0 emits `lost` once.
|
|
352
|
+
*/
|
|
353
|
+
declare class ScoreKeeper extends Behavior {
|
|
354
|
+
static readonly props: PropSchema;
|
|
355
|
+
static readonly signals: readonly string[];
|
|
356
|
+
score: number;
|
|
357
|
+
lives: number;
|
|
358
|
+
scoreToWin: number;
|
|
359
|
+
private hasWon;
|
|
360
|
+
private hasLost;
|
|
361
|
+
override onReady(): void;
|
|
362
|
+
/** Add `n` to the score (negative subtracts), emit `scoreChanged`, check win. */
|
|
363
|
+
addScore(n: number): void;
|
|
364
|
+
/** Set the score to `value`, emit `scoreChanged`, check win. */
|
|
365
|
+
setScore(value: number): void;
|
|
366
|
+
/** Lose one life (no-op when lives disabled or already lost). Emits `lifeLost`, then `lost` at 0. */
|
|
367
|
+
loseLife(): void;
|
|
368
|
+
}
|
|
369
|
+
//#endregion
|
|
370
|
+
//#region src/gameplay/spawner.d.ts
|
|
371
|
+
/**
|
|
372
|
+
* Drip-feed clones of a template into the scene on a timer — enemy generators,
|
|
373
|
+
* pickup fountains, particle emitters. `prefab` is a node PATH to a template
|
|
374
|
+
* (usually a hidden `visible: false` child) that gets cloned each `interval`.
|
|
375
|
+
*
|
|
376
|
+
* - `max` caps LIVE instances (0 = unlimited); the count drops automatically as
|
|
377
|
+
* spawned children free themselves (e.g. via `Lifetime` or `Health.died`), so
|
|
378
|
+
* the spawner refills.
|
|
379
|
+
* - `total` caps LIFETIME spawns (0 = infinite); on the last one it emits
|
|
380
|
+
* `finished` and stops.
|
|
381
|
+
* - `autoStart` (default) begins ticking at ready; otherwise call `start()`.
|
|
382
|
+
*
|
|
383
|
+
* Emits `spawned(node)` per spawn. Methods: `spawn()`, `start()`, `stop()`.
|
|
384
|
+
*/
|
|
385
|
+
declare class Spawner extends Behavior {
|
|
386
|
+
static readonly props: PropSchema;
|
|
387
|
+
static readonly signals: readonly string[];
|
|
388
|
+
prefab: string;
|
|
389
|
+
interval: number;
|
|
390
|
+
max: number;
|
|
391
|
+
at: number[];
|
|
392
|
+
autoStart: boolean;
|
|
393
|
+
total: number;
|
|
394
|
+
private readonly source;
|
|
395
|
+
private template;
|
|
396
|
+
private readonly live;
|
|
397
|
+
private timer;
|
|
398
|
+
private running;
|
|
399
|
+
private spawnedCount;
|
|
400
|
+
private done;
|
|
401
|
+
/** Live (un-freed) spawned instances. */
|
|
402
|
+
get liveCount(): number;
|
|
403
|
+
/** @internal The detached template node (test/debug only). */
|
|
404
|
+
_templateForTest(): Node;
|
|
405
|
+
override onReady(): void;
|
|
406
|
+
/** Begin (or resume) interval spawning. */
|
|
407
|
+
start(): void;
|
|
408
|
+
/** Pause interval spawning (spawn() still works). */
|
|
409
|
+
stop(): void;
|
|
410
|
+
/** Spawn one immediately (ignores the timer; still respects max/total). */
|
|
411
|
+
spawn(): Node | null;
|
|
412
|
+
override update(dt: number): void;
|
|
413
|
+
/** Drop instances that have been freed (parent cleared on free/queueFree). */
|
|
414
|
+
private prune;
|
|
415
|
+
}
|
|
416
|
+
//#endregion
|
|
417
|
+
//#region src/gameplay/wander.d.ts
|
|
418
|
+
/**
|
|
419
|
+
* Aimless roaming inside a circle around the spawn point — idle critters,
|
|
420
|
+
* ambient wildlife, restless guards. Picks a random destination within `radius`
|
|
421
|
+
* of where it started, walks there at `speed`, then (every `changeEvery`
|
|
422
|
+
* seconds, or on arrival) picks a new one. Uses `this.rng`, so a seeded engine
|
|
423
|
+
* wanders identically every run (replayable, test-stable).
|
|
424
|
+
*
|
|
425
|
+
* Dimension-agnostic: roams in the plane of however many position components
|
|
426
|
+
* the node has (2D `[x,y]`, 3D `[x,z]` ground plane keeping y).
|
|
427
|
+
*/
|
|
428
|
+
declare class Wander extends Behavior {
|
|
429
|
+
static readonly props: PropSchema;
|
|
430
|
+
static readonly signals: readonly string[];
|
|
431
|
+
speed: number;
|
|
432
|
+
radius: number;
|
|
433
|
+
changeEvery: number;
|
|
434
|
+
private origin;
|
|
435
|
+
private goal;
|
|
436
|
+
private timer;
|
|
437
|
+
override onReady(): void;
|
|
438
|
+
override update(dt: number): void;
|
|
439
|
+
private pickGoal;
|
|
440
|
+
}
|
|
441
|
+
//#endregion
|
|
442
|
+
//#region src/gameplay/wave-spawner.d.ts
|
|
443
|
+
/**
|
|
444
|
+
* Sequenced enemy waves — the survivor/tower-defense backbone. Each entry in
|
|
445
|
+
* `waves` is `{ prefab, count, interval, delayBefore }`: after `delayBefore`
|
|
446
|
+
* seconds it spawns `count` clones of `prefab` (a hidden template path) one
|
|
447
|
+
* every `interval` seconds, then waits until they're ALL cleared (freed) before
|
|
448
|
+
* starting the next wave.
|
|
449
|
+
*
|
|
450
|
+
* Signals: `waveStarted(i)` when a wave begins spawning, `waveCleared(i)` when
|
|
451
|
+
* its last instance frees, `allCleared` after the final wave clears.
|
|
452
|
+
*/
|
|
453
|
+
declare class WaveSpawner extends Behavior {
|
|
454
|
+
static readonly props: PropSchema;
|
|
455
|
+
static readonly signals: readonly string[];
|
|
456
|
+
waves: JsonValue[];
|
|
457
|
+
autoStart: boolean;
|
|
458
|
+
private readonly source;
|
|
459
|
+
private parsed;
|
|
460
|
+
private readonly live;
|
|
461
|
+
private waveIndex;
|
|
462
|
+
private phase;
|
|
463
|
+
private timer;
|
|
464
|
+
private spawnedThisWave;
|
|
465
|
+
private announced;
|
|
466
|
+
override onReady(): void;
|
|
467
|
+
/** Start (or restart from) wave 0. */
|
|
468
|
+
start(): void;
|
|
469
|
+
override update(dt: number): void;
|
|
470
|
+
private beginWave;
|
|
471
|
+
private prune;
|
|
472
|
+
private parseWave;
|
|
473
|
+
}
|
|
474
|
+
//#endregion
|
|
475
|
+
//#region src/gameplay/zombie-ai.d.ts
|
|
476
|
+
/**
|
|
477
|
+
* The staple "zombie / monster" AI: SHAMBLE around on its own, then LOCK ON and
|
|
478
|
+
* CHARGE a target (the player) once it wanders within `aggroRange` — giving up
|
|
479
|
+
* again past `deAggroRange` (hysteresis, so it doesn't flicker at the boundary).
|
|
480
|
+
* One behavior covers both phases so a single node can be a complete enemy
|
|
481
|
+
* (`Wander` + `Chase` can't co-exist — a node carries ONE behavior).
|
|
482
|
+
*
|
|
483
|
+
* While NOT aggroed it roams: with `goalTarget` set it DRIFTS toward that node
|
|
484
|
+
* (e.g. the objective the horde is marching on) with random lateral jitter, so it
|
|
485
|
+
* reads as wandering yet still advances; without one it roams around its spawn.
|
|
486
|
+
*
|
|
487
|
+
* Emits `movementStateChanged('idle'|'walk'|'run')` on every change so a skin can
|
|
488
|
+
* swap animation clips (shamble while roaming, sprint while charging), plus
|
|
489
|
+
* `enteredAggro` / `exitedAggro` (wire to a growl, a glow, a speed-up).
|
|
490
|
+
*
|
|
491
|
+
* Dimension-agnostic; in 3D it moves only in the ground plane (x,z) and leaves
|
|
492
|
+
* the up axis (y) to physics, so a CharacterBody3D settles on terrain.
|
|
493
|
+
*
|
|
494
|
+
* `moveParent` (default false) moves the parent instead of this node — the
|
|
495
|
+
* AI-on-a-child pattern, so the entity ROOT can hold `Health` (clone-safe
|
|
496
|
+
* `freeOnDeath`) while this child drives movement.
|
|
497
|
+
*/
|
|
498
|
+
declare class ZombieAI extends Behavior {
|
|
499
|
+
static readonly props: PropSchema;
|
|
500
|
+
static readonly signals: readonly string[];
|
|
501
|
+
aggroTarget: string;
|
|
502
|
+
aggroRange: number;
|
|
503
|
+
deAggroRange: number;
|
|
504
|
+
chaseSpeed: number;
|
|
505
|
+
wanderSpeed: number;
|
|
506
|
+
wanderRadius: number;
|
|
507
|
+
wanderChangeEvery: number;
|
|
508
|
+
goalTarget: string;
|
|
509
|
+
stopRange: number;
|
|
510
|
+
moveParent: boolean;
|
|
511
|
+
private aggro;
|
|
512
|
+
private started;
|
|
513
|
+
private home;
|
|
514
|
+
private goal;
|
|
515
|
+
private timer;
|
|
516
|
+
private lastState;
|
|
517
|
+
/** The node we actually move (the parent under moveParent, else this one). */
|
|
518
|
+
private mover;
|
|
519
|
+
private effectiveDeAggro;
|
|
520
|
+
override onReady(): void;
|
|
521
|
+
override update(dt: number): void;
|
|
522
|
+
/** Move `mover` toward `to` in the GROUND PLANE; returns true once within
|
|
523
|
+
* stopRange (no overshoot). Leaves the up axis (3D y) to physics. */
|
|
524
|
+
private approach;
|
|
525
|
+
/** Distance ignoring the up axis in 3D (so terrain height never blocks aggro). */
|
|
526
|
+
private groundDistance;
|
|
527
|
+
private setState;
|
|
528
|
+
private pickGoal;
|
|
529
|
+
}
|
|
530
|
+
//#endregion
|
|
531
|
+
//#region src/gameplay/index.d.ts
|
|
532
|
+
/** Every built-in gameplay behavior, keyed by its registration name. */
|
|
533
|
+
declare const GAMEPLAY_BEHAVIORS: Readonly<Record<string, BehaviorCtor>>;
|
|
534
|
+
/**
|
|
535
|
+
* Register all built-in gameplay behaviors. Idempotent and hot-reload tolerant
|
|
536
|
+
* (`replace: true`) — calling it twice, or after a user already registered a
|
|
537
|
+
* same-named behavior, is safe; pass `replace: false` to fail on conflicts.
|
|
538
|
+
*/
|
|
539
|
+
declare function registerGameplayBehaviors(opts?: {
|
|
540
|
+
replace?: boolean;
|
|
541
|
+
}): void;
|
|
542
|
+
//#endregion
|
|
543
|
+
export { Chase, Collector, DamageOnContact, FollowCamera, GAMEPLAY_BEHAVIORS, Health, Interactable, Lifetime, MoveTo, Oscillate, Patrol, Pickup, Projectile, ScoreKeeper, Spawner, Wander, WaveSpawner, ZombieAI, registerGameplayBehaviors };
|
package/dist/gameplay.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { _ as Health, a as Wander, c as Projectile, d as Oscillate, f as MoveTo, g as DamageOnContact, h as FollowCamera, i as WaveSpawner, l as Pickup, m as Interactable, n as registerGameplayBehaviors, o as Spawner, p as Lifetime, r as ZombieAI, s as ScoreKeeper, t as GAMEPLAY_BEHAVIORS, u as Patrol, v as Collector, y as Chase } from "./gameplay-Ccruc3Wd.js";
|
|
2
|
+
export { Chase, Collector, DamageOnContact, FollowCamera, GAMEPLAY_BEHAVIORS, Health, Interactable, Lifetime, MoveTo, Oscillate, Patrol, Pickup, Projectile, ScoreKeeper, Spawner, Wander, WaveSpawner, ZombieAI, registerGameplayBehaviors };
|