incanto 0.61.0 → 0.62.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/bin/incanto-verify.mjs +134 -55
- package/dist/2d.d.ts +42 -0
- package/dist/2d.js +3 -3
- package/dist/3d.js +5 -5
- package/dist/{create-game-DH7JI5xx.js → create-game-BpunnGPX.js} +8 -8
- package/dist/{create-game-IX5lEH0P.js → create-game-Caut3bqN.js} +6 -6
- package/dist/{duplicate-CGqAmK2h.js → duplicate-E4FUs5Bn.js} +1 -1
- package/dist/editor.js +39 -18
- package/dist/{environment-presets-CNxCuhZF.js → environment-presets-BAWeOeqf.js} +5 -3
- package/dist/{gameplay-Dtzd2itW.js → gameplay-CaHqDiQD.js} +126 -15
- package/dist/gameplay.js +1 -1
- package/dist/index.d.ts +92 -1
- package/dist/index.js +6 -6
- package/dist/{loader-D7jTvDQv.js → loader-DEe272nY.js} +103 -0
- package/dist/net.js +1 -1
- package/dist/{physics-2d-CBnor8Zf.js → physics-2d-BXmu2i7W.js} +11 -3
- package/dist/{physics-3d-BTUfUSWO.js → physics-3d-ClxP6Uv7.js} +121 -17
- package/dist/react.js +1 -1
- package/dist/{register-DL3izw8j.js → register-CNh4FlbD.js} +60 -9
- package/dist/{register-xuSRyD6b.js → register-D3yx8D4r.js} +158 -2
- package/dist/{replay-D7-yle3s.js → replay-DlgHItNv.js} +15 -2
- package/dist/{split-screen-5Ban4q4n.js → split-screen-CBM9wcMX.js} +2 -2
- package/dist/{src-DozXvyZS.js → src-CH00_JsR.js} +1 -1
- package/dist/{teardown-B6rwJOyS.js → teardown-C7qP-dcC.js} +1 -1
- package/dist/{test-Dch_7VQD.js → test-BMkg8zMV.js} +27 -15
- package/dist/test.d.ts +37 -0
- package/dist/test.js +2 -2
- package/dist/vite.js +2 -2
- package/editor/assets/{agent8-CF1JL2tR.js → agent8-m5mtAO_A.js} +1 -1
- package/editor/assets/{debug-3QzYhOPA.js → debug-CPhzCT8f.js} +1 -1
- package/editor/assets/{index-CAD2c5ug.js → index-D422P4kW.js} +91 -91
- package/editor/index.html +1 -1
- package/package.json +1 -1
- package/schemas/scene.schema.json +87 -0
- package/skills/incanto-behaviors-and-scripts.md +37 -0
- package/skills/incanto-building-2d-games.md +20 -1
- package/skills/incanto-building-3d-games.md +1 -1
- package/skills/incanto-gameplay-behaviors.md +15 -1
- package/skills/incanto-node-reference.md +11 -0
- package/skills/incanto-physics-and-input.md +23 -2
- package/skills/incanto-verifying-your-game.md +31 -1
- package/templates-app/beacon-isle-3d/package.json +1 -1
- package/templates-app/platformer-2d/package.json +1 -1
- package/templates-app/star-survivor/package.json +1 -1
- package/templates-app/tps-3d/package.json +1 -1
- package/templates-app/village-quest-3d/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { O as Node, P as Behavior, _ as SaveSlots, k as diagnose, n as loadScene, w as effectiveOrder, z as registerBehavior } from "./loader-
|
|
1
|
+
import { O as Node, P as Behavior, _ as SaveSlots, k as diagnose, n as loadScene, w as effectiveOrder, z as registerBehavior } from "./loader-DEe272nY.js";
|
|
2
2
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
3
3
|
import { t as jsonClone } from "./json-CwwhxQgb.js";
|
|
4
|
-
import { t as duplicateNode } from "./duplicate-
|
|
4
|
+
import { t as duplicateNode } from "./duplicate-E4FUs5Bn.js";
|
|
5
5
|
import { Color, CubeCamera, DepthTexture, DoubleSide, Euler, FloatType, Frustum, HalfFloatType, LinearMipmapLinearFilter, MathUtils, Matrix4, Mesh, MeshDepthMaterial, Object3D, PerspectiveCamera, Plane, PlaneGeometry, Quaternion, ShaderMaterial, Sphere, Vector2, Vector3, Vector4, WebGLCubeRenderTarget, WebGLRenderTarget } from "three";
|
|
6
6
|
//#region src/3d/frustum.ts
|
|
7
7
|
const scratchFrustum = new Frustum();
|
|
@@ -2625,6 +2625,51 @@ var CharacterBody3D = class extends PhysicsBody3D {
|
|
|
2625
2625
|
}
|
|
2626
2626
|
};
|
|
2627
2627
|
//#endregion
|
|
2628
|
+
//#region src/3d/nodes/unscalable.ts
|
|
2629
|
+
/**
|
|
2630
|
+
* Refuse `scale` on a node that keeps a CPU twin of itself.
|
|
2631
|
+
*
|
|
2632
|
+
* `scale` is a plain `Node3D` prop and the 3D skill actively recommends it —
|
|
2633
|
+
* *"resize with `scale`, not `size` — resizing a mesh rebuilds its geometry
|
|
2634
|
+
* every call, scaling is free"*. On a mesh that is true. On `Terrain3D`,
|
|
2635
|
+
* `Water3D` and `River3D` it resizes only the PICTURE: everything the gameplay
|
|
2636
|
+
* layer reads is scale-blind, because it reads `size`.
|
|
2637
|
+
*
|
|
2638
|
+
* - `Terrain3D.heightAt` indexes a heightmap built from `size` and composes
|
|
2639
|
+
* ancestor POSITIONS only
|
|
2640
|
+
* - `buildHeightfieldDesc3D` passes `{x: hm.width, y: 1, z: hm.depth}` with no
|
|
2641
|
+
* scale term
|
|
2642
|
+
* - `Water3D._waterYAt` rejects anything outside `size / 2` of the node
|
|
2643
|
+
*
|
|
2644
|
+
* Measured on `size: [100, 100]` at `scale: [2, 1, 2]`:
|
|
2645
|
+
*
|
|
2646
|
+
* ```
|
|
2647
|
+
* terrain rendered X extent = [-100.0, 100.0] (was [-50, 50])
|
|
2648
|
+
* terrain heightAt(70, 0) = -50.000 (unchanged: the island floor)
|
|
2649
|
+
* water rendered X extent = [-40.0, 40.0]
|
|
2650
|
+
* water _waterYAt(30, 0) = null (unchanged)
|
|
2651
|
+
* ```
|
|
2652
|
+
*
|
|
2653
|
+
* So the player walks off an invisible cliff at ±50 m onto ground that is
|
|
2654
|
+
* visibly there for another 50; drape, spawn placement and terrain-nav all
|
|
2655
|
+
* agree with the collider and disagree with the picture; a scaled water's
|
|
2656
|
+
* underwater fog, splash and `avoidWater` culling stop at half the visible
|
|
2657
|
+
* shoreline. `incanto check` called the scene valid and `auditScene` said
|
|
2658
|
+
* nothing.
|
|
2659
|
+
*
|
|
2660
|
+
* A hard load error rather than a warning, per the engine's own guardrail: the
|
|
2661
|
+
* dial the author wanted exists and is one word away.
|
|
2662
|
+
*/
|
|
2663
|
+
function rejectScale(node, reads) {
|
|
2664
|
+
const scale = node.scale;
|
|
2665
|
+
if (!Array.isArray(scale)) return;
|
|
2666
|
+
if (scale.every((v) => Math.abs((v ?? 1) - 1) < 1e-4)) return;
|
|
2667
|
+
const type = node.constructor.typeName ?? "node";
|
|
2668
|
+
const size = node.size;
|
|
2669
|
+
const suggestion = Array.isArray(size) ? `size: [${size.map((v, i) => (v ?? 0) * (scale[i === 1 ? 2 : i] ?? 1)).join(", ")}]` : "size";
|
|
2670
|
+
throw new IncantoError("BAD_FORMAT", `${type} '${node.name}' has scale ${JSON.stringify(scale)}. On this node scale resizes only the MESH — ${reads} read "size" — so the ground you can see would reach past the ground you can stand on. Resize with "${suggestion}" instead.`, { prop: "scale" });
|
|
2671
|
+
}
|
|
2672
|
+
//#endregion
|
|
2628
2673
|
//#region src/3d/nodes/water-cutout-3d.ts
|
|
2629
2674
|
/**
|
|
2630
2675
|
* A box the water does not enter.
|
|
@@ -3155,6 +3200,7 @@ var Water3D = class Water3D extends Node3D {
|
|
|
3155
3200
|
}
|
|
3156
3201
|
/** Loader hook: degenerate planes and bad enums fail at LOAD, not at render. */
|
|
3157
3202
|
static validateJson(node) {
|
|
3203
|
+
rejectScale(node, "the water surface query, underwater fog, splashes and buoyancy all");
|
|
3158
3204
|
const w = node;
|
|
3159
3205
|
if (!((w.size[0] ?? 0) > 0) || !((w.size[1] ?? 0) > 0)) throw new IncantoError("BAD_FORMAT", `Water3D '${node.name}' size must be positive [width, depth] meters, got ${JSON.stringify(w.size)}.`, { prop: "size" });
|
|
3160
3206
|
if (!WATER_QUALITIES.includes(w.quality)) throw new IncantoError("BAD_FORMAT", `Water3D '${node.name}' quality must be one of [${WATER_QUALITIES.join(", ")}], got '${w.quality}'.`, {
|
|
@@ -4388,6 +4434,56 @@ function smoothingFactor(smoothing, dt) {
|
|
|
4388
4434
|
const s = Math.min(Math.max(smoothing, 0), .99);
|
|
4389
4435
|
return s <= 0 ? 1 : 1 - s ** (dt * 60);
|
|
4390
4436
|
}
|
|
4437
|
+
/**
|
|
4438
|
+
* A node's position with every spatial ancestor's added in.
|
|
4439
|
+
*
|
|
4440
|
+
* The tree composes transforms for DRAWING — three does it for free — and every
|
|
4441
|
+
* piece of engine logic that reads `node.position` gets the LOCAL number
|
|
4442
|
+
* instead. Physics already knew (`worldPosition2D`/`worldPosition3D` in the
|
|
4443
|
+
* adapters); the camera did not, and neither did anything that chases a target.
|
|
4444
|
+
*
|
|
4445
|
+
* A camera parented to the player is the Godot and Phaser idiom, and the
|
|
4446
|
+
* authoring skill explicitly permits it — *"EVERY node type can hold children …
|
|
4447
|
+
* any node works as a grouping container"*. Measured on exactly that scene:
|
|
4448
|
+
*
|
|
4449
|
+
* ```
|
|
4450
|
+
* player world position : [1400, 900]
|
|
4451
|
+
* renderer view centre : {"x":0,"y":0}
|
|
4452
|
+
* framing : camera /Level/Player/Cam centred [1400, 900]
|
|
4453
|
+
* 1 in view, 0 outside it
|
|
4454
|
+
* ```
|
|
4455
|
+
*
|
|
4456
|
+
* The renderer drew empty world 1600 px from the player while `framing` — the
|
|
4457
|
+
* instrument the skills tell you to trust before handing a game back —
|
|
4458
|
+
* certified the player on screen.
|
|
4459
|
+
*
|
|
4460
|
+
* Arity comes from the node itself: a 2D node has two components, a 3D node
|
|
4461
|
+
* three, and an ancestor that is neither contributes nothing.
|
|
4462
|
+
*/
|
|
4463
|
+
function worldPosition(node) {
|
|
4464
|
+
const own = node.position;
|
|
4465
|
+
if (!Array.isArray(own)) return [];
|
|
4466
|
+
const out = own.slice();
|
|
4467
|
+
for (let at = node.parent; at; at = at.parent) {
|
|
4468
|
+
const p = at.position;
|
|
4469
|
+
if (!Array.isArray(p)) continue;
|
|
4470
|
+
for (let i = 0; i < out.length; i++) out[i] = (out[i] ?? 0) + (p[i] ?? 0);
|
|
4471
|
+
}
|
|
4472
|
+
return out;
|
|
4473
|
+
}
|
|
4474
|
+
/**
|
|
4475
|
+
* Turn a world position into the local one `node.position` has to hold for the
|
|
4476
|
+
* node to END UP there — the inverse of `worldPosition` for its parent chain.
|
|
4477
|
+
*/
|
|
4478
|
+
function localFromWorld(node, world) {
|
|
4479
|
+
const out = world.slice();
|
|
4480
|
+
for (let at = node.parent; at; at = at.parent) {
|
|
4481
|
+
const p = at.position;
|
|
4482
|
+
if (!Array.isArray(p)) continue;
|
|
4483
|
+
for (let i = 0; i < out.length; i++) out[i] = (out[i] ?? 0) - (p[i] ?? 0);
|
|
4484
|
+
}
|
|
4485
|
+
return out;
|
|
4486
|
+
}
|
|
4391
4487
|
//#endregion
|
|
4392
4488
|
//#region src/gameplay/chase.ts
|
|
4393
4489
|
/**
|
|
@@ -5062,11 +5158,12 @@ var FollowCamera = class extends Behavior {
|
|
|
5062
5158
|
if (!hasPosition$1(cam)) return;
|
|
5063
5159
|
const target = cam.getNodeOrNull(this.target);
|
|
5064
5160
|
if (!target || !hasPosition$1(target)) return;
|
|
5065
|
-
const
|
|
5066
|
-
|
|
5161
|
+
const here = worldPosition(cam);
|
|
5162
|
+
const desired = add(worldPosition(target), this.offset);
|
|
5163
|
+
if (!(this.deadzone > 0 && distance$1(here, desired) <= this.deadzone)) {
|
|
5067
5164
|
const f = smoothingFactor(this.smoothing, dt);
|
|
5068
|
-
if (f >= 1) cam.position =
|
|
5069
|
-
else cam.position = cam.
|
|
5165
|
+
if (f >= 1) cam.position = localFromWorld(cam, desired);
|
|
5166
|
+
else cam.position = localFromWorld(cam, here.map((c, i) => c + ((desired[i] ?? c) - c) * f));
|
|
5070
5167
|
}
|
|
5071
5168
|
if (this.shakeT > 0) {
|
|
5072
5169
|
this.shakeT -= dt;
|
|
@@ -6069,12 +6166,12 @@ var Projectile = class extends Behavior {
|
|
|
6069
6166
|
return [Math.cos(rad), Math.sin(rad)];
|
|
6070
6167
|
}
|
|
6071
6168
|
if (Array.isArray(rot)) {
|
|
6072
|
-
const
|
|
6073
|
-
const
|
|
6169
|
+
const ry = (rot[1] ?? 0) * Math.PI / 180;
|
|
6170
|
+
const rx = (rot[0] ?? 0) * Math.PI / 180;
|
|
6074
6171
|
return normalize([
|
|
6075
|
-
|
|
6076
|
-
Math.sin(
|
|
6077
|
-
|
|
6172
|
+
Math.sin(ry),
|
|
6173
|
+
-Math.sin(rx) * Math.cos(ry),
|
|
6174
|
+
Math.cos(rx) * Math.cos(ry)
|
|
6078
6175
|
]);
|
|
6079
6176
|
}
|
|
6080
6177
|
return [1, 0];
|
|
@@ -6360,13 +6457,27 @@ var SpawnSource = class {
|
|
|
6360
6457
|
* spawner's node), and return the clone.
|
|
6361
6458
|
*
|
|
6362
6459
|
* Placement: with no `at`, the clone keeps the template's authored position;
|
|
6363
|
-
* with `at`, it
|
|
6364
|
-
*
|
|
6460
|
+
* with `at`, it ends up at the spawner's position plus `at`.
|
|
6461
|
+
*
|
|
6462
|
+
* `at` is written as the clone's LOCAL position, because the clone is added
|
|
6463
|
+
* as a CHILD of the spawner's node and that parent's transform already
|
|
6464
|
+
* contributes the spawner's own position. This used to add the two, so the
|
|
6465
|
+
* spawner's position was applied twice and the further from the origin you
|
|
6466
|
+
* put the nest, the further away its enemies appeared. Measured on a spawner
|
|
6467
|
+
* at [820, 240] with `"at": [0, -50]`:
|
|
6468
|
+
*
|
|
6469
|
+
* ```
|
|
6470
|
+
* expected world = [820, 190]
|
|
6471
|
+
* clone WORLD position = [1640, 430] error = [820, 240]
|
|
6472
|
+
* ```
|
|
6473
|
+
*
|
|
6474
|
+
* The scene loads, the spawner spawns, the clone is alive and visible — it is
|
|
6475
|
+
* just somewhere else in the level, and nothing has anything to report.
|
|
6365
6476
|
*/
|
|
6366
6477
|
spawn(template, opts) {
|
|
6367
6478
|
const clone = duplicateNode(template);
|
|
6368
6479
|
const at = opts?.at;
|
|
6369
|
-
if (at && at.length > 0 && hasPosition$1(clone)) clone.position = add(hasPosition$1(this.behavior.node) ? this.behavior.node.position
|
|
6480
|
+
if (at && at.length > 0 && hasPosition$1(clone)) clone.position = add((opts?.parent ?? this.behavior.node) === this.behavior.node || !hasPosition$1(this.behavior.node) ? [] : this.behavior.node.position, at);
|
|
6370
6481
|
if (typeof clone.visible === "boolean") clone.visible = true;
|
|
6371
6482
|
(opts?.parent ?? this.behavior.node).addChild(clone);
|
|
6372
6483
|
return clone;
|
|
@@ -6867,4 +6978,4 @@ function registerGameplayBehaviors(opts) {
|
|
|
6867
6978
|
for (const [name, ctor] of Object.entries(GAMEPLAY_BEHAVIORS)) registerBehavior(name, ctor, { replace });
|
|
6868
6979
|
}
|
|
6869
6980
|
//#endregion
|
|
6870
|
-
export { Health as A,
|
|
6981
|
+
export { Health as A, CharacterBody3D as B, restartScene as C, DayNight as D, FloatAway as E, Water3D as F, validateCollider3D as G, RigidBody3D as H, WATER_CUTOUT_MAX as I, colliderFootDrop as J, createCausticsQuad as K, WaterCutout3D as L, Chase as M, localFromWorld as N, phaseOf as O, worldPosition as P, rejectScale as R, goToScene as S, FollowCamera as T, StaticBody3D as U, PhysicsBody3D as V, Node3D as W, Cooldown as _, Wander as a, Interactable as b, SavePoint as c, Patrol as d, PathFollow as f, CameraShake as g, Lifetime as h, WaveSpawner as i, Collector as j, DamageOnContact as k, Projectile as l, MoveTo as m, registerGameplayBehaviors as n, Spawner as o, Oscillate as p, WATER_MAX_RIPPLES as q, ZombieAI as r, ScoreKeeper as s, GAMEPLAY_BEHAVIORS as t, Pickup as u, hitStop as v, tolerateUnknownAction as w, GameFlow as x, screenFlash as y, Area3D as z };
|
package/dist/gameplay.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { A as Health, C as restartScene, D as DayNight, E as FloatAway, M as Chase, O as phaseOf, S as goToScene, T as FollowCamera, _ as Cooldown, a as Wander, b as Interactable, c as SavePoint, d as Patrol, f as PathFollow, g as CameraShake, h as Lifetime, i as WaveSpawner, j as Collector, k as DamageOnContact, l as Projectile, m as MoveTo, n as registerGameplayBehaviors, o as Spawner, p as Oscillate, r as ZombieAI, s as ScoreKeeper, t as GAMEPLAY_BEHAVIORS, u as Pickup, v as hitStop, x as GameFlow, y as screenFlash } from "./gameplay-
|
|
1
|
+
import { A as Health, C as restartScene, D as DayNight, E as FloatAway, M as Chase, O as phaseOf, S as goToScene, T as FollowCamera, _ as Cooldown, a as Wander, b as Interactable, c as SavePoint, d as Patrol, f as PathFollow, g as CameraShake, h as Lifetime, i as WaveSpawner, j as Collector, k as DamageOnContact, l as Projectile, m as MoveTo, n as registerGameplayBehaviors, o as Spawner, p as Oscillate, r as ZombieAI, s as ScoreKeeper, t as GAMEPLAY_BEHAVIORS, u as Pickup, v as hitStop, x as GameFlow, y as screenFlash } from "./gameplay-CaHqDiQD.js";
|
|
2
2
|
export { CameraShake, Chase, Collector, Cooldown, DamageOnContact, DayNight, FloatAway, FollowCamera, GAMEPLAY_BEHAVIORS, GameFlow, Health, Interactable, Lifetime, MoveTo, Oscillate, PathFollow, Patrol, Pickup, Projectile, SavePoint, ScoreKeeper, Spawner, Wander, WaveSpawner, ZombieAI, goToScene, hitStop, phaseOf, registerGameplayBehaviors, restartScene, screenFlash };
|
package/dist/index.d.ts
CHANGED
|
@@ -624,6 +624,97 @@ declare class UiDialogue extends HudWidgetBase {
|
|
|
624
624
|
override update(dt: number): void;
|
|
625
625
|
}
|
|
626
626
|
//#endregion
|
|
627
|
+
//#region src/core/nodes/respawn.d.ts
|
|
628
|
+
/**
|
|
629
|
+
* Catch whatever this node hangs off when it leaves the world, and put it back.
|
|
630
|
+
*
|
|
631
|
+
* Nothing in the engine did this. Not a node, not a behavior, not a scene
|
|
632
|
+
* header — and the shipped examples prove what that costs: with the `plays`
|
|
633
|
+
* rung finally counting defects, `basic-3d-sideview` fails 8 seeded runs out of
|
|
634
|
+
* 8, `water-lake-3d` 7, `water-ocean-3d` 5, `water-pool-3d` 4,
|
|
635
|
+
* `water-river-3d` 1. Every one of them the same way — the player walks off the
|
|
636
|
+
* edge of the terrain and falls forever, and the only fix available was a
|
|
637
|
+
* per-frame `y` check hand-written in TypeScript, which is exactly the kind of
|
|
638
|
+
* thing this engine exists to keep out of TypeScript.
|
|
639
|
+
*
|
|
640
|
+
* A CHILD NODE rather than a Behavior, deliberately: a node holds one behavior
|
|
641
|
+
* and the player's is already spoken for (`PlayerControl`, `Health`, the game's
|
|
642
|
+
* own script). Children stack, the way `CharacterController3D` already hangs
|
|
643
|
+
* off its body.
|
|
644
|
+
*
|
|
645
|
+
* ```jsonc
|
|
646
|
+
* { "name": "Player", "type": "RigidBody3D", "props": { … },
|
|
647
|
+
* "children": [
|
|
648
|
+
* { "name": "Ctl", "type": "CharacterController3D" },
|
|
649
|
+
* { "name": "Catch", "type": "Respawn" } // that is the whole thing
|
|
650
|
+
* ] }
|
|
651
|
+
* ```
|
|
652
|
+
*
|
|
653
|
+
* With no props it guards its parent, uses the same line the playtest's fall
|
|
654
|
+
* detector uses (50 m under the spawn in 3D, 1000 px in 2D), and puts the node
|
|
655
|
+
* back where it started. `respawned` fires each time, so a life can be taken
|
|
656
|
+
* off a `ScoreKeeper` or a `Health` with an ordinary connection — this node
|
|
657
|
+
* does not decide what falling COSTS, which is a game-design question and not
|
|
658
|
+
* a physics one.
|
|
659
|
+
*/
|
|
660
|
+
declare class Respawn extends Node {
|
|
661
|
+
static override readonly typeName: string;
|
|
662
|
+
static override readonly signals: readonly string[];
|
|
663
|
+
static readonly props: PropSchema;
|
|
664
|
+
/**
|
|
665
|
+
* Who is being caught. Defaults to the parent, which is the whole point of
|
|
666
|
+
* hanging this off the thing it guards.
|
|
667
|
+
*/
|
|
668
|
+
target: string;
|
|
669
|
+
/**
|
|
670
|
+
* The line past which the target has left the world, in the scene's own
|
|
671
|
+
* down: 3D counts down (−y), 2D counts down the screen (+y).
|
|
672
|
+
*
|
|
673
|
+
* `null` is AUTO — the spawn position offset by the same distance the
|
|
674
|
+
* playtest's own fall detector uses, so "the level says it fell" and "the
|
|
675
|
+
* ladder says it fell" cannot disagree. Author a number when the level has a
|
|
676
|
+
* real floor to name; leave it alone otherwise.
|
|
677
|
+
*/
|
|
678
|
+
below: number | null;
|
|
679
|
+
/** Where to put it back. Empty = wherever it started. */
|
|
680
|
+
to: number[];
|
|
681
|
+
/**
|
|
682
|
+
* Zero the body's velocity on the way back.
|
|
683
|
+
*
|
|
684
|
+
* On by default because the alternative is invisible: a body respawned with
|
|
685
|
+
* 40 m/s of accumulated fall still in it drops straight back through the
|
|
686
|
+
* line on the next frame, and the level flickers instead of resuming.
|
|
687
|
+
*/
|
|
688
|
+
resetVelocity: boolean;
|
|
689
|
+
/** How many times this has caught the target — for HUDs and tests. */
|
|
690
|
+
falls: number;
|
|
691
|
+
private home;
|
|
692
|
+
private line;
|
|
693
|
+
/** +1 when "out" means y greater (2D screen-down), −1 when smaller (3D). */
|
|
694
|
+
private down;
|
|
695
|
+
override onReady(): void;
|
|
696
|
+
private spawnY;
|
|
697
|
+
/**
|
|
698
|
+
* Which way is out, and where the line is.
|
|
699
|
+
*
|
|
700
|
+
* Resolved on the first `update` rather than in `onReady`, because
|
|
701
|
+
* `onReady` runs inside `loadScene` — BEFORE `setScene` attaches the engine —
|
|
702
|
+
* so the scene's `dimension` is not readable there yet. Reading it there
|
|
703
|
+
* silently gives every 2D scene the 3D answer, and a line above a falling
|
|
704
|
+
* player fires on frame one, forever.
|
|
705
|
+
*
|
|
706
|
+
* Not called `resolve`: `Node` has a private method by that name and
|
|
707
|
+
* `getNodeOrNull` calls it, so a subclass method with the same name
|
|
708
|
+
* overrides it on the prototype — `private` is a TypeScript fiction that
|
|
709
|
+
* costs nothing at runtime — and every path lookup this node made returned a
|
|
710
|
+
* number. `node-method-shadowing.test.ts` refuses the whole family now.
|
|
711
|
+
*/
|
|
712
|
+
private fallLine;
|
|
713
|
+
/** The node this guards, or itself if the path no longer resolves. */
|
|
714
|
+
private guarded;
|
|
715
|
+
override update(_dt: number): void;
|
|
716
|
+
}
|
|
717
|
+
//#endregion
|
|
627
718
|
//#region src/core/nodes/timer.d.ts
|
|
628
719
|
/**
|
|
629
720
|
* The canonical serializable game clock — never `setTimeout` in game logic.
|
|
@@ -1174,4 +1265,4 @@ declare function computeViewport(canvasW: number, canvasH: number, viewport: {
|
|
|
1174
1265
|
/** Engine version. Kept in sync with package.json by the release pipeline. */
|
|
1175
1266
|
declare const VERSION: string;
|
|
1176
1267
|
//#endregion
|
|
1177
|
-
export { type AnimationDef, type AnimationEntry, type AssetFailure, AudioBuses, type AudioElementLike, AudioPlayer, BASE_LOCALE, Behavior, type BehaviorCtor, type BehaviorState, type BusName, CONST_REF_KEY, type ComputedViewport, type ConnectionJson, type CrossfadeGains, type DebugLineSource, type DeviceHints, type DriveScript, type DriveStep, type EffectEvent, type EffectKind, EffectLog, Engine, type EngineOptions, type EngineStats, type FindPathOptions, type GameStats, type GroupedLog, type HudAnchor, HudLayer, IncantoError, type IncantoErrorCode, type IncantoErrorDetails, InputMap, type JsonKind, type JsonObject, type JsonValue, type Listener, type LiveInput, type LiveReport, type LoadSceneOptions, type LocaleTables, Localization, type LogEntry, type LogLevel, LogManager, type MusicBackend, MusicManager, type MusicTrack, Node, type NodeCtor, type NodeJson, type NodeLifecycle, ORDER_GROUP_BASE, type OrderGroup, type OrderGroupTable, PARTICLE_PRESETS, PARTICLE_PRESET_NAMES, type ParsedNodePath, type ParticlePresetValues, ParticleSim, type ParticleSimConfig, type ParticleView, type PathGrid, type PlayMusicOptions, type PreloadResult, type PropDef, type PropSchema, type QualityTier, ROLLOFF_MODELS, type Recorder, type RefNode, type RefProblem, type RefResult, type RendererStats, type ReplayEvent, type ReplayJson, type ResolvedRendering, type ResolvedViewport, type RestoreReport, Rng, type RolloffModel, SCENE_FORMAT, SFX_PRESETS, SFX_PRESET_NAMES, type SaveSlot, SaveSlots, type SaveStore, Scene, type SceneJson, SceneTree, type Scheduler, Settings, type SettingsValues, SfxEngine, type SfxParams, type SfxPlayOptions, type SfxWave, Signal, type SignalListener, type SpatialParams, type SynthOptions, T_PREFIX, Timer, TouchControls, type TouchControlsOptions, UiBanner, UiBar, UiButton, UiDialogue, UiFrameCapSelect, UiImage, UiLanguageSelect, UiMuteToggle, UiPanel, UiQualitySelect, UiRenderScaleSelect, UiSelect, UiSlider, UiText, UiToggle, UiVolumeSlider, VERSION, type Vec3, type ViewportFit, type Voice, type VoicePreset, WebAudioMusicBackend, applyParticlePreset, assetUrls, attachTouchControls, auditScene, behaviorSchema, behaviorSignals, behaviorsWithoutSave, captureBehaviors, clearBehaviors, clearRegistry, computeViewport, createNode, createNoise2D, createSaveStore, crossfadeGains, describeRefProblem, duplicateNode, effectiveOrder, fadeGain, findPath, getBehavior, getNodeSchema, getNodeSignals, getNodeType, gridFromRows, isAudioContextAvailable, isConstRef, joystickVector, jsonClone, jsonEquals, jsonKind, loadScene, logReport, logText, mergeStaticSignals, newUid, nodeRefWarnings, parseDrive, parseNodePath, preloadSceneAssets, preloadUrls, qualityEnvironment, readDeviceHints, registerBehavior, registerCoreNodes, registerNode, registeredBehaviors, registeredTypes, replay, resolveAnimation, resolveConstants, resolveFrames, resolveOrderGroups, resolveRefInJson, resolveRendering, resolveViewport, restoreBehaviors, savesWithoutUid, serializeNode, sfxDuration, spatialGain, spatialPan, startRecording, suggestLocale, suggestQuality, synthSfx, translationKey };
|
|
1268
|
+
export { type AnimationDef, type AnimationEntry, type AssetFailure, AudioBuses, type AudioElementLike, AudioPlayer, BASE_LOCALE, Behavior, type BehaviorCtor, type BehaviorState, type BusName, CONST_REF_KEY, type ComputedViewport, type ConnectionJson, type CrossfadeGains, type DebugLineSource, type DeviceHints, type DriveScript, type DriveStep, type EffectEvent, type EffectKind, EffectLog, Engine, type EngineOptions, type EngineStats, type FindPathOptions, type GameStats, type GroupedLog, type HudAnchor, HudLayer, IncantoError, type IncantoErrorCode, type IncantoErrorDetails, InputMap, type JsonKind, type JsonObject, type JsonValue, type Listener, type LiveInput, type LiveReport, type LoadSceneOptions, type LocaleTables, Localization, type LogEntry, type LogLevel, LogManager, type MusicBackend, MusicManager, type MusicTrack, Node, type NodeCtor, type NodeJson, type NodeLifecycle, ORDER_GROUP_BASE, type OrderGroup, type OrderGroupTable, PARTICLE_PRESETS, PARTICLE_PRESET_NAMES, type ParsedNodePath, type ParticlePresetValues, ParticleSim, type ParticleSimConfig, type ParticleView, type PathGrid, type PlayMusicOptions, type PreloadResult, type PropDef, type PropSchema, type QualityTier, ROLLOFF_MODELS, type Recorder, type RefNode, type RefProblem, type RefResult, type RendererStats, type ReplayEvent, type ReplayJson, type ResolvedRendering, type ResolvedViewport, Respawn, type RestoreReport, Rng, type RolloffModel, SCENE_FORMAT, SFX_PRESETS, SFX_PRESET_NAMES, type SaveSlot, SaveSlots, type SaveStore, Scene, type SceneJson, SceneTree, type Scheduler, Settings, type SettingsValues, SfxEngine, type SfxParams, type SfxPlayOptions, type SfxWave, Signal, type SignalListener, type SpatialParams, type SynthOptions, T_PREFIX, Timer, TouchControls, type TouchControlsOptions, UiBanner, UiBar, UiButton, UiDialogue, UiFrameCapSelect, UiImage, UiLanguageSelect, UiMuteToggle, UiPanel, UiQualitySelect, UiRenderScaleSelect, UiSelect, UiSlider, UiText, UiToggle, UiVolumeSlider, VERSION, type Vec3, type ViewportFit, type Voice, type VoicePreset, WebAudioMusicBackend, applyParticlePreset, assetUrls, attachTouchControls, auditScene, behaviorSchema, behaviorSignals, behaviorsWithoutSave, captureBehaviors, clearBehaviors, clearRegistry, computeViewport, createNode, createNoise2D, createSaveStore, crossfadeGains, describeRefProblem, duplicateNode, effectiveOrder, fadeGain, findPath, getBehavior, getNodeSchema, getNodeSignals, getNodeType, gridFromRows, isAudioContextAvailable, isConstRef, joystickVector, jsonClone, jsonEquals, jsonKind, loadScene, logReport, logText, mergeStaticSignals, newUid, nodeRefWarnings, parseDrive, parseNodePath, preloadSceneAssets, preloadUrls, qualityEnvironment, readDeviceHints, registerBehavior, registerCoreNodes, registerNode, registeredBehaviors, registeredTypes, replay, resolveAnimation, resolveConstants, resolveFrames, resolveOrderGroups, resolveRefInJson, resolveRendering, resolveViewport, restoreBehaviors, savesWithoutUid, serializeNode, sfxDuration, spatialGain, spatialPan, startRecording, suggestLocale, suggestQuality, synthSfx, translationKey };
|
package/dist/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { A as describeRefProblem, B as registeredBehaviors, C as ORDER_GROUP_BASE, E as InputMap, F as behaviorSchema, I as behaviorSignals, L as clearBehaviors, M as resolveRefInJson, N as parseNodePath, O as Node, P as Behavior, R as getBehavior, S as createSaveStore, T as resolveOrderGroups, V as Signal, _ as SaveSlots, a as serializeNode, b as restoreBehaviors, d as computeViewport, f as resolveViewport, g as resolveConstants, h as isConstRef, i as Scene, j as nodeRefWarnings, m as CONST_REF_KEY, n as loadScene, o as SCENE_FORMAT, p as SceneTree, v as behaviorsWithoutSave, w as effectiveOrder, x as savesWithoutUid, y as captureBehaviors, z as registerBehavior } from "./loader-
|
|
2
|
-
import { A as
|
|
1
|
+
import { A as describeRefProblem, B as registeredBehaviors, C as ORDER_GROUP_BASE, E as InputMap, F as behaviorSchema, I as behaviorSignals, L as clearBehaviors, M as resolveRefInJson, N as parseNodePath, O as Node, P as Behavior, R as getBehavior, S as createSaveStore, T as resolveOrderGroups, V as Signal, _ as SaveSlots, a as serializeNode, b as restoreBehaviors, d as computeViewport, f as resolveViewport, g as resolveConstants, h as isConstRef, i as Scene, j as nodeRefWarnings, m as CONST_REF_KEY, n as loadScene, o as SCENE_FORMAT, p as SceneTree, v as behaviorsWithoutSave, w as effectiveOrder, x as savesWithoutUid, y as captureBehaviors, z as registerBehavior } from "./loader-DEe272nY.js";
|
|
2
|
+
import { A as UiBanner, B as isAudioContextAvailable, D as EffectLog, E as LogManager, F as T_PREFIX, G as SFX_PRESET_NAMES, H as spatialGain, I as suggestLocale, J as MusicManager, K as sfxDuration, M as UiText, N as BASE_LOCALE, O as HudLayer, P as Localization, Q as AudioBuses, R as translationKey, S as qualityEnvironment, T as suggestQuality, U as spatialPan, V as ROLLOFF_MODELS, W as SFX_PRESETS, X as crossfadeGains, Y as WebAudioMusicBackend, Z as fadeGain, _ as AudioPlayer, a as UiMuteToggle, b as Settings, c as UiRenderScaleSelect, d as UiToggle, f as UiVolumeSlider, g as UiDialogue, h as UiButton, i as UiLanguageSelect, j as UiBar, l as UiSelect, m as Respawn, n as UiFrameCapSelect, o as UiPanel, p as Timer, q as synthSfx, r as UiImage, s as UiQualitySelect, t as registerCoreNodes, u as UiSlider, v as Engine, w as readDeviceHints, z as SfxEngine } from "./register-D3yx8D4r.js";
|
|
3
3
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
4
4
|
import { t as Rng } from "./rng-DP-SR7eg.js";
|
|
5
5
|
import { n as jsonEquals, r as jsonKind, t as jsonClone } from "./json-CwwhxQgb.js";
|
|
6
6
|
import { a as getNodeSignals, c as mergeStaticSignals, i as getNodeSchema, l as registerNode, n as clearRegistry, o as getNodeType, r as createNode, u as registeredTypes } from "./registry-CF70EArN.js";
|
|
7
|
-
import { n as startRecording, r as auditScene, t as replay } from "./replay-
|
|
7
|
+
import { n as startRecording, r as auditScene, t as replay } from "./replay-DlgHItNv.js";
|
|
8
8
|
import { a as logReport, i as resolveRendering, n as attachTouchControls, o as logText, r as joystickVector, s as parseDrive, t as TouchControls } from "./touch-DESwnpOc.js";
|
|
9
9
|
import { t as createNoise2D } from "./noise-CGUMx44x.js";
|
|
10
10
|
import { a as PARTICLE_PRESETS, i as ParticleSim, n as resolveFrames, o as PARTICLE_PRESET_NAMES, s as applyParticlePreset, t as resolveAnimation } from "./sprite-animation-CY-mrr1L.js";
|
|
11
|
-
import { a as preloadUrls, i as preloadSceneAssets, n as newUid, o as findPath, r as assetUrls, s as gridFromRows, t as VERSION } from "./src-
|
|
12
|
-
import { t as duplicateNode } from "./duplicate-
|
|
13
|
-
export { AudioBuses, AudioPlayer, BASE_LOCALE, Behavior, CONST_REF_KEY, EffectLog, Engine, HudLayer, IncantoError, InputMap, Localization, LogManager, MusicManager, Node, ORDER_GROUP_BASE, PARTICLE_PRESETS, PARTICLE_PRESET_NAMES, ParticleSim, ROLLOFF_MODELS, Rng, SCENE_FORMAT, SFX_PRESETS, SFX_PRESET_NAMES, SaveSlots, Scene, SceneTree, Settings, SfxEngine, Signal, T_PREFIX, Timer, TouchControls, UiBanner, UiBar, UiButton, UiDialogue, UiFrameCapSelect, UiImage, UiLanguageSelect, UiMuteToggle, UiPanel, UiQualitySelect, UiRenderScaleSelect, UiSelect, UiSlider, UiText, UiToggle, UiVolumeSlider, VERSION, WebAudioMusicBackend, applyParticlePreset, assetUrls, attachTouchControls, auditScene, behaviorSchema, behaviorSignals, behaviorsWithoutSave, captureBehaviors, clearBehaviors, clearRegistry, computeViewport, createNode, createNoise2D, createSaveStore, crossfadeGains, describeRefProblem, duplicateNode, effectiveOrder, fadeGain, findPath, getBehavior, getNodeSchema, getNodeSignals, getNodeType, gridFromRows, isAudioContextAvailable, isConstRef, joystickVector, jsonClone, jsonEquals, jsonKind, loadScene, logReport, logText, mergeStaticSignals, newUid, nodeRefWarnings, parseDrive, parseNodePath, preloadSceneAssets, preloadUrls, qualityEnvironment, readDeviceHints, registerBehavior, registerCoreNodes, registerNode, registeredBehaviors, registeredTypes, replay, resolveAnimation, resolveConstants, resolveFrames, resolveOrderGroups, resolveRefInJson, resolveRendering, resolveViewport, restoreBehaviors, savesWithoutUid, serializeNode, sfxDuration, spatialGain, spatialPan, startRecording, suggestLocale, suggestQuality, synthSfx, translationKey };
|
|
11
|
+
import { a as preloadUrls, i as preloadSceneAssets, n as newUid, o as findPath, r as assetUrls, s as gridFromRows, t as VERSION } from "./src-CH00_JsR.js";
|
|
12
|
+
import { t as duplicateNode } from "./duplicate-E4FUs5Bn.js";
|
|
13
|
+
export { AudioBuses, AudioPlayer, BASE_LOCALE, Behavior, CONST_REF_KEY, EffectLog, Engine, HudLayer, IncantoError, InputMap, Localization, LogManager, MusicManager, Node, ORDER_GROUP_BASE, PARTICLE_PRESETS, PARTICLE_PRESET_NAMES, ParticleSim, ROLLOFF_MODELS, Respawn, Rng, SCENE_FORMAT, SFX_PRESETS, SFX_PRESET_NAMES, SaveSlots, Scene, SceneTree, Settings, SfxEngine, Signal, T_PREFIX, Timer, TouchControls, UiBanner, UiBar, UiButton, UiDialogue, UiFrameCapSelect, UiImage, UiLanguageSelect, UiMuteToggle, UiPanel, UiQualitySelect, UiRenderScaleSelect, UiSelect, UiSlider, UiText, UiToggle, UiVolumeSlider, VERSION, WebAudioMusicBackend, applyParticlePreset, assetUrls, attachTouchControls, auditScene, behaviorSchema, behaviorSignals, behaviorsWithoutSave, captureBehaviors, clearBehaviors, clearRegistry, computeViewport, createNode, createNoise2D, createSaveStore, crossfadeGains, describeRefProblem, duplicateNode, effectiveOrder, fadeGain, findPath, getBehavior, getNodeSchema, getNodeSignals, getNodeType, gridFromRows, isAudioContextAvailable, isConstRef, joystickVector, jsonClone, jsonEquals, jsonKind, loadScene, logReport, logText, mergeStaticSignals, newUid, nodeRefWarnings, parseDrive, parseNodePath, preloadSceneAssets, preloadUrls, qualityEnvironment, readDeviceHints, registerBehavior, registerCoreNodes, registerNode, registeredBehaviors, registeredTypes, replay, resolveAnimation, resolveConstants, resolveFrames, resolveOrderGroups, resolveRefInJson, resolveRendering, resolveViewport, restoreBehaviors, savesWithoutUid, serializeNode, sfxDuration, spatialGain, spatialPan, startRecording, suggestLocale, suggestQuality, synthSfx, translationKey };
|
|
@@ -854,6 +854,92 @@ function nodeTypeMethods(type) {
|
|
|
854
854
|
return out;
|
|
855
855
|
}
|
|
856
856
|
const methodCache = /* @__PURE__ */ new Map();
|
|
857
|
+
/** Every code the engine can ever receive, keyboard + mouse + gamepad. */
|
|
858
|
+
const INPUT_CODES = new Set([
|
|
859
|
+
...[..."ABCDEFGHIJKLMNOPQRSTUVWXYZ"].map((c) => `Key${c}`),
|
|
860
|
+
...Array.from({ length: 10 }, (_, i) => `Digit${i}`),
|
|
861
|
+
...Array.from({ length: 10 }, (_, i) => `Numpad${i}`),
|
|
862
|
+
"NumpadAdd",
|
|
863
|
+
"NumpadSubtract",
|
|
864
|
+
"NumpadMultiply",
|
|
865
|
+
"NumpadDivide",
|
|
866
|
+
"NumpadDecimal",
|
|
867
|
+
"NumpadEnter",
|
|
868
|
+
...Array.from({ length: 12 }, (_, i) => `F${i + 1}`),
|
|
869
|
+
"ArrowUp",
|
|
870
|
+
"ArrowDown",
|
|
871
|
+
"ArrowLeft",
|
|
872
|
+
"ArrowRight",
|
|
873
|
+
"Space",
|
|
874
|
+
"Enter",
|
|
875
|
+
"Escape",
|
|
876
|
+
"Tab",
|
|
877
|
+
"Backspace",
|
|
878
|
+
"Delete",
|
|
879
|
+
"Insert",
|
|
880
|
+
"Home",
|
|
881
|
+
"End",
|
|
882
|
+
"PageUp",
|
|
883
|
+
"PageDown",
|
|
884
|
+
"CapsLock",
|
|
885
|
+
"ShiftLeft",
|
|
886
|
+
"ShiftRight",
|
|
887
|
+
"ControlLeft",
|
|
888
|
+
"ControlRight",
|
|
889
|
+
"AltLeft",
|
|
890
|
+
"AltRight",
|
|
891
|
+
"MetaLeft",
|
|
892
|
+
"MetaRight",
|
|
893
|
+
"ContextMenu",
|
|
894
|
+
"Backquote",
|
|
895
|
+
"Minus",
|
|
896
|
+
"Equal",
|
|
897
|
+
"BracketLeft",
|
|
898
|
+
"BracketRight",
|
|
899
|
+
"Backslash",
|
|
900
|
+
"Semicolon",
|
|
901
|
+
"Quote",
|
|
902
|
+
"Comma",
|
|
903
|
+
"Period",
|
|
904
|
+
"Slash",
|
|
905
|
+
"IntlBackslash",
|
|
906
|
+
"IntlRo",
|
|
907
|
+
"IntlYen",
|
|
908
|
+
...Array.from({ length: 5 }, (_, i) => `Mouse${i}`),
|
|
909
|
+
...Array.from({ length: 17 }, (_, i) => `Pad${i}`)
|
|
910
|
+
]);
|
|
911
|
+
/** The one a typo probably meant, or null when nothing is close enough. */
|
|
912
|
+
function nearestCode(written) {
|
|
913
|
+
const lower = written.toLowerCase();
|
|
914
|
+
if (/^[a-z]$/.test(lower)) return `Key${lower.toUpperCase()}`;
|
|
915
|
+
if (/^[0-9]$/.test(written)) return `Digit${written}`;
|
|
916
|
+
if (lower === "shift" || lower === "ctrl" || lower === "control" || lower === "alt") {
|
|
917
|
+
const side = lower === "ctrl" ? "Control" : lower[0]?.toUpperCase() + lower.slice(1);
|
|
918
|
+
return `${side}Left" or "${side}Right`;
|
|
919
|
+
}
|
|
920
|
+
if (lower === "esc") return "Escape";
|
|
921
|
+
if (lower === "return") return "Enter";
|
|
922
|
+
if (lower === "up" || lower === "down" || lower === "left" || lower === "right") return `Arrow${lower[0]?.toUpperCase()}${lower.slice(1)}`;
|
|
923
|
+
let best = null;
|
|
924
|
+
let bestScore = 3;
|
|
925
|
+
for (const code of INPUT_CODES) {
|
|
926
|
+
const d = distance$1(lower, code.toLowerCase());
|
|
927
|
+
if (d < bestScore) {
|
|
928
|
+
bestScore = d;
|
|
929
|
+
best = code;
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
return best;
|
|
933
|
+
}
|
|
934
|
+
function distance$1(a, b) {
|
|
935
|
+
const rows = Array.from({ length: a.length + 1 }, (_, i) => [i, ...Array(b.length).fill(0)]);
|
|
936
|
+
for (let j = 0; j <= b.length; j++) rows[0][j] = j;
|
|
937
|
+
for (let i = 1; i <= a.length; i++) for (let j = 1; j <= b.length; j++) {
|
|
938
|
+
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
939
|
+
rows[i][j] = Math.min(rows[i - 1][j] + 1, rows[i][j - 1] + 1, rows[i - 1][j - 1] + cost);
|
|
940
|
+
}
|
|
941
|
+
return rows[a.length][b.length];
|
|
942
|
+
}
|
|
857
943
|
//#endregion
|
|
858
944
|
//#region src/core/input.ts
|
|
859
945
|
/** Keys typed into editable elements belong to the page UI, not the game. */
|
|
@@ -1322,6 +1408,21 @@ const DIRECTIONS = [
|
|
|
1322
1408
|
"left",
|
|
1323
1409
|
"right"
|
|
1324
1410
|
];
|
|
1411
|
+
/**
|
|
1412
|
+
* Refuse a key code the engine can never receive.
|
|
1413
|
+
*
|
|
1414
|
+
* The map is looked up by EXACT string against what the browser hands us, so
|
|
1415
|
+
* `"W"`, `"space"` and `"Shift"` — the three most natural things to write — bind
|
|
1416
|
+
* to nothing at all. They loaded clean, passed `incanto check`, and left the
|
|
1417
|
+
* player without that control, with nothing anywhere to say so.
|
|
1418
|
+
*/
|
|
1419
|
+
function checkCodes(action, where, keys) {
|
|
1420
|
+
for (const key of keys) {
|
|
1421
|
+
if (typeof key !== "string" || INPUT_CODES.has(key)) continue;
|
|
1422
|
+
const guess = nearestCode(key);
|
|
1423
|
+
throw new IncantoError("BAD_FORMAT", `Input action '${action}'${where}: '${key}' is not a key code, so nothing can ever press it${guess ? ` — did you mean "${guess}"?` : ""}. Codes are KeyboardEvent.code values (KeyW, Space, ArrowLeft, ShiftLeft), plus Mouse0..4 and Pad0..16.`, { prop: "keys" });
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1325
1426
|
function parseInputDecls(decls) {
|
|
1326
1427
|
const out = /* @__PURE__ */ new Map();
|
|
1327
1428
|
for (const [name, raw] of Object.entries(decls)) {
|
|
@@ -1330,6 +1431,7 @@ function parseInputDecls(decls) {
|
|
|
1330
1431
|
const keys = decl.keys;
|
|
1331
1432
|
if (!Array.isArray(keys) || keys.some((k) => typeof k !== "string")) throw new IncantoError("BAD_FORMAT", `Input action '${name}': button "keys" must be an array of KeyboardEvent.code strings.`);
|
|
1332
1433
|
if (decl.touch !== void 0 && decl.touch !== "button") throw new IncantoError("BAD_FORMAT", `Input action '${name}': button "touch" must be 'button', got ${JSON.stringify(decl.touch)}.`);
|
|
1434
|
+
checkCodes(name, "", keys);
|
|
1333
1435
|
out.set(name, {
|
|
1334
1436
|
type: "button",
|
|
1335
1437
|
keys: [...keys],
|
|
@@ -1345,6 +1447,7 @@ function parseInputDecls(decls) {
|
|
|
1345
1447
|
}
|
|
1346
1448
|
if (decl.touch !== void 0 && decl.touch !== "joystick") throw new IncantoError("BAD_FORMAT", `Input action '${name}': vector2 "touch" must be 'joystick', got ${JSON.stringify(decl.touch)}.`);
|
|
1347
1449
|
const d = dirs;
|
|
1450
|
+
for (const dir of DIRECTIONS) checkCodes(name, ` (${dir})`, d[dir]);
|
|
1348
1451
|
out.set(name, {
|
|
1349
1452
|
type: "vector2",
|
|
1350
1453
|
keys: {
|
package/dist/net.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { n as createAgent8Server } from "./agent8-CvsfVskX.js";
|
|
2
|
-
import { a as NetworkManager, d as createLocalGameServer, f as LoopbackHub, l as LocalGameServer, n as registerNodesNet, o as applySyncPatch, p as LoopbackTransport, r as NetworkSpawner, t as createSplitScreen, u as LocalGameServerTransport } from "./split-screen-
|
|
2
|
+
import { a as NetworkManager, d as createLocalGameServer, f as LoopbackHub, l as LocalGameServer, n as registerNodesNet, o as applySyncPatch, p as LoopbackTransport, r as NetworkSpawner, t as createSplitScreen, u as LocalGameServerTransport } from "./split-screen-CBM9wcMX.js";
|
|
3
3
|
export { LocalGameServer, LocalGameServerTransport, LoopbackHub, LoopbackTransport, NetworkManager, NetworkSpawner, applySyncPatch, createAgent8Server, createLocalGameServer, createSplitScreen, registerNodesNet };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
|
|
2
|
-
import { k as diagnose } from "./loader-
|
|
2
|
+
import { k as diagnose } from "./loader-DEe272nY.js";
|
|
3
3
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
4
|
-
import { _ as RigidBody2D, b as validateCollider2D, g as PhysicsBody2D, h as CharacterBody2D, m as Area2D, p as Joint2D, y as Node2D } from "./register-
|
|
4
|
+
import { _ as RigidBody2D, b as validateCollider2D, g as PhysicsBody2D, h as CharacterBody2D, m as Area2D, p as Joint2D, y as Node2D } from "./register-CNh4FlbD.js";
|
|
5
5
|
import { n as registerDebugSource } from "./debug-draw-BM3DsvtT.js";
|
|
6
6
|
import { t as withoutRapierInitNoise } from "./quiet-rapier-BAJ4K94N.js";
|
|
7
7
|
//#region src/2d/physics/physics-2d.ts
|
|
@@ -100,7 +100,10 @@ var Physics2D = class {
|
|
|
100
100
|
node.position = [t.x * SCALE - ox, t.y * SCALE - oy];
|
|
101
101
|
}
|
|
102
102
|
if (node instanceof RigidBody2D) {
|
|
103
|
-
if (!node.fixedRotation)
|
|
103
|
+
if (!node.fixedRotation) {
|
|
104
|
+
node.rotation = e.body.rotation() / DEG;
|
|
105
|
+
e.lastRot = node.rotation;
|
|
106
|
+
}
|
|
104
107
|
const lv = e.body.linvel();
|
|
105
108
|
node.linearVelocity = [lv.x * SCALE, lv.y * SCALE];
|
|
106
109
|
e.lastVX = node.linearVelocity[0] ?? 0;
|
|
@@ -428,6 +431,7 @@ var Physics2D = class {
|
|
|
428
431
|
collider,
|
|
429
432
|
lastX: wx,
|
|
430
433
|
lastY: wy,
|
|
434
|
+
lastRot: node.rotation,
|
|
431
435
|
lastVX: 0,
|
|
432
436
|
lastVY: 0
|
|
433
437
|
};
|
|
@@ -456,6 +460,10 @@ var Physics2D = class {
|
|
|
456
460
|
e.lastX = px;
|
|
457
461
|
e.lastY = py;
|
|
458
462
|
}
|
|
463
|
+
if (node.rotation !== e.lastRot) {
|
|
464
|
+
e.body.setRotation(node.rotation * DEG, true);
|
|
465
|
+
e.lastRot = node.rotation;
|
|
466
|
+
}
|
|
459
467
|
if (node instanceof RigidBody2D) {
|
|
460
468
|
const vx = node.linearVelocity[0] ?? 0;
|
|
461
469
|
const vy = node.linearVelocity[1] ?? 0;
|