incanto 0.65.0 → 0.66.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/dist/2d.d.ts +38 -3
- package/dist/2d.js +3 -3
- package/dist/3d.d.ts +130 -3
- package/dist/3d.js +4 -4
- package/dist/{audio-player-BrEHwbK1.d.ts → audio-player-_UAcHxnC.d.ts} +1 -1
- package/dist/{behavior-CmMuQ6CL.d.ts → behavior-BXNLfIJk.d.ts} +19 -0
- package/dist/{create-game-W2xzTJhs.js → create-game-DYJCIzO0.js} +66 -5
- package/dist/{create-game-DIyh5Zy9.js → create-game-Dd7H4bJV.js} +5 -5
- package/dist/debug.d.ts +1 -1
- package/dist/{environment-presets-BvHs6HEk.js → environment-presets-BlPsEmq6.js} +69 -5
- package/dist/{gameplay-D-H986A4.js → gameplay-D1RADWu3.js} +267 -7
- package/dist/gameplay.d.ts +78 -3
- package/dist/gameplay.js +2 -2
- package/dist/index.d.ts +4 -4
- package/dist/index.js +3 -3
- package/dist/{loader-CTB441z4.d.ts → loader-Cga7FVP4.d.ts} +1 -1
- package/dist/net.d.ts +2 -2
- package/dist/net.js +1 -1
- package/dist/{physics-2d-CmnunaR2.js → physics-2d-Cji5A6sX.js} +29 -3
- package/dist/{physics-3d-DULB1lD1.js → physics-3d-BkHjwJgI.js} +46 -4
- package/dist/{quiet-rapier-BAJ4K94N.js → quiet-rapier-C6fW4zcW.js} +14 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.js +1 -1
- package/dist/{register-CgeR4ckF.js → register-BmuqYTiY.js} +29 -0
- package/dist/{register-DO5_Qp0Q.js → register-D0CxCveZ.js} +37 -3
- package/dist/{replay-CThvwkcQ.d.ts → replay-BHoB6fCU.d.ts} +1 -1
- package/dist/{replay-CEw2xAhG.js → replay-IsZbNu6d.js} +1 -1
- package/dist/{split-screen-gb0c3xdb.js → split-screen-D_i7GRcY.js} +1 -1
- package/dist/{split-screen-DxZzC1nm.d.ts → split-screen-eJUFjhi1.d.ts} +2 -2
- package/dist/{src-DYffzHbd.js → src-BTLbXFPZ.js} +1 -1
- package/dist/{teardown-BordHL9o.js → teardown-byR9USax.js} +1 -1
- package/dist/{test-CXZuXs8k.js → test-DgrD0jHD.js} +11 -11
- package/dist/test.d.ts +4 -4
- package/dist/test.js +2 -2
- package/dist/vite.js +2 -2
- package/editor/assets/{agent8-DO5qzIOD.js → agent8-9N-Pd_YS.js} +1 -1
- package/editor/assets/{debug-DntG9CVD.js → debug-CkbJICYp.js} +1 -1
- package/editor/assets/{index-CqEUVaPN.js → index-CeDhIPTC.js} +72 -72
- package/editor/index.html +1 -1
- package/package.json +1 -1
- package/schemas/scene.schema.json +19 -0
- package/skills/incanto-gameplay-behaviors.md +85 -6
- package/skills/incanto-node-reference.md +59 -1
- package/skills/incanto-physics-and-input.md +69 -0
- package/skills/incanto-web-integration.md +24 -3
- 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
- package/templates-app/beacon-isle-3d/coverage.json +0 -9
- package/templates-app/platformer-2d/coverage.json +0 -5
- package/templates-app/star-survivor/coverage.json +0 -5
- package/templates-app/tps-3d/coverage.json +0 -5
- package/templates-app/village-quest-3d/coverage.json +0 -9
package/dist/2d.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { P as Scene$1, S as Scheduler, T as RendererStats, b as Engine, d as PropSchema, jt as Node, n as BehaviorCtor, w as GameStats } from "./behavior-
|
|
1
|
+
import { P as Scene$1, S as Scheduler, T as RendererStats, b as Engine, d as PropSchema, jt as Node, n as BehaviorCtor, w as GameStats } from "./behavior-BXNLfIJk.js";
|
|
2
2
|
import { n as DiagnosticSink, t as EditorSwitchOptions } from "./editor-switch-DAvWQeld.js";
|
|
3
3
|
import { i as SceneJson, s as JsonObject } from "./schema-CFeioQRE.js";
|
|
4
4
|
import { r as FrameStats } from "./frame-report-DCnHFmto.js";
|
|
5
|
-
import { t as LoadSceneOptions } from "./loader-
|
|
5
|
+
import { t as LoadSceneOptions } from "./loader-Cga7FVP4.js";
|
|
6
6
|
import { n as AnimationEntry } from "./sprite-animation-CMr6f1K2.js";
|
|
7
|
-
import { i as ParticleSim, o as ParticleView, r as SpatialPose } from "./audio-player-
|
|
7
|
+
import { i as ParticleSim, o as ParticleView, r as SpatialPose } from "./audio-player-_UAcHxnC.js";
|
|
8
8
|
import { Group, Mesh, Object3D, Scene, Texture } from "three";
|
|
9
9
|
import * as RapierNs from "@dimforge/rapier2d-compat";
|
|
10
10
|
|
|
@@ -157,6 +157,11 @@ declare class StaticBody2D extends PhysicsBody2D {
|
|
|
157
157
|
*/
|
|
158
158
|
declare class Area2D extends PhysicsBody2D {
|
|
159
159
|
static override readonly typeName: string;
|
|
160
|
+
/**
|
|
161
|
+
* Who is inside RIGHT NOW — the standing answer behind the enter/exit pair.
|
|
162
|
+
* See `Area3D.overlapping`. Empty in a scene with no physics world.
|
|
163
|
+
*/
|
|
164
|
+
overlapping(group?: string): PhysicsBody2D[];
|
|
160
165
|
}
|
|
161
166
|
/** Dynamic simulated body. */
|
|
162
167
|
declare class RigidBody2D extends PhysicsBody2D {
|
|
@@ -271,6 +276,11 @@ declare class Physics2D {
|
|
|
271
276
|
private scopedLines;
|
|
272
277
|
/** Create newly-arrived joints; tear down departed ones. */
|
|
273
278
|
private syncJoints;
|
|
279
|
+
/** Who is currently inside each sensor/body, maintained from the event drain. */
|
|
280
|
+
private readonly overlaps;
|
|
281
|
+
private trackOverlap;
|
|
282
|
+
/** The bodies currently overlapping `node`. Freed nodes are dropped on read. */
|
|
283
|
+
overlapping(node: PhysicsBody2D): PhysicsBody2D[];
|
|
274
284
|
/**
|
|
275
285
|
* World-space raycast in PIXELS (y-down). `exclude` skips that body — a
|
|
276
286
|
* shooter probing from inside its own collider needs it. Sensors (Area2D)
|
|
@@ -719,6 +729,31 @@ declare class Joint2D extends Node2D {
|
|
|
719
729
|
length: number;
|
|
720
730
|
stiffness: number;
|
|
721
731
|
damping: number;
|
|
732
|
+
/**
|
|
733
|
+
* Do the two linked bodies still collide with EACH OTHER?
|
|
734
|
+
*
|
|
735
|
+
* `null` (default) decides from the joint type, because the two families want
|
|
736
|
+
* opposite answers:
|
|
737
|
+
*
|
|
738
|
+
* - **pivots** (`fixed`, `spherical`, `revolute`) → **off**. A hinge's bodies
|
|
739
|
+
* overlap at the pivot by construction, so the contact solver fights the
|
|
740
|
+
* joint and flings them. A puzzle builder's first hinge produced a bar that
|
|
741
|
+
* spun chaotically forever and threw a 40 kg box thirty metres, and they
|
|
742
|
+
* nearly filed "spherical joints inject energy":
|
|
743
|
+
*
|
|
744
|
+
* ```
|
|
745
|
+
* t= 0 Plank r=[0,0,0] Box [ 0.00, 5.50, 2.40]
|
|
746
|
+
* t=3000 Plank r=[-66,24,64] Box [-29.70, 0.40, -4.91]
|
|
747
|
+
* ```
|
|
748
|
+
*
|
|
749
|
+
* - **tethers** (`rope`, `spring`) → **on**. These anchor a thing to the world,
|
|
750
|
+
* and the thing has to rest on what it is tethered to. Defaulting these off
|
|
751
|
+
* drops a barrel roped to the floor straight through it — measured, in this
|
|
752
|
+
* repo's own conformance room.
|
|
753
|
+
*
|
|
754
|
+
* Set `true`/`false` to say it outright.
|
|
755
|
+
*/
|
|
756
|
+
collide: boolean | null;
|
|
722
757
|
override onEnterTree(): void;
|
|
723
758
|
/** @internal The two bodies, resolved (throws on a bad target at step time). */
|
|
724
759
|
_resolveBodies(): {
|
package/dist/2d.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
2
|
-
import { a as AssetStore2D, i as syncTree2D, r as Renderer2D, t as createGame2D } from "./create-game-
|
|
3
|
-
import { _ as RigidBody2D, a as parseCells, c as ColorRect2D, d as AnimatedSprite2D, f as Sprite2D, g as PhysicsBody2D, h as CharacterBody2D, i as mergeSolidRects, l as CharacterController2D, m as Area2D, n as UILayer, o as Particles2D, p as Joint2D, r as TileMap2D, s as Label, t as registerNodes2D, u as Camera2D, v as StaticBody2D, y as Node2D } from "./register-
|
|
4
|
-
import { n as enablePhysics2D, t as Physics2D } from "./physics-2d-
|
|
2
|
+
import { a as AssetStore2D, i as syncTree2D, r as Renderer2D, t as createGame2D } from "./create-game-Dd7H4bJV.js";
|
|
3
|
+
import { _ as RigidBody2D, a as parseCells, c as ColorRect2D, d as AnimatedSprite2D, f as Sprite2D, g as PhysicsBody2D, h as CharacterBody2D, i as mergeSolidRects, l as CharacterController2D, m as Area2D, n as UILayer, o as Particles2D, p as Joint2D, r as TileMap2D, s as Label, t as registerNodes2D, u as Camera2D, v as StaticBody2D, y as Node2D } from "./register-D0CxCveZ.js";
|
|
4
|
+
import { n as enablePhysics2D, t as Physics2D } from "./physics-2d-Cji5A6sX.js";
|
|
5
5
|
//#region src/2d/library-sprite.ts
|
|
6
6
|
/**
|
|
7
7
|
* What a `CharacterController2D`/`3D` will ask a skin to play, and the clip in
|
package/dist/3d.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { D as QualityCaps, P as Scene$1, S as Scheduler, T as RendererStats, b as Engine, d as PropSchema, jt as Node, n as BehaviorCtor, w as GameStats } from "./behavior-
|
|
1
|
+
import { D as QualityCaps, P as Scene$1, S as Scheduler, T as RendererStats, b as Engine, d as PropSchema, jt as Node, n as BehaviorCtor, w as GameStats } from "./behavior-BXNLfIJk.js";
|
|
2
2
|
import { n as DiagnosticSink, t as EditorSwitchOptions } from "./editor-switch-DAvWQeld.js";
|
|
3
3
|
import { i as SceneJson$1, s as JsonObject } from "./schema-CFeioQRE.js";
|
|
4
4
|
import { a as GridCell, c as diffText, d as frameText, i as FrameStatsOptions, l as frameSignature, n as FrameSignature, o as SIGNATURE_GRID, r as FrameStats, s as diffSignatures, t as FrameDiff, u as frameStats } from "./frame-report-DCnHFmto.js";
|
|
5
|
-
import { t as LoadSceneOptions } from "./loader-
|
|
6
|
-
import { i as ParticleSim, o as ParticleView, r as SpatialPose } from "./audio-player-
|
|
5
|
+
import { t as LoadSceneOptions } from "./loader-Cga7FVP4.js";
|
|
6
|
+
import { i as ParticleSim, o as ParticleView, r as SpatialPose } from "./audio-player-_UAcHxnC.js";
|
|
7
7
|
import { n as PathGrid } from "./pathfinding-_fGrCFmH.js";
|
|
8
8
|
import { AnimationClip, AnimationMixer, BufferGeometry, Color, DirectionalLight, Group, InstancedMesh, Mesh, MeshPhysicalMaterial, Object3D, PerspectiveCamera, Scene, ShaderMaterial, Texture, Vector3, WebGLRenderer } from "three";
|
|
9
9
|
import { VRM } from "@pixiv/three-vrm";
|
|
@@ -358,6 +358,33 @@ declare class StaticBody3D extends PhysicsBody3D {
|
|
|
358
358
|
/** Sensor volume emitting `triggerEnter(other)` / `triggerExit(other)`. */
|
|
359
359
|
declare class Area3D extends PhysicsBody3D {
|
|
360
360
|
static override readonly typeName: string;
|
|
361
|
+
/**
|
|
362
|
+
* Who is inside RIGHT NOW — the standing answer behind the enter/exit pair.
|
|
363
|
+
*
|
|
364
|
+
* Enter and exit tell you about crossings; a pressure plate, a capture point,
|
|
365
|
+
* a "how many enemies are in the blast" count and a shop trigger all want
|
|
366
|
+
* OCCUPANCY. Without this every one of them kept a private `Set` fed by the
|
|
367
|
+
* two signals, and had to guard it, because a body that is teleported or
|
|
368
|
+
* freed inside a sensor does not reliably announce its exit. Physics already
|
|
369
|
+
* knows; now it says.
|
|
370
|
+
*
|
|
371
|
+
* ```ts
|
|
372
|
+
* const load = this.area.overlapping()
|
|
373
|
+
* .reduce((kg, b) => kg + ((b as RigidBody3D).mass ?? 0), 0);
|
|
374
|
+
* door.open = load >= 60;
|
|
375
|
+
* ```
|
|
376
|
+
*
|
|
377
|
+
* It reports everything the solver says is inside, STATIC WORLD INCLUDED — a
|
|
378
|
+
* plate laid into the floor genuinely contains the floor. Pass a group to ask
|
|
379
|
+
* the question you usually mean:
|
|
380
|
+
*
|
|
381
|
+
* ```ts
|
|
382
|
+
* area.overlapping('crate') // only things tagged `crate`
|
|
383
|
+
* ```
|
|
384
|
+
*
|
|
385
|
+
* Empty in a scene with no physics world.
|
|
386
|
+
*/
|
|
387
|
+
overlapping(group?: string): PhysicsBody3D[];
|
|
361
388
|
}
|
|
362
389
|
/** Dynamic simulated body. */
|
|
363
390
|
declare class RigidBody3D extends PhysicsBody3D {
|
|
@@ -370,6 +397,14 @@ declare class RigidBody3D extends PhysicsBody3D {
|
|
|
370
397
|
restitution: number;
|
|
371
398
|
/** m/s, y-up. Read back every step; write to launch. */
|
|
372
399
|
linearVelocity: number[];
|
|
400
|
+
/**
|
|
401
|
+
* rad/s about each world axis. Read back every step; write to spin.
|
|
402
|
+
*
|
|
403
|
+
* A puzzle builder could neither launch a spinning body nor read how fast a
|
|
404
|
+
* lever was swinging — only its angle, differenced by hand — because this had
|
|
405
|
+
* no counterpart to `linearVelocity`. `fixedRotation` pins it at zero.
|
|
406
|
+
*/
|
|
407
|
+
angularVelocity: number[];
|
|
373
408
|
/** @internal set by Physics3D */
|
|
374
409
|
_physics3d: Physics3D | null;
|
|
375
410
|
/** World-space impulse (kg·m/s) — the floating-capsule controller's verb. */
|
|
@@ -539,6 +574,17 @@ declare class Physics3D {
|
|
|
539
574
|
velocityOf(node: PhysicsBody3D): [number, number, number];
|
|
540
575
|
/** Create newly-arrived joints; tear down departed ones. */
|
|
541
576
|
private syncJoints;
|
|
577
|
+
/** Who is currently inside each sensor/body, maintained from the event drain. */
|
|
578
|
+
private readonly overlaps;
|
|
579
|
+
private trackOverlap;
|
|
580
|
+
/**
|
|
581
|
+
* The bodies currently overlapping `node` — the standing answer behind
|
|
582
|
+
* `triggerEnter`/`triggerExit`.
|
|
583
|
+
*
|
|
584
|
+
* Freed nodes are dropped on read rather than tracked, so a hazard that
|
|
585
|
+
* despawns inside a plate cannot leave a ghost holding a door open.
|
|
586
|
+
*/
|
|
587
|
+
overlapping(node: PhysicsBody3D): PhysicsBody3D[];
|
|
542
588
|
/**
|
|
543
589
|
* World-space raycast (meters). `exclude` skips that body's collider —
|
|
544
590
|
* ground probes from inside a capsule need it. `opts.staticOnly` hits ONLY the
|
|
@@ -1264,6 +1310,25 @@ declare class CharacterController3D extends Node3D {
|
|
|
1264
1310
|
airControl: number;
|
|
1265
1311
|
fallGravity: number;
|
|
1266
1312
|
floatHeight: number;
|
|
1313
|
+
/**
|
|
1314
|
+
* How high a step the PLAYER walks up without jumping (0 = off).
|
|
1315
|
+
*
|
|
1316
|
+
* The hover spring holds the capsule a fixed distance above whatever is
|
|
1317
|
+
* DIRECTLY below it, so a vertical face stopped the player dead at about
|
|
1318
|
+
* 0.2 m — while `CharacterBody3D.stepHeight` let every enemy climb 0.35 m.
|
|
1319
|
+
* The docs said the player did not need this ("it floats over small ledges
|
|
1320
|
+
* already"); it floats over 18 cm ones.
|
|
1321
|
+
*
|
|
1322
|
+
* This probes just AHEAD of the capsule in the direction of travel: if the
|
|
1323
|
+
* ground there is higher, but by no more than `stepHeight`, the spring aims
|
|
1324
|
+
* at THAT surface and lifts the character onto it. A wall taller than the
|
|
1325
|
+
* step is not a step and still stops you.
|
|
1326
|
+
*
|
|
1327
|
+
* Do not reach for `floatHeight` instead. It does raise the character over
|
|
1328
|
+
* ledges, and it silently makes it WEIGHTLESS: at `floatHeight: 0.28` a
|
|
1329
|
+
* 200 kg character does not move a seesaw a 70 kg crate tips.
|
|
1330
|
+
*/
|
|
1331
|
+
stepHeight: number;
|
|
1267
1332
|
mouseLook: boolean;
|
|
1268
1333
|
zoomMin: number;
|
|
1269
1334
|
zoomMax: number;
|
|
@@ -1836,6 +1901,31 @@ declare class Joint3D extends Node3D {
|
|
|
1836
1901
|
length: number;
|
|
1837
1902
|
stiffness: number;
|
|
1838
1903
|
damping: number;
|
|
1904
|
+
/**
|
|
1905
|
+
* Do the two linked bodies still collide with EACH OTHER?
|
|
1906
|
+
*
|
|
1907
|
+
* `null` (default) decides from the joint type, because the two families want
|
|
1908
|
+
* opposite answers:
|
|
1909
|
+
*
|
|
1910
|
+
* - **pivots** (`fixed`, `spherical`, `revolute`) → **off**. A hinge's bodies
|
|
1911
|
+
* overlap at the pivot by construction, so the contact solver fights the
|
|
1912
|
+
* joint and flings them. A puzzle builder's first hinge produced a bar that
|
|
1913
|
+
* spun chaotically forever and threw a 40 kg box thirty metres, and they
|
|
1914
|
+
* nearly filed "spherical joints inject energy":
|
|
1915
|
+
*
|
|
1916
|
+
* ```
|
|
1917
|
+
* t= 0 Plank r=[0,0,0] Box [ 0.00, 5.50, 2.40]
|
|
1918
|
+
* t=3000 Plank r=[-66,24,64] Box [-29.70, 0.40, -4.91]
|
|
1919
|
+
* ```
|
|
1920
|
+
*
|
|
1921
|
+
* - **tethers** (`rope`, `spring`) → **on**. These anchor a thing to the world,
|
|
1922
|
+
* and the thing has to rest on what it is tethered to. Defaulting these off
|
|
1923
|
+
* drops a barrel roped to the floor straight through it — measured, in this
|
|
1924
|
+
* repo's own conformance room.
|
|
1925
|
+
*
|
|
1926
|
+
* Set `true`/`false` to say it outright.
|
|
1927
|
+
*/
|
|
1928
|
+
collide: boolean | null;
|
|
1839
1929
|
override onEnterTree(): void;
|
|
1840
1930
|
/** @internal The two bodies, resolved (throws on a bad target at step time). */
|
|
1841
1931
|
_resolveBodies(): {
|
|
@@ -3719,6 +3809,43 @@ declare class Renderer3D {
|
|
|
3719
3809
|
behind: boolean;
|
|
3720
3810
|
};
|
|
3721
3811
|
/**
|
|
3812
|
+
* The WORLD POINT under canvas pixel (sx, sy) — the other half of
|
|
3813
|
+
* `screenFromWorld`, and the call `incanto-web-integration.md` has always
|
|
3814
|
+
* offered "for taps and clicks".
|
|
3815
|
+
*
|
|
3816
|
+
* It did not exist in 3D. `Renderer2D` has had it since the beginning, the
|
|
3817
|
+
* doc covers both runtimes, and an agent building a tower defense went looking
|
|
3818
|
+
* for it and measured `typeof game.renderer.worldFromScreen === "undefined"`.
|
|
3819
|
+
* `pick()` gives you the NODE under a pixel but never the POINT, so "put the
|
|
3820
|
+
* thing where the player clicked on the ground" was not expressible and that
|
|
3821
|
+
* game discretised its whole map into clickable pads instead.
|
|
3822
|
+
*
|
|
3823
|
+
* A pixel in 3D is a RAY, not a point, so this needs a surface to land on and
|
|
3824
|
+
* takes the horizontal plane at `planeY` (default 0 — the ground). Returns
|
|
3825
|
+
* null when the ray runs parallel to that plane or would only meet it behind
|
|
3826
|
+
* the camera, which is what "the sky" looks like from here.
|
|
3827
|
+
*
|
|
3828
|
+
* For anything not flat — terrain, a hillside, a stack of crates — raycast
|
|
3829
|
+
* physics instead: `rayFromScreen` gives you the origin and direction to feed
|
|
3830
|
+
* `physics.castRay`.
|
|
3831
|
+
*/
|
|
3832
|
+
worldFromScreen(sx: number, sy: number, planeY?: number): {
|
|
3833
|
+
x: number;
|
|
3834
|
+
y: number;
|
|
3835
|
+
z: number;
|
|
3836
|
+
} | null;
|
|
3837
|
+
/**
|
|
3838
|
+
* The camera ray through canvas pixel (sx, sy) — origin and unit direction,
|
|
3839
|
+
* ready for `physics.castRay(origin, dir, maxLen)`.
|
|
3840
|
+
*
|
|
3841
|
+
* This is the honest 3D answer to "where did the player click": on uneven
|
|
3842
|
+
* ground the only thing that knows is the collision world.
|
|
3843
|
+
*/
|
|
3844
|
+
rayFromScreen(sx: number, sy: number): {
|
|
3845
|
+
origin: [number, number, number];
|
|
3846
|
+
dir: [number, number, number];
|
|
3847
|
+
} | null;
|
|
3848
|
+
/**
|
|
3722
3849
|
* The node rendered under canvas pixel (sx, sy), or null — raycasts the last
|
|
3723
3850
|
* rendered camera into the scene and resolves the hit up to its `incantoNode`
|
|
3724
3851
|
* (every Node3D stamps that in `_ensureObject3D`). 3D depth-sorts, so the
|
package/dist/3d.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { c as parseEnvironment3D, l as sunDirectionFromElevationAzimuth, s as horizonColorFromSky, u as sunDirectionFromSky } from "./loader-lQDCwNag.js";
|
|
2
2
|
import { a as frameSignature, n as diffSignatures, o as frameStats, r as diffText, s as frameText, t as SIGNATURE_GRID } from "./frame-report-BSMny7oe.js";
|
|
3
|
-
import {
|
|
4
|
-
import { A as Terrain3D, B as keyboardIntensity, C as resolveFlowerDensity, D as BoneLookAt3D, E as Camera3D, F as InstancedMesh3D, G as acquireTexture, H as rigPose, I as MeshInstance3D, M as TERRAIN_THEMES, N as terrainThemeLayers, O as BoneAttachment3D, P as Joint3D, R as QUARTER_PITCH, S as Flowers3D, T as CharacterController3D, U as TextureCache3D, V as movementState, W as acquireOwnTexture, _ as LoftMesh3D, a as Tree3D, b as Foliage3D, c as buildRiverRings, d as riverCarveChannels, f as riverStepFor, g as ModelInstance3D, h as Particles3D, i as VoxelGrid3D, j as DEFAULT_TERRAIN_TEXTURE_BASE, k as Billboard3D, l as findRiverCoverageGaps, m as traceDownhillPath, n as registerNodes3D, o as Trail3D, p as smoothCourse, r as VOXEL_PALETTE, s as River3D, u as projectToRiver, v as DirectionalLight3D, w as FLOWER_VARIETIES, x as DENSITY_PRESETS, y as OmniLight3D, z as cameraRelative } from "./environment-presets-
|
|
5
|
-
import { a as Environment3D, i as syncTree, o as setEnvironment3D, r as Renderer3D, s as AssetStore3D, t as createGame3D } from "./create-game-
|
|
3
|
+
import { G as StaticBody3D, H as CharacterBody3D, K as Node3D, L as Water3D, R as WATER_CUTOUT_MAX, U as PhysicsBody3D, V as Area3D, W as RigidBody3D, Y as WATER_MAX_RIPPLES, z as WaterCutout3D } from "./gameplay-D1RADWu3.js";
|
|
4
|
+
import { A as Terrain3D, B as keyboardIntensity, C as resolveFlowerDensity, D as BoneLookAt3D, E as Camera3D, F as InstancedMesh3D, G as acquireTexture, H as rigPose, I as MeshInstance3D, M as TERRAIN_THEMES, N as terrainThemeLayers, O as BoneAttachment3D, P as Joint3D, R as QUARTER_PITCH, S as Flowers3D, T as CharacterController3D, U as TextureCache3D, V as movementState, W as acquireOwnTexture, _ as LoftMesh3D, a as Tree3D, b as Foliage3D, c as buildRiverRings, d as riverCarveChannels, f as riverStepFor, g as ModelInstance3D, h as Particles3D, i as VoxelGrid3D, j as DEFAULT_TERRAIN_TEXTURE_BASE, k as Billboard3D, l as findRiverCoverageGaps, m as traceDownhillPath, n as registerNodes3D, o as Trail3D, p as smoothCourse, r as VOXEL_PALETTE, s as River3D, u as projectToRiver, v as DirectionalLight3D, w as FLOWER_VARIETIES, x as DENSITY_PRESETS, y as OmniLight3D, z as cameraRelative } from "./environment-presets-BlPsEmq6.js";
|
|
5
|
+
import { a as Environment3D, i as syncTree, o as setEnvironment3D, r as Renderer3D, s as AssetStore3D, t as createGame3D } from "./create-game-DYJCIzO0.js";
|
|
6
6
|
import { n as splatWeights, t as buildHeightmap } from "./heightmap-CRK0M4jT.js";
|
|
7
|
-
import { n as enablePhysics3D, t as Physics3D } from "./physics-3d-
|
|
7
|
+
import { n as enablePhysics3D, t as Physics3D } from "./physics-3d-BkHjwJgI.js";
|
|
8
8
|
//#region src/3d/model-verdict.ts
|
|
9
9
|
/** Mixamo exports every bone as `mixamorigX`; the retargeter binds by that name. */
|
|
10
10
|
const MIXAMO = /^mixamorig[:_]?/i;
|
|
@@ -1649,6 +1649,25 @@ declare class Engine {
|
|
|
1649
1649
|
* and cleared on dispose; null when nothing renders (headless).
|
|
1650
1650
|
*/
|
|
1651
1651
|
picker: ((x: number, y: number) => Node | null) | null;
|
|
1652
|
+
/** Frames the engine has stepped — monotonic, and the pick cache's key. */
|
|
1653
|
+
frameNumber: number;
|
|
1654
|
+
/** @internal frame number + answer, so N Clickables cost ONE raycast. */
|
|
1655
|
+
private pickCacheFrame;
|
|
1656
|
+
private pickCacheKey;
|
|
1657
|
+
private pickCacheHit;
|
|
1658
|
+
/**
|
|
1659
|
+
* The node under (x, y), answered at most ONCE per frame per cursor position.
|
|
1660
|
+
*
|
|
1661
|
+
* `Clickable` asks every frame, and a board game has one per cell: 42 pads
|
|
1662
|
+
* measured **420 picker calls over ten frames** — one GPU raycast per pad per
|
|
1663
|
+
* frame, all answering the same question about the same pixel. At 60 fps that
|
|
1664
|
+
* is ~2500 raycasts a second to find out what the cursor is on, and a 200-tile
|
|
1665
|
+
* board was unusable.
|
|
1666
|
+
*
|
|
1667
|
+
* Cached on (frame, x, y), so a game that picks at two different points in one
|
|
1668
|
+
* frame still gets two real answers.
|
|
1669
|
+
*/
|
|
1670
|
+
pickAt(x: number, y: number): Node | null;
|
|
1652
1671
|
/** Global volume buses — `master` × `sfx`/`music` gain + `muted`. AudioPlayer
|
|
1653
1672
|
* routes its volume through this; games set it for global volume/mute. */
|
|
1654
1673
|
readonly audio: AudioBuses;
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
|
|
2
2
|
import { c as parseEnvironment3D, k as diagnose, n as loadScene, s as horizonColorFromSky, u as sunDirectionFromSky, z as registerBehavior } from "./loader-lQDCwNag.js";
|
|
3
|
-
import { C as qualityRendering, _ as AudioPlayer, v as Engine, x as qualityCaps } from "./register-
|
|
3
|
+
import { C as qualityRendering, _ as AudioPlayer, v as Engine, x as qualityCaps } from "./register-BmuqYTiY.js";
|
|
4
4
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
5
5
|
import { i as resolveRendering, n as attachTouchControls } from "./touch-DESwnpOc.js";
|
|
6
|
-
import { a as openBundledEditor, c as claimCanvasGestures, i as devServerLibrary, l as audioErrors, n as pauseWhenHidden, o as poseFromRenderer, r as crossFade, s as wireDevChannel, t as teardown } from "./teardown-
|
|
6
|
+
import { a as openBundledEditor, c as claimCanvasGestures, i as devServerLibrary, l as audioErrors, n as pauseWhenHidden, o as poseFromRenderer, r as crossFade, s as wireDevChannel, t as teardown } from "./teardown-byR9USax.js";
|
|
7
7
|
import { o as frameStats } from "./frame-report-BSMny7oe.js";
|
|
8
|
-
import {
|
|
8
|
+
import { J as createCausticsQuad, K as Node3D, U as PhysicsBody3D, n as registerGameplayBehaviors } from "./gameplay-D1RADWu3.js";
|
|
9
9
|
import { t as debugSources } from "./debug-draw-BM3DsvtT.js";
|
|
10
|
-
import { E as Camera3D, U as TextureCache3D, g as ModelInstance3D, n as registerNodes3D, t as resolveEnvironmentHdri, v as DirectionalLight3D } from "./environment-presets-
|
|
11
|
-
import { n as enablePhysics3D } from "./physics-3d-
|
|
10
|
+
import { E as Camera3D, U as TextureCache3D, g as ModelInstance3D, n as registerNodes3D, t as resolveEnvironmentHdri, v as DirectionalLight3D } from "./environment-presets-BlPsEmq6.js";
|
|
11
|
+
import { n as enablePhysics3D } from "./physics-3d-BkHjwJgI.js";
|
|
12
12
|
import { ACESFilmicToneMapping, AmbientLight, Box3, BufferAttribute, BufferGeometry, Color, DepthTexture, EquirectangularReflectionMapping, FloatType, Fog, HalfFloatType, LineBasicMaterial, LineSegments, Matrix4, Mesh, PCFShadowMap, PMREMGenerator, PerspectiveCamera, PlaneGeometry, Quaternion, Raycaster, Scene, ShaderMaterial, Vector2, Vector3, WebGLRenderTarget, WebGLRenderer } from "three";
|
|
13
13
|
import { VRMLoaderPlugin, VRMUtils } from "@pixiv/three-vrm";
|
|
14
14
|
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
|
|
@@ -1967,6 +1967,67 @@ var Renderer3D = class {
|
|
|
1967
1967
|
};
|
|
1968
1968
|
}
|
|
1969
1969
|
/**
|
|
1970
|
+
* The WORLD POINT under canvas pixel (sx, sy) — the other half of
|
|
1971
|
+
* `screenFromWorld`, and the call `incanto-web-integration.md` has always
|
|
1972
|
+
* offered "for taps and clicks".
|
|
1973
|
+
*
|
|
1974
|
+
* It did not exist in 3D. `Renderer2D` has had it since the beginning, the
|
|
1975
|
+
* doc covers both runtimes, and an agent building a tower defense went looking
|
|
1976
|
+
* for it and measured `typeof game.renderer.worldFromScreen === "undefined"`.
|
|
1977
|
+
* `pick()` gives you the NODE under a pixel but never the POINT, so "put the
|
|
1978
|
+
* thing where the player clicked on the ground" was not expressible and that
|
|
1979
|
+
* game discretised its whole map into clickable pads instead.
|
|
1980
|
+
*
|
|
1981
|
+
* A pixel in 3D is a RAY, not a point, so this needs a surface to land on and
|
|
1982
|
+
* takes the horizontal plane at `planeY` (default 0 — the ground). Returns
|
|
1983
|
+
* null when the ray runs parallel to that plane or would only meet it behind
|
|
1984
|
+
* the camera, which is what "the sky" looks like from here.
|
|
1985
|
+
*
|
|
1986
|
+
* For anything not flat — terrain, a hillside, a stack of crates — raycast
|
|
1987
|
+
* physics instead: `rayFromScreen` gives you the origin and direction to feed
|
|
1988
|
+
* `physics.castRay`.
|
|
1989
|
+
*/
|
|
1990
|
+
worldFromScreen(sx, sy, planeY = 0) {
|
|
1991
|
+
const ray = this.rayFromScreen(sx, sy);
|
|
1992
|
+
if (!ray) return null;
|
|
1993
|
+
const dy = ray.dir[1];
|
|
1994
|
+
if (Math.abs(dy) < 1e-6) return null;
|
|
1995
|
+
const t = (planeY - ray.origin[1]) / dy;
|
|
1996
|
+
if (t < 0) return null;
|
|
1997
|
+
return {
|
|
1998
|
+
x: ray.origin[0] + ray.dir[0] * t,
|
|
1999
|
+
y: planeY,
|
|
2000
|
+
z: ray.origin[2] + ray.dir[2] * t
|
|
2001
|
+
};
|
|
2002
|
+
}
|
|
2003
|
+
/**
|
|
2004
|
+
* The camera ray through canvas pixel (sx, sy) — origin and unit direction,
|
|
2005
|
+
* ready for `physics.castRay(origin, dir, maxLen)`.
|
|
2006
|
+
*
|
|
2007
|
+
* This is the honest 3D answer to "where did the player click": on uneven
|
|
2008
|
+
* ground the only thing that knows is the collision world.
|
|
2009
|
+
*/
|
|
2010
|
+
rayFromScreen(sx, sy) {
|
|
2011
|
+
const cam = this.lastCamera;
|
|
2012
|
+
if (!cam) return null;
|
|
2013
|
+
pickNdc.set(sx / this.lastSize.w * 2 - 1, -(sy / this.lastSize.h * 2 - 1));
|
|
2014
|
+
pickRaycaster.setFromCamera(pickNdc, cam);
|
|
2015
|
+
const o = pickRaycaster.ray.origin;
|
|
2016
|
+
const d = pickRaycaster.ray.direction;
|
|
2017
|
+
return {
|
|
2018
|
+
origin: [
|
|
2019
|
+
o.x,
|
|
2020
|
+
o.y,
|
|
2021
|
+
o.z
|
|
2022
|
+
],
|
|
2023
|
+
dir: [
|
|
2024
|
+
d.x,
|
|
2025
|
+
d.y,
|
|
2026
|
+
d.z
|
|
2027
|
+
]
|
|
2028
|
+
};
|
|
2029
|
+
}
|
|
2030
|
+
/**
|
|
1970
2031
|
* The node rendered under canvas pixel (sx, sy), or null — raycasts the last
|
|
1971
2032
|
* rendered camera into the scene and resolves the hit up to its `incantoNode`
|
|
1972
2033
|
* (every Node3D stamps that in `_ensureObject3D`). 3D depth-sorts, so the
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
|
|
2
2
|
import { d as computeViewport, f as resolveViewport, k as diagnose, n as loadScene, z as registerBehavior } from "./loader-lQDCwNag.js";
|
|
3
|
-
import { _ as AudioPlayer, v as Engine } from "./register-
|
|
3
|
+
import { _ as AudioPlayer, v as Engine } from "./register-BmuqYTiY.js";
|
|
4
4
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
5
5
|
import { i as resolveRendering, n as attachTouchControls } from "./touch-DESwnpOc.js";
|
|
6
|
-
import { a as openBundledEditor, c as claimCanvasGestures, i as devServerLibrary, l as audioErrors, n as pauseWhenHidden, r as crossFade, s as wireDevChannel, t as teardown } from "./teardown-
|
|
6
|
+
import { a as openBundledEditor, c as claimCanvasGestures, i as devServerLibrary, l as audioErrors, n as pauseWhenHidden, r as crossFade, s as wireDevChannel, t as teardown } from "./teardown-byR9USax.js";
|
|
7
7
|
import { o as frameStats } from "./frame-report-BSMny7oe.js";
|
|
8
|
-
import { n as registerGameplayBehaviors } from "./gameplay-
|
|
9
|
-
import { g as PhysicsBody2D, n as UILayer, t as registerNodes2D, u as Camera2D, y as Node2D } from "./register-
|
|
8
|
+
import { n as registerGameplayBehaviors } from "./gameplay-D1RADWu3.js";
|
|
9
|
+
import { g as PhysicsBody2D, n as UILayer, t as registerNodes2D, u as Camera2D, y as Node2D } from "./register-D0CxCveZ.js";
|
|
10
10
|
import { t as debugSources } from "./debug-draw-BM3DsvtT.js";
|
|
11
|
-
import { n as enablePhysics2D } from "./physics-2d-
|
|
11
|
+
import { n as enablePhysics2D } from "./physics-2d-Cji5A6sX.js";
|
|
12
12
|
import { Box3, BufferAttribute, BufferGeometry, Color, LineBasicMaterial, LineSegments, LinearFilter, NearestFilter, OrthographicCamera, Raycaster, SRGBColorSpace, Scene, TextureLoader, Vector2, Vector3, WebGLRenderer } from "three";
|
|
13
13
|
//#region src/2d/assets.ts
|
|
14
14
|
/**
|
package/dist/debug.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Ft as LogLevel, T as RendererStats, b as Engine } from "./behavior-
|
|
1
|
+
import { Ft as LogLevel, T as RendererStats, b as Engine } from "./behavior-BXNLfIJk.js";
|
|
2
2
|
|
|
3
3
|
//#region src/debug/panel.d.ts
|
|
4
4
|
/** Minimal document surface the overlay needs (injectable for tests). */
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { k as diagnose } from "./loader-lQDCwNag.js";
|
|
2
|
-
import { L as translateOn, t as registerCoreNodes } from "./register-
|
|
2
|
+
import { L as translateOn, t as registerCoreNodes } from "./register-BmuqYTiY.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 { i as getNodeSchema, l as registerNode } from "./registry-CF70EArN.js";
|
|
6
6
|
import { t as createNoise2D } from "./noise-CGUMx44x.js";
|
|
7
7
|
import { i as ParticleSim, n as resolveFrames, o as PARTICLE_PRESET_NAMES, r as validateAnimationAliases, s as applyParticlePreset, t as resolveAnimation } from "./sprite-animation-CY-mrr1L.js";
|
|
8
|
-
import { B as
|
|
8
|
+
import { B as rejectScale, G as StaticBody3D, H as CharacterBody3D, K as Node3D, L as Water3D, U as PhysicsBody3D, V as Area3D, W as RigidBody3D, X as colliderFootDrop, w as tolerateUnknownAction, z as WaterCutout3D } from "./gameplay-D1RADWu3.js";
|
|
9
9
|
import { t as checkSheetGrid } from "./sheet-grid-BT6N_Bjs.js";
|
|
10
10
|
import { n as splatWeights, t as buildHeightmap } from "./heightmap-CRK0M4jT.js";
|
|
11
11
|
import { AdditiveBlending, AnimationClip, AnimationMixer, Box3, BoxGeometry, BufferAttribute, BufferGeometry, CanvasTexture, CapsuleGeometry, ClampToEdgeWrapping, Color, ConeGeometry, CylinderGeometry, DataTexture, DirectionalLight, DoubleSide, DynamicDrawUsage, Euler, Group, IcosahedronGeometry, ImageBitmapLoader, InstancedBufferAttribute, InstancedMesh, LinearFilter, LinearMipmapLinearFilter, LoopOnce, LoopRepeat, Matrix4, Mesh, MeshBasicMaterial, MeshDepthMaterial, MeshPhysicalMaterial, MeshStandardMaterial, NearestFilter, NoBlending, NoColorSpace, NormalBlending, PerspectiveCamera, PlaneGeometry, PointLight, Points, PointsMaterial, Quaternion, QuaternionKeyframeTrack, RGBADepthPacking, RGBAFormat, RepeatWrapping, SRGBColorSpace, ShaderChunk, ShaderMaterial, SphereGeometry, Texture, TextureLoader, UniformsLib, UniformsUtils, Vector3, Vector4, VectorKeyframeTrack } from "three";
|
|
@@ -742,7 +742,8 @@ var Joint3D = class extends Node3D {
|
|
|
742
742
|
] },
|
|
743
743
|
length: { default: 0 },
|
|
744
744
|
stiffness: { default: 50 },
|
|
745
|
-
damping: { default: 5 }
|
|
745
|
+
damping: { default: 5 },
|
|
746
|
+
collide: { default: null }
|
|
746
747
|
};
|
|
747
748
|
type = "spherical";
|
|
748
749
|
target = "";
|
|
@@ -760,6 +761,31 @@ var Joint3D = class extends Node3D {
|
|
|
760
761
|
length = 0;
|
|
761
762
|
stiffness = 50;
|
|
762
763
|
damping = 5;
|
|
764
|
+
/**
|
|
765
|
+
* Do the two linked bodies still collide with EACH OTHER?
|
|
766
|
+
*
|
|
767
|
+
* `null` (default) decides from the joint type, because the two families want
|
|
768
|
+
* opposite answers:
|
|
769
|
+
*
|
|
770
|
+
* - **pivots** (`fixed`, `spherical`, `revolute`) → **off**. A hinge's bodies
|
|
771
|
+
* overlap at the pivot by construction, so the contact solver fights the
|
|
772
|
+
* joint and flings them. A puzzle builder's first hinge produced a bar that
|
|
773
|
+
* spun chaotically forever and threw a 40 kg box thirty metres, and they
|
|
774
|
+
* nearly filed "spherical joints inject energy":
|
|
775
|
+
*
|
|
776
|
+
* ```
|
|
777
|
+
* t= 0 Plank r=[0,0,0] Box [ 0.00, 5.50, 2.40]
|
|
778
|
+
* t=3000 Plank r=[-66,24,64] Box [-29.70, 0.40, -4.91]
|
|
779
|
+
* ```
|
|
780
|
+
*
|
|
781
|
+
* - **tethers** (`rope`, `spring`) → **on**. These anchor a thing to the world,
|
|
782
|
+
* and the thing has to rest on what it is tethered to. Defaulting these off
|
|
783
|
+
* drops a barrel roped to the floor straight through it — measured, in this
|
|
784
|
+
* repo's own conformance room.
|
|
785
|
+
*
|
|
786
|
+
* Set `true`/`false` to say it outright.
|
|
787
|
+
*/
|
|
788
|
+
collide = null;
|
|
763
789
|
onEnterTree() {
|
|
764
790
|
if (!(this.parent instanceof PhysicsBody3D)) throw new IncantoError("TREE_VIOLATION", `Joint3D '${this.name}' must be a child of a physics body (its body A); parent is '${this.parent?.name ?? "none"}'.`);
|
|
765
791
|
if (this.target === "") throw new IncantoError("BAD_FORMAT", `Joint3D '${this.name}' needs a "target" node path to the body it links to.`);
|
|
@@ -2641,6 +2667,7 @@ var CharacterController3D = class extends Node3D {
|
|
|
2641
2667
|
/** Gravity multiplier while falling — >1 is the "snappy" arc. */
|
|
2642
2668
|
fallGravity: { default: 2.5 },
|
|
2643
2669
|
floatHeight: { default: .01 },
|
|
2670
|
+
stepHeight: { default: .35 },
|
|
2644
2671
|
mouseLook: { default: true },
|
|
2645
2672
|
zoomMin: { default: 0 },
|
|
2646
2673
|
zoomMax: { default: 0 },
|
|
@@ -2673,6 +2700,25 @@ var CharacterController3D = class extends Node3D {
|
|
|
2673
2700
|
airControl = .2;
|
|
2674
2701
|
fallGravity = 2.5;
|
|
2675
2702
|
floatHeight = .01;
|
|
2703
|
+
/**
|
|
2704
|
+
* How high a step the PLAYER walks up without jumping (0 = off).
|
|
2705
|
+
*
|
|
2706
|
+
* The hover spring holds the capsule a fixed distance above whatever is
|
|
2707
|
+
* DIRECTLY below it, so a vertical face stopped the player dead at about
|
|
2708
|
+
* 0.2 m — while `CharacterBody3D.stepHeight` let every enemy climb 0.35 m.
|
|
2709
|
+
* The docs said the player did not need this ("it floats over small ledges
|
|
2710
|
+
* already"); it floats over 18 cm ones.
|
|
2711
|
+
*
|
|
2712
|
+
* This probes just AHEAD of the capsule in the direction of travel: if the
|
|
2713
|
+
* ground there is higher, but by no more than `stepHeight`, the spring aims
|
|
2714
|
+
* at THAT surface and lifts the character onto it. A wall taller than the
|
|
2715
|
+
* step is not a step and still stops you.
|
|
2716
|
+
*
|
|
2717
|
+
* Do not reach for `floatHeight` instead. It does raise the character over
|
|
2718
|
+
* ledges, and it silently makes it WEIGHTLESS: at `floatHeight: 0.28` a
|
|
2719
|
+
* 200 kg character does not move a seesaw a 70 kg crate tips.
|
|
2720
|
+
*/
|
|
2721
|
+
stepHeight = .35;
|
|
2676
2722
|
mouseLook = true;
|
|
2677
2723
|
zoomMin = 0;
|
|
2678
2724
|
zoomMax = 0;
|
|
@@ -2803,8 +2849,26 @@ var CharacterController3D = class extends Node3D {
|
|
|
2803
2849
|
0,
|
|
2804
2850
|
-vel[2] * DRAG_DAMPING * mass
|
|
2805
2851
|
]);
|
|
2806
|
-
|
|
2807
|
-
|
|
2852
|
+
let springToi = toi;
|
|
2853
|
+
if (this.stepHeight > 0 && moving && toi !== null && !this.jumping && (vel[1] ?? 0) <= .5) {
|
|
2854
|
+
const ahead = radius + .12;
|
|
2855
|
+
const probeTop = originY + this.stepHeight + .05;
|
|
2856
|
+
const stepHit = physics.castRay([
|
|
2857
|
+
pos[0] + mx * ahead,
|
|
2858
|
+
probeTop,
|
|
2859
|
+
pos[2] + mz * ahead
|
|
2860
|
+
], [
|
|
2861
|
+
0,
|
|
2862
|
+
-1,
|
|
2863
|
+
0
|
|
2864
|
+
], this.stepHeight + .05 + rayLen, body);
|
|
2865
|
+
if (stepHit) {
|
|
2866
|
+
const rise = probeTop - stepHit.distance - (originY - toi);
|
|
2867
|
+
if (rise > .02 && rise <= this.stepHeight + .02) springToi = toi - rise;
|
|
2868
|
+
}
|
|
2869
|
+
}
|
|
2870
|
+
if (springToi !== null && springToi < floatingDis * 2 && !this.jumping) {
|
|
2871
|
+
const spring = SPRING_K * (floatingDis - springToi) - vel[1] * SPRING_DAMPING;
|
|
2808
2872
|
body.applyImpulse([
|
|
2809
2873
|
0,
|
|
2810
2874
|
spring * mass,
|