lecodes-cli 0.19.0 → 0.19.2
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/index.js +730 -235
- package/package.json +14 -13
- package/runtime/scene-harness.json +1 -1
- package/runtime/sdk-types.json +1 -1
- package/src/api.ts +302 -0
- package/src/browserAuth.ts +87 -0
- package/src/cmgenTool.ts +104 -0
- package/src/commands/app.ts +891 -0
- package/src/commands/appAndroid.ts +603 -0
- package/src/commands/appDesktop.ts +326 -0
- package/src/commands/appDesktopMac.ts +470 -0
- package/src/commands/appIcon.ts +187 -0
- package/src/commands/appShared.ts +448 -0
- package/src/commands/appTemplates.ts +883 -0
- package/src/commands/appTemplatesAndroid.ts +599 -0
- package/src/commands/appTemplatesGradlew.ts +9 -0
- package/src/commands/assets.ts +28 -0
- package/src/commands/clone.ts +60 -0
- package/src/commands/compile.ts +253 -0
- package/src/commands/create.ts +59 -0
- package/src/commands/design.ts +863 -0
- package/src/commands/designTemplates.ts +11 -0
- package/src/commands/desktop.ts +122 -0
- package/src/commands/dev.ts +214 -0
- package/src/commands/diff.ts +59 -0
- package/src/commands/init.ts +191 -0
- package/src/commands/install.ts +198 -0
- package/src/commands/lightmap.ts +290 -0
- package/src/commands/link.ts +147 -0
- package/src/commands/login.ts +24 -0
- package/src/commands/navmesh.ts +225 -0
- package/src/commands/pn.ts +305 -0
- package/src/commands/projectTemplates.ts +129 -0
- package/src/commands/pull.ts +109 -0
- package/src/commands/push.ts +173 -0
- package/src/commands/render.ts +414 -0
- package/src/commands/scene.ts +148 -0
- package/src/commands/shaders.ts +157 -0
- package/src/commands/status.ts +29 -0
- package/src/commands/test.ts +370 -0
- package/src/commands/thumbs.ts +178 -0
- package/src/commands/types.ts +87 -0
- package/src/commands/update.ts +190 -0
- package/src/compile/assetIcons.ts +214 -0
- package/src/compile/collect.ts +46 -0
- package/src/compile/collectLocal.ts +37 -0
- package/src/compile/designCompile.ts +104 -0
- package/src/compile/fonts.ts +156 -0
- package/src/compile/headlessBundle.ts +129 -0
- package/src/compile/nativeStack.ts +21 -0
- package/src/compile/projectCompile.ts +109 -0
- package/src/compile/sceneCompile.ts +113 -0
- package/src/compile/screenEntry.ts +127 -0
- package/src/compile/shaders.ts +245 -0
- package/src/config.ts +42 -0
- package/src/designMeta.ts +35 -0
- package/src/desktopRenderer.ts +532 -0
- package/src/desktopScript.ts +276 -0
- package/src/dev/clientTemplates.ts +160 -0
- package/src/dev/devServer.ts +292 -0
- package/src/dev/wsServer.ts +144 -0
- package/src/distRoot.ts +20 -0
- package/src/ignore.ts +163 -0
- package/src/index.ts +491 -0
- package/src/lecodes-3d-editor.d.ts +41 -0
- package/src/lecodes-assets.d.ts +7 -0
- package/src/lecodes-design.d.ts +191 -0
- package/src/lecodes-renderer.d.ts +131 -0
- package/src/localFiles.ts +144 -0
- package/src/manifest.ts +46 -0
- package/src/matcTool.ts +137 -0
- package/src/peers.ts +40 -0
- package/src/project.ts +61 -0
- package/src/projectEnv.ts +94 -0
- package/src/qrcode-terminal.d.ts +9 -0
- package/src/releases.ts +125 -0
- package/src/serverDiff.ts +78 -0
- package/src/textDiff.ts +103 -0
- package/src/types.ts +0 -0
- package/src/util.ts +146 -0
- package/runtime/sdk/animate/animate.ts +0 -238
- package/runtime/sdk/animate/bezier.ts +0 -138
- package/runtime/sdk/animate/easings.ts +0 -126
- package/runtime/sdk/canvas/Canvas.ts +0 -305
- package/runtime/sdk/compile/aspectMacro.ts +0 -86
- package/runtime/sdk/compile/assetIconMacro.ts +0 -384
- package/runtime/sdk/compile/assetMacro.ts +0 -146
- package/runtime/sdk/compile/assetName.ts +0 -50
- package/runtime/sdk/compile/bundler.ts +0 -287
- package/runtime/sdk/compile/compileProject.ts +0 -129
- package/runtime/sdk/compile/detectEntry.ts +0 -128
- package/runtime/sdk/compile/fontMacro.ts +0 -459
- package/runtime/sdk/compile/fontRegistry.ts +0 -78
- package/runtime/sdk/compile/header.ts +0 -67
- package/runtime/sdk/compile/index.ts +0 -100
- package/runtime/sdk/compile/libraryImports.ts +0 -52
- package/runtime/sdk/compile/liteMaterial.ts +0 -247
- package/runtime/sdk/compile/sceneEditor.ts +0 -88
- package/runtime/sdk/compile/serverSplit.ts +0 -233
- package/runtime/sdk/compile/serverTypes.ts +0 -227
- package/runtime/sdk/compile/sfnt.ts +0 -98
- package/runtime/sdk/compile/shaderSchema.ts +0 -202
- package/runtime/sdk/compile/shaderTargets.ts +0 -81
- package/runtime/sdk/compile/sourcemap.ts +0 -25
- package/runtime/sdk/core/Aspect.ts +0 -568
- package/runtime/sdk/core/InspectorUI.ts +0 -212
- package/runtime/sdk/core/StateMachine.ts +0 -308
- package/runtime/sdk/core/color.ts +0 -66
- package/runtime/sdk/core/compWrite.ts +0 -42
- package/runtime/sdk/core/events.ts +0 -38
- package/runtime/sdk/core/fields.ts +0 -120
- package/runtime/sdk/core/registry.ts +0 -23
- package/runtime/sdk/core/signals.ts +0 -277
- package/runtime/sdk/core/time.ts +0 -84
- package/runtime/sdk/g2/Camera2D.ts +0 -40
- package/runtime/sdk/g2/CharacterController2D.ts +0 -276
- package/runtime/sdk/g2/Node2D.ts +0 -267
- package/runtime/sdk/g2/OneWay2D.ts +0 -66
- package/runtime/sdk/g2/Physics2D.ts +0 -346
- package/runtime/sdk/g2/Scene2D.ts +0 -209
- package/runtime/sdk/g2/Shape2D.ts +0 -259
- package/runtime/sdk/g2/Sprite.ts +0 -89
- package/runtime/sdk/g2/SpriteAnimation.ts +0 -171
- package/runtime/sdk/g2/SpriteSheet.ts +0 -166
- package/runtime/sdk/g2/Texture2D.ts +0 -47
- package/runtime/sdk/g2/Tilemap.ts +0 -41
- package/runtime/sdk/g2/Tileset.ts +0 -71
- package/runtime/sdk/g2/Trigger2D.ts +0 -77
- package/runtime/sdk/g2/autotile.ts +0 -433
- package/runtime/sdk/g2/cells.ts +0 -91
- package/runtime/sdk/g2/defineScene2d.ts +0 -381
- package/runtime/sdk/g2/groups2d.ts +0 -106
- package/runtime/sdk/g2/loop.ts +0 -50
- package/runtime/sdk/g2/scenarios2d.ts +0 -69
- package/runtime/sdk/g2/touch.ts +0 -83
- package/runtime/sdk/gl/Camera.ts +0 -160
- package/runtime/sdk/gl/CameraPlace.ts +0 -52
- package/runtime/sdk/gl/CharacterController.ts +0 -238
- package/runtime/sdk/gl/Gearbox.ts +0 -212
- package/runtime/sdk/gl/Geometry.ts +0 -279
- package/runtime/sdk/gl/IK.ts +0 -193
- package/runtime/sdk/gl/InstancedMesh.ts +0 -132
- package/runtime/sdk/gl/Light.ts +0 -107
- package/runtime/sdk/gl/Lightmap.ts +0 -256
- package/runtime/sdk/gl/Material.ts +0 -260
- package/runtime/sdk/gl/Mesh.ts +0 -83
- package/runtime/sdk/gl/Model.ts +0 -124
- package/runtime/sdk/gl/NavAgent.ts +0 -337
- package/runtime/sdk/gl/NavMesh.ts +0 -397
- package/runtime/sdk/gl/Node.ts +0 -350
- package/runtime/sdk/gl/Noise.ts +0 -30
- package/runtime/sdk/gl/Particles.ts +0 -676
- package/runtime/sdk/gl/Physics.ts +0 -222
- package/runtime/sdk/gl/Plane.ts +0 -53
- package/runtime/sdk/gl/Ragdoll.ts +0 -270
- package/runtime/sdk/gl/Ray.ts +0 -16
- package/runtime/sdk/gl/Scene.ts +0 -486
- package/runtime/sdk/gl/Shape.ts +0 -409
- package/runtime/sdk/gl/Terrain.ts +0 -1092
- package/runtime/sdk/gl/Texture.ts +0 -63
- package/runtime/sdk/gl/Trigger.ts +0 -45
- package/runtime/sdk/gl/Vehicle.ts +0 -473
- package/runtime/sdk/gl/Wheel.ts +0 -240
- package/runtime/sdk/gl/animation/AnimationClip.ts +0 -204
- package/runtime/sdk/gl/animation/Animator.ts +0 -120
- package/runtime/sdk/gl/animation/Layer.ts +0 -31
- package/runtime/sdk/gl/animation/Loop.ts +0 -30
- package/runtime/sdk/gl/animation/Playback.ts +0 -44
- package/runtime/sdk/gl/animation/core.ts +0 -336
- package/runtime/sdk/gl/controls.ts +0 -95
- package/runtime/sdk/gl/physicsEvents.ts +0 -20
- package/runtime/sdk/gl/scenarios.ts +0 -291
- package/runtime/sdk/gl/state.ts +0 -6
- package/runtime/sdk/gl/terrainMesh.ts +0 -219
- package/runtime/sdk/gl/touch.ts +0 -68
- package/runtime/sdk/inject.ts +0 -197
- package/runtime/sdk/math/Mathf.ts +0 -118
- package/runtime/sdk/math/mat4.ts +0 -278
- package/runtime/sdk/math/quat.ts +0 -232
- package/runtime/sdk/math/vec.ts +0 -255
- package/runtime/sdk/net/codec.ts +0 -119
- package/runtime/sdk/net/core.ts +0 -384
- package/runtime/sdk/net/index.ts +0 -181
- package/runtime/sdk/net/replication.ts +0 -622
- package/runtime/sdk/plugins/camera.ts +0 -81
- package/runtime/sdk/plugins/geolocation.ts +0 -123
- package/runtime/sdk/plugins/oauth.ts +0 -61
- package/runtime/sdk/plugins/permission.ts +0 -7
- package/runtime/sdk/plugins/push.ts +0 -132
- package/runtime/sdk/plugins/qr.ts +0 -73
- package/runtime/sdk/plugins/service.ts +0 -47
- package/runtime/sdk/runtime/app.ts +0 -101
- package/runtime/sdk/runtime/appEvents.ts +0 -54
- package/runtime/sdk/runtime/channel.ts +0 -61
- package/runtime/sdk/runtime/clipboard.ts +0 -20
- package/runtime/sdk/runtime/datetime.ts +0 -329
- package/runtime/sdk/runtime/device.ts +0 -293
- package/runtime/sdk/runtime/fetch.ts +0 -77
- package/runtime/sdk/runtime/files.ts +0 -23
- package/runtime/sdk/runtime/input.ts +0 -175
- package/runtime/sdk/runtime/media.ts +0 -111
- package/runtime/sdk/runtime/misc.ts +0 -16
- package/runtime/sdk/runtime/net.ts +0 -36
- package/runtime/sdk/runtime/rpc.ts +0 -218
- package/runtime/sdk/runtime/service.ts +0 -83
- package/runtime/sdk/runtime/share.ts +0 -9
- package/runtime/sdk/runtime/storage.ts +0 -13
- package/runtime/sdk/runtime/touch.ts +0 -76
- package/runtime/sdk/scene/defineScene.ts +0 -1353
- package/runtime/sdk/scene/editorPlugins.ts +0 -110
- package/runtime/sdk/scene/gizmos.ts +0 -148
- package/runtime/sdk/scene/grammar.ts +0 -120
- package/runtime/sdk/scene/material.ts +0 -188
- package/runtime/sdk/server/auth/appConfig.ts +0 -12
- package/runtime/sdk/server/auth/global.ts +0 -80
- package/runtime/sdk/server/auth/host.ts +0 -318
- package/runtime/sdk/server/auth/models.ts +0 -83
- package/runtime/sdk/server/auth/types.ts +0 -50
- package/runtime/sdk/server/channel.ts +0 -56
- package/runtime/sdk/server/context.ts +0 -36
- package/runtime/sdk/server/db/defineDb.ts +0 -237
- package/runtime/sdk/server/db/fields.ts +0 -132
- package/runtime/sdk/server/db/httpTransport.ts +0 -93
- package/runtime/sdk/server/db/index.ts +0 -7
- package/runtime/sdk/server/db/marci/query.ts +0 -412
- package/runtime/sdk/server/db/types.ts +0 -202
- package/runtime/sdk/server/errors.ts +0 -12
- package/runtime/sdk/server/host.ts +0 -74
- package/runtime/sdk/server/inject.ts +0 -13
- package/runtime/sdk/server/runtime.ts +0 -133
- package/runtime/sdk/server/validate.ts +0 -87
- package/runtime/sdk/ui/NativeView.ts +0 -142
- package/runtime/sdk/ui/UI.ts +0 -39
- package/runtime/sdk/ui/UIBottomSheet.ts +0 -139
- package/runtime/sdk/ui/UIButton.ts +0 -101
- package/runtime/sdk/ui/UIContainer.ts +0 -60
- package/runtime/sdk/ui/UIImage.ts +0 -83
- package/runtime/sdk/ui/UIInput.ts +0 -185
- package/runtime/sdk/ui/UIModal.ts +0 -139
- package/runtime/sdk/ui/UINode.ts +0 -830
- package/runtime/sdk/ui/UIPager.ts +0 -362
- package/runtime/sdk/ui/UIPopover.ts +0 -100
- package/runtime/sdk/ui/UIScreen.ts +0 -123
- package/runtime/sdk/ui/UIScrollable.ts +0 -87
- package/runtime/sdk/ui/UISpacer.ts +0 -14
- package/runtime/sdk/ui/UITabs.ts +0 -236
- package/runtime/sdk/ui/UIText.ts +0 -51
- package/runtime/sdk/ui/UIVideo.ts +0 -88
- package/runtime/sdk/ui/UIVirtualizedList.ts +0 -241
- package/runtime/sdk/ui/UIWidget.ts +0 -127
- package/runtime/sdk/ui/fonts.ts +0 -13
- package/runtime/sdk/ui/presentable.ts +0 -117
- package/runtime/sdk/ui/router.ts +0 -132
- package/runtime/sdk/ui/theme.ts +0 -84
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
// Playback — the handle `play()` returns (docs/animator-plan.md). Thenable: `await anim.play('slash')`
|
|
2
|
-
// resolves at the clip's HAND-OVER — where its fade-back starts (`end − fadeOut`; the end when there
|
|
3
|
-
// is no fadeOut) — with `true`; `false` when it was cut short (replaced / stopped). What
|
|
4
|
-
// you call right after the await is what the clip fades into: `anim.play(next)` (a chained one-shot,
|
|
5
|
-
// crossfaded), `anim.playLoop(next)` — nothing = back to the loop (or hold, on a layer without one).
|
|
6
|
-
// Returning one from an `async` function flattens it into `Promise<boolean>` — return `p.done` (or
|
|
7
|
-
// make the function sync) when the caller needs the handle.
|
|
8
|
-
|
|
9
|
-
import type { AnimationClip } from "./AnimationClip"
|
|
10
|
-
import type { Core, PlaybackRec, StopOptions } from "./core"
|
|
11
|
-
import type { Layer } from "./Layer"
|
|
12
|
-
|
|
13
|
-
export class Playback implements PromiseLike<boolean> {
|
|
14
|
-
private readonly _r: PlaybackRec
|
|
15
|
-
private readonly _c: Core
|
|
16
|
-
/** @internal — created by play(). */
|
|
17
|
-
constructor(rec: PlaybackRec, core: Core) { this._r = rec; this._c = core }
|
|
18
|
-
|
|
19
|
-
/** The clip that plays. */
|
|
20
|
-
get clip(): AnimationClip { return this._r.slot.clip }
|
|
21
|
-
/** The layer it plays on. */
|
|
22
|
-
get layer(): Layer { return this._r.slot.layer.view }
|
|
23
|
-
/** Clock (s). */
|
|
24
|
-
get time(): number { return this._r.slot.last === this._r ? this._c.slotTime(this._r.slot) : 0 }
|
|
25
|
-
/** 0–1 through the clip (the current cycle, when looping). */
|
|
26
|
-
get progress(): number { const d = this.clip.duration; return d > 0 ? this.time / d : 0 }
|
|
27
|
-
/** Not handed over yet (the clip still owns the layer). */
|
|
28
|
-
get playing(): boolean { return this._r.playing }
|
|
29
|
-
/** Current contribution to the pose, 0–1 — moves during crossfades, still falling after the
|
|
30
|
-
* hand-over while the clip fades beneath what took over. */
|
|
31
|
-
get weight(): number { return this._r.slot.last === this._r ? this._c.slotWeight(this._r.slot) : 0 }
|
|
32
|
-
/** Resolves at the hand-over (`true`) or when cut short (`false`) — the promise `await playback`
|
|
33
|
-
* uses; the one to return from async functions or put in `Promise.all`. */
|
|
34
|
-
get done(): Promise<boolean> { return this._r.done }
|
|
35
|
-
|
|
36
|
-
then<A = boolean, B = never>(onFulfilled?: ((v: boolean) => A | PromiseLike<A>) | null, onRejected?: ((e: unknown) => B | PromiseLike<B>) | null): Promise<A | B> {
|
|
37
|
-
return this._r.done.then(onFulfilled, onRejected)
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/** Move the clock (s). */
|
|
41
|
-
seek(time: number): this { this._c.seek(this._r.slot, time); return this }
|
|
42
|
-
/** Cut this clip short: fade it out (the layer's loop returns if nothing else is coming in). */
|
|
43
|
-
stop(options: StopOptions = {}): this { this._c.stopSlot(this._r.slot, options.fade ?? 0); return this }
|
|
44
|
-
}
|
|
@@ -1,336 +0,0 @@
|
|
|
1
|
-
// The engine-facing core behind Animator / Layer / Blend / Playback (docs/animator-plan.md). NOT exported
|
|
2
|
-
// from the SDK: the public classes are thin views over the records here. The engine runs the whole
|
|
3
|
-
// per-frame loop (fades, blend spaces, one-shot fade-back, root motion); this file binds clips,
|
|
4
|
-
// issues play/stop/blend calls and routes the engine's slot events back to playbacks.
|
|
5
|
-
|
|
6
|
-
import { AnimationClip } from "./AnimationClip"
|
|
7
|
-
import { Loop } from "./Loop"
|
|
8
|
-
import { Layer } from "./Layer"
|
|
9
|
-
import { Playback } from "./Playback"
|
|
10
|
-
import type { Node } from "../Node"
|
|
11
|
-
|
|
12
|
-
/** A position on a blend axis (1D) or plane (2D). */
|
|
13
|
-
export type BlendPosition = number | readonly [number, number]
|
|
14
|
-
|
|
15
|
-
export type PlayOptions = {
|
|
16
|
-
/** Crossfade seconds for BOTH ends (default 0 = cut). */
|
|
17
|
-
fade?: number
|
|
18
|
-
/** Fade-in seconds (overrides `fade`). */
|
|
19
|
-
fadeIn?: number
|
|
20
|
-
/** One-shots: fade-back seconds at the END (overrides `fade`). The return fade starts this long
|
|
21
|
-
* BEFORE the clip ends, while it still plays — no freeze-frame on the last pose. On a layer with
|
|
22
|
-
* no blend to return to, giving `fadeOut` releases the layer at the end instead of holding the
|
|
23
|
-
* last frame. */
|
|
24
|
-
fadeOut?: number
|
|
25
|
-
/** Playback rate for this clip (default 1). */
|
|
26
|
-
speed?: number
|
|
27
|
-
/** Rewind even if the clip is already playing (default: rewind only if it isn't). */
|
|
28
|
-
restart?: boolean
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export type StopOptions = { fade?: number }
|
|
32
|
-
|
|
33
|
-
export type LoopOptions = {
|
|
34
|
-
/** Crossfade seconds from whatever the layer shows — the previous loop, or a one-shot still playing
|
|
35
|
-
* (default 0 = cut). */
|
|
36
|
-
fade?: number
|
|
37
|
-
/** Playback rate of the loop's clips (default 1). */
|
|
38
|
-
speed?: number
|
|
39
|
-
/** Where in the cycle to start, 0–1 (default 0): a blend's members share one clock, so this is the
|
|
40
|
-
* phase of every member — e.g. the phase whose pose matches the clip the loop takes over from. */
|
|
41
|
-
phase?: number
|
|
42
|
-
}
|
|
43
|
-
/** What a layer loops: one clip (name / index), or a blend space `{ name: position }`. */
|
|
44
|
-
export type LoopDef = string | number | Record<string, BlendPosition>
|
|
45
|
-
|
|
46
|
-
/** One clip the layer shows this frame — `layer.active` / `anim.active` (a debug overlay's list). */
|
|
47
|
-
export type ActiveClip = {
|
|
48
|
-
name: string
|
|
49
|
-
clip: AnimationClip
|
|
50
|
-
/** contribution to the pose, 0–1 — the crossfades' state */
|
|
51
|
-
weight: number
|
|
52
|
-
/** clock (s) */
|
|
53
|
-
time: number
|
|
54
|
-
/** a member of the layer's loop (else a one-shot — playing, or fading after its hand-over) */
|
|
55
|
-
loop: boolean
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export type LayerOptions = {
|
|
59
|
-
/** Bone name(s): the layer drives only these subtrees (`'Spine1'` = upper body). Default: the whole rig. */
|
|
60
|
-
mask?: string | string[]
|
|
61
|
-
/** Blend each clip's DELTA from its own first frame on top of the layers below (lean, breathe, recoil)
|
|
62
|
-
* instead of overriding them. */
|
|
63
|
-
additive?: boolean
|
|
64
|
-
/** Layer contribution 0–1 (default 1). */
|
|
65
|
-
weight?: number
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export type ClipEventHandler = (clip: string, layer: Layer) => void
|
|
69
|
-
|
|
70
|
-
// ---- records -------------------------------------------------------------------------------------
|
|
71
|
-
|
|
72
|
-
/** One INSTANCE of a clip on a layer (an engine slot). A clip has as many as it needs at once: a
|
|
73
|
-
* clip started again while its last instance still fades gets another slot — the old one keeps
|
|
74
|
-
* fading beneath (a rewind in place would snap the pose). `playback` = the one-shot that owns it
|
|
75
|
-
* until its hand-over; `last` = the one that took it most recently (its weight / time after that). */
|
|
76
|
-
export type SlotRec = { name: string, clip: AnimationClip, slot: number, layer: LayerRec, inBlend: boolean, playback?: PlaybackRec, last?: PlaybackRec }
|
|
77
|
-
export type PlaybackRec = { slot: SlotRec, playing: boolean, done: Promise<boolean>, resolve: (natural: boolean) => void }
|
|
78
|
-
export type LayerRec = { index: number, view: Layer, slots: SlotRec[], loop?: LoopRec, weight: number, mask: string, additive: boolean }
|
|
79
|
-
export type LoopRec = { layer: LayerRec, members: { name: string, slot: SlotRec }[], value: BlendPosition, view: Loop, dead: boolean }
|
|
80
|
-
|
|
81
|
-
const handlers = new Map<number, (slot: number, type: number) => void>()
|
|
82
|
-
let eventsInstalled = false
|
|
83
|
-
const ensureEvents = (): void => {
|
|
84
|
-
if (eventsInstalled) return
|
|
85
|
-
eventsInstalled = true
|
|
86
|
-
_creator.setOnAnimatorEvent((animatorId, slot, type) => handlers.get(animatorId)?.(slot, type))
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
const settled = (slot: SlotRec): PlaybackRec => {
|
|
90
|
-
let resolve = (_n: boolean): void => {}
|
|
91
|
-
const done = new Promise<boolean>((r) => { resolve = r })
|
|
92
|
-
resolve(false)
|
|
93
|
-
return { slot, playing: false, done, resolve }
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
export class Core {
|
|
97
|
-
id = 0
|
|
98
|
-
/** Added clips by name (`addClip`) — the lookup index; an added name overrides an embedded one. */
|
|
99
|
-
readonly table = new Map<string, AnimationClip>()
|
|
100
|
-
readonly layers: LayerRec[] = []
|
|
101
|
-
speed = 1
|
|
102
|
-
private _embedded?: AnimationClip[]
|
|
103
|
-
private readonly _added: { name: string, clip: AnimationClip }[] = []
|
|
104
|
-
private _list?: AnimationClip[]
|
|
105
|
-
private readonly _listeners = new Map<string, Set<ClipEventHandler>>()
|
|
106
|
-
|
|
107
|
-
readonly node: Node
|
|
108
|
-
constructor(node: Node) { this.node = node; this.layers.push(this.newLayer()) }
|
|
109
|
-
|
|
110
|
-
// ---- clips ----
|
|
111
|
-
embedded(): AnimationClip[] {
|
|
112
|
-
if (!this._embedded) {
|
|
113
|
-
this._embedded = AnimationClip._ofSet(_creator.getGlbClipSet(this.node.id))
|
|
114
|
-
const seen = new Set<string>()
|
|
115
|
-
for (const c of this._embedded) {
|
|
116
|
-
if (seen.has(c.name)) console.warn(`Animator: ${this.node.name || "the node"} has several clips named '${c.name}' — by name you get the first; reach the others by index (anim.clip(n))`)
|
|
117
|
-
seen.add(c.name)
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
return this._embedded
|
|
121
|
-
}
|
|
122
|
-
/** The ordered clip list: the GLB's clips in file order (an added clip of the same name takes the
|
|
123
|
-
* embedded one's place), then the remaining added clips in insertion order. Cached until addClip. */
|
|
124
|
-
clips(): AnimationClip[] {
|
|
125
|
-
if (this._list) return this._list
|
|
126
|
-
const out: AnimationClip[] = []
|
|
127
|
-
const placed = new Set<string>()
|
|
128
|
-
for (const c of this.embedded()) {
|
|
129
|
-
const override = this.table.get(c.name)
|
|
130
|
-
if (override && !placed.has(c.name)) { out.push(override); placed.add(c.name) }
|
|
131
|
-
else out.push(c)
|
|
132
|
-
}
|
|
133
|
-
for (const a of this._added) if (!placed.has(a.name)) { out.push(a.clip); placed.add(a.name) }
|
|
134
|
-
return this._list = out
|
|
135
|
-
}
|
|
136
|
-
addClip(name: string, clip: AnimationClip): void {
|
|
137
|
-
const i = this._added.findIndex((a) => a.name === name)
|
|
138
|
-
if (i >= 0) this._added[i] = { name, clip }
|
|
139
|
-
else this._added.push({ name, clip })
|
|
140
|
-
this.table.set(name, clip)
|
|
141
|
-
this._list = undefined
|
|
142
|
-
}
|
|
143
|
-
/** A clip by name (added first, then embedded), or by index into `clips()` (none = the first). */
|
|
144
|
-
resolveClip(ref: string | number | undefined): [string, AnimationClip] | undefined {
|
|
145
|
-
if (ref === undefined || typeof ref === "number") { const c = this.clips()[ref ?? 0]; return c ? [ c.name, c ] : undefined }
|
|
146
|
-
const c = this.table.get(ref) ?? this.embedded().find((e) => e.name === ref)
|
|
147
|
-
return c ? [ ref, c ] : undefined
|
|
148
|
-
}
|
|
149
|
-
private clipNames(): string { return this.clips().map((c) => c.name).join(", ") || "(empty)" }
|
|
150
|
-
|
|
151
|
-
// ---- lifecycle ----
|
|
152
|
-
/** Create the native animator on demand. False = nothing to animate (warned). */
|
|
153
|
-
ensure(): boolean {
|
|
154
|
-
if (this.id) return true
|
|
155
|
-
if (this.embedded().length === 0 && this.table.size === 0) { console.warn(`Animator: no clips on ${this.node.name || "the node"} — nothing to play`); return false }
|
|
156
|
-
ensureEvents()
|
|
157
|
-
this.id = _creator.animatorCreate(this.node.id)
|
|
158
|
-
if (!this.id) { console.warn("Animator: node has no transform hierarchy"); return false }
|
|
159
|
-
handlers.set(this.id, (slot, type) => this.onEvent(slot, type))
|
|
160
|
-
if (this.speed !== 1) _creator.animatorSetGlobal(this.id, this.speed, false)
|
|
161
|
-
for (const L of this.layers) if (L.index > 0) this.pushLayer(L)
|
|
162
|
-
return true
|
|
163
|
-
}
|
|
164
|
-
destroy(): void {
|
|
165
|
-
for (const L of this.layers) for (const s of L.slots) if (s.playback) this.settle(s.playback, false)
|
|
166
|
-
if (this.id) { _creator.animatorDestroy(this.id); handlers.delete(this.id); this.id = 0 }
|
|
167
|
-
for (const L of this.layers) { L.slots = []; if (L.loop) { L.loop.dead = true; L.loop = undefined } }
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// ---- layers ----
|
|
171
|
-
newLayer(options?: LayerOptions): LayerRec {
|
|
172
|
-
const rec: LayerRec = { index: this.layers.length, view: undefined as unknown as Layer, slots: [], weight: options?.weight ?? 1, mask: "", additive: options?.additive ?? false }
|
|
173
|
-
if (options?.mask !== undefined) rec.mask = Array.isArray(options.mask) ? options.mask.join("\n") : options.mask
|
|
174
|
-
rec.view = new Layer(rec, this)
|
|
175
|
-
return rec
|
|
176
|
-
}
|
|
177
|
-
addLayer(options: LayerOptions): Layer {
|
|
178
|
-
if (this.layers.length >= 255) { console.warn("Animator: too many layers"); return this.layers[this.layers.length - 1].view }
|
|
179
|
-
const rec = this.newLayer(options)
|
|
180
|
-
this.layers.push(rec)
|
|
181
|
-
if (this.id) this.pushLayer(rec)
|
|
182
|
-
return rec.view
|
|
183
|
-
}
|
|
184
|
-
pushLayer(L: LayerRec): void {
|
|
185
|
-
if (!this.id) return
|
|
186
|
-
for (const m of L.mask.split("\n")) if (m && !this.node.bone(m)) console.warn(`Animator: layer mask bone '${m}' not found under ${this.node.name || "the node"}`)
|
|
187
|
-
_creator.animatorSetLayer(this.id, L.index, L.weight, L.additive, L.mask)
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// ---- slots ----
|
|
191
|
-
/** A slot for the clip on the layer: one of its own that is silent now (never shown, or faded
|
|
192
|
-
* out), else a new binding — so a clip still fading can start again OVER itself. */
|
|
193
|
-
slotFor(L: LayerRec, name: string, clip: AnimationClip): SlotRec | undefined {
|
|
194
|
-
const have = L.slots.find((s) => s.name === name && s.clip === clip && !s.inBlend && !s.playback && this.slotWeight(s) <= 0)
|
|
195
|
-
if (have) return have
|
|
196
|
-
const slot = _creator.animatorBind(this.id, clip._set, clip._index, L.index)
|
|
197
|
-
if (slot < 0) { console.warn(`Animator: could not bind clip '${name}'`); return undefined }
|
|
198
|
-
const bound = _creator.animatorBoundTracks(this.id, slot)
|
|
199
|
-
if (clip.trackCount > 0 && bound === 0) console.warn(`Animator: '${name}' — no track matched a node name under ${this.node.name || "the node"} (different rig?)`)
|
|
200
|
-
else if (bound < clip.trackCount) console.warn(`Animator: '${name}' — ${clip.trackCount - bound}/${clip.trackCount} tracks unbound (bone names not found)`)
|
|
201
|
-
const rec: SlotRec = { name, clip, slot, layer: L, inBlend: false }
|
|
202
|
-
L.slots.push(rec)
|
|
203
|
-
return rec
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
// ---- play / stop ----
|
|
207
|
-
play(L: LayerRec, ref: string | number | undefined, o: PlayOptions): Playback {
|
|
208
|
-
const found = this.resolveClip(ref)
|
|
209
|
-
if (!found) {
|
|
210
|
-
console.warn(`Animator: no clip ${ref === undefined ? "to play" : JSON.stringify(ref)} on ${this.node.name || "the node"} — table: ${this.clipNames()}`)
|
|
211
|
-
return new Playback(settled({ name: "", clip: AnimationClip._none(), slot: -1, layer: L, inBlend: false }), this)
|
|
212
|
-
}
|
|
213
|
-
const [name, clip] = found
|
|
214
|
-
if (!this.ensure()) return new Playback(settled({ name, clip, slot: -1, layer: L, inBlend: false }), this)
|
|
215
|
-
const s = this.slotFor(L, name, clip)
|
|
216
|
-
if (!s) return new Playback(settled({ name, clip, slot: -1, layer: L, inBlend: false }), this)
|
|
217
|
-
if (s.inBlend) { console.warn(`Animator: '${name}' is part of this layer's loop — use playLoop() to change what it rests on`); return new Playback(settled(s), this) }
|
|
218
|
-
const fadeIn = o.fadeIn ?? o.fade ?? 0
|
|
219
|
-
const fadeOut = o.fadeOut ?? o.fade ?? -1
|
|
220
|
-
// the other one-shots on this layer are cut short (their promises resolve false)
|
|
221
|
-
for (const other of L.slots) if (other.playback) this.settle(other.playback, false)
|
|
222
|
-
let resolve = (_n: boolean): void => {}
|
|
223
|
-
const done = new Promise<boolean>((r) => { resolve = r })
|
|
224
|
-
const rec: PlaybackRec = { slot: s, playing: true, done, resolve }
|
|
225
|
-
s.playback = rec; s.last = rec
|
|
226
|
-
_creator.animatorPlay(this.id, s.slot, false, o.speed ?? 1, fadeIn, fadeOut, o.restart ?? false)
|
|
227
|
-
return new Playback(rec, this)
|
|
228
|
-
}
|
|
229
|
-
/** A one-shot on the layer hasn't handed over yet. */
|
|
230
|
-
busy(L: LayerRec): boolean { return L.slots.some((s) => s.playback?.playing) }
|
|
231
|
-
settle(p: PlaybackRec, natural: boolean): void {
|
|
232
|
-
p.playing = false
|
|
233
|
-
if (p.slot.playback === p) p.slot.playback = undefined
|
|
234
|
-
p.resolve(natural)
|
|
235
|
-
}
|
|
236
|
-
stopSlot(s: SlotRec, fade: number): void {
|
|
237
|
-
if (s.playback) this.settle(s.playback, false)
|
|
238
|
-
if (this.id && s.slot >= 0) _creator.animatorStop(this.id, s.layer.index, s.slot, fade)
|
|
239
|
-
}
|
|
240
|
-
stopLayer(L: LayerRec, fade: number): void {
|
|
241
|
-
for (const s of L.slots) if (s.playback) this.settle(s.playback, false)
|
|
242
|
-
if (L.loop) { L.loop.dead = true; L.loop = undefined }
|
|
243
|
-
if (this.id) _creator.animatorStop(this.id, L.index, -1, fade)
|
|
244
|
-
}
|
|
245
|
-
stopAll(fade: number): void { for (const L of this.layers) this.stopLayer(L, fade) }
|
|
246
|
-
|
|
247
|
-
// ---- loop ----
|
|
248
|
-
loop(L: LayerRec, def: LoopDef, o: LoopOptions): Loop | undefined {
|
|
249
|
-
if (!this.ensure()) return undefined
|
|
250
|
-
const fade = o.fade ?? 0
|
|
251
|
-
if (L.loop) { L.loop.dead = true; for (const m of L.loop.members) m.slot.inBlend = false; L.loop = undefined }
|
|
252
|
-
for (const s of L.slots) if (s.playback) this.settle(s.playback, false) // one-shots on the layer are cut short
|
|
253
|
-
const space: Record<string, BlendPosition> = typeof def === "object" ? def : {}
|
|
254
|
-
if (typeof def !== "object") {
|
|
255
|
-
const found = this.resolveClip(def)
|
|
256
|
-
if (!found) { console.warn(`Animator: no clip ${JSON.stringify(def)} to loop — table: ${this.clipNames()}`); return undefined }
|
|
257
|
-
space[found[0]] = 0
|
|
258
|
-
}
|
|
259
|
-
const rec: LoopRec = { layer: L, members: [], value: 0, view: undefined as unknown as Loop, dead: false }
|
|
260
|
-
rec.view = new Loop(rec, this)
|
|
261
|
-
const slots: number[] = [], positions: number[] = []
|
|
262
|
-
const is2D = Object.values(space).some((p) => typeof p !== "number")
|
|
263
|
-
for (const [name, at] of Object.entries(space)) {
|
|
264
|
-
const found = this.resolveClip(name)
|
|
265
|
-
if (!found) { console.warn(`Animator: loop clip '${name}' is not in the clip table`); continue }
|
|
266
|
-
const s = this.slotFor(L, name, found[1])
|
|
267
|
-
if (!s) continue
|
|
268
|
-
if (s.playback) this.settle(s.playback, false)
|
|
269
|
-
s.inBlend = true
|
|
270
|
-
rec.members.push({ name, slot: s })
|
|
271
|
-
slots.push(s.slot)
|
|
272
|
-
if (is2D) positions.push(typeof at === "number" ? at : at[0], typeof at === "number" ? 0 : at[1])
|
|
273
|
-
else positions.push(at as number)
|
|
274
|
-
}
|
|
275
|
-
L.loop = rec
|
|
276
|
-
_creator.animatorSetBlend(this.id, L.index, is2D ? 2 : 1, new Uint16Array(slots), new Float32Array(positions), fade, o.speed ?? 1)
|
|
277
|
-
if (o.phase !== undefined) this.setLoopPhase(rec, o.phase)
|
|
278
|
-
return rec.view
|
|
279
|
-
}
|
|
280
|
-
/** The loop's phase through its cycle, 0–1 (the members share one clock). */
|
|
281
|
-
loopPhase(b: LoopRec): number {
|
|
282
|
-
const m = b.members[0]
|
|
283
|
-
if (!m || b.dead) return 0
|
|
284
|
-
const d = m.slot.clip.duration
|
|
285
|
-
return d > 0 ? this.slotTime(m.slot) / d : 0
|
|
286
|
-
}
|
|
287
|
-
setLoopPhase(b: LoopRec, phase: number): void {
|
|
288
|
-
const m = b.members[0]
|
|
289
|
-
if (!m || b.dead) return
|
|
290
|
-
this.seek(m.slot, (((phase % 1) + 1) % 1) * m.slot.clip.duration) // seeking one member moves the group
|
|
291
|
-
}
|
|
292
|
-
setLoopValue(b: LoopRec, v: BlendPosition): void {
|
|
293
|
-
if (b.dead) { console.warn("Animator: this loop was replaced — use the object the latest playLoop() returned"); return }
|
|
294
|
-
b.value = v
|
|
295
|
-
if (!this.id) return
|
|
296
|
-
const [x, y] = typeof v === "number" ? [ v, 0 ] : [ v[0], v[1] ]
|
|
297
|
-
_creator.animatorSetBlendValue(this.id, b.layer.index, x, y)
|
|
298
|
-
}
|
|
299
|
-
/** What the layer shows this frame: every instance with a weight, in binding order (stable rows). */
|
|
300
|
-
active(L: LayerRec): ActiveClip[] {
|
|
301
|
-
const out: ActiveClip[] = []
|
|
302
|
-
for (const s of L.slots) {
|
|
303
|
-
const weight = this.slotWeight(s)
|
|
304
|
-
if (weight <= 0) continue
|
|
305
|
-
out.push({ name: s.name, clip: s.clip, weight, time: this.slotTime(s), loop: s.inBlend })
|
|
306
|
-
}
|
|
307
|
-
return out
|
|
308
|
-
}
|
|
309
|
-
slotWeight(s: SlotRec): number { return this.id && s.slot >= 0 ? _creator.animatorGetSlotWeight(this.id, s.slot) : 0 }
|
|
310
|
-
slotTime(s: SlotRec): number { return this.id && s.slot >= 0 ? _creator.animatorGetSlotTime(this.id, s.slot) : 0 }
|
|
311
|
-
seek(s: SlotRec, time: number): void { if (this.id && s.slot >= 0) _creator.animatorSeek(this.id, s.slot, time) }
|
|
312
|
-
|
|
313
|
-
// ---- props ----
|
|
314
|
-
setSpeed(v: number): void { this.speed = v; if (this.id) _creator.animatorSetGlobal(this.id, v, false) }
|
|
315
|
-
setRootMotion(on: boolean, rotation = false): void { if (this.ensure()) _creator.animatorSetRootMotion(this.id, on ? "*" : "", (on ? 2 : 0) | (on && rotation ? 4 : 0)) }
|
|
316
|
-
|
|
317
|
-
// ---- events ----
|
|
318
|
-
on(event: string, cb: ClipEventHandler): void { (this._listeners.get(event) ?? this._listeners.set(event, new Set()).get(event)!).add(cb) }
|
|
319
|
-
off(event: string, cb: ClipEventHandler): void { this._listeners.get(event)?.delete(cb) }
|
|
320
|
-
/** Native slot event: 0 completed / 1 loop / 2 settled (faded to 0) / 3 hand-over / 4+i clip event i. */
|
|
321
|
-
private onEvent(slotIndex: number, type: number): void {
|
|
322
|
-
let s: SlotRec | undefined
|
|
323
|
-
for (const L of this.layers) { s = L.slots.find((x) => x.slot === slotIndex); if (s) break }
|
|
324
|
-
if (!s) return
|
|
325
|
-
if (type >= 4) {
|
|
326
|
-
const name = s.clip._events[type - 4]?.name
|
|
327
|
-
const cbs = name ? this._listeners.get(name) : undefined
|
|
328
|
-
if (cbs) for (const cb of [ ...cbs ]) cb(s.name, s.layer.view)
|
|
329
|
-
return
|
|
330
|
-
}
|
|
331
|
-
const p = s.playback
|
|
332
|
-
if (!p) return
|
|
333
|
-
if (type === 3) this.settle(p, true) // hand-over: the clip is over; the app's next call redirects the fade
|
|
334
|
-
else if (type === 2) this.settle(p, false) // faded out after a stop / replacement before handing over
|
|
335
|
-
}
|
|
336
|
-
}
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
// AR object-placement controls — the classic "drop a model in the room and manipulate it" gesture
|
|
2
|
-
// recipe: ONE finger drags the target across the ground plane (camera-relative), TWO fingers pinch to
|
|
3
|
-
// scale and twist to rotate (yaw). Lives on ARScene (see Scene.ts) because it orchestrates the scene's
|
|
4
|
-
// camera + touch input against a target node; it's built entirely on the public API (no native calls
|
|
5
|
-
// the user couldn't make), so it's a convenience, not a primitive.
|
|
6
|
-
|
|
7
|
-
import { Vec2, Vec3 } from "../math/vec"
|
|
8
|
-
import { Quat } from "../math/quat"
|
|
9
|
-
import type { Node } from "./Node"
|
|
10
|
-
import type { Scene } from "./Scene"
|
|
11
|
-
import type { TouchStartEvent } from "../runtime/touch"
|
|
12
|
-
|
|
13
|
-
export type ControlsOptions = {
|
|
14
|
-
/** Smallest uniform scale the pinch gesture allows (default 0.08). */
|
|
15
|
-
minScale?: number
|
|
16
|
-
/** Largest uniform scale the pinch gesture allows (default 2). */
|
|
17
|
-
maxScale?: number
|
|
18
|
-
/** One-finger drag moves the target across the ground plane (default true). */
|
|
19
|
-
pan?: boolean
|
|
20
|
-
/** Two-finger pinch scales the target (default true). */
|
|
21
|
-
pinch?: boolean
|
|
22
|
-
/** Two-finger twist rotates the target around its Y axis (default true). */
|
|
23
|
-
twist?: boolean
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/** Returned by `addControls` — call `remove()` to detach the gesture listeners. */
|
|
27
|
-
export type ControlsHandle = { remove(): void }
|
|
28
|
-
|
|
29
|
-
type ActiveTouch = { pointerId: number, x: number, y: number }
|
|
30
|
-
|
|
31
|
-
const clamp = (v: number, lo: number, hi: number): number => (v < lo ? lo : v > hi ? hi : v)
|
|
32
|
-
|
|
33
|
-
export const attachControls = (scene: Scene, target: Node, options: ControlsOptions = {}): ControlsHandle => {
|
|
34
|
-
const minScale = options.minScale ?? 0.08
|
|
35
|
-
const maxScale = options.maxScale ?? 2
|
|
36
|
-
const pan = options.pan ?? true
|
|
37
|
-
const pinch = options.pinch ?? true
|
|
38
|
-
const twist = options.twist ?? true
|
|
39
|
-
|
|
40
|
-
const active: ActiveTouch[] = []
|
|
41
|
-
|
|
42
|
-
const onTouchStart = (e: TouchStartEvent<Node | null>): void => {
|
|
43
|
-
const touch: ActiveTouch = { pointerId: e.pointerId, x: e.clientX, y: e.clientY }
|
|
44
|
-
active.push(touch)
|
|
45
|
-
e.track({
|
|
46
|
-
onMove(m) {
|
|
47
|
-
if (active.length === 2) {
|
|
48
|
-
// --- two-finger: pinch-scale + twist-rotate about the gesture axis ---
|
|
49
|
-
const other = active.find((t) => t !== touch)
|
|
50
|
-
if (other) {
|
|
51
|
-
const axis = new Vec2(other.x - touch.x, other.y - touch.y)
|
|
52
|
-
const span = axis.length()
|
|
53
|
-
if (span > 1e-3) {
|
|
54
|
-
const dir = axis.scale(1 / span)
|
|
55
|
-
const delta = new Vec2(m.deltaX, m.deltaY)
|
|
56
|
-
if (pinch) {
|
|
57
|
-
const along = -dir.dot(delta) // movement along the pinch axis
|
|
58
|
-
target.scale = clamp(target.scale.x * (span + along) / span, minScale * 0.4, maxScale * 1.5)
|
|
59
|
-
}
|
|
60
|
-
if (twist) {
|
|
61
|
-
const tangent = dir.perp().dot(delta) // movement across the axis
|
|
62
|
-
target.quaternion = target.quaternion.mul(Quat.fromAxisAngle(Vec3.up, Math.atan2(tangent, span)))
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
} else if (active.length === 1 && pan) {
|
|
67
|
-
// --- one-finger: drag across the ground plane, relative to where the camera looks ---
|
|
68
|
-
let dir = scene.camera.forward
|
|
69
|
-
const parent = target.parent
|
|
70
|
-
if (parent) dir = dir.rotate(parent.quaternion.invert()) // into the parent's local frame
|
|
71
|
-
dir = dir.withY(0)
|
|
72
|
-
const k = Math.hypot(dir.x, dir.z)
|
|
73
|
-
const screen = Math.max(...scene.camera.displaySize)
|
|
74
|
-
if (k > 1e-4 && screen > 0) {
|
|
75
|
-
const dist = target.worldPosition.distanceTo(scene.camera.worldPosition)
|
|
76
|
-
const right = new Vec3(-dir.z, 0, dir.x).scale(m.deltaX / k / screen * dist)
|
|
77
|
-
const fwd = dir.scale(-m.deltaY / k / screen * dist)
|
|
78
|
-
const move = right.add(fwd)
|
|
79
|
-
const p = target.position
|
|
80
|
-
target.position = new Vec3(p.x + move.x, p.y, p.z + move.z) // keep height fixed
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
touch.x = m.clientX
|
|
84
|
-
touch.y = m.clientY
|
|
85
|
-
},
|
|
86
|
-
onEnd() {
|
|
87
|
-
const i = active.indexOf(touch)
|
|
88
|
-
if (i >= 0) active.splice(i, 1)
|
|
89
|
-
},
|
|
90
|
-
})
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
scene.addEventListener("touchstart", onTouchStart)
|
|
94
|
-
return { remove() { scene.removeEventListener("touchstart", onTouchStart); active.length = 0 } }
|
|
95
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
// Routes native physics contact/sensor events to the owning nodes' 'enter'/'exit' events. Each event
|
|
2
|
-
// is delivered to BOTH nodes with the other as the argument. type: 0 = enter (contact/overlap began),
|
|
3
|
-
// 1 = exit (ended). Registered lazily on the first trigger/physics body or 'enter'/'exit' listener.
|
|
4
|
-
|
|
5
|
-
import { nodeRegistry } from "./Node"
|
|
6
|
-
|
|
7
|
-
let registered = false
|
|
8
|
-
export const ensurePhysicsEvents = (): void => {
|
|
9
|
-
if (registered) return
|
|
10
|
-
if (!_creator.setOnPhysicsEvent) return // physics-less build / bridge without the hook
|
|
11
|
-
registered = true
|
|
12
|
-
_creator.setOnPhysicsEvent((a, b, type) => {
|
|
13
|
-
const na = nodeRegistry.get(a)
|
|
14
|
-
const nb = nodeRegistry.get(b)
|
|
15
|
-
if (!na || !nb) return
|
|
16
|
-
const channel = type === 1 ? "exit" : "enter"
|
|
17
|
-
na._emitCollision(channel, nb)
|
|
18
|
-
nb._emitCollision(channel, na)
|
|
19
|
-
})
|
|
20
|
-
}
|